feat(ai): on-device RAG over bookmarks + Spotlight indexing + unified logging
All checks were successful
CI / build-and-deploy (push) Successful in 22s

- SpotlightIndexer: actually push BookmarkEntity into the Spotlight index via
  indexAppEntities (IndexedEntity conformance alone indexes nothing). Wired into
  every sync/mutation point. This is what lets Apple Intelligence answer
  free-form Siri questions grounded in the user's bookmarks.
- On-device RAG: BookmarkAssistant (LanguageModelSession) + BookmarkSearchTool
  + SpotlightBookmarkSearch (CSSearchQuery retrieval), surfaced via AskView with
  lightweight Markdown rendering of answers.
- Log: os.Logger facility (com.magicive.marks) replacing ad-hoc print(); shared
  with ShareExtension. ClaudeService now logs server error bodies on non-2xx.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-06-24 12:55:32 -05:00
parent e82e69c5f3
commit 96ea5fe6f6
14 changed files with 499 additions and 18 deletions

43
Marks/Services/Log.swift Normal file
View File

@@ -0,0 +1,43 @@
import Foundation
import os
/// Organized, category-based logging for Marks, backed by `os.Logger`.
///
/// Unlike `print()` which only reaches stdout and is invisible to
/// `log collect` / Console.app these entries are captured under the
/// `com.magicive.marks` subsystem and can be filtered by category off-device.
///
/// Pull logs from a connected device:
/// ```
/// log collect --device-udid <UDID> --last 5m --output marks.logarchive
/// log show marks.logarchive --info --debug \
/// --predicate 'subsystem == "com.magicive.marks"'
/// # one category:
/// log show marks.logarchive --predicate \
/// 'subsystem == "com.magicive.marks" AND category == "assistant"'
/// ```
///
/// Privacy: `os.Logger` redacts interpolations to `<private>` by default. The
/// on-device RAG path (`assistant`, `tool`, `spotlight`) logs queries/counts as
/// `.public` so the feature is debuggable; bookmark *content* in the cloud
/// enrichment path stays default-private.
enum Log {
private static let subsystem = "com.magicive.marks"
/// On-device RAG: model availability, questions asked, answers produced.
static let assistant = Logger(subsystem: subsystem, category: "assistant")
/// The `searchBookmarks` tool the on-device model calls.
static let tool = Logger(subsystem: subsystem, category: "tool")
/// Spotlight retrieval (`CSSearchQuery`) and indexing (`indexAppEntities`).
static let spotlight = Logger(subsystem: subsystem, category: "spotlight")
/// Cloud AI enrichment (summaries, tags) via the backend.
static let ai = Logger(subsystem: subsystem, category: "ai")
/// Bookmark sync / disk cache.
static let sync = Logger(subsystem: subsystem, category: "sync")
/// Backend HTTP primitives (requests, status codes, error bodies).
static let network = Logger(subsystem: subsystem, category: "network")
/// Anonymous device auth / token registration.
static let auth = Logger(subsystem: subsystem, category: "auth")
/// Product analytics event delivery.
static let analytics = Logger(subsystem: subsystem, category: "analytics")
}