agents 0.22.0 → 0.24.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 (215) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-B2XLNMxq.d.ts} +1094 -443
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +26 -26
  5. package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
  6. package/dist/agent-tools.d.ts +21 -21
  7. package/dist/browser/ai.js +4 -1
  8. package/dist/browser/ai.js.map +1 -1
  9. package/dist/browser/tanstack-ai.js.map +1 -1
  10. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  11. package/dist/callable-decorator.d.ts +18 -0
  12. package/dist/callable-decorator.js +71 -0
  13. package/dist/callable-decorator.js.map +1 -0
  14. package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
  15. package/dist/capability-B4WbF81e.js.map +1 -0
  16. package/dist/capability-runner-BUBa6Ake.d.ts +484 -0
  17. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  18. package/dist/channels/ai-sdk.d.ts +46 -0
  19. package/dist/channels/ai-sdk.js +120 -0
  20. package/dist/channels/ai-sdk.js.map +1 -0
  21. package/dist/channels/email.d.ts +95 -0
  22. package/dist/channels/email.js +323 -0
  23. package/dist/channels/email.js.map +1 -0
  24. package/dist/channels/index.d.ts +233 -0
  25. package/dist/channels/index.js +608 -0
  26. package/dist/channels/index.js.map +1 -0
  27. package/dist/channels/slack.d.ts +140 -0
  28. package/dist/channels/slack.js +614 -0
  29. package/dist/channels/slack.js.map +1 -0
  30. package/dist/channels/tanstack-ai.d.ts +39 -0
  31. package/dist/channels/tanstack-ai.js +17 -0
  32. package/dist/channels/tanstack-ai.js.map +1 -0
  33. package/dist/channels/telegram.d.ts +106 -0
  34. package/dist/channels/telegram.js +427 -0
  35. package/dist/channels/telegram.js.map +1 -0
  36. package/dist/channels/voice.d.ts +45 -0
  37. package/dist/channels/voice.js +122 -0
  38. package/dist/channels/voice.js.map +1 -0
  39. package/dist/chat/index.d.ts +2319 -2010
  40. package/dist/chat/index.js +892 -518
  41. package/dist/chat/index.js.map +1 -1
  42. package/dist/chat-sdk/index.d.ts +7 -7
  43. package/dist/chat-sdk/index.js +1 -1
  44. package/dist/client-BxdkCuVy.d.ts +411 -0
  45. package/dist/client-C9DAjZIY.js +518 -0
  46. package/dist/client-C9DAjZIY.js.map +1 -0
  47. package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
  48. package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
  49. package/dist/client.d.ts +27 -283
  50. package/dist/client.js +2 -274
  51. package/dist/context/index.d.ts +216 -0
  52. package/dist/context/index.js +454 -0
  53. package/dist/context/index.js.map +1 -0
  54. package/dist/current-agent-C4w86kcN.d.ts +93 -0
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  57. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  58. package/dist/diagnostics-C4jcz3VK.js +360 -0
  59. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  60. package/dist/durable-object-lifecycle-ei7M7lqB.d.ts +157 -0
  61. package/dist/index-BB0kqhIz.d.ts +101 -0
  62. package/dist/index-BVVgDSdq.d.ts +1 -0
  63. package/dist/index-Dlgtd3Mj.d.ts +78 -0
  64. package/dist/index-XDkuQ7zm.d.ts +89 -0
  65. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  66. package/dist/index.d.ts +92 -83
  67. package/dist/index.js +4 -3
  68. package/dist/ingress-BfetZbMO.js +83 -0
  69. package/dist/ingress-BfetZbMO.js.map +1 -0
  70. package/dist/internal-CYlgHl1l.js +59 -0
  71. package/dist/internal-CYlgHl1l.js.map +1 -0
  72. package/dist/internal_context.d.ts +1 -1
  73. package/dist/lifecycle/index.d.ts +39 -19
  74. package/dist/lifecycle/index.js +2 -2
  75. package/dist/lifecycle-Mm_jQh7r.js +1314 -0
  76. package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
  77. package/dist/mcp/client/index.d.ts +20 -20
  78. package/dist/mcp/client/index.js +1 -1
  79. package/dist/mcp/index.d.ts +35 -35
  80. package/dist/mcp/index.js +2 -2
  81. package/dist/observability/index.d.ts +1 -1
  82. package/dist/observability/index.js +1 -1
  83. package/dist/queue/index.d.ts +123 -0
  84. package/dist/queue/index.js +2 -0
  85. package/dist/queue-BC9F5cUo.js +406 -0
  86. package/dist/queue-BC9F5cUo.js.map +1 -0
  87. package/dist/react.d.ts +34 -16
  88. package/dist/react.js +31 -8
  89. package/dist/react.js.map +1 -1
  90. package/dist/{retries-CAvxtG9d.d.ts → retries-D9B2UCq3.d.ts} +23 -6
  91. package/dist/retries.d.ts +10 -6
  92. package/dist/retries.js +21 -1
  93. package/dist/retries.js.map +1 -1
  94. package/dist/routing/index.d.ts +137 -0
  95. package/dist/routing/index.js +244 -0
  96. package/dist/routing/index.js.map +1 -0
  97. package/dist/sanitize-D9TujEK8.js +79 -0
  98. package/dist/sanitize-D9TujEK8.js.map +1 -0
  99. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-BGq6M5Kd.d.ts} +20 -21
  100. package/dist/scheduler-D_KHqxBa.js +658 -0
  101. package/dist/scheduler-D_KHqxBa.js.map +1 -0
  102. package/dist/schedules/index.d.ts +1 -1
  103. package/dist/schedules/index.js +1 -1
  104. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  105. package/dist/serializable.d.ts +1 -1
  106. package/dist/sessions/index.d.ts +441 -0
  107. package/dist/sessions/index.js +2063 -0
  108. package/dist/sessions/index.js.map +1 -0
  109. package/dist/skills/index.d.ts +99 -0
  110. package/dist/skills/index.js +254 -5
  111. package/dist/skills/index.js.map +1 -1
  112. package/dist/{src-5W6JNKVb.js → src-BNU3ZiJM.js} +1524 -1441
  113. package/dist/src-BNU3ZiJM.js.map +1 -0
  114. package/dist/state/index.d.ts +6 -0
  115. package/dist/state/index.js +137 -0
  116. package/dist/state/index.js.map +1 -0
  117. package/dist/streams/index.d.ts +120 -0
  118. package/dist/streams/index.js +107 -0
  119. package/dist/streams/index.js.map +1 -0
  120. package/dist/streams-BcE8JP2X.d.ts +370 -0
  121. package/dist/streams-CCPRV6dt.js +709 -0
  122. package/dist/streams-CCPRV6dt.js.map +1 -0
  123. package/dist/sub-routing.d.ts +12 -12
  124. package/dist/surface-bZZJqBka.js +17 -0
  125. package/dist/surface-bZZJqBka.js.map +1 -0
  126. package/dist/tasks/index.d.ts +64 -0
  127. package/dist/tasks/index.js +2 -0
  128. package/dist/tasks-D4nLqVSI.js +1656 -0
  129. package/dist/tasks-D4nLqVSI.js.map +1 -0
  130. package/dist/tasks-V2lCT8ZV.d.ts +517 -0
  131. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  132. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  133. package/dist/text-stream-CpdiKrJB.js +272 -0
  134. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  135. package/dist/tokens-nHAKcN6M.js +52 -0
  136. package/dist/tokens-nHAKcN6M.js.map +1 -0
  137. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  138. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  139. package/dist/transport-protocol-BxyngQ_R.js +25 -0
  140. package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
  141. package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
  142. package/dist/types-B7LojTe4.d.ts +202 -0
  143. package/dist/types-DCD6BNZH.d.ts +70 -0
  144. package/dist/types-_Faxb570.d.ts +439 -0
  145. package/dist/voice/client.d.ts +226 -0
  146. package/dist/voice/client.js +932 -0
  147. package/dist/voice/client.js.map +1 -0
  148. package/dist/voice/errors.d.ts +43 -0
  149. package/dist/voice/errors.js +41 -0
  150. package/dist/voice/errors.js.map +1 -0
  151. package/dist/voice/index.d.ts +271 -0
  152. package/dist/voice/index.js +1812 -0
  153. package/dist/voice/index.js.map +1 -0
  154. package/dist/voice/react.d.ts +167 -0
  155. package/dist/voice/react.js +234 -0
  156. package/dist/voice/react.js.map +1 -0
  157. package/dist/voice/sfu.d.ts +71 -0
  158. package/dist/voice/sfu.js +157 -0
  159. package/dist/voice/sfu.js.map +1 -0
  160. package/dist/voice/text.d.ts +6 -0
  161. package/dist/voice/text.js +2 -0
  162. package/dist/voice/types.d.ts +58 -0
  163. package/dist/voice/types.js +18 -0
  164. package/dist/voice/types.js.map +1 -0
  165. package/dist/voice/workers-ai.d.ts +136 -0
  166. package/dist/voice/workers-ai.js +568 -0
  167. package/dist/voice/workers-ai.js.map +1 -0
  168. package/dist/websockets/index.d.ts +301 -0
  169. package/dist/websockets/index.js +3 -0
  170. package/dist/websockets-D7IzWbZb.js +1005 -0
  171. package/dist/websockets-D7IzWbZb.js.map +1 -0
  172. package/dist/workflow-types.d.ts +25 -25
  173. package/dist/workflows.d.ts +21 -21
  174. package/dist/workflows.js +1 -1
  175. package/docs/agent-class.md +4 -4
  176. package/docs/agent-tools.md +2 -1
  177. package/docs/channels.md +323 -0
  178. package/docs/chat-agents.md +6 -13
  179. package/docs/client-sdk.md +30 -0
  180. package/docs/context.md +131 -0
  181. package/docs/index.md +16 -13
  182. package/docs/lifecycle.md +179 -57
  183. package/docs/long-running-agents.md +2 -2
  184. package/docs/mcp-servers.md +5 -1
  185. package/docs/queue.md +135 -241
  186. package/docs/resumable-streaming.md +1 -1
  187. package/docs/retries.md +1 -1
  188. package/docs/routing.md +105 -0
  189. package/docs/sessions.md +237 -871
  190. package/docs/streams.md +213 -0
  191. package/docs/sub-agents.md +184 -124
  192. package/docs/tasks.md +246 -0
  193. package/docs/voice.md +745 -0
  194. package/package.json +126 -14
  195. package/dist/capability-BjSKYpzg.js.map +0 -1
  196. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  197. package/dist/client.js.map +0 -1
  198. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  199. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  200. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  201. package/dist/current-agent-CuMErtly.d.ts +0 -283
  202. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  203. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  204. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  205. package/dist/experimental/memory/session/index.d.ts +0 -671
  206. package/dist/experimental/memory/session/index.js +0 -2379
  207. package/dist/experimental/memory/session/index.js.map +0 -1
  208. package/dist/experimental/memory/utils/index.d.ts +0 -96
  209. package/dist/experimental/memory/utils/index.js +0 -79
  210. package/dist/experimental/memory/utils/index.js.map +0 -1
  211. package/dist/scheduler-CR9RHGos.js +0 -857
  212. package/dist/scheduler-CR9RHGos.js.map +0 -1
  213. package/dist/src-5W6JNKVb.js.map +0 -1
  214. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  215. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/context/search.ts","../../src/context/blocks.ts","../../src/context/sqlite-provider.ts"],"sourcesContent":["/**\n * Search Provider — full-text searchable context blocks.\n *\n * Extends ContextProvider with `search()` for querying indexed content\n * and a keyed `set()` for indexing individual entries.\n *\n * Duck-typed: if a provider has a `search` method, it's a SearchProvider.\n */\n\nimport type { ContextProvider } from \"./blocks\";\nimport type { SqlProvider } from \"./sqlite-provider\";\n\n/**\n * Storage interface for searchable context.\n *\n * - `get()` returns a summary of indexed content (rendered into system prompt)\n * - `search(query)` full-text search (via search_context tool)\n * - `set(key, content)` indexes content under a key (via set_context tool)\n */\nexport interface SearchProvider extends ContextProvider {\n search(query: string): Promise<string | null>;\n set?(key: string, content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is a SearchProvider (has a `search` method).\n */\nexport function isSearchProvider(\n provider: unknown\n): provider is SearchProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"search\" in provider &&\n typeof (provider as SearchProvider).search === \"function\"\n );\n}\n\n// ── Agent Search Provider (DO SQLite FTS5) ─────────────────────────\n\n/**\n * SearchProvider backed by Durable Object SQLite with FTS5.\n *\n * - `get()` returns a count of indexed entries\n * - `search(query)` full-text search using FTS5\n * - `set(key, content)` indexes or replaces content under a key\n *\n * Entries live in one namespaced FTS5 table, separate from the session\n * message index.\n *\n * @example\n * ```ts\n * const context = new ContextBlocks([\n * { label: \"knowledge\", provider: new AgentSearchProvider(this) }\n * ]);\n * ```\n */\nexport class AgentSearchProvider implements SearchProvider {\n private agent: SqlProvider;\n private label = \"\";\n private initialized = false;\n\n constructor(agent: SqlProvider) {\n this.agent = agent;\n }\n\n init(label: string): void {\n this.label = label;\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n // The FTS table is the only store: a mirror row table would double the\n // billed writes of every indexed entry to serve a count and a lookup the\n // index already answers.\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS cf_agents_search_fts\n USING fts5(\n label UNINDEXED,\n key UNINDEXED,\n content,\n tokenize='porter unicode61'\n )\n `;\n this.agent.sql`DROP TABLE IF EXISTS cf_agents_search_entries`;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_search_fts\n WHERE label = ${this.label}\n `;\n const count = rows[0]?.count ?? 0;\n if (count === 0) return null;\n return `${count} entries indexed.`;\n }\n\n async search(query: string): Promise<string | null> {\n this.ensureTable();\n // Quote each word individually to prevent FTS5 syntax injection\n // while preserving implicit AND between terms\n const sanitized = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w.replace(/\"/g, '\"\"')}\"`)\n .join(\" \");\n if (!sanitized) return null;\n try {\n const rows = this.agent.sql<{\n key: string;\n content: string;\n }>`\n SELECT f.key, f.content\n FROM cf_agents_search_fts f\n WHERE cf_agents_search_fts MATCH ${sanitized}\n AND f.label = ${this.label}\n ORDER BY rank\n LIMIT 10\n `;\n if (rows.length === 0) return null;\n return rows.map((r) => `[${r.key}]\\n${r.content}`).join(\"\\n\\n\");\n } catch {\n // Malformed FTS query\n return null;\n }\n }\n\n async set(key: string, content: string): Promise<void> {\n this.ensureTable();\n this.agent.sql`\n DELETE FROM cf_agents_search_fts\n WHERE label = ${this.label} AND key = ${key}\n `;\n this.agent.sql`\n INSERT INTO cf_agents_search_fts (label, key, content)\n VALUES (${this.label}, ${key}, ${content})\n `;\n }\n}\n","/**\n * Context Block Management\n *\n * Persistent key-value blocks (MEMORY, USER, SOUL, etc.) that are:\n * - Loaded from their providers at init\n * - Frozen into a snapshot when toSystemPrompt() is called\n * - Updated via setBlock() which writes to the provider immediately\n * but does NOT update the frozen snapshot (preserves LLM prefix cache)\n * - Re-snapshotted on next toSystemPrompt() call\n *\n * Provider type determines behavior:\n * - ContextProvider (get only) → readonly block in system prompt\n * - WritableContextProvider (get+set) → writable via set_context tool\n * - SearchProvider (get+search+set?) → searchable via search_context tool\n */\n\nimport type { ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport { estimateStringTokens } from \"../sessions/tokens\";\nimport { isSearchProvider, type SearchProvider } from \"./search\";\n\nfunction slugify(text: string): string {\n return text\n .slice(0, 60)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nfunction stableHash(text: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(36);\n}\n\nfunction contextEntryKey(metadataTitle: string | undefined, content: string) {\n if (metadataTitle?.trim()) {\n const slug = slugify(metadataTitle);\n return slug || `entry-${stableHash(metadataTitle)}`;\n }\n\n const slug = slugify(content) || \"entry\";\n return `${slug}-${stableHash(content)}`;\n}\n\n/**\n * Base storage interface for a context block.\n * A provider with only `get()` is readonly.\n */\nexport interface ContextProvider {\n get(): Promise<string | null>;\n /** Called by the context system to provide the block label before first use. */\n init?(label: string): void;\n}\n\n/**\n * Writable context provider — extends ContextProvider with `set()`.\n * Blocks backed by this provider are writable via the `set_context` tool.\n */\nexport interface WritableContextProvider extends ContextProvider {\n set(content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is writable (has a `set` method).\n */\nexport function isWritableProvider(\n provider: unknown\n): provider is WritableContextProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"set\" in provider &&\n typeof (provider as WritableContextProvider).set === \"function\"\n );\n}\n\n/**\n * Configuration for a context block.\n */\nexport interface ContextConfig {\n /** Block label — used as key and in tool descriptions */\n label: string;\n /** Human-readable description (shown to AI in tool) */\n description?: string;\n /** Maximum tokens allowed. Enforced on set. */\n maxTokens?: number;\n /** Storage provider. Determines block behavior:\n * - ContextProvider (get only) → readonly\n * - WritableContextProvider (get+set) → writable via set_context\n * - SearchProvider (get+search+set?) → searchable via search_context\n * If omitted, auto-wired to writable SQLite when using builder. */\n provider?: ContextProvider | WritableContextProvider | SearchProvider;\n}\n\n/**\n * A loaded context block with computed token count.\n */\nexport interface ContextBlock {\n label: string;\n description?: string;\n content: string;\n tokens: number;\n maxTokens?: number;\n /** True if provider is writable (has set) */\n writable: boolean;\n /** True if backed by a SearchProvider */\n isSearchable: boolean;\n}\n\n/**\n * Manages context blocks with frozen snapshot support.\n */\nexport class ContextBlocks {\n private configs: ContextConfig[];\n private blocks = new Map<string, ContextBlock>();\n private snapshot: string | null = null;\n private loaded = false;\n private promptStore: WritableContextProvider | null;\n private defaultProvider: ((label: string) => ContextProvider) | null;\n\n /**\n * @param configs Blocks to load on first use.\n * @param promptStore Persists the frozen system prompt, keeping the\n * provider's prefix cache warm across wakes.\n * @param defaultProvider Supplies storage for blocks declared without a\n * provider, so a host can offer durable writable blocks by label alone.\n */\n constructor(\n configs: ContextConfig[],\n promptStore?: WritableContextProvider,\n defaultProvider?: (label: string) => ContextProvider\n ) {\n this.configs = configs;\n this.promptStore = promptStore ?? null;\n this.defaultProvider = defaultProvider ?? null;\n }\n\n /** Fill in the host's storage for a block declared without a provider. */\n private withDefaultProvider(config: ContextConfig): ContextConfig {\n if (config.provider || !this.defaultProvider) return config;\n return { ...config, provider: this.defaultProvider(config.label) };\n }\n\n /**\n * Load all blocks from their providers. Hosts call this once at startup;\n * every other entry point loads lazily.\n */\n async load(): Promise<void> {\n this.configs = this.configs.map((config) =>\n this.withDefaultProvider(config)\n );\n for (const config of this.configs) {\n this.blocks.set(config.label, await this.loadBlock(config));\n }\n this.loaded = true;\n }\n\n /** Initialize a block's provider and read its current content. */\n private async loadBlock(config: ContextConfig): Promise<ContextBlock> {\n const provider = config.provider;\n provider?.init?.(config.label);\n const content = provider ? ((await provider.get()) ?? \"\") : \"\";\n const searchable = isSearchProvider(provider);\n return {\n label: config.label,\n description: config.description,\n content,\n tokens: estimateStringTokens(content),\n maxTokens: config.maxTokens,\n writable: isWritableProvider(provider) || (searchable && !!provider?.set),\n isSearchable: searchable\n };\n }\n\n /**\n * Dynamically register a new context block after initialization.\n * Used by extensions to contribute context at runtime.\n *\n * If blocks have already been loaded, the new block's provider is\n * initialized and loaded immediately. The snapshot is NOT updated\n * automatically — call `refreshSystemPrompt()` to rebuild.\n */\n async addBlock(input: ContextConfig): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n\n if (this.configs.some((c) => c.label === input.label)) {\n throw new Error(`Block \"${input.label}\" already exists`);\n }\n\n const config = this.withDefaultProvider(input);\n this.configs.push(config);\n const block = await this.loadBlock(config);\n this.blocks.set(config.label, block);\n return block;\n }\n\n /**\n * Remove a dynamically registered context block.\n * Used during extension unload cleanup.\n *\n * Returns true if the block existed and was removed.\n * The snapshot is NOT updated automatically — call\n * `refreshSystemPrompt()` to rebuild.\n */\n removeBlock(label: string): boolean {\n const idx = this.configs.findIndex((c) => c.label === label);\n if (idx === -1) return false;\n\n this.configs.splice(idx, 1);\n this.blocks.delete(label);\n return true;\n }\n\n /**\n * Get a block by label.\n */\n getBlock(label: string): ContextBlock | null {\n return this.blocks.get(label) ?? null;\n }\n\n /**\n * Get all blocks.\n */\n getBlocks(): ContextBlock[] {\n return Array.from(this.blocks.values());\n }\n\n /**\n * Set block content. Writes to provider immediately.\n * Does NOT update the frozen snapshot.\n */\n async setBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.writable) {\n throw new Error(`Block \"${label}\" is readonly`);\n }\n\n if (existing.isSearchable) {\n throw new Error(\n `Block \"${label}\" is a keyed provider. Use setSearchEntry() instead.`\n );\n }\n\n const tokens = estimateStringTokens(content);\n const maxTokens = config?.maxTokens ?? existing?.maxTokens;\n\n if (maxTokens !== undefined && tokens > maxTokens) {\n throw new Error(\n `Block \"${label}\" exceeds maxTokens: ${tokens} > ${maxTokens}`\n );\n }\n\n const block: ContextBlock = {\n label,\n description: config?.description ?? existing?.description,\n content,\n tokens,\n maxTokens,\n writable: true,\n isSearchable: false\n };\n\n this.blocks.set(label, block);\n\n // Write to provider immediately (durable)\n if (config?.provider && isWritableProvider(config.provider)) {\n await config.provider.set(content);\n }\n\n return block;\n }\n\n /** Index a search entry within a searchable block. */\n private async setSearchEntry(\n label: string,\n key: string,\n content: string\n ): Promise<void> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.isSearchable) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n const provider = config?.provider;\n if (!provider || !isSearchProvider(provider) || !provider.set) {\n throw new Error(`Block \"${label}\" does not support writes`);\n }\n\n await provider.set(key, content);\n\n // Refresh summary\n const summary = await provider.get();\n existing.content = summary ?? \"\";\n existing.tokens = estimateStringTokens(existing.content);\n }\n\n /** Search a searchable block. */\n private async searchContext(\n label: string,\n query: string\n ): Promise<string | null> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n\n if (!config?.provider || !isSearchProvider(config.provider)) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n return config.provider.search(query);\n }\n\n /**\n * Append content to a block.\n */\n async appendToBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const existing = this.blocks.get(label);\n if (!existing) {\n throw new Error(`Block \"${label}\" not found`);\n }\n const needsSep = existing.content.length > 0 && !content.startsWith(\"\\n\");\n return this.setBlock(\n label,\n existing.content + (needsSep ? \"\\n\" : \"\") + content\n );\n }\n\n private renderPrompt(): string {\n const parts: string[] = [];\n const sep = \"═\".repeat(46);\n\n for (const block of this.blocks.values()) {\n // Skip empty readonly blocks — writable and searchable blocks always\n // render so the LLM knows which tools can address them.\n if (!block.content && !block.writable && !block.isSearchable) continue;\n\n let header = block.label.toUpperCase();\n if (block.description) header += ` (${block.description})`;\n if (block.maxTokens) {\n const pct = Math.round((block.tokens / block.maxTokens) * 100);\n header += ` [${pct}% — ${block.tokens}/${block.maxTokens} tokens]`;\n }\n if (block.isSearchable) header += \" [searchable]\";\n else if (!block.writable) header += \" [readonly]\";\n else header += \" [writable]\";\n\n parts.push(`${sep}\\n${header}\\n${sep}\\n${block.content}`);\n }\n\n return parts.join(\"\\n\\n\");\n }\n\n // ── Public API ──────────────────────────────────────────────────\n\n /**\n * The frozen system prompt. The first call renders the blocks and stores\n * the result; every later call returns that same string, so the model\n * provider's prefix cache stays warm. Block edits do not change it until\n * `refreshSystemPrompt()` is called.\n */\n async freezeSystemPrompt(): Promise<string> {\n if (this.promptStore) {\n const stored = await this.promptStore.get();\n if (stored !== null) return stored;\n }\n if (this.snapshot !== null) return this.snapshot;\n\n if (!this.loaded) await this.load();\n this.snapshot = this.renderPrompt();\n await this.promptStore?.set(this.snapshot);\n return this.snapshot;\n }\n\n /**\n * Reload every block from its provider, re-render the system prompt, and\n * persist it. Use this after block content has changed.\n */\n async refreshSystemPrompt(): Promise<string> {\n this.loaded = false;\n await this.load();\n this.snapshot = this.renderPrompt();\n await this.promptStore?.set(this.snapshot);\n return this.snapshot;\n }\n\n /**\n * AI tools for context blocks.\n *\n * Auto-wired based on provider capabilities:\n * - `set_context` — when any block is writable\n * - `search_context` — when any block is a search provider\n */\n async tools(): Promise<ToolSet> {\n if (!this.loaded) await this.load();\n\n const blocks = Array.from(this.blocks.values());\n const writable = blocks.filter((b) => b.writable);\n const searchLabels = blocks\n .filter((b) => b.isSearchable)\n .map((b) => b.label);\n const toolSet: ToolSet = {};\n\n // ── set_context ──────────────────────────────────────────────\n\n if (writable.length > 0) {\n const blockDescriptions = writable.map((b) => {\n const kind = b.isSearchable ? \"searchable, keyed entries\" : \"writable\";\n return `- \"${b.label}\" (${kind}): ${b.description ?? \"no description\"}`;\n });\n const keyedBlocks = writable.filter((b) => b.isSearchable);\n\n const properties: Record<string, unknown> = {\n label: {\n type: \"string\" as const,\n enum: writable.map((b) => b.label),\n description: \"Block label to write to\"\n },\n content: {\n type: \"string\" as const,\n description: \"The main content to write to the block.\"\n },\n action: {\n type: \"string\" as const,\n enum: [\"replace\", \"append\"],\n description: \"replace (default) or append\"\n }\n };\n\n if (keyedBlocks.length > 0) {\n properties.metadata = {\n type: \"object\" as const,\n description:\n \"Optional metadata for keyed entries (searchable blocks: \" +\n keyedBlocks.map((b) => `\"${b.label}\"`).join(\", \") +\n \"). A title keeps updates stable; a description helps the model \" +\n \"pick the right entry.\",\n properties: {\n title: {\n type: \"string\" as const,\n description:\n \"Short title. Used as a stable identifier — entries with the \" +\n \"same title are updated in place, different titles create new entries.\"\n },\n description: {\n type: \"string\" as const,\n description:\n \"One-line summary shown alongside the title in the system prompt \" +\n \"so the model can decide when to load the entry.\"\n }\n }\n };\n }\n\n const metadataHint =\n keyedBlocks.length > 0\n ? \"\\n\\nFor searchable blocks, pass `metadata: { title, description }` \" +\n \"— title stabilises updates, description helps the model pick \" +\n \"entries. Metadata is optional.\"\n : \"\";\n\n toolSet.set_context = {\n description: `Write to a context block. Available blocks:\\n${blockDescriptions.join(\"\\n\")}\\n\\nWrites are durable and persist across sessions.${metadataHint}`,\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: properties as Record<string, Record<string, unknown>>,\n required: [\"label\", \"content\"]\n }),\n execute: async ({\n label,\n content,\n metadata,\n action\n }: {\n label: string;\n content: string;\n metadata?: { title?: string; description?: string };\n action?: string;\n }) => {\n try {\n const block = this.blocks.get(label);\n if (!block) return `Error: block \"${label}\" not found`;\n\n if (block.isSearchable) {\n const key = contextEntryKey(metadata?.title, content);\n await this.setSearchEntry(label, key, content);\n return `Indexed \"${key}\" in ${label}.`;\n }\n\n const updated =\n action === \"append\"\n ? await this.appendToBlock(label, content)\n : await this.setBlock(label, content);\n const usage = updated.maxTokens\n ? `${Math.round((updated.tokens / updated.maxTokens) * 100)}% (${updated.tokens}/${updated.maxTokens} tokens)`\n : `${updated.tokens} tokens`;\n return `Written to ${label}. Usage: ${usage}`;\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n // ── search_context ────────────────────────────────────────────\n\n if (searchLabels.length > 0) {\n toolSet.search_context = {\n description:\n \"Search for information in a searchable context block. \" +\n \"ONLY these blocks are searchable: \" +\n searchLabels.map((l) => `\"${l}\"`).join(\", \") +\n \". Other blocks cannot be searched.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: searchLabels,\n description: \"Searchable block label\"\n },\n query: {\n type: \"string\" as const,\n description: \"Search query\"\n }\n },\n required: [\"label\", \"query\"]\n }),\n execute: async ({ label, query }: { label: string; query: string }) => {\n try {\n if (!searchLabels.includes(label)) {\n return `Error: \"${label}\" is not searchable. Searchable blocks: ${searchLabels.join(\", \")}`;\n }\n const results = await this.searchContext(label, query);\n return results ?? \"No results found.\";\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n return toolSet;\n }\n}\n","/**\n * SQLite Context Block Provider\n *\n * Default durable storage for context blocks using DO SQLite.\n * Each block is a row in cf_agents_context_blocks.\n */\n\nimport type { WritableContextProvider } from \"./blocks\";\n\n/** Minimal tagged-template SQL surface used by SQLite context providers. */\nexport interface SqlProvider {\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[];\n}\n\n/** SQLite-backed writable context block provider. */\nexport class AgentContextProvider implements WritableContextProvider {\n private agent: SqlProvider;\n private label: string;\n private initialized = false;\n\n constructor(agent: SqlProvider, label?: string) {\n this.agent = agent;\n this.label = label ?? \"\";\n }\n\n init(label: string): void {\n if (!this.label) {\n this.label = label;\n }\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_context_blocks (\n label TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM cf_agents_context_blocks WHERE label = ${this.label}\n `;\n return rows[0]?.content ?? null;\n }\n\n async set(content: string): Promise<void> {\n this.ensureTable();\n this.agent.sql`\n INSERT INTO cf_agents_context_blocks (label, content)\n VALUES (${this.label}, ${content})\n ON CONFLICT(label) DO UPDATE SET content = ${content}, updated_at = CURRENT_TIMESTAMP\n `;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import {
2
+ _ as LifecycleJobContext,
3
+ o as MemoryLimitContext,
4
+ v as LifecycleJobOutcome,
5
+ x as Connection
6
+ } from "./capability-runner-BUBa6Ake.js";
7
+ import { t as Lifecycle } from "./durable-object-lifecycle-ei7M7lqB.js";
8
+ import { AsyncLocalStorage } from "node:async_hooks";
9
+ import { DurableObject } from "cloudflare:workers";
10
+
11
+ //#region src/lifecycle/current-agent.d.ts
12
+ /**
13
+ * A Durable Object that has installed the Agents SDK Lifecycle.
14
+ *
15
+ * Pass a more specific Lifecycle Object type to {@link getCurrentAgent} when
16
+ * shared host code needs APIs implemented by a particular object.
17
+ *
18
+ * @experimental The API surface may change before stabilizing.
19
+ */
20
+ interface LifecycleObject<
21
+ Env extends object = Cloudflare.Env,
22
+ Props extends Record<string, unknown> = Record<string, unknown>
23
+ > extends DurableObject<Env> {
24
+ readonly lifecycle: Lifecycle<Env, Props>;
25
+ onStart?(props?: Props): void | Promise<void>;
26
+ onRequest?(request: Request): Response | Promise<Response>;
27
+ onAlarm?(): void | Promise<void>;
28
+ onJob?(
29
+ context: LifecycleJobContext
30
+ ): LifecycleJobOutcome | void | Promise<LifecycleJobOutcome | void>;
31
+ /**
32
+ * Host domain policy applied when the alarm memory-limit circuit breaker
33
+ * records a strike (#1825), after every capability's `onMemoryLimit` hook.
34
+ *
35
+ * Lifecycle dispatches host hooks structurally through its internal host
36
+ * cast, so TS visibility is the host's to choose: a framework host whose
37
+ * implementation is internal machinery declares the hook `protected` (the
38
+ * pattern — see `AIChatAgent`/`Think`) and keeps the real work in a
39
+ * `private _cf_`-prefixed method, without falling out of this contract at
40
+ * runtime.
41
+ */
42
+ onAlarmMemoryLimit?(context: MemoryLimitContext): void | Promise<void>;
43
+ }
44
+ /** Values associated with the currently executing Lifecycle host. */
45
+ type AgentContextStore = {
46
+ /** Lifecycle host selected for this invocation. */ agent: unknown /** WebSocket connection selected for this invocation, when applicable. */;
47
+ connection:
48
+ | Connection
49
+ | undefined /** HTTP request selected for this invocation, when applicable. */;
50
+ request:
51
+ | Request
52
+ | undefined /** Extension-owned value selected for this invocation, when applicable. */;
53
+ email: unknown;
54
+ };
55
+ /** Values returned by {@link getCurrentAgent}. */
56
+ type CurrentAgentContext<
57
+ Host extends DurableObject = LifecycleObject,
58
+ Email = unknown
59
+ > = {
60
+ agent: Host | undefined;
61
+ connection: Connection | undefined;
62
+ request: Request | undefined;
63
+ email: Email | undefined;
64
+ };
65
+ /**
66
+ * Shared invocation context for Lifecycle, Agent, AIChatAgent, and Think.
67
+ *
68
+ * @internal Importing or relying on this symbol will break your code in a
69
+ * future release. Use {@link getCurrentAgent} to read the public context.
70
+ */
71
+ declare const __DO_NOT_USE_WILL_BREAK__agentContext: AsyncLocalStorage<AgentContextStore>;
72
+ /**
73
+ * Return the current Agent or Lifecycle Object and invocation-specific values.
74
+ *
75
+ * Lifecycle host startup and alarm hooks receive the current object with no
76
+ * request. Request hooks additionally receive the request being handled.
77
+ * Lifecycle-managed WebSocket hooks receive their connection and, during
78
+ * connect, its upgrade request. Agent extensions may also establish context
79
+ * for email, chat turns, callable methods, and detached work. Capability hooks
80
+ * do not run in this ambient context.
81
+ */
82
+ declare function getCurrentAgent<
83
+ Host extends DurableObject = LifecycleObject
84
+ >(): CurrentAgentContext<Host>;
85
+ //#endregion
86
+ export {
87
+ getCurrentAgent as a,
88
+ __DO_NOT_USE_WILL_BREAK__agentContext as i,
89
+ CurrentAgentContext as n,
90
+ LifecycleObject as r,
91
+ AgentContextStore as t
92
+ };
93
+ //# sourceMappingURL=current-agent-C4w86kcN.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"current-agent-DhoDkSnH.js","names":[],"sources":["../src/lifecycle/current-agent.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { DurableObject } from \"cloudflare:workers\";\n\nimport type { AlarmContribution } from \"./capability-runner\";\nimport type { Lifecycle, WSMessage } from \"./durable-object-lifecycle\";\nimport type { Connection, ConnectionContext } from \"./types\";\n\n/**\n * A Durable Object that has installed the Agents SDK Lifecycle.\n *\n * Pass a more specific Lifecycle Object type to {@link getCurrentAgent} when\n * shared host code needs APIs implemented by a particular object.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport interface LifecycleObject<\n Env extends object = Cloudflare.Env,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends DurableObject<Env> {\n readonly lifecycle: Lifecycle<Env, Props>;\n onStart?(props?: Props): void | Promise<void>;\n onRequest?(request: Request): Response | Promise<Response>;\n onAlarm?(): void | Promise<void>;\n getNextAlarm?(): AlarmContribution | Promise<AlarmContribution>;\n onConnect?(\n connection: Connection,\n context: ConnectionContext\n ): void | Promise<void>;\n onMessage?(connection: Connection, message: WSMessage): void | Promise<void>;\n onClose?(\n connection: Connection,\n code: number,\n reason: string,\n wasClean: boolean\n ): void | Promise<void>;\n onError?(connection: Connection, error: unknown): void | Promise<void>;\n getConnectionTags?(\n connection: Connection,\n context: ConnectionContext\n ): string[] | Promise<string[]>;\n}\n\n/** Values associated with the currently executing Lifecycle host. */\nexport type AgentContextStore = {\n /** Lifecycle host selected for this invocation. */\n agent: unknown;\n /** WebSocket connection selected for this invocation, when applicable. */\n connection: Connection | undefined;\n /** HTTP request selected for this invocation, when applicable. */\n request: Request | undefined;\n /** Extension-owned value selected for this invocation, when applicable. */\n email: unknown;\n};\n\n/** Values returned by {@link getCurrentAgent}. */\nexport type CurrentAgentContext<\n Host extends DurableObject = LifecycleObject,\n Email = unknown\n> = {\n agent: Host | undefined;\n connection: Connection | undefined;\n request: Request | undefined;\n email: Email | undefined;\n};\n\n/**\n * Shared invocation context for Lifecycle, Agent, AIChatAgent, and Think.\n *\n * @internal Importing or relying on this symbol will break your code in a\n * future release. Use {@link getCurrentAgent} to read the public context.\n */\nexport const __DO_NOT_USE_WILL_BREAK__agentContext =\n new AsyncLocalStorage<AgentContextStore>();\n\n/**\n * Return the current Agent or Lifecycle Object and invocation-specific values.\n *\n * Lifecycle host startup and alarm hooks receive the current object with no\n * request. Request hooks additionally receive the request being handled.\n * Lifecycle-managed WebSocket hooks receive their connection and, during\n * connect, its upgrade request. Agent extensions may also establish context\n * for email, chat turns, callable methods, and detached work. Capability hooks\n * do not run in this ambient context.\n */\nexport function getCurrentAgent<\n Host extends DurableObject = LifecycleObject\n>(): CurrentAgentContext<Host> {\n const store = __DO_NOT_USE_WILL_BREAK__agentContext.getStore();\n if (!store) {\n return {\n agent: undefined,\n connection: undefined,\n request: undefined,\n email: undefined\n };\n }\n\n return {\n agent: store.agent as Host,\n connection: store.connection,\n request: store.request,\n email: store.email\n };\n}\n\ntype LifecycleHostContext<\n Env extends object,\n Props extends Record<string, unknown>\n> = {\n readonly host: LifecycleObject<Env, Props>;\n readonly connection?: Connection;\n readonly request?: Request;\n};\n\n/** Run one host hook in the context of its Lifecycle Object. */\nexport function runInLifecycleHostContext<\n Env extends object,\n Props extends Record<string, unknown>,\n T\n>(context: LifecycleHostContext<Env, Props>, operation: () => T): T {\n return __DO_NOT_USE_WILL_BREAK__agentContext.run(\n {\n agent: context.host,\n connection: context.connection,\n request: context.request,\n email: undefined\n },\n operation\n );\n}\n\n/** Run a capability hook without inheriting a current Agent or host context. */\nexport function runWithoutCurrentAgent<T>(operation: () => T): T {\n return __DO_NOT_USE_WILL_BREAK__agentContext.exit(operation);\n}\n"],"mappings":";;;;;;;;AAuEA,MAAa,wCACX,IAAI,kBAAqC;;;;;;;;;;;AAY3C,SAAgB,kBAEe;CAC7B,MAAM,QAAQ,sCAAsC,SAAS;CAC7D,IAAI,CAAC,OACH,OAAO;EACL,OAAO,KAAA;EACP,YAAY,KAAA;EACZ,SAAS,KAAA;EACT,OAAO,KAAA;CACT;CAGF,OAAO;EACL,OAAO,MAAM;EACb,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,OAAO,MAAM;CACf;AACF;;AAYA,SAAgB,0BAId,SAA2C,WAAuB;CAClE,OAAO,sCAAsC,IAC3C;EACE,OAAO,QAAQ;EACf,YAAY,QAAQ;EACpB,SAAS,QAAQ;EACjB,OAAO,KAAA;CACT,GACA,SACF;AACF;;AAGA,SAAgB,uBAA0B,WAAuB;CAC/D,OAAO,sCAAsC,KAAK,SAAS;AAC7D"}
1
+ {"version":3,"file":"current-agent-DhoDkSnH.js","names":[],"sources":["../src/lifecycle/current-agent.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { DurableObject } from \"cloudflare:workers\";\n\nimport type { MemoryLimitContext } from \"./capability-runner\";\nimport type { Lifecycle } from \"./durable-object-lifecycle\";\nimport type { Connection } from \"./types\";\nimport type { LifecycleJobContext, LifecycleJobOutcome } from \"./job-queue\";\n\n/**\n * A Durable Object that has installed the Agents SDK Lifecycle.\n *\n * Pass a more specific Lifecycle Object type to {@link getCurrentAgent} when\n * shared host code needs APIs implemented by a particular object.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport interface LifecycleObject<\n Env extends object = Cloudflare.Env,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends DurableObject<Env> {\n readonly lifecycle: Lifecycle<Env, Props>;\n onStart?(props?: Props): void | Promise<void>;\n onRequest?(request: Request): Response | Promise<Response>;\n onAlarm?(): void | Promise<void>;\n onJob?(\n context: LifecycleJobContext\n ): LifecycleJobOutcome | void | Promise<LifecycleJobOutcome | void>;\n /**\n * Host domain policy applied when the alarm memory-limit circuit breaker\n * records a strike (#1825), after every capability's `onMemoryLimit` hook.\n *\n * Lifecycle dispatches host hooks structurally through its internal host\n * cast, so TS visibility is the host's to choose: a framework host whose\n * implementation is internal machinery declares the hook `protected` (the\n * pattern — see `AIChatAgent`/`Think`) and keeps the real work in a\n * `private _cf_`-prefixed method, without falling out of this contract at\n * runtime.\n */\n onAlarmMemoryLimit?(context: MemoryLimitContext): void | Promise<void>;\n}\n\n/** Values associated with the currently executing Lifecycle host. */\nexport type AgentContextStore = {\n /** Lifecycle host selected for this invocation. */\n agent: unknown;\n /** WebSocket connection selected for this invocation, when applicable. */\n connection: Connection | undefined;\n /** HTTP request selected for this invocation, when applicable. */\n request: Request | undefined;\n /** Extension-owned value selected for this invocation, when applicable. */\n email: unknown;\n};\n\n/** Values returned by {@link getCurrentAgent}. */\nexport type CurrentAgentContext<\n Host extends DurableObject = LifecycleObject,\n Email = unknown\n> = {\n agent: Host | undefined;\n connection: Connection | undefined;\n request: Request | undefined;\n email: Email | undefined;\n};\n\n/**\n * Shared invocation context for Lifecycle, Agent, AIChatAgent, and Think.\n *\n * @internal Importing or relying on this symbol will break your code in a\n * future release. Use {@link getCurrentAgent} to read the public context.\n */\nexport const __DO_NOT_USE_WILL_BREAK__agentContext =\n new AsyncLocalStorage<AgentContextStore>();\n\n/**\n * Return the current Agent or Lifecycle Object and invocation-specific values.\n *\n * Lifecycle host startup and alarm hooks receive the current object with no\n * request. Request hooks additionally receive the request being handled.\n * Lifecycle-managed WebSocket hooks receive their connection and, during\n * connect, its upgrade request. Agent extensions may also establish context\n * for email, chat turns, callable methods, and detached work. Capability hooks\n * do not run in this ambient context.\n */\nexport function getCurrentAgent<\n Host extends DurableObject = LifecycleObject\n>(): CurrentAgentContext<Host> {\n const store = __DO_NOT_USE_WILL_BREAK__agentContext.getStore();\n if (!store) {\n return {\n agent: undefined,\n connection: undefined,\n request: undefined,\n email: undefined\n };\n }\n\n return {\n agent: store.agent as Host,\n connection: store.connection,\n request: store.request,\n email: store.email\n };\n}\n\ntype LifecycleHostContext<\n Env extends object,\n Props extends Record<string, unknown>\n> = {\n readonly host: LifecycleObject<Env, Props>;\n readonly connection?: Connection;\n readonly request?: Request;\n};\n\n/** Run one host hook in the context of its Lifecycle Object. */\nexport function runInLifecycleHostContext<\n Env extends object,\n Props extends Record<string, unknown>,\n T\n>(context: LifecycleHostContext<Env, Props>, operation: () => T): T {\n return __DO_NOT_USE_WILL_BREAK__agentContext.run(\n {\n agent: context.host,\n connection: context.connection,\n request: context.request,\n email: undefined\n },\n operation\n );\n}\n\n/** Run a capability hook without inheriting a current Agent or host context. */\nexport function runWithoutCurrentAgent<T>(operation: () => T): T {\n return __DO_NOT_USE_WILL_BREAK__agentContext.exit(operation);\n}\n"],"mappings":";;;;;;;;AAsEA,MAAa,wCACX,IAAI,kBAAqC;;;;;;;;;;;AAY3C,SAAgB,kBAEe;CAC7B,MAAM,QAAQ,sCAAsC,SAAS;CAC7D,IAAI,CAAC,OACH,OAAO;EACL,OAAO,KAAA;EACP,YAAY,KAAA;EACZ,SAAS,KAAA;EACT,OAAO,KAAA;CACT;CAGF,OAAO;EACL,OAAO,MAAM;EACb,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,OAAO,MAAM;CACf;AACF;;AAYA,SAAgB,0BAId,SAA2C,WAAuB;CAClE,OAAO,sCAAsC,IAC3C;EACE,OAAO,QAAQ;EACf,YAAY,QAAQ;EACpB,SAAS,QAAQ;EACjB,OAAO,KAAA;CACT,GACA,SACF;AACF;;AAGA,SAAgB,uBAA0B,WAAuB;CAC/D,OAAO,sCAAsC,KAAK,SAAS;AAC7D"}
@@ -8,6 +8,8 @@ const channels = {
8
8
  chat: channel("agents:chat"),
9
9
  transcript: channel("agents:transcript"),
10
10
  fiber: channel("agents:fiber"),
11
+ task: channel("agents:task"),
12
+ stream: channel("agents:stream"),
11
13
  agentTool: channel("agents:agent_tool"),
12
14
  schedule: channel("agents:schedule"),
13
15
  lifecycle: channel("agents:lifecycle"),
@@ -20,6 +22,8 @@ function getChannel(type) {
20
22
  if (type.startsWith("mcp:")) return channels.mcp;
21
23
  if (type.startsWith("workflow:")) return channels.workflow;
22
24
  if (type.startsWith("fiber:")) return channels.fiber;
25
+ if (type.startsWith("task:")) return channels.task;
26
+ if (type.startsWith("stream:")) return channels.stream;
23
27
  if (type.startsWith("transcript:") || type.startsWith("chat:transcript:")) return channels.transcript;
24
28
  if (type.startsWith("chat:")) return channels.chat;
25
29
  if (type.startsWith("agent_tool:")) return channels.agentTool;
@@ -38,4 +42,4 @@ function publishDiagnosticsEvent(event) {
38
42
  //#endregion
39
43
  export { publishDiagnosticsEvent as n, channels as t };
40
44
 
41
- //# sourceMappingURL=diagnostics-CaBjfz4J.js.map
45
+ //# sourceMappingURL=diagnostics-BzvaX2UT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-BzvaX2UT.js","names":[],"sources":["../src/observability/diagnostics.ts"],"sourcesContent":["import { channel, type Channel } from \"node:diagnostics_channel\";\n\n/** Event shape accepted by the diagnostics-channel publisher. */\nexport type DiagnosticsEvent = {\n readonly type: string;\n readonly source?: string;\n readonly agent?: string;\n readonly name?: string;\n readonly payload: unknown;\n readonly timestamp: number;\n};\n\n/** Diagnostics channels for Agent and Lifecycle telemetry. */\nexport const channels = {\n state: channel(\"agents:state\"),\n rpc: channel(\"agents:rpc\"),\n message: channel(\"agents:message\"),\n chat: channel(\"agents:chat\"),\n transcript: channel(\"agents:transcript\"),\n fiber: channel(\"agents:fiber\"),\n task: channel(\"agents:task\"),\n stream: channel(\"agents:stream\"),\n agentTool: channel(\"agents:agent_tool\"),\n schedule: channel(\"agents:schedule\"),\n lifecycle: channel(\"agents:lifecycle\"),\n workflow: channel(\"agents:workflow\"),\n mcp: channel(\"agents:mcp\"),\n email: channel(\"agents:email\"),\n channel: channel(\"agents:channel\")\n} as const;\n\nfunction getChannel(type: string): Channel {\n if (type.startsWith(\"mcp:\")) return channels.mcp;\n if (type.startsWith(\"workflow:\")) return channels.workflow;\n if (type.startsWith(\"fiber:\")) return channels.fiber;\n if (type.startsWith(\"task:\")) return channels.task;\n if (type.startsWith(\"stream:\")) return channels.stream;\n if (type.startsWith(\"transcript:\") || type.startsWith(\"chat:transcript:\"))\n return channels.transcript;\n if (type.startsWith(\"chat:\")) return channels.chat;\n if (type.startsWith(\"agent_tool:\")) return channels.agentTool;\n if (type.startsWith(\"schedule:\") || type.startsWith(\"queue:\"))\n return channels.schedule;\n if (\n type.startsWith(\"message:\") ||\n type.startsWith(\"tool:\") ||\n type.startsWith(\"submission:\") ||\n type.startsWith(\"action:\")\n )\n return channels.message;\n if (type === \"rpc\" || type.startsWith(\"rpc:\")) return channels.rpc;\n if (type.startsWith(\"state:\")) return channels.state;\n if (type.startsWith(\"email:\")) return channels.email;\n if (type.startsWith(\"channel:\") || type.startsWith(\"notice:\"))\n return channels.channel;\n return channels.lifecycle;\n}\n\n/** Publish one event to its existing diagnostics channel. */\nexport function publishDiagnosticsEvent(event: DiagnosticsEvent): void {\n getChannel(event.type).publish(event);\n}\n"],"mappings":";;;AAaA,MAAa,WAAW;CACtB,OAAO,QAAQ,cAAc;CAC7B,KAAK,QAAQ,YAAY;CACzB,SAAS,QAAQ,gBAAgB;CACjC,MAAM,QAAQ,aAAa;CAC3B,YAAY,QAAQ,mBAAmB;CACvC,OAAO,QAAQ,cAAc;CAC7B,MAAM,QAAQ,aAAa;CAC3B,QAAQ,QAAQ,eAAe;CAC/B,WAAW,QAAQ,mBAAmB;CACtC,UAAU,QAAQ,iBAAiB;CACnC,WAAW,QAAQ,kBAAkB;CACrC,UAAU,QAAQ,iBAAiB;CACnC,KAAK,QAAQ,YAAY;CACzB,OAAO,QAAQ,cAAc;CAC7B,SAAS,QAAQ,gBAAgB;AACnC;AAEA,SAAS,WAAW,MAAuB;CACzC,IAAI,KAAK,WAAW,MAAM,GAAG,OAAO,SAAS;CAC7C,IAAI,KAAK,WAAW,WAAW,GAAG,OAAO,SAAS;CAClD,IAAI,KAAK,WAAW,QAAQ,GAAG,OAAO,SAAS;CAC/C,IAAI,KAAK,WAAW,OAAO,GAAG,OAAO,SAAS;CAC9C,IAAI,KAAK,WAAW,SAAS,GAAG,OAAO,SAAS;CAChD,IAAI,KAAK,WAAW,aAAa,KAAK,KAAK,WAAW,kBAAkB,GACtE,OAAO,SAAS;CAClB,IAAI,KAAK,WAAW,OAAO,GAAG,OAAO,SAAS;CAC9C,IAAI,KAAK,WAAW,aAAa,GAAG,OAAO,SAAS;CACpD,IAAI,KAAK,WAAW,WAAW,KAAK,KAAK,WAAW,QAAQ,GAC1D,OAAO,SAAS;CAClB,IACE,KAAK,WAAW,UAAU,KAC1B,KAAK,WAAW,OAAO,KACvB,KAAK,WAAW,aAAa,KAC7B,KAAK,WAAW,SAAS,GAEzB,OAAO,SAAS;CAClB,IAAI,SAAS,SAAS,KAAK,WAAW,MAAM,GAAG,OAAO,SAAS;CAC/D,IAAI,KAAK,WAAW,QAAQ,GAAG,OAAO,SAAS;CAC/C,IAAI,KAAK,WAAW,QAAQ,GAAG,OAAO,SAAS;CAC/C,IAAI,KAAK,WAAW,UAAU,KAAK,KAAK,WAAW,SAAS,GAC1D,OAAO,SAAS;CAClB,OAAO,SAAS;AAClB;;AAGA,SAAgB,wBAAwB,OAA+B;CACrE,WAAW,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK;AACtC"}
@@ -0,0 +1,360 @@
1
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
2
+ import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
3
+ import { VoiceProviderError } from "./voice/errors.js";
4
+ //#region src/voice/diagnostics.ts
5
+ const MAX_STRING_LENGTH = 160;
6
+ const PRIVATE_KEY = /(^|_)(audio|body|contents?|exceptions?|messages?|prompts?|query|results?|stack|text|tokens?|tools?|transcripts?|arguments?)(_|$)/i;
7
+ function boundedString(value, maxLength = MAX_STRING_LENGTH) {
8
+ const normalized = value.replace(/\s+/g, " ").trim();
9
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1)}…`;
10
+ }
11
+ function diagnosticErrorData(error) {
12
+ const summary = {
13
+ name: boundedString(error.name || "Error"),
14
+ message: boundedString(error.message || "Unknown error")
15
+ };
16
+ if (error instanceof VoiceProviderError) {
17
+ if (error.code !== void 0) summary.code = error.code;
18
+ if (error.status !== void 0) summary.status = error.status;
19
+ if (error.closeCode !== void 0) summary.closeCode = error.closeCode;
20
+ if (error.closeReason !== void 0) summary.closeReason = boundedString(error.closeReason);
21
+ if (error.wasClean !== void 0) summary.wasClean = error.wasClean;
22
+ }
23
+ return summary;
24
+ }
25
+ /**
26
+ * Keep diagnostic metadata bounded and reject fields that could carry user or
27
+ * provider content. Instrumentation should still pass only known-safe values.
28
+ */
29
+ function sanitizeDiagnosticData(data) {
30
+ if (!data) return void 0;
31
+ const sanitized = {};
32
+ for (const [key, value] of Object.entries(data)) {
33
+ if (PRIVATE_KEY.test(key)) continue;
34
+ sanitized[key] = value instanceof Error ? diagnosticErrorData(value) : typeof value === "string" ? boundedString(value) : value;
35
+ }
36
+ return Object.keys(sanitized).length > 0 ? sanitized : void 0;
37
+ }
38
+ function createDiagnosticEvent(event, data, timestamp = Date.now()) {
39
+ const safeData = sanitizeDiagnosticData(data);
40
+ return {
41
+ event,
42
+ timestamp,
43
+ ...safeData ? { data: safeData } : {}
44
+ };
45
+ }
46
+ /** Server-only diagnostics. The sink is the reserved voice protocol message. */
47
+ var ServerDiagnostics = class {
48
+ constructor(browserConsole) {
49
+ this.browserConsole = browserConsole;
50
+ }
51
+ emit(connection, event, data) {
52
+ if (!this.browserConsole) return;
53
+ try {
54
+ connection.send(JSON.stringify({
55
+ type: "diagnostic",
56
+ ...createDiagnosticEvent(event, data)
57
+ }));
58
+ } catch {}
59
+ }
60
+ turn(connection, turnId, source = "speech", now = Date.now) {
61
+ return new TurnDiagnostics(this, connection, turnId, source, now);
62
+ }
63
+ };
64
+ function safeDuration(value) {
65
+ return Math.max(0, value);
66
+ }
67
+ var _turn = /* @__PURE__ */ new WeakMap();
68
+ var _startedAt = /* @__PURE__ */ new WeakMap();
69
+ /** One sentence attempt measured by its parent turn clock. */
70
+ var TtsSentenceTracker = class {
71
+ constructor(turn, startedAt) {
72
+ _classPrivateFieldInitSpec(this, _turn, void 0);
73
+ _classPrivateFieldInitSpec(this, _startedAt, void 0);
74
+ _classPrivateFieldSet2(_turn, this, turn);
75
+ _classPrivateFieldSet2(_startedAt, this, startedAt);
76
+ }
77
+ providerStarted() {
78
+ _classPrivateFieldGet2(_turn, this).recordTtsProviderStarted();
79
+ }
80
+ settle(outcome) {
81
+ return _classPrivateFieldGet2(_turn, this).recordTtsSentence(_classPrivateFieldGet2(_startedAt, this), outcome);
82
+ }
83
+ };
84
+ var _diagnostics = /* @__PURE__ */ new WeakMap();
85
+ var _connection = /* @__PURE__ */ new WeakMap();
86
+ var _now = /* @__PURE__ */ new WeakMap();
87
+ var _startedAt2 = /* @__PURE__ */ new WeakMap();
88
+ var _speechStartedAt = /* @__PURE__ */ new WeakMap();
89
+ var _firstInterimObserved = /* @__PURE__ */ new WeakMap();
90
+ var _finalInputAt = /* @__PURE__ */ new WeakMap();
91
+ var _firstTtsProviderAt = /* @__PURE__ */ new WeakMap();
92
+ var _firstAudioAt = /* @__PURE__ */ new WeakMap();
93
+ var _ttsFinished = /* @__PURE__ */ new WeakMap();
94
+ var _hasTtsFailures = /* @__PURE__ */ new WeakMap();
95
+ var _metrics = /* @__PURE__ */ new WeakMap();
96
+ /**
97
+ * One content-free turn lifecycle. Diagnostics and stable metrics are emitted
98
+ * from the same recorded landmarks; application metrics never parse event
99
+ * names or diagnostic metadata.
100
+ */
101
+ var TurnDiagnostics = class {
102
+ constructor(diagnostics, connection, turnId, source, now) {
103
+ _classPrivateFieldInitSpec(this, _diagnostics, void 0);
104
+ _classPrivateFieldInitSpec(this, _connection, void 0);
105
+ _classPrivateFieldInitSpec(this, _now, void 0);
106
+ _classPrivateFieldInitSpec(this, _startedAt2, void 0);
107
+ _classPrivateFieldInitSpec(this, _speechStartedAt, void 0);
108
+ _classPrivateFieldInitSpec(this, _firstInterimObserved, false);
109
+ _classPrivateFieldInitSpec(this, _finalInputAt, void 0);
110
+ _classPrivateFieldInitSpec(this, _firstTtsProviderAt, void 0);
111
+ _classPrivateFieldInitSpec(this, _firstAudioAt, void 0);
112
+ _classPrivateFieldInitSpec(this, _ttsFinished, false);
113
+ _classPrivateFieldInitSpec(this, _hasTtsFailures, false);
114
+ _classPrivateFieldInitSpec(this, _metrics, {});
115
+ _classPrivateFieldSet2(_diagnostics, this, diagnostics);
116
+ _classPrivateFieldSet2(_connection, this, connection);
117
+ _classPrivateFieldSet2(_now, this, now);
118
+ _classPrivateFieldSet2(_startedAt2, this, now());
119
+ this.turnId = turnId;
120
+ this.source = source;
121
+ }
122
+ get hasTtsFailures() {
123
+ return _classPrivateFieldGet2(_hasTtsFailures, this);
124
+ }
125
+ get ttsWorkMs() {
126
+ return _classPrivateFieldGet2(_metrics, this).ttsWorkMs ?? 0;
127
+ }
128
+ emit(event, data) {
129
+ const scopedData = {
130
+ ...data,
131
+ turn_id: this.turnId
132
+ };
133
+ _classPrivateFieldGet2(_diagnostics, this).emit(_classPrivateFieldGet2(_connection, this), event, scopedData);
134
+ }
135
+ startModel() {
136
+ return new ModelDiagnosticTracker(this, _classPrivateFieldGet2(_now, this));
137
+ }
138
+ markTextInput() {
139
+ _classPrivateFieldGet2(_finalInputAt, this) ?? _classPrivateFieldSet2(_finalInputAt, this, _classPrivateFieldGet2(_startedAt2, this));
140
+ }
141
+ speechStarted() {
142
+ _classPrivateFieldGet2(_speechStartedAt, this) ?? _classPrivateFieldSet2(_speechStartedAt, this, _classPrivateFieldGet2(_now, this).call(this));
143
+ this.emit("speech.started");
144
+ }
145
+ firstInterim(characters) {
146
+ if (_classPrivateFieldGet2(_firstInterimObserved, this)) return;
147
+ _classPrivateFieldSet2(_firstInterimObserved, this, true);
148
+ const elapsed = _classPrivateFieldGet2(_speechStartedAt, this) === void 0 ? void 0 : safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_speechStartedAt, this));
149
+ if (elapsed !== void 0) _classPrivateFieldGet2(_metrics, this).speechStartToFirstInterimMs = elapsed;
150
+ this.emit("stt.interim", {
151
+ ...characters === void 0 ? {} : { characters },
152
+ ...elapsed === void 0 ? {} : { speech_to_interim_ms: elapsed }
153
+ });
154
+ }
155
+ finalInput(characters) {
156
+ _classPrivateFieldSet2(_finalInputAt, this, _classPrivateFieldGet2(_now, this).call(this));
157
+ const elapsed = _classPrivateFieldGet2(_speechStartedAt, this) === void 0 ? void 0 : safeDuration(_classPrivateFieldGet2(_finalInputAt, this) - _classPrivateFieldGet2(_speechStartedAt, this));
158
+ if (elapsed !== void 0) _classPrivateFieldGet2(_metrics, this).speechStartToFinalMs = elapsed;
159
+ this.emit("stt.utterance", {
160
+ ...characters === void 0 ? {} : { characters },
161
+ ...elapsed === void 0 ? {} : { speech_to_final_ms: elapsed }
162
+ });
163
+ }
164
+ recordAfterTranscribe(durationMs, outcome, characters) {
165
+ _classPrivateFieldGet2(_metrics, this).afterTranscribeMs = safeDuration(durationMs);
166
+ this.emit("after_transcribe.completed", {
167
+ duration_ms: safeDuration(durationMs),
168
+ outcome,
169
+ characters
170
+ });
171
+ }
172
+ beginTtsSentence() {
173
+ _classPrivateFieldGet2(_metrics, this).ttsWorkMs ??= 0;
174
+ return new TtsSentenceTracker(this, _classPrivateFieldGet2(_now, this).call(this));
175
+ }
176
+ recordTtsProviderStarted() {
177
+ _classPrivateFieldGet2(_firstTtsProviderAt, this) ?? _classPrivateFieldSet2(_firstTtsProviderAt, this, _classPrivateFieldGet2(_now, this).call(this));
178
+ }
179
+ recordTtsSentence(startedAt, outcome) {
180
+ const duration = safeDuration(_classPrivateFieldGet2(_now, this).call(this) - startedAt);
181
+ _classPrivateFieldGet2(_metrics, this).ttsWorkMs = (_classPrivateFieldGet2(_metrics, this).ttsWorkMs ?? 0) + duration;
182
+ if (outcome === "failed") _classPrivateFieldSet2(_hasTtsFailures, this, true);
183
+ return duration;
184
+ }
185
+ finishTts() {
186
+ if (_classPrivateFieldGet2(_ttsFinished, this)) return;
187
+ _classPrivateFieldSet2(_ttsFinished, this, true);
188
+ if (_classPrivateFieldGet2(_firstTtsProviderAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).ttsWallMs = safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_firstTtsProviderAt, this));
189
+ }
190
+ audioSent() {
191
+ const now = _classPrivateFieldGet2(_now, this).call(this);
192
+ if (_classPrivateFieldGet2(_firstAudioAt, this) !== void 0) return;
193
+ _classPrivateFieldSet2(_firstAudioAt, this, now);
194
+ if (_classPrivateFieldGet2(_finalInputAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).finalInputToFirstAudioMs = safeDuration(now - _classPrivateFieldGet2(_finalInputAt, this));
195
+ if (_classPrivateFieldGet2(_firstTtsProviderAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).ttsToFirstAudioMs = safeDuration(now - _classPrivateFieldGet2(_firstTtsProviderAt, this));
196
+ }
197
+ recordModelFirstText(durationMs) {
198
+ _classPrivateFieldGet2(_metrics, this).modelToFirstTextMs = safeDuration(durationMs);
199
+ }
200
+ recordReasoning(durationMs) {
201
+ _classPrivateFieldGet2(_metrics, this).exposedReasoningMs = (_classPrivateFieldGet2(_metrics, this).exposedReasoningMs ?? 0) + safeDuration(durationMs);
202
+ }
203
+ recordModelTerminal(durationMs) {
204
+ _classPrivateFieldGet2(_metrics, this).modelStreamConsumptionMs = safeDuration(durationMs);
205
+ }
206
+ finish(outcome) {
207
+ this.finishTts();
208
+ const summary = {
209
+ turnId: this.turnId,
210
+ source: this.source,
211
+ outcome,
212
+ turnTotalMs: safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_startedAt2, this)),
213
+ ..._classPrivateFieldGet2(_metrics, this)
214
+ };
215
+ this.emit("turn.ended", {
216
+ outcome,
217
+ duration_ms: summary.turnTotalMs
218
+ });
219
+ try {
220
+ _classPrivateFieldGet2(_connection, this).send(JSON.stringify({
221
+ type: "turn_metrics",
222
+ ...summary
223
+ }));
224
+ } catch {}
225
+ return summary;
226
+ }
227
+ };
228
+ var _turn2 = /* @__PURE__ */ new WeakMap();
229
+ var _now2 = /* @__PURE__ */ new WeakMap();
230
+ var _startedAt3 = /* @__PURE__ */ new WeakMap();
231
+ var _firstTextObserved = /* @__PURE__ */ new WeakMap();
232
+ var _reasoningActive = /* @__PURE__ */ new WeakMap();
233
+ var _reasoningStartedAt = /* @__PURE__ */ new WeakMap();
234
+ var _characters = /* @__PURE__ */ new WeakMap();
235
+ var _terminal = /* @__PURE__ */ new WeakMap();
236
+ var _ModelDiagnosticTracker_brand = /* @__PURE__ */ new WeakSet();
237
+ /**
238
+ * Tracks one model stream without retaining model or reasoning content.
239
+ * Lifecycle methods are idempotent so stale turn cleanup cannot affect a
240
+ * successor tracker.
241
+ */
242
+ var ModelDiagnosticTracker = class {
243
+ constructor(turn, now) {
244
+ _classPrivateMethodInitSpec(this, _ModelDiagnosticTracker_brand);
245
+ _classPrivateFieldInitSpec(this, _turn2, void 0);
246
+ _classPrivateFieldInitSpec(this, _now2, void 0);
247
+ _classPrivateFieldInitSpec(this, _startedAt3, void 0);
248
+ _classPrivateFieldInitSpec(this, _firstTextObserved, false);
249
+ _classPrivateFieldInitSpec(this, _reasoningActive, false);
250
+ _classPrivateFieldInitSpec(this, _reasoningStartedAt, 0);
251
+ _classPrivateFieldInitSpec(this, _characters, 0);
252
+ _classPrivateFieldInitSpec(this, _terminal, false);
253
+ _classPrivateFieldSet2(_turn2, this, turn);
254
+ _classPrivateFieldSet2(_now2, this, now);
255
+ _classPrivateFieldSet2(_startedAt3, this, now());
256
+ _classPrivateFieldGet2(_turn2, this).emit("model.started");
257
+ }
258
+ observe(event) {
259
+ if (_classPrivateFieldGet2(_terminal, this)) return;
260
+ switch (event.type) {
261
+ case "text":
262
+ _classPrivateFieldSet2(_characters, this, _classPrivateFieldGet2(_characters, this) + event.text.length);
263
+ if (!_classPrivateFieldGet2(_firstTextObserved, this) && event.text.trim().length > 0) {
264
+ _classPrivateFieldSet2(_firstTextObserved, this, true);
265
+ const elapsed = safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_startedAt3, this));
266
+ _classPrivateFieldGet2(_turn2, this).recordModelFirstText(elapsed);
267
+ _classPrivateFieldGet2(_turn2, this).emit("model.first_text", { elapsed_ms: elapsed });
268
+ }
269
+ break;
270
+ case "reasoning-start":
271
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _startReasoning).call(this);
272
+ break;
273
+ case "reasoning-end":
274
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "completed");
275
+ break;
276
+ case "finish":
277
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "stream_finished");
278
+ break;
279
+ case "error": break;
280
+ case "boundary": break;
281
+ }
282
+ }
283
+ complete(outcome, finishReason) {
284
+ if (_classPrivateFieldGet2(_terminal, this)) return;
285
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "stream_completed");
286
+ _classPrivateFieldSet2(_terminal, this, true);
287
+ const duration = this.elapsedMs();
288
+ _classPrivateFieldGet2(_turn2, this).recordModelTerminal(duration);
289
+ _classPrivateFieldGet2(_turn2, this).emit("model.completed", {
290
+ duration_ms: duration,
291
+ outcome,
292
+ characters: _classPrivateFieldGet2(_characters, this),
293
+ ...finishReason === void 0 ? {} : { finish_reason: finishReason }
294
+ });
295
+ }
296
+ fail(error) {
297
+ if (_classPrivateFieldGet2(_terminal, this)) return;
298
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "error");
299
+ _classPrivateFieldSet2(_terminal, this, true);
300
+ _classPrivateFieldGet2(_turn2, this).recordModelTerminal(this.elapsedMs());
301
+ _classPrivateFieldGet2(_turn2, this).emit("model.failed", { error });
302
+ }
303
+ abort() {
304
+ if (_classPrivateFieldGet2(_terminal, this)) return;
305
+ _assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "aborted");
306
+ _classPrivateFieldSet2(_terminal, this, true);
307
+ _classPrivateFieldGet2(_turn2, this).recordModelTerminal(this.elapsedMs());
308
+ }
309
+ elapsedMs() {
310
+ return safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_startedAt3, this));
311
+ }
312
+ };
313
+ function _startReasoning() {
314
+ if (_classPrivateFieldGet2(_reasoningActive, this)) return;
315
+ _classPrivateFieldSet2(_reasoningActive, this, true);
316
+ _classPrivateFieldSet2(_reasoningStartedAt, this, _classPrivateFieldGet2(_now2, this).call(this));
317
+ _classPrivateFieldGet2(_turn2, this).emit("model.reasoning_started");
318
+ }
319
+ function _completeReasoning(outcome) {
320
+ if (!_classPrivateFieldGet2(_reasoningActive, this)) return;
321
+ _classPrivateFieldSet2(_reasoningActive, this, false);
322
+ const duration = safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_reasoningStartedAt, this));
323
+ _classPrivateFieldGet2(_turn2, this).recordReasoning(duration);
324
+ _classPrivateFieldGet2(_turn2, this).emit("model.reasoning_completed", {
325
+ duration_ms: duration,
326
+ outcome
327
+ });
328
+ }
329
+ var _enabled = /* @__PURE__ */ new WeakMap();
330
+ var _ClientDiagnostics_brand = /* @__PURE__ */ new WeakSet();
331
+ /** Browser-only diagnostics. Activation always comes from the server welcome. */
332
+ var ClientDiagnostics = class {
333
+ constructor() {
334
+ _classPrivateMethodInitSpec(this, _ClientDiagnostics_brand);
335
+ _classPrivateFieldInitSpec(this, _enabled, false);
336
+ }
337
+ setEnabled(enabled) {
338
+ _classPrivateFieldSet2(_enabled, this, enabled);
339
+ }
340
+ emit(event, data) {
341
+ if (!_classPrivateFieldGet2(_enabled, this)) return;
342
+ _assertClassBrand(_ClientDiagnostics_brand, this, _log).call(this, "client", createDiagnosticEvent(event, data));
343
+ }
344
+ receive(event) {
345
+ if (!_classPrivateFieldGet2(_enabled, this)) return;
346
+ _assertClassBrand(_ClientDiagnostics_brand, this, _log).call(this, "server", event);
347
+ }
348
+ };
349
+ function _log(origin, event) {
350
+ try {
351
+ console.info(`[voice:${origin}] ${event.event}`, {
352
+ timestamp: event.timestamp,
353
+ ...event.data ?? {}
354
+ });
355
+ } catch {}
356
+ }
357
+ //#endregion
358
+ export { ServerDiagnostics as n, ClientDiagnostics as t };
359
+
360
+ //# sourceMappingURL=diagnostics-C4jcz3VK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-C4jcz3VK.js","names":[],"sources":["../src/voice/diagnostics.ts"],"sourcesContent":["import { VoiceProviderError } from \"./errors\";\nimport type { TextStreamEvent } from \"./text-stream\";\nimport type {\n VoiceDiagnosticEvent,\n VoiceModelFinishReason,\n VoiceTurnMetrics,\n VoiceTurnOutcome,\n VoiceTurnSource\n} from \"./types\";\n\nconst MAX_STRING_LENGTH = 160;\n\nconst PRIVATE_KEY =\n /(^|_)(audio|body|contents?|exceptions?|messages?|prompts?|query|results?|stack|text|tokens?|tools?|transcripts?|arguments?)(_|$)/i;\n\ntype DiagnosticValue = string | number | boolean | null | Error;\nexport type DiagnosticData = Record<string, DiagnosticValue>;\n\ntype DiagnosticConnection = {\n send(data: string | ArrayBuffer): void;\n};\n\nfunction boundedString(value: string, maxLength = MAX_STRING_LENGTH): string {\n const normalized = value.replace(/\\s+/g, \" \").trim();\n return normalized.length <= maxLength\n ? normalized\n : `${normalized.slice(0, maxLength - 1)}…`;\n}\n\nfunction diagnosticErrorData(error: Error): Record<string, unknown> {\n const summary: Record<string, unknown> = {\n name: boundedString(error.name || \"Error\"),\n message: boundedString(error.message || \"Unknown error\")\n };\n\n if (error instanceof VoiceProviderError) {\n if (error.code !== undefined) summary.code = error.code;\n if (error.status !== undefined) summary.status = error.status;\n if (error.closeCode !== undefined) summary.closeCode = error.closeCode;\n if (error.closeReason !== undefined) {\n summary.closeReason = boundedString(error.closeReason);\n }\n if (error.wasClean !== undefined) summary.wasClean = error.wasClean;\n }\n\n return summary;\n}\n\n/**\n * Keep diagnostic metadata bounded and reject fields that could carry user or\n * provider content. Instrumentation should still pass only known-safe values.\n */\nexport function sanitizeDiagnosticData(\n data?: DiagnosticData\n): Record<string, unknown> | undefined {\n if (!data) return undefined;\n\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (PRIVATE_KEY.test(key)) continue;\n sanitized[key] =\n value instanceof Error\n ? diagnosticErrorData(value)\n : typeof value === \"string\"\n ? boundedString(value)\n : value;\n }\n\n return Object.keys(sanitized).length > 0 ? sanitized : undefined;\n}\n\nfunction createDiagnosticEvent(\n event: string,\n data?: DiagnosticData,\n timestamp = Date.now()\n): VoiceDiagnosticEvent {\n const safeData = sanitizeDiagnosticData(data);\n return {\n event,\n timestamp,\n ...(safeData ? { data: safeData } : {})\n };\n}\n\n/** Server-only diagnostics. The sink is the reserved voice protocol message. */\nexport class ServerDiagnostics {\n readonly browserConsole: boolean;\n\n constructor(browserConsole: boolean) {\n this.browserConsole = browserConsole;\n }\n\n emit(\n connection: DiagnosticConnection,\n event: string,\n data?: DiagnosticData\n ): void {\n if (!this.browserConsole) return;\n\n try {\n connection.send(\n JSON.stringify({\n type: \"diagnostic\",\n ...createDiagnosticEvent(event, data)\n })\n );\n } catch {\n // Diagnostics must never alter call behavior.\n }\n }\n\n turn(\n connection: DiagnosticConnection,\n turnId: string,\n source: VoiceTurnSource = \"speech\",\n now: () => number = Date.now\n ): TurnDiagnostics {\n return new TurnDiagnostics(this, connection, turnId, source, now);\n }\n}\n\nfunction safeDuration(value: number): number {\n return Math.max(0, value);\n}\n\nexport type TtsSentenceOutcome = \"completed\" | \"skipped\" | \"failed\";\n\n/** One sentence attempt measured by its parent turn clock. */\nexport class TtsSentenceTracker {\n #turn: TurnDiagnostics;\n #startedAt: number;\n\n constructor(turn: TurnDiagnostics, startedAt: number) {\n this.#turn = turn;\n this.#startedAt = startedAt;\n }\n\n providerStarted(): void {\n this.#turn.recordTtsProviderStarted();\n }\n\n settle(outcome: TtsSentenceOutcome): number {\n return this.#turn.recordTtsSentence(this.#startedAt, outcome);\n }\n}\n\n/**\n * One content-free turn lifecycle. Diagnostics and stable metrics are emitted\n * from the same recorded landmarks; application metrics never parse event\n * names or diagnostic metadata.\n */\nexport class TurnDiagnostics {\n readonly turnId: string;\n readonly source: VoiceTurnSource;\n #diagnostics: ServerDiagnostics;\n #connection: DiagnosticConnection;\n #now: () => number;\n #startedAt: number;\n #speechStartedAt: number | undefined;\n #firstInterimObserved = false;\n #finalInputAt: number | undefined;\n #firstTtsProviderAt: number | undefined;\n #firstAudioAt: number | undefined;\n #ttsFinished = false;\n #hasTtsFailures = false;\n #metrics: Partial<VoiceTurnMetrics> = {};\n\n constructor(\n diagnostics: ServerDiagnostics,\n connection: DiagnosticConnection,\n turnId: string,\n source: VoiceTurnSource,\n now: () => number\n ) {\n this.#diagnostics = diagnostics;\n this.#connection = connection;\n this.#now = now;\n this.#startedAt = now();\n this.turnId = turnId;\n this.source = source;\n }\n\n get hasTtsFailures(): boolean {\n return this.#hasTtsFailures;\n }\n\n get ttsWorkMs(): number {\n return this.#metrics.ttsWorkMs ?? 0;\n }\n\n emit(event: string, data?: DiagnosticData): void {\n const scopedData: DiagnosticData = {\n ...data,\n turn_id: this.turnId\n };\n this.#diagnostics.emit(this.#connection, event, scopedData);\n }\n\n startModel(): ModelDiagnosticTracker {\n return new ModelDiagnosticTracker(this, this.#now);\n }\n\n markTextInput(): void {\n this.#finalInputAt ??= this.#startedAt;\n }\n\n speechStarted(): void {\n this.#speechStartedAt ??= this.#now();\n this.emit(\"speech.started\");\n }\n\n firstInterim(characters?: number): void {\n if (this.#firstInterimObserved) return;\n this.#firstInterimObserved = true;\n const elapsed =\n this.#speechStartedAt === undefined\n ? undefined\n : safeDuration(this.#now() - this.#speechStartedAt);\n if (elapsed !== undefined) {\n this.#metrics.speechStartToFirstInterimMs = elapsed;\n }\n this.emit(\"stt.interim\", {\n ...(characters === undefined ? {} : { characters }),\n ...(elapsed === undefined ? {} : { speech_to_interim_ms: elapsed })\n });\n }\n\n finalInput(characters?: number): void {\n this.#finalInputAt = this.#now();\n const elapsed =\n this.#speechStartedAt === undefined\n ? undefined\n : safeDuration(this.#finalInputAt - this.#speechStartedAt);\n if (elapsed !== undefined) this.#metrics.speechStartToFinalMs = elapsed;\n this.emit(\"stt.utterance\", {\n ...(characters === undefined ? {} : { characters }),\n ...(elapsed === undefined ? {} : { speech_to_final_ms: elapsed })\n });\n }\n\n recordAfterTranscribe(\n durationMs: number,\n outcome: \"accepted\" | \"skipped\",\n characters: number\n ): void {\n this.#metrics.afterTranscribeMs = safeDuration(durationMs);\n this.emit(\"after_transcribe.completed\", {\n duration_ms: safeDuration(durationMs),\n outcome,\n characters\n });\n }\n\n beginTtsSentence(): TtsSentenceTracker {\n this.#metrics.ttsWorkMs ??= 0;\n return new TtsSentenceTracker(this, this.#now());\n }\n\n recordTtsProviderStarted(): void {\n this.#firstTtsProviderAt ??= this.#now();\n }\n\n recordTtsSentence(startedAt: number, outcome: TtsSentenceOutcome): number {\n const duration = safeDuration(this.#now() - startedAt);\n this.#metrics.ttsWorkMs = (this.#metrics.ttsWorkMs ?? 0) + duration;\n if (outcome === \"failed\") this.#hasTtsFailures = true;\n return duration;\n }\n\n finishTts(): void {\n if (this.#ttsFinished) return;\n this.#ttsFinished = true;\n if (this.#firstTtsProviderAt !== undefined) {\n this.#metrics.ttsWallMs = safeDuration(\n this.#now() - this.#firstTtsProviderAt\n );\n }\n }\n\n audioSent(): void {\n const now = this.#now();\n if (this.#firstAudioAt !== undefined) return;\n this.#firstAudioAt = now;\n if (this.#finalInputAt !== undefined) {\n this.#metrics.finalInputToFirstAudioMs = safeDuration(\n now - this.#finalInputAt\n );\n }\n if (this.#firstTtsProviderAt !== undefined) {\n this.#metrics.ttsToFirstAudioMs = safeDuration(\n now - this.#firstTtsProviderAt\n );\n }\n }\n\n recordModelFirstText(durationMs: number): void {\n this.#metrics.modelToFirstTextMs = safeDuration(durationMs);\n }\n\n recordReasoning(durationMs: number): void {\n this.#metrics.exposedReasoningMs =\n (this.#metrics.exposedReasoningMs ?? 0) + safeDuration(durationMs);\n }\n\n recordModelTerminal(durationMs: number): void {\n this.#metrics.modelStreamConsumptionMs = safeDuration(durationMs);\n }\n\n finish(outcome: VoiceTurnOutcome): VoiceTurnMetrics {\n this.finishTts();\n\n const summary: VoiceTurnMetrics = {\n turnId: this.turnId,\n source: this.source,\n outcome,\n turnTotalMs: safeDuration(this.#now() - this.#startedAt),\n ...this.#metrics\n };\n\n this.emit(\"turn.ended\", {\n outcome,\n duration_ms: summary.turnTotalMs\n });\n try {\n this.#connection.send(\n JSON.stringify({ type: \"turn_metrics\", ...summary })\n );\n } catch {\n // A closing connection can make the terminal summary undeliverable.\n }\n return summary;\n }\n}\n\n/**\n * Tracks one model stream without retaining model or reasoning content.\n * Lifecycle methods are idempotent so stale turn cleanup cannot affect a\n * successor tracker.\n */\nexport class ModelDiagnosticTracker {\n #turn: TurnDiagnostics;\n #now: () => number;\n #startedAt: number;\n #firstTextObserved = false;\n #reasoningActive = false;\n #reasoningStartedAt = 0;\n #characters = 0;\n #terminal = false;\n\n constructor(turn: TurnDiagnostics, now: () => number) {\n this.#turn = turn;\n this.#now = now;\n this.#startedAt = now();\n this.#turn.emit(\"model.started\");\n }\n\n observe(event: TextStreamEvent): void {\n if (this.#terminal) return;\n\n switch (event.type) {\n case \"text\":\n this.#characters += event.text.length;\n if (!this.#firstTextObserved && event.text.trim().length > 0) {\n this.#firstTextObserved = true;\n const elapsed = safeDuration(this.#now() - this.#startedAt);\n this.#turn.recordModelFirstText(elapsed);\n this.#turn.emit(\"model.first_text\", { elapsed_ms: elapsed });\n }\n break;\n case \"reasoning-start\":\n this.#startReasoning();\n break;\n case \"reasoning-end\":\n this.#completeReasoning(\"completed\");\n break;\n case \"finish\":\n this.#completeReasoning(\"stream_finished\");\n break;\n case \"error\":\n break;\n case \"boundary\":\n break;\n }\n }\n\n complete(\n outcome: \"output\" | \"no_output\",\n finishReason?: VoiceModelFinishReason\n ): void {\n if (this.#terminal) return;\n this.#completeReasoning(\"stream_completed\");\n this.#terminal = true;\n const duration = this.elapsedMs();\n this.#turn.recordModelTerminal(duration);\n this.#turn.emit(\"model.completed\", {\n duration_ms: duration,\n outcome,\n characters: this.#characters,\n ...(finishReason === undefined ? {} : { finish_reason: finishReason })\n });\n }\n\n fail(error: Error): void {\n if (this.#terminal) return;\n this.#completeReasoning(\"error\");\n this.#terminal = true;\n this.#turn.recordModelTerminal(this.elapsedMs());\n this.#turn.emit(\"model.failed\", { error });\n }\n\n abort(): void {\n if (this.#terminal) return;\n this.#completeReasoning(\"aborted\");\n this.#terminal = true;\n this.#turn.recordModelTerminal(this.elapsedMs());\n }\n\n elapsedMs(): number {\n return safeDuration(this.#now() - this.#startedAt);\n }\n\n #startReasoning(): void {\n if (this.#reasoningActive) return;\n this.#reasoningActive = true;\n this.#reasoningStartedAt = this.#now();\n this.#turn.emit(\"model.reasoning_started\");\n }\n\n #completeReasoning(outcome: string): void {\n if (!this.#reasoningActive) return;\n this.#reasoningActive = false;\n const duration = safeDuration(this.#now() - this.#reasoningStartedAt);\n this.#turn.recordReasoning(duration);\n this.#turn.emit(\"model.reasoning_completed\", {\n duration_ms: duration,\n outcome\n });\n }\n}\n\n/** Browser-only diagnostics. Activation always comes from the server welcome. */\nexport class ClientDiagnostics {\n #enabled = false;\n\n setEnabled(enabled: boolean): void {\n this.#enabled = enabled;\n }\n\n emit(event: string, data?: DiagnosticData): void {\n if (!this.#enabled) return;\n this.#log(\"client\", createDiagnosticEvent(event, data));\n }\n\n receive(event: VoiceDiagnosticEvent): void {\n if (!this.#enabled) return;\n this.#log(\"server\", event);\n }\n\n #log(origin: \"client\" | \"server\", event: VoiceDiagnosticEvent): void {\n try {\n console.info(`[voice:${origin}] ${event.event}`, {\n timestamp: event.timestamp,\n ...(event.data ?? {})\n });\n } catch {\n // Console replacements and test spies are allowed to throw.\n }\n }\n}\n"],"mappings":"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"}