@extentos/mcp-server 0.0.93 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/tools/data/capabilityPatterns.d.ts.map +1 -1
  2. package/dist/tools/data/capabilityPatterns.js +250 -3
  3. package/dist/tools/data/capabilityPatterns.js.map +1 -1
  4. package/dist/tools/data/codeExamples.d.ts.map +1 -1
  5. package/dist/tools/data/codeExamples.js +421 -10
  6. package/dist/tools/data/codeExamples.js.map +1 -1
  7. package/dist/tools/data/version.d.ts +0 -1
  8. package/dist/tools/data/version.d.ts.map +1 -1
  9. package/dist/tools/data/version.js +9 -1
  10. package/dist/tools/data/version.js.map +1 -1
  11. package/dist/tools/definitions.d.ts.map +1 -1
  12. package/dist/tools/definitions.js +54 -3
  13. package/dist/tools/definitions.js.map +1 -1
  14. package/dist/tools/docs/index.d.ts.map +1 -1
  15. package/dist/tools/docs/index.js +115 -2
  16. package/dist/tools/docs/index.js.map +1 -1
  17. package/dist/tools/handlers/assertToolCalled.d.ts +3 -0
  18. package/dist/tools/handlers/assertToolCalled.d.ts.map +1 -0
  19. package/dist/tools/handlers/assertToolCalled.js +171 -0
  20. package/dist/tools/handlers/assertToolCalled.js.map +1 -0
  21. package/dist/tools/handlers/getProductionChecklist.d.ts.map +1 -1
  22. package/dist/tools/handlers/getProductionChecklist.js +60 -9
  23. package/dist/tools/handlers/getProductionChecklist.js.map +1 -1
  24. package/dist/tools/handlers/injectAssistantUtterance.d.ts +3 -0
  25. package/dist/tools/handlers/injectAssistantUtterance.d.ts.map +1 -0
  26. package/dist/tools/handlers/injectAssistantUtterance.js +139 -0
  27. package/dist/tools/handlers/injectAssistantUtterance.js.map +1 -0
  28. package/dist/tools/handlers/validateIntegration.d.ts.map +1 -1
  29. package/dist/tools/handlers/validateIntegration.js +168 -0
  30. package/dist/tools/handlers/validateIntegration.js.map +1 -1
  31. package/dist/tools/registry.d.ts.map +1 -1
  32. package/dist/tools/registry.js +4 -0
  33. package/dist/tools/registry.js.map +1 -1
  34. package/dist/tools/templates/androidBootstrap.d.ts.map +1 -1
  35. package/dist/tools/templates/androidBootstrap.js +35 -0
  36. package/dist/tools/templates/androidBootstrap.js.map +1 -1
  37. package/package.json +1 -1
@@ -1604,20 +1604,63 @@ The agent reads each \`speak\` event's \`details.text\` — that is what the app
1604
1604
  };
1605
1605
  const CONVERSATION_AGENT_LOOP = {
1606
1606
  pattern: "conversation_agent_loop",
1607
- title: "Phase 3 conversation runtime + agent-driven E2E loop",
1608
- description: "The Phase 3 `glasses.conversation.onWake { listen() / speak() / ai.complete() }` API in one place, plus the headless agent loop that verifies it end-to-end via `injectTranscript` + `getEventLog`. The runtime composes VAD + STT + Smart Turn + TTS + BYOK LLM in the shared Rust core the customer code is one block of structured-concurrency Kotlin/Swift. The agent loop drives wake + follow-up utterances via MCP, then asserts symmetric `conversation.handler_started`/`turn_started`/`turn_ended`/`handler_finished` pairs in the event log. Pair this with `voice_qa_assistant` (which uses the legacy `recordDiscrete` API) when comparing the two paths.",
1607
+ title: "LEGACY Phase 3 conversation runtime (DEPRECATED in v1.4.0; removed in v2.0.0 — use assistant_agent_loop for new apps)",
1608
+ description: "**LEGACY — DEPRECATED in v1.4.0; removed entirely in v2.0.0.** For new voice-assistant work use `assistant_agent_loop` (Phase 4 `glasses.assistant.start { tool(...) { ... } }`). The Phase 4 customer surface drops ~60% LoC vs this pattern, ships zero on-device ML (no ONNX models to bundle), and lets the model decide which tool to call instead of the customer hand-writing `when (turn.text)` keyword routing. This Phase 3 pattern stays in the catalog for the v1.4.0 v2.0.0 migration window (3-month deprecation period) — existing apps continue to work unchanged. See `searchDocs(topic:'assistant_runtime')` migration section for the side-by-side Phase 3 → Phase 4 walkthrough. The Phase 3 `glasses.conversation.onWake { listen() / speak() / ai.complete() }` API composes VAD + STT + Smart Turn + TTS + BYOK LLM in the shared Rust core; the agent loop here drives wake + follow-up utterances via `injectTranscript` and asserts symmetric `conversation.*` event pairs.",
1609
1609
  code: {
1610
- kotlin: `import com.extentos.glasses.core.ExtentosGlasses
1610
+ kotlin: `// ── Application bootstrap (do once, typically in Application.onCreate
1611
+ // after RECORD_AUDIO is granted) ────────────────────────────────────
1612
+ //
1613
+ // The conversation runtime needs two ONNX models — Silero VAD (~2.2 MB)
1614
+ // and Smart Turn v3 (~8.7 MB) — bundled inside the glasses-core AAR.
1615
+ // ConversationModels.ensureExtracted() copies them from AAR assets to
1616
+ // the app's cacheDir on first launch and is idempotent on subsequent
1617
+ // calls. Run in a coroutine on Dispatchers.IO (the helper switches
1618
+ // internally; just call from a suspend context).
1619
+ import com.extentos.glasses.core.ConversationCoreOptions
1620
+ import com.extentos.glasses.core.ConversationConfig
1621
+ import com.extentos.glasses.core.ConversationModels
1622
+ import com.extentos.glasses.core.ExtentosConfig
1623
+ import com.extentos.glasses.core.ExtentosGlasses
1624
+ import com.extentos.glasses.core.SttConfig
1611
1625
  import com.extentos.glasses.core.Turn
1626
+ import com.extentos.glasses.core.TtsConfig
1627
+
1628
+ suspend fun createGlasses(context: android.content.Context): ExtentosGlasses {
1629
+ val models = ConversationModels.ensureExtracted(context)
1630
+ return ExtentosGlasses.create(
1631
+ ExtentosConfig(
1632
+ applicationContext = context,
1633
+ conversationOptions = ConversationCoreOptions(
1634
+ config = ConversationConfig(
1635
+ stt = SttConfig(provider = "openai", backup = null),
1636
+ tts = TtsConfig(provider = "openai", voice = "alloy", backup = null),
1637
+ model = "openai/gpt-4o-mini",
1638
+ modelBackup = null,
1639
+ coalesceTrailingSilenceMs = 600u,
1640
+ bargeIn = true,
1641
+ vadSpeechThreshold = 0.5f,
1642
+ ),
1643
+ sileroVadModelPath = models.sileroVadPath,
1644
+ smartTurnModelPath = models.smartTurnPath,
1645
+ backendBaseUrl = "https://api.extentos.com",
1646
+ aiEndpoint = null, // null = OpenAI direct (BYOK)
1647
+ ),
1648
+ )
1649
+ ).also { glasses ->
1650
+ // BYOK OpenAI key — see getCredentialGuide(service:"openai")
1651
+ // for the local.properties + resValue plumbing.
1652
+ glasses.ai?.setOpenaiApiKey(BuildConfig.OPENAI_API_KEY)
1653
+ }
1654
+ }
1655
+
1656
+ // ── Handler class — register once after createGlasses(...) returns ────
1612
1657
 
1613
1658
  class AssistantHandler(
1614
1659
  private val glasses: ExtentosGlasses,
1615
1660
  ) {
1616
1661
  fun start() {
1617
- // glasses.ai requires a BYOK OpenAI key set once at app
1618
- // init. Key flows direct to OpenAI (no Extentos proxy);
1619
- // never logged, never persisted. See getCredentialGuide.
1620
- glasses.ai?.setOpenaiApiKey(BuildConfig.OPENAI_API_KEY)
1662
+ // glasses.ai key was set in createGlasses(); no need to repeat
1663
+ // here. setOpenaiApiKey is idempotent if you do.
1621
1664
 
1622
1665
  // onWake registers a wake phrase + handler block. The block
1623
1666
  // runs under structured concurrency inside a ConversationScope —
@@ -1670,14 +1713,47 @@ class AssistantHandler(
1670
1713
  }`,
1671
1714
  swift: `import GlassesCore
1672
1715
 
1716
+ // ── App bootstrap (do once, e.g. in App.init or your DI container) ────
1717
+ //
1718
+ // The conversation runtime needs two ONNX models — Silero VAD (~2.2 MB)
1719
+ // and Smart Turn v3 (~8.7 MB) — bundled as resources in the GlassesCore
1720
+ // Swift package. ConversationModels.paths resolves them via
1721
+ // Bundle.module synchronously (no copy step is needed; iOS bundle
1722
+ // resources are file URLs directly).
1723
+ func makeGlasses() async throws -> ExtentosGlasses {
1724
+ let models = ConversationModels.paths
1725
+ let glasses = try await Extentos.create(
1726
+ ExtentosConfig(
1727
+ conversation: ConversationCoreOptions(
1728
+ config: ConversationConfig(
1729
+ stt: SttConfig(provider: "openai", backup: nil),
1730
+ tts: TtsConfig(provider: "openai", voice: "alloy", backup: nil),
1731
+ model: "openai/gpt-4o-mini",
1732
+ modelBackup: nil,
1733
+ coalesceTrailingSilenceMs: 600,
1734
+ bargeIn: true,
1735
+ vadSpeechThreshold: 0.5
1736
+ ),
1737
+ sileroVadModelPath: models.sileroVadPath,
1738
+ smartTurnModelPath: models.smartTurnPath,
1739
+ backendBaseUrl: "https://api.extentos.com",
1740
+ aiEndpoint: nil // nil = OpenAI direct (BYOK)
1741
+ )
1742
+ )
1743
+ )
1744
+ glasses.ai?.setOpenAiApiKey(Secrets.openAiKey)
1745
+ return glasses
1746
+ }
1747
+
1748
+ // ── Handler — register once after makeGlasses() returns ───────────────
1749
+
1673
1750
  final class AssistantHandler {
1674
1751
  private let glasses: ExtentosGlasses
1675
1752
 
1676
1753
  init(_ glasses: ExtentosGlasses) { self.glasses = glasses }
1677
1754
 
1678
1755
  func start() {
1679
- // BYOK OpenAI key set once at app init.
1680
- glasses.ai?.setOpenAiApiKey(Secrets.openAiKey)
1756
+ // BYOK OpenAI key was set in makeGlasses(); harmless to repeat.
1681
1757
 
1682
1758
  // onWake's handler closure receives a ConversationHandler whose
1683
1759
  // listen / speak / cancelSpeak proxy to the same core. \`glasses.ai\`
@@ -1819,12 +1895,346 @@ browser side-by-side with this agent loop and watch the panel react.`,
1819
1895
  "**Wait for `turn_started` before injecting the question.** The H1 bridge only resolves listen() — if you inject text before the handler is parked, the inject lands in the void (DefaultConversationClient's H1 forwarder returns false; the text is dropped, no FSM state poisoning). Watching for `conversation.turn_started` proves the handler reached its listen() before the next inject.",
1820
1896
  "**The PII boundary is real.** `details.textLen` is the only field carrying user-input length. The transcript text itself never appears in the event log. If you need the actual text for an LLM evaluator, you'll need a separate channel — Phase 3 deliberately doesn't ship a backdoor.",
1821
1897
  "**`glasses.conversation` and `glasses.ai` are nullable.** Both are null when the host app didn't pass `ExtentosConfig.conversationOptions` (the manifest's `conversation` block was absent). Phase 3 is opt-in to avoid the ~10 MB model load cost for voice-only apps. Use `glasses.conversation?.onWake(...)` defensively.",
1822
- "**Smart Turn requires the silero_vad + smart-turn-v3.2-cpu ONNX models bundled as assets.** Host app discovers their paths and passes them in `ConversationCoreOptions`. Missing model files raise `ConversationCoreException.VadModelLoad` / `SmartTurnModelLoad` at app init — the library logs warn-level and leaves `glasses.conversation` null (rest of the library stays usable). Check `glasses.runtime.events` for `conversation.init_failed` if your conversation surface is unexpectedly null.",
1898
+ "**Smart Turn + Silero VAD ONNX models ship inside the library.** `silero_vad.onnx` (~2.2 MB) + `smart-turn-v3.2-cpu.onnx` (~8.7 MB) are bundled in the `glasses-core` AAR (Android assets/) and the `GlassesCore` Swift package (Resources/). Resolve their paths with `ConversationModels.ensureExtracted(context)` on Android (suspend; copies AAR assets to cacheDir on first launch, idempotent on subsequent calls) or `ConversationModels.paths` on iOS (synchronous; `Bundle.module.url(forResource:withExtension:)` lookup). Both helpers are shown in the `kotlin` / `swift` snippets above. Bypassing the helpers by passing made-up paths raises `ConversationCoreException.VadModelLoad` / `SmartTurnModelLoad` at app init — the library logs warn-level and leaves `glasses.conversation` null; check `glasses.runtime.events` for `conversation.init_failed` if your conversation surface is unexpectedly null.",
1823
1899
  "**OpenAI API key flows direct, not via Extentos.** synthesis §6 + plan §4.3 BYOK contract — `glasses.ai.complete()` POSTs straight to `https://api.openai.com/v1/chat/completions` with the key in the `Authorization: Bearer` header. The Extentos backend doesn't see the key. Test endpoint override is `ConversationCoreOptions.aiEndpoint` (also the swap point for the future Track-B AI Gateway).",
1824
1900
  "**`ai_stream` is deferred core-side.** v1 ships `complete()` only — single-turn, non-streaming. If your handler needs streaming responses (long answers, perceived latency), you'll either chunk on the customer side or wait for v1.1's ai_stream surface.",
1825
1901
  ],
1826
1902
  relatedFeatures: ["voice_command", "speak", "transcription_incremental", "ai_call", "smart_turn_eou"],
1827
1903
  };
1904
+ const ASSISTANT_AGENT_LOOP = {
1905
+ pattern: "assistant_agent_loop",
1906
+ title: "Phase 4 assistant runtime + agent-driven E2E loop (canonical voice-AI for new apps)",
1907
+ description: "**Canonical Phase 4 voice-AI pattern. Start here for any new voice assistant work on Extentos.** The customer code is one block: `glasses.assistant.start(provider) { tool(name, description) { body -> ToolResult } }`. The model owns wake detection, turn taking, intent parsing, and confirmation speech — the customer only writes tool bodies that act on the app's own state (route data, app DB, camera, library). Provider abstraction wraps OpenAI Realtime in v1; Gemini Live follows. The agent-test loop drives utterances via `injectAssistantUtterance` (Mock provider — deterministic, $0) and asserts via `assertToolCalled`, closing E2E verification without humans. **This replaces `conversation_agent_loop` (Phase 3 cascaded VAD+STT+SmartTurn+TTS+LLM) which is deprecated in v1.4.0 and removed in v2.0.0.** Customer code typically drops ~60% LoC vs Phase 3.",
1908
+ code: {
1909
+ kotlin: `// ── Application bootstrap (do once in Application.onCreate after
1910
+ // RECORD_AUDIO is granted) ──────────────────────────────────────────
1911
+ //
1912
+ // No ONNX models, no model paths, no cascaded options — Phase 4 ships
1913
+ // end-to-end via the provider's WebSocket. glasses.assistant is
1914
+ // always-on (no opt-in conversationOptions needed).
1915
+ import com.extentos.glasses.core.ExtentosConfig
1916
+ import com.extentos.glasses.core.ExtentosGlasses
1917
+ import com.extentos.glasses.core.assistant.AssistantProvider
1918
+ import com.extentos.glasses.core.assistant.ToolResult
1919
+ import com.extentos.glasses.core.assistant.tool
1920
+
1921
+ suspend fun createGlasses(context: android.content.Context): ExtentosGlasses {
1922
+ return ExtentosGlasses.create(
1923
+ ExtentosConfig(applicationContext = context)
1924
+ ).also { glasses ->
1925
+ // BYOK OpenAI key — see getCredentialGuide(service:"openai") for
1926
+ // the local.properties + resValue plumbing. Key flows direct from
1927
+ // device → api.openai.com via WS Authorization header; Extentos
1928
+ // backend never sees it.
1929
+ glasses.assistant.setOpenaiApiKey(BuildConfig.OPENAI_API_KEY)
1930
+ }
1931
+ }
1932
+
1933
+ // ── Handler — Strava-style example. Wire after createGlasses returns. ──
1934
+
1935
+ class StravaAssistantHandler(
1936
+ private val glasses: ExtentosGlasses,
1937
+ private val routeTracker: RouteTracker, // app-internal state
1938
+ private val library: ClipLibrary, // app-internal state
1939
+ private val scope: kotlinx.coroutines.CoroutineScope,
1940
+ ) {
1941
+ private var activeVideo: kotlinx.coroutines.Deferred<*>? = null
1942
+
1943
+ fun start() {
1944
+ // Sugar form (the trailing-lambda builder). The block runs once
1945
+ // at start to register tools + instructions; \`session.update\` is
1946
+ // sent to OpenAI and the audio pump engages. Returns when the
1947
+ // session reaches Active state.
1948
+ scope.launch {
1949
+ glasses.assistant.start(
1950
+ provider = AssistantProvider.OpenAi(
1951
+ model = "gpt-realtime",
1952
+ voice = "alloy",
1953
+ ),
1954
+ ) {
1955
+ instructions = """
1956
+ You are a Strava companion. Help the runner with route
1957
+ stats and capture moments. Speak briefly — they're
1958
+ running. Don't narrate what you're doing — just do it
1959
+ and confirm.
1960
+ """.trimIndent()
1961
+
1962
+ // Read-tools: instant data the AI reads aloud or weaves
1963
+ // into the answer.
1964
+ tool("get_route_remaining", "How much of the planned route is left, in km.") {
1965
+ ToolResult.Ok("\${routeTracker.kmRemaining()} km remaining")
1966
+ }
1967
+ tool("get_average_pace", "Current average pace in minutes per km.") {
1968
+ ToolResult.Ok("\${routeTracker.avgPaceMinKm()} min per km")
1969
+ }
1970
+ tool("get_route_length", "Total planned route length in km.") {
1971
+ ToolResult.Ok("\${routeTracker.totalKm} km")
1972
+ }
1973
+
1974
+ // Action-tools: side effects on the app's own state. The
1975
+ // AI manages the take/stop pair — it knows from context
1976
+ // that stop_video pairs with take_video.
1977
+ tool("take_video", "Start recording a video clip of the runner's view.") {
1978
+ activeVideo = scope.async {
1979
+ glasses.camera.captureVideo(
1980
+ VideoConfig(maxDurationSeconds = 30),
1981
+ )
1982
+ }
1983
+ ToolResult.Ok("recording started")
1984
+ }
1985
+ tool("stop_video", "Stop the current video recording.") {
1986
+ // Cooperative cancellation: cancel the Deferred awaiting
1987
+ // captureVideo. The library's transport layer catches the
1988
+ // cancellation, fires core.abortCaptureVideo() internally,
1989
+ // and surfaces a partial clip (or nothing if cancel landed
1990
+ // before any frames). There is no glasses.camera.stopVideo()
1991
+ // — Deferred cancellation IS the customer-facing stop
1992
+ // mechanism. Matches the iOS Task.cancel() pattern.
1993
+ val pending = activeVideo
1994
+ activeVideo = null
1995
+ if (pending == null) return@tool ToolResult.Err("nothing was recording")
1996
+ pending.cancel()
1997
+ val clip = runCatching { pending.await().valueOrNull() }.getOrNull()
1998
+ clip?.let { library.add(it); ToolResult.Ok("video saved") }
1999
+ ?: ToolResult.Err("nothing was recording")
2000
+ }
2001
+ }
2002
+ }
2003
+ }
2004
+ }
2005
+
2006
+ // ── Raw form — equivalent, for programmatic construction (tools loaded
2007
+ // from config, conditional registration). Customer-can-skip-it: the
2008
+ // trailing-lambda builder above reduces to this. ────────────────────
2009
+
2010
+ import com.extentos.glasses.core.assistant.AssistantConfig
2011
+ import com.extentos.glasses.core.assistant.ToolDefinition
2012
+
2013
+ suspend fun startRawForm(glasses: ExtentosGlasses) {
2014
+ val session = glasses.assistant.createSession(
2015
+ AssistantConfig(
2016
+ provider = AssistantProvider.OpenAi(model = "gpt-realtime", voice = "alloy"),
2017
+ instructions = "You are a helpful assistant.",
2018
+ tools = listOf(
2019
+ ToolDefinition("take_picture", "Take a photo when asked.") { _ ->
2020
+ ToolResult.Ok("photo saved")
2021
+ },
2022
+ ),
2023
+ ),
2024
+ )
2025
+ session.start()
2026
+ }`,
2027
+ swift: `import GlassesCore
2028
+
2029
+ // ── App bootstrap (do once, e.g. in App.init or DI container) ─────────
2030
+ //
2031
+ // Phase 4 is end-to-end via the provider's WebSocket — no ONNX models
2032
+ // to bundle, no cascaded options. glasses.assistant is always-on.
2033
+ // \`Extentos.create(config:)\` is synchronous + non-throwing on iOS.
2034
+ func makeGlasses() -> ExtentosGlasses {
2035
+ let glasses = Extentos.create(config: ExtentosConfig())
2036
+ // BYOK OpenAI key — see getCredentialGuide(service:"openai") for the
2037
+ // Info.plist plumbing. Key flows direct from device → api.openai.com
2038
+ // via WS Authorization header; Extentos backend never sees it.
2039
+ glasses.assistant.setOpenAiApiKey(Secrets.openAiKey)
2040
+ return glasses
2041
+ }
2042
+
2043
+ // ── Handler — Strava-style example ────────────────────────────────────
2044
+ //
2045
+ // Plain final class (not @MainActor) so the @Sendable tool-body
2046
+ // closures can call into the handler without forcing every access
2047
+ // through an actor hop. State mutation (\`activeVideo\`) is single-
2048
+ // dispatch in practice — OpenAi + Mock providers serialize per-call_id
2049
+ // tool dispatch in v1.
2050
+
2051
+ final class StravaAssistantHandler: @unchecked Sendable {
2052
+ private let glasses: ExtentosGlasses
2053
+ private let routeTracker: RouteTracker // app-internal
2054
+ private let library: ClipLibrary // app-internal
2055
+ private var activeVideo: Task<VideoClip?, Never>?
2056
+
2057
+ init(glasses: ExtentosGlasses, routeTracker: RouteTracker, library: ClipLibrary) {
2058
+ self.glasses = glasses
2059
+ self.routeTracker = routeTracker
2060
+ self.library = library
2061
+ }
2062
+
2063
+ func start() async throws {
2064
+ // Sugar form (trailing-closure builder). Returns once the session
2065
+ // reaches Active. Q3 asymmetry: Swift's typed-args overload
2066
+ // requires an explicit \`schema:\` parameter (no Mirror walk on
2067
+ // types — see assistant_tool capability guide).
2068
+ _ = try await glasses.assistant.start(
2069
+ provider: .openAI(model: "gpt-realtime", voice: "alloy")
2070
+ ) { config in
2071
+ config.instructions = """
2072
+ You are a Strava companion. Help the runner with route
2073
+ stats and capture moments. Speak briefly — they're
2074
+ running. Don't narrate what you're doing — just do it.
2075
+ """
2076
+
2077
+ // Read-tools
2078
+ config.tool("get_route_remaining", description: "How much of the planned route is left, in km.") {
2079
+ .ok("\\(self.routeTracker.kmRemaining()) km remaining")
2080
+ }
2081
+ config.tool("get_average_pace", description: "Current average pace in minutes per km.") {
2082
+ .ok("\\(self.routeTracker.avgPaceMinKm()) min per km")
2083
+ }
2084
+ config.tool("get_route_length", description: "Total planned route length in km.") {
2085
+ .ok("\\(self.routeTracker.totalKm) km")
2086
+ }
2087
+
2088
+ // Action-tools — fire-and-forget via Task; stop_video cancels
2089
+ // the activeVideo task + reads its (possibly partial) result.
2090
+ // Camera's captureVideo returns \`ExtentosResult<VideoClip,
2091
+ // CaptureError>\` async — we extract the success branch into
2092
+ // an optional clip via the \`.success\` accessor.
2093
+ config.tool("take_video", description: "Start recording a video clip of the runner's view.") {
2094
+ self.activeVideo = Task {
2095
+ let result = await self.glasses.camera.captureVideo(
2096
+ VideoConfig(maxDurationSeconds: 30)
2097
+ )
2098
+ return result.success
2099
+ }
2100
+ return .ok("recording started")
2101
+ }
2102
+ config.tool("stop_video", description: "Stop the current video recording.") {
2103
+ // Cooperative cancellation: the camera capture finishes
2104
+ // its current chunk and surfaces a partial clip (or
2105
+ // nothing if the cancel landed before any frames).
2106
+ self.activeVideo?.cancel()
2107
+ let clip = await self.activeVideo?.value ?? nil
2108
+ self.activeVideo = nil
2109
+ if let clip {
2110
+ self.library.add(clip)
2111
+ return .ok("video saved")
2112
+ } else {
2113
+ return .err("nothing was recording")
2114
+ }
2115
+ }
2116
+ }
2117
+ }
2118
+ }
2119
+
2120
+ // ── Raw form — equivalent, for programmatic construction ──────────────
2121
+
2122
+ func startRawForm(_ glasses: ExtentosGlasses) async throws {
2123
+ let session = glasses.assistant.createSession(config: AssistantConfig(
2124
+ provider: .openAI(model: "gpt-realtime", voice: "alloy"),
2125
+ instructions: "You are a helpful assistant.",
2126
+ tools: [
2127
+ ToolDefinition(name: "take_picture", description: "Take a photo when asked.") { _ in
2128
+ .ok("photo saved")
2129
+ },
2130
+ ]
2131
+ ))
2132
+ try await session.start()
2133
+ }`,
2134
+ },
2135
+ explanation: `AGENT-DRIVEN E2E TEST LOOP — RUN AFTER createGlasses + handler.start()
2136
+
2137
+ The headless verification: drive the assistant with synthetic utterances,
2138
+ assert the expected tools fire, then read the event log. Two providers
2139
+ satisfy the same agent loop:
2140
+
2141
+ - AssistantProvider.Mock — deterministic, sub-millisecond, $0. Word-
2142
+ overlap-matches the injected utterance against tool descriptions
2143
+ and dispatches the first match. Use for CI + tight inner loop.
2144
+ - AssistantProvider.OpenAi — real WebSocket to api.openai.com,
2145
+ real LLM picks the tool, real audio output. Use for end-to-end
2146
+ smoke when the sim browser tab has mic input.
2147
+
2148
+ // Mock-provider path — set useMockProvider when constructing the
2149
+ // handler in your dogfood / test build. Production stays on OpenAi.
2150
+ const { sessionId } = await createSimulatorSession({
2151
+ glasses: "meta_rayban", platform: "android",
2152
+ });
2153
+ // Anchor cursor BEFORE inject so a fresh log read starts at 'now'.
2154
+ const head = await getEventLog({ sessionId, filter: "voice", limit: 1 });
2155
+ let cur = head.cursor;
2156
+
2157
+ // 1. Inject the utterance. text: routes to MockAssistantProvider via
2158
+ // the BrowserSim raw-frame observer (S2.W.0 wiring).
2159
+ await injectAssistantUtterance({ sessionId, text: "take a picture" });
2160
+
2161
+ // 2. Assert the expected tool was called within the timeout.
2162
+ const call = await assertToolCalled({
2163
+ sessionId, name: "take_picture", timeoutMs: 5000,
2164
+ });
2165
+ // call.args is the parsed JsonObject from the tool's args schema
2166
+ // (or {} for no-arg tools); call.call_id pairs with the result event.
2167
+
2168
+ // 3. (Optional) Read the full event-log trace for assertions on the
2169
+ // speak transcript, the tool result, etc.
2170
+ const log = await getEventLog({
2171
+ sessionId, cursor: cur, filter: "voice",
2172
+ });
2173
+ // Expected events (in order):
2174
+ // assistant.user_spoke transcript="take a picture"
2175
+ // assistant.tool_called name="take_picture", call_id
2176
+ // assistant.tool_result name="take_picture", output, is_error,
2177
+ // duration_ms
2178
+ // assistant.assistant_spoke transcript="ok, take_picture" (Mock
2179
+ // synthesizes; OpenAi has the model
2180
+ // speak its own confirmation)
2181
+
2182
+ // 4. To drive a multi-utterance flow, just repeat steps 1-3 with the
2183
+ // next text. The session stays Active across injects until you
2184
+ // explicitly stop it.
2185
+
2186
+ WHAT GETS LOGGED — assistant.* event family (per synthesis #15)
2187
+
2188
+ assistant.session_started provider, model, voice
2189
+ assistant.session_ended reason (user / error / ceiling), message
2190
+ assistant.user_spoke transcript (verbatim — see PII note below)
2191
+ assistant.assistant_spoke transcript (verbatim)
2192
+ assistant.tool_called name, args (JsonObject), call_id
2193
+ assistant.tool_result call_id, name, output, is_error, duration_ms
2194
+ assistant.reconnected reason, downtime_ms (synthesis #23
2195
+ transparent 60-min ceiling + onFailure
2196
+ recovery — library hides this from
2197
+ customers; observable here for debugging)
2198
+ assistant.error kind, message (non-fatal; fatal errors
2199
+ emit session_ended(error))
2200
+
2201
+ PII BOUNDARY — Phase 4 differs from Phase 3 conversation.* events
2202
+
2203
+ Phase 4 assistant events DO carry verbatim transcripts in
2204
+ user_spoke / assistant_spoke. Phase 3 conversation.* events strip
2205
+ text (only text_len) because the cascaded path routed transcripts
2206
+ through Extentos backend. Phase 4's BYOK contract sends transcripts
2207
+ device → openai.com directly without touching Extentos backend, so
2208
+ the platform-side PII boundary that Phase 3 enforced doesn't apply.
2209
+ Customer apps own their data retention story.
2210
+
2211
+ FILTER QUICK REFERENCE
2212
+
2213
+ - filter: "voice" → all assistant.* events + legacy stt_/speak/
2214
+ audio_/tts_audio_chunk frames coexist here
2215
+ - filter: "errors" → assistant.error AUTOMATICALLY (the backend
2216
+ bumps severity to warn for this type)
2217
+
2218
+ SIMULATOR UI
2219
+
2220
+ The sim's right rail renders an AssistantPanel showing the active
2221
+ session's provider + model + voice + current state. Recent turns
2222
+ appear as colored chips (UserSpoke=sky, AssistantSpoke=emerald,
2223
+ ToolCalled→Result=indigo, Error=red). Open the sim browser side-by-
2224
+ side with this agent loop and watch the panel react.`,
2225
+ gotchas: [
2226
+ "**Anchor a cursor BEFORE the first inject.** A no-cursor getEventLog returns the tail of the log + a cursor positioned after it — that's your 'now' bookmark. Without it, a resumed sim's stale assistant.tool_called from a prior run can satisfy your assertion and you'd never know the new inject silently failed.",
2227
+ "**Mock provider matches utterances by word overlap (≥3 chars) against tool descriptions.** Tool descriptions whose keywords appear in your test utterances get matched; ones without don't. Write descriptions like \"Take a photo when the user asks to capture a moment\" rather than \"Captures imagery via the camera SDK\" — both the model AND the Mock matcher work better when descriptions describe WHEN to call, not what they do internally. For deterministic tests with ambiguous text, use `argsMatch` on assertToolCalled to constrain the matched call further.",
2228
+ "**Mock provider only attaches when transport is BrowserSim.** RealMeta + LocalSim sessions silently no-op the inject subscription (Mock is sim-only by design). To test against the OpenAi provider in sim, open the sim browser tab — its mic input flows through audio_chunks → OpenAI WebSocket → tool dispatch. injectAssistantUtterance.text: still works against Mock; for real-provider audio injection use the sim browser mic or wait for v1.1's audioWavBase64 path.",
2229
+ "**No ONNX models, no model paths, no conversationOptions.** Phase 4 ships zero on-device ML — the provider's WebSocket carries everything. If you're carrying old conversationOptions / ConversationModels code from Phase 3, delete it during migration (see `searchDocs(topic:'assistant_runtime')` → migration section). The deprecation warning fires on first `glasses.conversation.*` call in v1.4.0; the API is removed in v2.0.0.",
2230
+ "**Singleton-active sessions — synthesis #13.** At most one assistant.start at a time per ExtentosGlasses instance. A second start while one is active throws AssistantException(AlreadyActive). Call assistant.stop() (or session.stop()) before starting a new one. For v1 simplicity; can relax in v1.x if customer demand surfaces.",
2231
+ "**Reconnection is library-owned + transparent — synthesis #23.** OpenAI Realtime hard-caps sessions at 60 min; the library proactively reconnects every ~50 min (configurable in v1.1+). assistant.reconnected fires for observability; customer code doesn't see the swap. Conversation history is replayed (recent 40 turns) on each reconnect. Tool dispatches in flight at reconnect time are preserved.",
2232
+ "**Tool body runs on Dispatchers.IO (Kotlin) / Swift Task (Swift); suspending camera/storage/HTTP calls are fine.** Per-tool blocking opt-out via `tool(name, desc, blocking = true) { ... }` per synthesis #9 — when true, the model waits silently for the result before speaking. Default is non-blocking (model says \"let me check...\" while the tool runs). Use blocking=true for sub-100ms tools where the filler would be awkward (\"what time is it\" returning in 10 ms).",
2233
+ "**BYOK key flows direct, not via Extentos.** synthesis §12. `glasses.assistant.setOpenaiApiKey(key)` stores the key in the AssistantClient. When start() opens a WebSocket, the key goes into `Authorization: Bearer ...` for the wss://api.openai.com/v1/realtime?model=gpt-realtime connection. Extentos backend never sees the key. Test endpoint override is on the AssistantProvider.OpenAi case if you need to point at a mock OpenAI proxy.",
2234
+ "**`glasses.ai.complete` is deprecated in v1.4.0 and removed in v2.0.0.** Use the OpenAI SDK directly for non-voice LLM calls (image description, summarization, etc.). Migration: see `searchDocs(topic:'assistant_runtime')` → migration section walkthrough C.",
2235
+ ],
2236
+ relatedFeatures: ["assistant_runtime", "assistant_start", "assistant_tool", "assistant_provider_openai", "audio_chunks", "speak"],
2237
+ };
1828
2238
  export const CODE_EXAMPLES = {
1829
2239
  voice_qa_assistant: VOICE_QA_ASSISTANT,
1830
2240
  barge_in_speak: BARGE_IN_SPEAK,
@@ -1834,6 +2244,7 @@ export const CODE_EXAMPLES = {
1834
2244
  connection_page_setup: CONNECTION_PAGE_SETUP,
1835
2245
  byok_anthropic: BYOK_ANTHROPIC,
1836
2246
  agent_test_loop: AGENT_TEST_LOOP,
2247
+ assistant_agent_loop: ASSISTANT_AGENT_LOOP,
1837
2248
  conversation_agent_loop: CONVERSATION_AGENT_LOOP,
1838
2249
  };
1839
2250
  export const CODE_EXAMPLE_PATTERNS = Object.keys(CODE_EXAMPLES).sort();
@@ -1 +1 @@
1
- {"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"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"}
@@ -23,7 +23,6 @@ export declare const VERSION_INFO: {
23
23
  android: {
24
24
  core: string;
25
25
  ui: string;
26
- debug: string;
27
26
  };
28
27
  ios: {
29
28
  package: string;
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DxB,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkExB,CAAC"}
@@ -61,7 +61,15 @@ export const VERSION_INFO = {
61
61
  android: {
62
62
  core: "com.extentos:glasses:1.3.0",
63
63
  ui: "com.extentos:glasses-ui:1.3.0",
64
- debug: "com.extentos:glasses-debug:1.3.0",
64
+ // glasses-debug is NOT yet a real Android module. iOS has a `GlassesDebug`
65
+ // product in the Swift package (see ios.products below), but the Android
66
+ // equivalent was never scaffolded into `android-library/settings.gradle.kts`
67
+ // and never published to Maven Central. Surfacing a phantom artifact here
68
+ // caused agents that wrote `implementation("com.extentos:glasses-debug:…")`
69
+ // to dead-end at "Could not find" at gradle resolve. Re-add this entry
70
+ // once a `glasses-debug` Gradle module exists AND its AAR is published.
71
+ // generateConnectionModule + manifest.ts already exclude it from emission;
72
+ // this just stops it appearing in `getPlatformInfo.artifacts.android`.
65
73
  },
66
74
  ios: {
67
75
  package: "https://github.com/extentos/swift-glasses",
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,qEAAqE;AACrE,2DAA2D;AAC3D,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,8DAA8D;AAC9D,uEAAuE;AACvE,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;QACd,yEAAyE;QACzE,wEAAwE;QACxE,qEAAqE;QACrE,kEAAkE;QAClE,yFAAyF;QACzF,oEAAoE;QACpE,gEAAgE;QAChE,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,aAAa,EACX,wPAAwP;QAC1P,0EAA0E;QAC1E,uEAAuE;QACvE,4EAA4E;QAC5E,yEAAyE;QACzE,uDAAuD;QACvD,aAAa,EAAE,QAAQ;QACvB,wEAAwE;QACxE,oCAAoC;QACpC,qEAAqE;QACrE,iDAAiD;QACjD,gEAAgE;QAChE,8EAA8E;QAC9E,2EAA2E;QAC3E,qDAAqD;QACrD,iBAAiB,EAAE,OAAO;QAC1B,oBAAoB,EAAE,KAAK;KAC5B;IACD,GAAG,EAAE;QACH,uBAAuB,EAAE,MAAM;QAC/B,YAAY,EAAE,KAAK;QACnB,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,+DAA+D;QAC/D,mBAAmB,EAAE,MAAM;KAC5B;IACD,aAAa,EAAE;QACb,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,OAAO;KACb;IACD,SAAS,EAAE;QACT,OAAO,EAAE;YACP,IAAI,EAAE,4BAA4B;YAClC,EAAE,EAAE,+BAA+B;YACnC,KAAK,EAAE,kCAAkC;SAC1C;QACD,GAAG,EAAE;YACH,OAAO,EAAE,2CAA2C;YACpD,OAAO,EAAE,aAAa;YACtB,QAAQ,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,CAAC;SAC7F;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,qEAAqE;AACrE,2DAA2D;AAC3D,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,8DAA8D;AAC9D,uEAAuE;AACvE,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;QACd,yEAAyE;QACzE,wEAAwE;QACxE,qEAAqE;QACrE,kEAAkE;QAClE,yFAAyF;QACzF,oEAAoE;QACpE,gEAAgE;QAChE,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,aAAa,EACX,wPAAwP;QAC1P,0EAA0E;QAC1E,uEAAuE;QACvE,4EAA4E;QAC5E,yEAAyE;QACzE,uDAAuD;QACvD,aAAa,EAAE,QAAQ;QACvB,wEAAwE;QACxE,oCAAoC;QACpC,qEAAqE;QACrE,iDAAiD;QACjD,gEAAgE;QAChE,8EAA8E;QAC9E,2EAA2E;QAC3E,qDAAqD;QACrD,iBAAiB,EAAE,OAAO;QAC1B,oBAAoB,EAAE,KAAK;KAC5B;IACD,GAAG,EAAE;QACH,uBAAuB,EAAE,MAAM;QAC/B,YAAY,EAAE,KAAK;QACnB,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,+DAA+D;QAC/D,mBAAmB,EAAE,MAAM;KAC5B;IACD,aAAa,EAAE;QACb,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,OAAO;KACb;IACD,SAAS,EAAE;QACT,OAAO,EAAE;YACP,IAAI,EAAE,4BAA4B;YAClC,EAAE,EAAE,+BAA+B;YACnC,2EAA2E;YAC3E,yEAAyE;YACzE,6EAA6E;YAC7E,0EAA0E;YAC1E,4EAA4E;YAC5E,uEAAuE;YACvE,wEAAwE;YACxE,2EAA2E;YAC3E,uEAAuE;SACxE;QACD,GAAG,EAAE;YACH,OAAO,EAAE,2CAA2C;YACpD,OAAO,EAAE,aAAa;YACtB,QAAQ,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,CAAC;SAC7F;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAMpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,EAAE,KAAK,CAAC;KAC7B,CAAC;CACH;AAMD,eAAO,MAAM,eAAe,EAAE,OAAO,EAicpC,CAAC;AAEF,eAAO,MAAM,SAAS,QAAyB,CAAC;AAShD,wBAAgB,iCAAiC,CAC/C,IAAI,GAAE,SAAS,OAAO,EAAoB,GACzC,IAAI,CAiBN"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAMpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,EAAE,KAAK,CAAC;KAC7B,CAAC;CACH;AAMD,eAAO,MAAM,eAAe,EAAE,OAAO,EA2fpC,CAAC;AAEF,eAAO,MAAM,SAAS,QAAyB,CAAC;AAShD,wBAAgB,iCAAiC,CAC/C,IAAI,GAAE,SAAS,OAAO,EAAoB,GACzC,IAAI,CAiBN"}