agents 0.24.0 → 0.26.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 (170) hide show
  1. package/dist/{agent-routing-B2XLNMxq.d.ts → agent-routing-0DR0Tk2v.d.ts} +205 -132
  2. package/dist/agent-routing.d.ts +1 -1
  3. package/dist/agent-routing.js.map +1 -1
  4. package/dist/agent-tool-types.d.ts +28 -22
  5. package/dist/agent-tool-types.js +23 -1
  6. package/dist/agent-tool-types.js.map +1 -1
  7. package/dist/{agent-tools-y7zLfw4Q.js → agent-tools-CdJC-8Dc.js} +72 -9
  8. package/dist/agent-tools-CdJC-8Dc.js.map +1 -0
  9. package/dist/{agent-tools-Dj5Mzlw7.d.ts → agent-tools-YrATZJu2.d.ts} +34 -20
  10. package/dist/agent-tools.d.ts +20 -18
  11. package/dist/agent-tools.js.map +1 -1
  12. package/dist/ai-fm7xx1BK.js +312 -0
  13. package/dist/ai-fm7xx1BK.js.map +1 -0
  14. package/dist/base64-redaction-C1Uu29t5.js +59 -0
  15. package/dist/base64-redaction-C1Uu29t5.js.map +1 -0
  16. package/dist/browser/ai-sdk.d.ts +90 -0
  17. package/dist/browser/ai-sdk.js +51 -0
  18. package/dist/browser/ai-sdk.js.map +1 -0
  19. package/dist/browser/ai.d.ts +4 -4
  20. package/dist/browser/ai.js +1 -347
  21. package/dist/browser/index.d.ts +81 -79
  22. package/dist/browser/index.js +361 -2
  23. package/dist/browser/index.js.map +1 -0
  24. package/dist/browser/tanstack-ai.d.ts +96 -1
  25. package/dist/browser/tanstack-ai.js +62 -2
  26. package/dist/browser/tanstack-ai.js.map +1 -1
  27. package/dist/browser-DE3d-RLk.d.ts +275 -0
  28. package/dist/browser-tool-CQ10e6Kj.js +480 -0
  29. package/dist/browser-tool-CQ10e6Kj.js.map +1 -0
  30. package/dist/browser-tool-DuNdlwZ9.d.ts +73 -0
  31. package/dist/capability-B4WbF81e.js.map +1 -1
  32. package/dist/{capability-runner-BUBa6Ake.d.ts → capability-runner-DBAnGr6L.d.ts} +7 -2
  33. package/dist/chat/index.d.ts +340 -234
  34. package/dist/chat/index.js +592 -66
  35. package/dist/chat/index.js.map +1 -1
  36. package/dist/chat/react.d.ts +42 -2
  37. package/dist/chat/react.js +191 -35
  38. package/dist/chat/react.js.map +1 -1
  39. package/dist/chat/transport.d.ts +1 -1
  40. package/dist/chat/transport.js +1 -1
  41. package/dist/chat-sdk/index.d.ts +17 -3
  42. package/dist/chat-sdk/index.js +28 -2
  43. package/dist/chat-sdk/index.js.map +1 -1
  44. package/dist/{client-C9DAjZIY.js → client-4OlMIJx-.js} +102 -29
  45. package/dist/client-4OlMIJx-.js.map +1 -0
  46. package/dist/{client-BxdkCuVy.d.ts → client-je3koD9Z.d.ts} +45 -10
  47. package/dist/client.d.ts +7 -5
  48. package/dist/client.js +2 -2
  49. package/dist/{connector-CptFKzRh.js → connector-58XDGvc3.js} +251 -120
  50. package/dist/connector-58XDGvc3.js.map +1 -0
  51. package/dist/{connector-CkQD4MK3.d.ts → connector-Cl-VqPmA.d.ts} +244 -146
  52. package/dist/context/index.d.ts +29 -0
  53. package/dist/context/index.js +64 -17
  54. package/dist/context/index.js.map +1 -1
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{current-agent-C4w86kcN.d.ts → current-agent-vAk_5JMt.d.ts} +4 -4
  57. package/dist/{durable-object-lifecycle-ei7M7lqB.d.ts → durable-object-lifecycle-HhgOMWq9.d.ts} +15 -7
  58. package/dist/harness/pi/index.d.ts +344 -0
  59. package/dist/harness/pi/index.js +873 -0
  60. package/dist/harness/pi/index.js.map +1 -0
  61. package/dist/images-iiTDSyRu.js +1631 -0
  62. package/dist/images-iiTDSyRu.js.map +1 -0
  63. package/dist/{index-Dlgtd3Mj.d.ts → index-BreL0YrQ.d.ts} +2 -2
  64. package/dist/index-kbSUIer3.d.ts +343 -0
  65. package/dist/index.d.ts +46 -44
  66. package/dist/index.js +1 -1
  67. package/dist/internal_context.d.ts +1 -1
  68. package/dist/lifecycle/index.d.ts +3 -3
  69. package/dist/lifecycle/index.js +1 -1
  70. package/dist/{lifecycle-Mm_jQh7r.js → lifecycle-CFu6OV03.js} +39 -10
  71. package/dist/{lifecycle-Mm_jQh7r.js.map → lifecycle-CFu6OV03.js.map} +1 -1
  72. package/dist/mcp/client/index.d.ts +20 -20
  73. package/dist/mcp/client/x402.js +21 -19
  74. package/dist/mcp/client/x402.js.map +1 -1
  75. package/dist/mcp/index.d.ts +35 -35
  76. package/dist/mcp/index.js +1 -1
  77. package/dist/{message-builder-BymO4N_D.js → message-builder-DAl9AhHH.js} +89 -4
  78. package/dist/message-builder-DAl9AhHH.js.map +1 -0
  79. package/dist/models/ai-sdk/index.d.ts +353 -0
  80. package/dist/models/ai-sdk/index.js +2443 -0
  81. package/dist/models/ai-sdk/index.js.map +1 -0
  82. package/dist/models/pi-ai/index.d.ts +313 -0
  83. package/dist/models/pi-ai/index.js +1795 -0
  84. package/dist/models/pi-ai/index.js.map +1 -0
  85. package/dist/observability/ai/index.js +20 -4
  86. package/dist/observability/ai/index.js.map +1 -1
  87. package/dist/{protocol-B0nh6KNf.js → protocol-kHsr-f0X.js} +26 -12
  88. package/dist/{protocol-B0nh6KNf.js.map → protocol-kHsr-f0X.js.map} +1 -1
  89. package/dist/queue/index.d.ts +3 -3
  90. package/dist/queue/index.js +1 -1
  91. package/dist/{queue-BC9F5cUo.js → queue-BB-zfIYF.js} +2 -2
  92. package/dist/{queue-BC9F5cUo.js.map → queue-BB-zfIYF.js.map} +1 -1
  93. package/dist/react.d.ts +6 -6
  94. package/dist/react.js +160 -64
  95. package/dist/react.js.map +1 -1
  96. package/dist/{retries-D9B2UCq3.d.ts → retries-CV6AkXmQ.d.ts} +18 -9
  97. package/dist/retries.d.ts +11 -9
  98. package/dist/retries.js +11 -1
  99. package/dist/retries.js.map +1 -1
  100. package/dist/routing/index.d.ts +2 -2
  101. package/dist/routing/index.js +1 -1
  102. package/dist/{scheduler-D_KHqxBa.js → scheduler-DZ3xQfeK.js} +2 -2
  103. package/dist/{scheduler-D_KHqxBa.js.map → scheduler-DZ3xQfeK.js.map} +1 -1
  104. package/dist/{scheduler-BGq6M5Kd.d.ts → scheduler-RdACNXDP.d.ts} +3 -3
  105. package/dist/schedules/index.d.ts +1 -1
  106. package/dist/schedules/index.js +1 -1
  107. package/dist/serializable.d.ts +1 -1
  108. package/dist/sessions/index.d.ts +70 -3
  109. package/dist/sessions/index.js +276 -67
  110. package/dist/sessions/index.js.map +1 -1
  111. package/dist/skills/index.d.ts +29 -314
  112. package/dist/socket-address.d.ts +16 -0
  113. package/dist/socket-address.js +19 -0
  114. package/dist/socket-address.js.map +1 -0
  115. package/dist/{src-BNU3ZiJM.js → src-BZeu-SCD.js} +423 -115
  116. package/dist/src-BZeu-SCD.js.map +1 -0
  117. package/dist/state/index.d.ts +1 -1
  118. package/dist/state/index.js +1 -1
  119. package/dist/streams/index.d.ts +1 -1
  120. package/dist/streams/index.js +1 -1
  121. package/dist/{streams-BcE8JP2X.d.ts → streams-Cmkj9QfW.d.ts} +4 -2
  122. package/dist/{streams-CCPRV6dt.js → streams-DW-UCOUc.js} +9 -2
  123. package/dist/streams-DW-UCOUc.js.map +1 -0
  124. package/dist/sub-routing.d.ts +12 -12
  125. package/dist/tasks/index.d.ts +1 -1
  126. package/dist/tasks/index.js +1 -1
  127. package/dist/{tasks-D4nLqVSI.js → tasks-68DESxf0.js} +2 -2
  128. package/dist/{tasks-D4nLqVSI.js.map → tasks-68DESxf0.js.map} +1 -1
  129. package/dist/{tasks-V2lCT8ZV.d.ts → tasks-9YxYtByh.d.ts} +2 -2
  130. package/dist/transport-PfFnt-Ld.d.ts +525 -0
  131. package/dist/{types-DCD6BNZH.d.ts → types-BA4anrjI.d.ts} +2 -2
  132. package/dist/voice/index.d.ts +2 -2
  133. package/dist/websockets/index.d.ts +23 -6
  134. package/dist/websockets/index.js +1 -1
  135. package/dist/{websockets-D7IzWbZb.js → websockets-Ci-LZFHH.js} +45 -20
  136. package/dist/{websockets-D7IzWbZb.js.map → websockets-Ci-LZFHH.js.map} +1 -1
  137. package/dist/wire-types-CnMt6_HR.js.map +1 -1
  138. package/dist/wire-types-CrjKvDyi.d.ts +300 -0
  139. package/dist/workflow-types.d.ts +25 -25
  140. package/dist/workflows.d.ts +21 -21
  141. package/dist/workflows.js +1 -1
  142. package/dist/{ws-chat-transport-UNRIS2xl.d.ts → ws-chat-transport-BbT1A5Lc.d.ts} +51 -2
  143. package/dist/{ws-chat-transport-rWwta645.js → ws-chat-transport-cqMKq3IY.js} +143 -16
  144. package/dist/ws-chat-transport-cqMKq3IY.js.map +1 -0
  145. package/docs/agent-tools.md +29 -4
  146. package/docs/browse-the-web.md +87 -5
  147. package/docs/chat-agents.md +124 -16
  148. package/docs/context.md +27 -0
  149. package/docs/durable-execution.md +2 -0
  150. package/docs/harnesses/pi.md +173 -0
  151. package/docs/human-in-the-loop.md +4 -0
  152. package/docs/index.md +3 -0
  153. package/docs/lifecycle.md +20 -4
  154. package/docs/models-pi-ai.md +325 -0
  155. package/docs/models.md +504 -0
  156. package/docs/resumable-streaming.md +2 -0
  157. package/docs/routing.md +13 -13
  158. package/docs/sessions.md +36 -1
  159. package/docs/state.md +1 -0
  160. package/docs/sub-agents.md +9 -0
  161. package/package.json +40 -2
  162. package/dist/agent-tools-y7zLfw4Q.js.map +0 -1
  163. package/dist/browser/ai.js.map +0 -1
  164. package/dist/client-C9DAjZIY.js.map +0 -1
  165. package/dist/client-tools-aIBO0Fk7.d.ts +0 -53
  166. package/dist/connector-CptFKzRh.js.map +0 -1
  167. package/dist/message-builder-BymO4N_D.js.map +0 -1
  168. package/dist/src-BNU3ZiJM.js.map +0 -1
  169. package/dist/streams-CCPRV6dt.js.map +0 -1
  170. package/dist/ws-chat-transport-rWwta645.js.map +0 -1
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "durable objects"
10
10
  ],
11
11
  "type": "module",
12
- "version": "0.24.0",
12
+ "version": "0.26.0",
13
13
  "license": "MIT",
14
14
  "repository": {
15
15
  "directory": "packages/agents",
@@ -34,9 +34,14 @@
34
34
  "yaml": "^2.9.0"
35
35
  },
36
36
  "devDependencies": {
37
+ "@ai-sdk/anthropic": "^4.0.0",
38
+ "@ai-sdk/openai": "^4.0.0",
39
+ "@ai-sdk/provider": "^4.0.0",
37
40
  "@ai-sdk/react": "^4.0.0",
38
41
  "@ai-sdk/valibot": "3.0.6",
39
- "@cloudflare/codemode": "^0.5.2",
42
+ "@cloudflare/codemode": "^0.5.3",
43
+ "@earendil-works/pi-ai": "^1.0.0",
44
+ "@earendil-works/pi-durable": "^1.0.0",
40
45
  "@modelcontextprotocol/client": "2.0.0",
41
46
  "@modelcontextprotocol/conformance-v2": "npm:@modelcontextprotocol/conformance@0.2.0-alpha.10",
42
47
  "@modelcontextprotocol/sdk": "1.30.0",
@@ -56,8 +61,11 @@
56
61
  "zod": "^4.5.4"
57
62
  },
58
63
  "peerDependencies": {
64
+ "@ai-sdk/provider": "^4.0.0",
59
65
  "@ai-sdk/react": "^3.0.0 || ^4.0.0",
60
66
  "@cloudflare/codemode": ">=0.5.0",
67
+ "@earendil-works/pi-ai": "^1.0.0",
68
+ "@earendil-works/pi-durable": "^1.0.0",
61
69
  "@modelcontextprotocol/client": "2.0.0",
62
70
  "@modelcontextprotocol/sdk": "1.30.0",
63
71
  "@modelcontextprotocol/server": "2.0.0",
@@ -72,12 +80,21 @@
72
80
  "zod": "^4.0.0"
73
81
  },
74
82
  "peerDependenciesMeta": {
83
+ "@ai-sdk/provider": {
84
+ "optional": true
85
+ },
75
86
  "@ai-sdk/react": {
76
87
  "optional": true
77
88
  },
78
89
  "@cloudflare/codemode": {
79
90
  "optional": true
80
91
  },
92
+ "@earendil-works/pi-ai": {
93
+ "optional": true
94
+ },
95
+ "@earendil-works/pi-durable": {
96
+ "optional": true
97
+ },
81
98
  "@tanstack/ai": {
82
99
  "optional": true
83
100
  },
@@ -150,6 +167,11 @@
150
167
  "import": "./dist/lifecycle/index.js",
151
168
  "require": "./dist/lifecycle/index.js"
152
169
  },
170
+ "./harness/pi": {
171
+ "types": "./dist/harness/pi/index.d.ts",
172
+ "import": "./dist/harness/pi/index.js",
173
+ "require": "./dist/harness/pi/index.js"
174
+ },
153
175
  "./agent-tools": {
154
176
  "types": "./dist/agent-tools.d.ts",
155
177
  "import": "./dist/agent-tools.js",
@@ -185,6 +207,16 @@
185
207
  "import": "./dist/observability/index.js",
186
208
  "require": "./dist/observability/index.js"
187
209
  },
210
+ "./models/ai-sdk": {
211
+ "types": "./dist/models/ai-sdk/index.d.ts",
212
+ "import": "./dist/models/ai-sdk/index.js",
213
+ "require": "./dist/models/ai-sdk/index.js"
214
+ },
215
+ "./models/pi-ai": {
216
+ "types": "./dist/models/pi-ai/index.d.ts",
217
+ "import": "./dist/models/pi-ai/index.js",
218
+ "require": "./dist/models/pi-ai/index.js"
219
+ },
188
220
  "./observability/ai": {
189
221
  "types": "./dist/observability/ai/index.d.ts",
190
222
  "import": "./dist/observability/ai/index.js",
@@ -295,6 +327,11 @@
295
327
  "import": "./dist/browser/ai.js",
296
328
  "require": "./dist/browser/ai.js"
297
329
  },
330
+ "./browser/ai-sdk": {
331
+ "types": "./dist/browser/ai-sdk.d.ts",
332
+ "import": "./dist/browser/ai-sdk.js",
333
+ "require": "./dist/browser/ai-sdk.js"
334
+ },
298
335
  "./browser/tanstack-ai": {
299
336
  "types": "./dist/browser/tanstack-ai.d.ts",
300
337
  "import": "./dist/browser/tanstack-ai.js",
@@ -434,6 +471,7 @@
434
471
  "test:browser": "vitest run --config src/browser-tests/vitest.config.ts",
435
472
  "test:workers": "vitest --project workers",
436
473
  "test:chat": "vitest --project chat",
474
+ "test:harness:pi": "vitest --project harness-pi",
437
475
  "test:webmcp": "vitest --project webmcp",
438
476
  "test:x402": "vitest --project x402",
439
477
  "test:e2e": "vitest --run -c src/e2e-tests/vitest.config.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-tools-y7zLfw4Q.js","names":[],"sources":["../src/chat/agent-tools.ts"],"sourcesContent":["import { applyChunkToParts, type MessagePart } from \"./message-builder\";\nimport {\n AGENT_TOOL_MILESTONE_PART,\n AGENT_TOOL_PROGRESS_PART\n} from \"../agent-tool-types\";\nimport type {\n AgentToolEventMessage,\n AgentToolEventState,\n AgentToolMilestone,\n AgentToolProgress,\n AgentToolProgressSnapshot,\n AgentToolRunPart,\n AgentToolRunState,\n AgentToolStoredChunk\n} from \"../agent-tool-types\";\n\n/**\n * Pull a reserved `data-agent-progress` chunk (emitted by a running sub-agent's\n * `reportProgress`) into a latest-wins snapshot. Returns `undefined` for any\n * other chunk so the caller keeps the prior snapshot.\n */\nfunction readAgentToolProgressChunk(\n chunk: unknown\n): AgentToolProgressSnapshot | undefined {\n if (\n typeof chunk !== \"object\" ||\n chunk === null ||\n (chunk as { type?: unknown }).type !== AGENT_TOOL_PROGRESS_PART\n ) {\n return undefined;\n }\n const data = (chunk as { data?: AgentToolProgress }).data ?? {};\n return {\n ...(typeof data.fraction === \"number\" ? { fraction: data.fraction } : {}),\n ...(typeof data.message === \"string\" ? { message: data.message } : {}),\n ...(typeof data.phase === \"string\" ? { phase: data.phase } : {}),\n ...(data.data !== undefined ? { data: data.data } : {}),\n at: Date.now()\n };\n}\n\n/**\n * Pull a reserved `data-agent-milestone` chunk into a durable milestone record,\n * or `undefined` for any other chunk. Milestones carry their own monotonic\n * `sequence` so the caller can dedupe replay-vs-live races.\n */\nfunction readAgentToolMilestoneChunk(\n chunk: unknown\n): AgentToolMilestone | undefined {\n if (\n typeof chunk !== \"object\" ||\n chunk === null ||\n (chunk as { type?: unknown }).type !== AGENT_TOOL_MILESTONE_PART\n ) {\n return undefined;\n }\n const data = (chunk as { data?: Partial<AgentToolMilestone> }).data ?? {};\n if (typeof data.name !== \"string\") return undefined;\n return {\n name: data.name,\n sequence: typeof data.sequence === \"number\" ? data.sequence : 0,\n at: typeof data.at === \"number\" ? data.at : Date.now(),\n ...(data.data !== undefined ? { data: data.data } : {})\n };\n}\n\n/**\n * Merge a milestone into a run's ordered milestone list, deduping on `sequence`\n * (idempotent across replay + live races) and keeping the list sorted.\n */\nfunction mergeMilestone(\n existing: AgentToolMilestone[] | undefined,\n milestone: AgentToolMilestone\n): AgentToolMilestone[] {\n // Returns `existing` unchanged (same reference) when the milestone is a dup,\n // so callers can identity-compare to detect a genuinely new milestone.\n if (existing?.some((m) => m.sequence === milestone.sequence)) return existing;\n const list = existing ? [...existing, milestone] : [milestone];\n list.sort((a, b) => a.sequence - b.sequence);\n return list;\n}\n\n/** Latest-wins coalescing window for `reportProgress` emits (per run). */\nconst AGENT_TOOL_PROGRESS_COALESCE_MS = 200;\n\nexport type AgentToolProgressEmitResult = \"emitted\" | \"coalesced\" | \"inactive\";\n\n/**\n * Host-injected seams the shared progress emitter needs. Keeps the per-host\n * `reportProgress` thin: Think / AIChatAgent supply how to resolve the active\n * agent-tool run, how to broadcast a chat-response frame, and how to persist the\n * latest snapshot on their own child-run table.\n */\nexport type AgentToolProgressEmitHooks = {\n /** The agent-tool run currently executing in this turn, or null. */\n resolveActiveRun: () => { runId: string; requestId: string } | null;\n /** Broadcast a chat-response frame (id = requestId) to clients/tailers. */\n broadcast: (requestId: string, chunkBody: string) => void;\n /** Persist the latest snapshot + signal timestamp on the child run row. */\n persistSnapshot: (\n runId: string,\n snapshot: {\n fraction?: number;\n message?: string;\n phase?: string;\n data?: unknown;\n },\n at: number\n ) => void;\n /**\n * Persist a durable milestone row, bump the run's signal timestamp, and return\n * the assigned monotonic per-run `sequence` (used to dedupe replay/live races).\n */\n persistMilestone: (\n runId: string,\n name: string,\n data: unknown,\n at: number\n ) => number;\n};\n\n/**\n * Shared implementation of `reportProgress` for chat hosts. Builds the reserved\n * transient `data-agent-progress` wire frame, coalesces bursts to a bounded\n * cadence (latest-wins; a `fraction >= 1` \"done\" frame always flushes), and\n * persists a latest snapshot. `data` rides the live frame but is only persisted\n * when the caller opts in via `{ persist: true }`.\n */\nexport class AgentToolProgressEmitter {\n private readonly _lastEmitAt = new Map<string, number>();\n\n constructor(private readonly hooks: AgentToolProgressEmitHooks) {}\n\n report(\n progress: AgentToolProgress,\n options?: { persist?: boolean }\n ): AgentToolProgressEmitResult {\n const active = this.hooks.resolveActiveRun();\n if (!active) return \"inactive\";\n const { runId, requestId } = active;\n const now = Date.now();\n\n // Durable milestone: never coalesced (each named boundary must land,\n // persist, and replay). Rides the stream as a PERSISTED data part.\n if (typeof progress.milestone === \"string\" && progress.milestone) {\n this._lastEmitAt.set(runId, now);\n const sequence = this.hooks.persistMilestone(\n runId,\n progress.milestone,\n progress.data,\n now\n );\n this.hooks.broadcast(\n requestId,\n JSON.stringify({\n type: AGENT_TOOL_MILESTONE_PART,\n data: {\n name: progress.milestone,\n sequence,\n at: now,\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\"\n ? { phase: progress.phase }\n : {}),\n ...(progress.data !== undefined ? { data: progress.data } : {})\n }\n })\n );\n return \"emitted\";\n }\n\n const last = this._lastEmitAt.get(runId) ?? 0;\n const isDone =\n typeof progress.fraction === \"number\" && progress.fraction >= 1;\n if (now - last < AGENT_TOOL_PROGRESS_COALESCE_MS && !isDone) {\n return \"coalesced\";\n }\n this._lastEmitAt.set(runId, now);\n\n const wire: AgentToolProgress = {\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\" ? { phase: progress.phase } : {}),\n ...(progress.data !== undefined ? { data: progress.data } : {})\n };\n this.hooks.broadcast(\n requestId,\n JSON.stringify({\n type: AGENT_TOOL_PROGRESS_PART,\n transient: true,\n data: wire\n })\n );\n this.hooks.persistSnapshot(\n runId,\n {\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\"\n ? { phase: progress.phase }\n : {}),\n ...(options?.persist && progress.data !== undefined\n ? { data: progress.data }\n : {})\n },\n now\n );\n return \"emitted\";\n }\n\n /** Drop coalescing state for a settled run (called on terminal). */\n forget(runId: string): void {\n this._lastEmitAt.delete(runId);\n }\n}\n\nfunction sortRuns<Part extends AgentToolRunPart>(\n runs: AgentToolRunState<Part>[]\n): AgentToolRunState<Part>[] {\n return [...runs].sort((a, b) => {\n if (a.order !== b.order) return a.order - b.order;\n return a.runId.localeCompare(b.runId);\n });\n}\n\nfunction rebuildIndexes<Part extends AgentToolRunPart>(\n runsById: Record<string, AgentToolRunState<Part>>\n): Pick<AgentToolEventState<Part>, \"runsByToolCallId\" | \"unboundRuns\"> {\n const grouped: Record<string, AgentToolRunState<Part>[]> = {};\n const unboundRuns: AgentToolRunState<Part>[] = [];\n for (const run of Object.values(runsById)) {\n if (run.parentToolCallId) {\n grouped[run.parentToolCallId] = grouped[run.parentToolCallId] ?? [];\n grouped[run.parentToolCallId].push(run);\n } else {\n unboundRuns.push(run);\n }\n }\n for (const [toolCallId, runs] of Object.entries(grouped)) {\n grouped[toolCallId] = sortRuns(runs);\n }\n return { runsByToolCallId: grouped, unboundRuns: sortRuns(unboundRuns) };\n}\n\nfunction emptyRun<Part extends AgentToolRunPart>(\n message: AgentToolEventMessage\n): AgentToolRunState<Part> | undefined {\n const { event } = message;\n if (event.kind === \"started\") {\n return {\n runId: event.runId,\n agentType: event.agentType,\n parentToolCallId: message.parentToolCallId,\n inputPreview: event.inputPreview,\n order: event.order,\n display: event.display,\n status: \"running\",\n parts: [],\n subAgent: { agent: event.agentType, name: event.runId }\n };\n }\n return undefined;\n}\n\nfunction applyToRun<Part extends AgentToolRunPart>(\n prev: AgentToolRunState<Part> | undefined,\n message: AgentToolEventMessage\n): AgentToolRunState<Part> | undefined {\n const seeded = prev ?? emptyRun(message);\n const { event } = message;\n\n switch (event.kind) {\n case \"started\":\n if (\n seeded?.status === \"completed\" ||\n seeded?.status === \"error\" ||\n seeded?.status === \"aborted\" ||\n seeded?.status === \"interrupted\"\n ) {\n return seeded;\n }\n return {\n ...seeded,\n runId: event.runId,\n agentType: event.agentType,\n parentToolCallId: message.parentToolCallId,\n inputPreview: event.inputPreview,\n order: event.order,\n display: event.display,\n status: \"running\",\n parts: seeded?.parts ?? [],\n subAgent: { agent: event.agentType, name: event.runId }\n };\n case \"chunk\": {\n if (!seeded) return undefined;\n // `applyChunkToParts` mutates part objects in place (e.g.\n // `lastTextPart.text += delta`). A shallow array copy (`[...seeded.parts]`)\n // keeps the *element* references shared with the previous state, so those\n // in-place mutations leak back into `prev`. React double-invokes setState\n // updaters in StrictMode / dev hydration, replaying each chunk against the\n // same (already-mutated) `prev` and doubling the text (#1835). Clone each\n // part so the reducer stays pure — every mutation here is to a top-level\n // field, so a per-part shallow copy is sufficient.\n const parts = seeded.parts.map((part) => ({ ...part }) as Part);\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.body);\n applyChunkToParts(\n parts as MessagePart[],\n parsed as Parameters<typeof applyChunkToParts>[1]\n );\n } catch {\n return seeded;\n }\n // Project a reserved `data-agent-progress` part onto the run's latest\n // progress snapshot so a tray can render a bar/phase without drilling in.\n // The part is transient (not persisted into `parts`), so it is read here\n // off the raw chunk rather than from the reduced parts array.\n const progress = readAgentToolProgressChunk(parsed);\n if (progress) {\n return { ...seeded, parts, progress };\n }\n // Durable milestones land as a persisted `data-agent-milestone` part:\n // append (deduped by sequence) to the run's milestone list, and reflect\n // any progress fields the milestone carried onto the latest snapshot.\n const milestone = readAgentToolMilestoneChunk(parsed);\n if (milestone) {\n const milestones = mergeMilestone(seeded.milestones, milestone);\n // Only advance the snapshot for a genuinely new, not-older milestone, so\n // a late replay of an earlier milestone never rolls `progress` backward.\n const isNew = milestones !== seeded.milestones;\n const notOlder =\n seeded.progress === undefined || milestone.at >= seeded.progress.at;\n if (!isNew || !notOlder) {\n return { ...seeded, parts, milestones };\n }\n const data = (parsed as { data?: AgentToolProgress }).data ?? {};\n const snapshot: AgentToolProgressSnapshot = {\n ...(typeof data.fraction === \"number\"\n ? { fraction: data.fraction }\n : {}),\n ...(typeof data.message === \"string\"\n ? { message: data.message }\n : {}),\n ...(typeof data.phase === \"string\" ? { phase: data.phase } : {}),\n milestone: milestone.name,\n at: milestone.at\n };\n return { ...seeded, parts, progress: snapshot, milestones };\n }\n return { ...seeded, parts };\n }\n case \"finished\":\n if (!seeded) return undefined;\n return {\n ...seeded,\n status: \"completed\",\n summary: event.summary,\n error: undefined\n };\n case \"error\":\n if (!seeded) return undefined;\n return { ...seeded, status: \"error\", error: event.error };\n case \"aborted\":\n if (!seeded) return undefined;\n return { ...seeded, status: \"aborted\", error: event.reason };\n case \"interrupted\":\n if (!seeded) return undefined;\n return {\n ...seeded,\n status: \"interrupted\",\n error: event.error,\n reason: event.reason,\n childStillRunning: event.childStillRunning\n };\n }\n}\n\nexport function createAgentToolEventState<\n Part extends AgentToolRunPart = AgentToolRunPart\n>(): AgentToolEventState<Part> {\n return {\n runsById: {},\n runsByToolCallId: {},\n unboundRuns: []\n };\n}\n\nexport function applyAgentToolEvent<\n Part extends AgentToolRunPart = AgentToolRunPart\n>(\n state: AgentToolEventState<Part>,\n message: AgentToolEventMessage\n): AgentToolEventState<Part> {\n if (message.type !== \"agent-tool-event\") return state;\n const runId = message.event.runId;\n const nextRun = applyToRun(state.runsById[runId], message);\n if (!nextRun) return state;\n\n const runsById = { ...state.runsById, [runId]: nextRun };\n return { runsById, ...rebuildIndexes(runsById) };\n}\n\nexport type {\n AgentToolEvent,\n AgentToolEventMessage,\n AgentToolEventState,\n AgentToolRunPart,\n AgentToolRunState\n} from \"../agent-tool-types\";\n\n/**\n * @internal Host substrate the {@link interceptAgentToolBroadcast} snoop reads,\n * abstracting the divergent per-host run-lookup and response-frame constant.\n */\nexport interface AgentToolBroadcastHooks {\n /** Live tailers per run; iterated to forward each progress chunk. */\n forwarders: Map<string, Set<(chunk: AgentToolStoredChunk) => void>>;\n /**\n * Per-run forwarded-chunk counter; advanced even with no tailer attached.\n *\n * This is deliberately a SEPARATE counter from the resumable stream's stored\n * chunk_index — do NOT try to \"simplify\" it away by sequencing off the store\n * position. Not every forwarded frame is durably stored: progress/milestone\n * frames (`reportProgress`) ride the same `USE_CHAT_RESPONSE` wire type and\n * are snooped + forwarded here, but persist out-of-band (progress snapshot /\n * milestone rows), so they have no store position. Sourcing the sequence from\n * the store would give them a colliding position and the tail's high-water\n * dedupe (`emit`) would silently drop them, breaking live progress/milestone\n * delivery to the parent. This counter sequences stored AND non-stored frames\n * on one monotonic line; the tail realigns it to the stored high-water on each\n * (re)attach so a replay→live handoff stays gap/duplicate-free.\n */\n liveSequences: Map<string, number>;\n /** Per-run last error body, captured for replay to a late-attaching tailer. */\n lastErrors: Map<string, string>;\n /** The host's use-chat-response wire type (`CHAT_MESSAGE_TYPES.USE_CHAT_RESPONSE`). */\n responseType: string;\n /** Resolve the agent-tool run that owns a turn request id, or null. */\n runForRequest: (requestId: string) => string | null;\n}\n\n/**\n * Snoop a host's outgoing chat frames while any agent-tool run is in flight and\n * forward the owning run's streamed body to its live tailers (or capture its\n * error), without altering the frame — the caller still broadcasts it (#1575).\n *\n * Shared verbatim by `@cloudflare/ai-chat` and `@cloudflare/think`; the only\n * per-host variance (the response-frame type constant and the run-lookup, whose\n * SQL differs) is supplied via {@link AgentToolBroadcastHooks}. Inspection runs\n * for a run's whole lifecycle (live sequences exist even with no tailer), so\n * error capture never depends on tailer timing. A frame belongs to a run iff it\n * carries that run's turn request id, so concurrent runs can't cross-contaminate\n * each other's progress or error state.\n */\nexport function interceptAgentToolBroadcast(\n msg: string | ArrayBuffer | ArrayBufferView,\n hooks: AgentToolBroadcastHooks\n): void {\n if (\n (hooks.forwarders.size > 0 || hooks.liveSequences.size > 0) &&\n typeof msg === \"string\"\n ) {\n try {\n const parsed = JSON.parse(msg) as {\n type?: unknown;\n body?: unknown;\n error?: unknown;\n id?: unknown;\n };\n if (parsed.type === hooks.responseType && typeof parsed.id === \"string\") {\n const runId = hooks.runForRequest(parsed.id);\n if (runId !== null) {\n if (parsed.error === true && typeof parsed.body === \"string\") {\n hooks.lastErrors.set(runId, parsed.body);\n } else if (\n typeof parsed.body === \"string\" &&\n parsed.body.length > 0\n ) {\n // Advance the live sequence even with no tailer attached so a tailer\n // registering mid-run resumes at the right offset.\n const sequence = hooks.liveSequences.get(runId) ?? 0;\n hooks.liveSequences.set(runId, sequence + 1);\n const chunk: AgentToolStoredChunk = { sequence, body: parsed.body };\n const forwarders = hooks.forwarders.get(runId);\n if (forwarders) {\n for (const forward of forwarders) forward(chunk);\n }\n }\n }\n }\n } catch {\n // Non-chat frames pass through unchanged.\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ai.js","names":["agentContext"],"sources":["../../src/browser/ai.ts"],"sourcesContent":["import { tool, type JSONValue, type ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport {\n createCodemodeRuntime,\n DynamicWorkerExecutor,\n truncateResult,\n type CodemodeRuntimeHandle\n} from \"@cloudflare/codemode\";\nimport { __DO_NOT_USE_WILL_BREAK__agentContext as agentContext } from \"../internal_context\";\nimport type { BrowserBinding } from \"./browser-run\";\nimport {\n browserContent,\n browserExtract,\n browserLinks,\n browserMarkdown,\n browserScrape,\n type QuickActionBinding,\n type QuickActionCommonOptions,\n type QuickActionPage\n} from \"./quick-actions\";\nimport {\n BrowserConnector,\n type BrowserConnectorOptions,\n type BrowserConnectorSessionOptions\n} from \"./connector\";\nimport {\n DurableBrowserSessionStore,\n type BrowserSessionStore\n} from \"./session-manager\";\n\nexport interface CreateBrowserToolsOptions {\n /**\n * Durable Object state. The codemode runtime that backs the browser tool\n * lives in a facet of this DO, and browser session ids are stored in its\n * storage — so the tool must be created from inside a Durable Object\n * (e.g. an Agent).\n *\n * Optional: when omitted, it is resolved from the current Agent via\n * `getCurrentAgent()`, so inside an Agent method you can just pass `browser`\n * and `loader`. Pass it explicitly outside an Agent context.\n *\n * The worker must export the `CodemodeRuntime` class (the\n * `@cloudflare/codemode/vite` plugin does this automatically, or add\n * `export { CodemodeRuntime } from \"@cloudflare/codemode\"` to your entry).\n */\n ctx?: DurableObjectState;\n\n /**\n * WorkerLoader binding for sandboxed code execution.\n *\n * Requires `\"worker_loaders\": [{ \"binding\": \"LOADER\" }]` in wrangler.jsonc.\n */\n loader: WorkerLoader;\n\n /**\n * Browser Rendering binding (Fetcher).\n *\n * This is the primary way to connect — works both locally in\n * `wrangler dev` and when deployed to Cloudflare Workers.\n *\n * Requires `\"browser\": { \"binding\": \"BROWSER\" }` in wrangler.jsonc.\n */\n browser?: BrowserBinding;\n\n /**\n * Optional CDP base URL override (e.g. `http://localhost:9222`).\n *\n * Use when connecting to a manually managed Chrome instance or\n * a remote CDP endpoint behind a tunnel.\n */\n cdpUrl?: string;\n\n /**\n * Headers to send with CDP URL discovery requests.\n * Useful when the CDP endpoint requires authentication\n * (e.g. Cloudflare Access headers).\n */\n cdpHeaders?: Record<string, string>;\n\n /**\n * Browser session lifecycle (binding-backed only). Defaults to one fresh\n * session per codemode execution (`one-shot`).\n */\n session?: BrowserConnectorSessionOptions;\n\n /**\n * Durable store for Browser Run session ids. Defaults to a\n * {@link DurableBrowserSessionStore} over `ctx.storage`.\n */\n store?: BrowserSessionStore;\n\n /**\n * Sandbox execution timeout in milliseconds. Defaults to 30000 (30s).\n * Also used as the per-CDP-command timeout.\n */\n timeout?: number;\n\n /**\n * Codemode runtime name — the durable identity of the tool's executions\n * and snippets. Defaults to `\"browser\"`.\n */\n name?: string;\n\n /**\n * Also expose stateless {@link createQuickActionTools | Quick Action} tools\n * (`browser_markdown`, `browser_extract`, …) alongside the durable\n * `browser_execute` tool.\n *\n * Enabled by default whenever a Browser Run `browser` binding is available\n * (they share it), except when `session.browser` selects Kitesurf because\n * the binding RPC cannot select that engine. Pass `true` or an object to\n * explicitly add Chromium Quick Actions alongside Kitesurf, or `false` to\n * disable them. The Quick Action binding defaults to `browser`; override it via\n * `quickActions.browser`. When only `cdpUrl` is set (no binding), the\n * defaults are skipped silently — pass `quickActions: { browser }` to force\n * them.\n */\n quickActions?:\n | boolean\n | {\n browser?: QuickActionBinding;\n actions?: QuickActionToolName[];\n maxChars?: number;\n options?: QuickActionCommonOptions;\n };\n}\n\n/**\n * The browser tool's moving parts, for hosts that need more than the tools:\n *\n * - `runtime` — the codemode runtime handle (approve/reject paused runs,\n * `expirePaused`, audit via `executions()`, snippets).\n * - `connector` — host-side session helpers: `sessionInfo()`,\n * `closeSession()`, and `sweep()` for a recurring cleanup task.\n * - `tools` — what `createBrowserTools` returns.\n */\nexport interface BrowserRuntime {\n runtime: CodemodeRuntimeHandle;\n connector: BrowserConnector;\n tools: ToolSet;\n}\n\nlet didWarnExperimental = false;\nlet didDebugQuickActionSkip = false;\n\ninterface BrowserScreenshotOutput {\n type: \"browser_screenshot\";\n mediaType: string;\n data: string;\n}\n\nfunction browserScreenshotOutput(\n value: unknown\n): BrowserScreenshotOutput | null {\n const outer =\n typeof value === \"object\" && value !== null\n ? (value as Record<string, unknown>)\n : null;\n const result =\n outer && typeof outer.result === \"object\" && outer.result !== null\n ? (outer.result as Record<string, unknown>)\n : outer;\n if (\n result?.type !== \"browser_screenshot\" ||\n typeof result.mediaType !== \"string\" ||\n typeof result.data !== \"string\"\n ) {\n return null;\n }\n return result as unknown as BrowserScreenshotOutput;\n}\n\nconst BASE64_REDACTION_THRESHOLD = 4096;\nconst MAX_REDACTION_DEPTH = 20;\nconst MAX_REDACTION_NODES = 10_000;\n\nfunction base64Details(\n value: string,\n minimumLength = BASE64_REDACTION_THRESHOLD\n): {\n mediaType?: string;\n chars: number;\n bytes: number;\n} | null {\n if (value.length < minimumLength) return null;\n\n const dataUrl =\n /^data:([^;,]+)(?:;[^;,]*)*;base64,([A-Za-z0-9+/]*={0,2})$/i.exec(value);\n const encoded = dataUrl?.[2] ?? value;\n if (encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {\n return null;\n }\n\n const padding = encoded.endsWith(\"==\") ? 2 : encoded.endsWith(\"=\") ? 1 : 0;\n return {\n mediaType: dataUrl?.[1],\n chars: encoded.length,\n bytes: (encoded.length / 4) * 3 - padding\n };\n}\n\nfunction base64Redaction(\n value: string,\n mediaType?: string,\n minimumLength?: number\n): string {\n const details = base64Details(value, minimumLength);\n if (!details) return value;\n const type = mediaType ?? details.mediaType;\n return `[base64${type ? ` ${type}` : \"\"} data omitted: ${details.chars.toLocaleString()} chars, approximately ${details.bytes.toLocaleString()} bytes]`;\n}\n\nfunction redactBase64Payloads(value: unknown): unknown {\n const ancestors = new WeakSet<object>();\n let nodes = 0;\n\n function visit(current: unknown, depth: number): unknown {\n if (depth > MAX_REDACTION_DEPTH) return \"[nested value omitted]\";\n if (++nodes > MAX_REDACTION_NODES) return \"[remaining values omitted]\";\n if (typeof current === \"string\") return base64Redaction(current);\n if (typeof current !== \"object\" || current === null) return current;\n // Binary values cross the sandbox boundary as Uint8Array/ArrayBuffer —\n // walking them would rebuild them as index-keyed plain objects. The same\n // is true of Date/Map/Set, whose own enumerable entries are empty.\n if (\n current instanceof ArrayBuffer ||\n ArrayBuffer.isView(current) ||\n current instanceof Date ||\n current instanceof Map ||\n current instanceof Set\n ) {\n return current;\n }\n if (ancestors.has(current)) return \"[circular reference omitted]\";\n\n ancestors.add(current);\n try {\n if (Array.isArray(current)) {\n return current.map((entry) => visit(entry, depth + 1));\n }\n\n const record = current as Record<string, unknown>;\n const screenshot =\n record.type === \"browser_screenshot\" &&\n typeof record.mediaType === \"string\";\n return Object.fromEntries(\n Object.entries(record).map(([key, entry]) => [\n key,\n screenshot && key === \"data\" && typeof entry === \"string\"\n ? base64Redaction(entry, record.mediaType as string, 0)\n : visit(entry, depth + 1)\n ])\n );\n } finally {\n ancestors.delete(current);\n }\n }\n\n return visit(value, 0);\n}\n\nfunction transformBrowserResult(value: unknown): unknown {\n // Keep canonical screenshot output intact for UIMessage persistence and the\n // chat renderer. Other results are redacted before truncation so a nested\n // binary payload cannot become a large serialized preview.\n return browserScreenshotOutput(value)\n ? value\n : truncateResult(redactBase64Payloads(value));\n}\n\nfunction browserExecuteModelOutput(\n output: unknown\n): { type: \"text\"; value: string } | { type: \"json\"; value: JSONValue } {\n const screenshot = browserScreenshotOutput(output);\n if (screenshot) {\n const approximateBytes = Math.floor((screenshot.data.length * 3) / 4);\n return {\n type: \"text\",\n value: `Screenshot captured successfully (${screenshot.mediaType}, approximately ${approximateBytes.toLocaleString()} bytes); the image is kept for the UI and omitted here.`\n };\n }\n\n // `calls` is the durable audit log; like the codemode tool's own projection,\n // it stays on the persisted part and never enters the model's context, and\n // the sandbox `logs` are bounded like a result.\n const modelFacing =\n typeof output === \"object\" && output !== null && !Array.isArray(output)\n ? (({ calls: _calls, ...rest }: { calls?: unknown; logs?: unknown }) => ({\n ...rest,\n ...(Array.isArray(rest.logs)\n ? { logs: truncateResult(rest.logs) }\n : {})\n }))(output)\n : output;\n const redacted = redactBase64Payloads(modelFacing);\n try {\n const serialized = JSON.stringify(redacted);\n return {\n type: \"json\",\n value:\n serialized === undefined ? null : (JSON.parse(serialized) as JSONValue)\n };\n } catch {\n return {\n type: \"text\",\n value:\n \"Browser execution completed, but its result could not be serialized for model context.\"\n };\n }\n}\n\n/**\n * The Durable Object state to build the runtime in: the explicit `ctx` if\n * given, otherwise the current Agent's `ctx` (via `getCurrentAgent()`), so\n * `createBrowserRuntime` can be called from an Agent method without threading\n * `this.ctx` through.\n */\nfunction resolveCtx(\n options: CreateBrowserToolsOptions\n): DurableObjectState | undefined {\n if (options.ctx) return options.ctx;\n const agent = agentContext.getStore()?.agent as\n | { ctx?: DurableObjectState }\n | undefined;\n return agent?.ctx;\n}\n\nfunction connectorOptions(\n options: CreateBrowserToolsOptions,\n ctx: DurableObjectState\n): BrowserConnectorOptions {\n if (options.cdpUrl) {\n return {\n cdpUrl: options.cdpUrl,\n cdpHeaders: options.cdpHeaders,\n timeout: options.timeout\n };\n }\n if (!options.browser) {\n throw new Error(\n \"Either 'browser' (Fetcher binding) or 'cdpUrl' must be provided\"\n );\n }\n return {\n browser: options.browser,\n store: options.store ?? new DurableBrowserSessionStore(ctx.storage),\n session: options.session,\n timeout: options.timeout\n };\n}\n\n/**\n * Create the browser codemode runtime: the `browser_execute` tool plus the\n * runtime handle and connector for host-side wiring (approvals, session info,\n * sweeps).\n *\n * @example\n * ```ts\n * export class MyAgent extends Agent<Env> {\n * get browser() {\n * return createBrowserRuntime({\n * ctx: this.ctx,\n * browser: this.env.BROWSER,\n * loader: this.env.LOADER,\n * session: { mode: \"dynamic\" }\n * });\n * }\n *\n * @callable()\n * async closeBrowserSession() {\n * await this.browser.connector.closeSession();\n * }\n * }\n * ```\n */\nexport function createBrowserRuntime(\n options: CreateBrowserToolsOptions\n): BrowserRuntime {\n if (!didWarnExperimental) {\n didWarnExperimental = true;\n console.warn(\n \"[agents/browser] Browser tools are experimental and may change in a future release.\"\n );\n }\n\n const ctx = resolveCtx(options);\n if (!ctx) {\n throw new Error(\n \"createBrowserRuntime requires a Durable Object 'ctx' — pass it explicitly, or call from within an Agent so it can be resolved via getCurrentAgent()\"\n );\n }\n\n const connector = new BrowserConnector(ctx, connectorOptions(options, ctx));\n const runtime = createCodemodeRuntime({\n ctx,\n executor: new DynamicWorkerExecutor({\n loader: options.loader,\n timeout: options.timeout\n }),\n connectors: [connector],\n name: options.name ?? \"browser\",\n transformResult: transformBrowserResult\n });\n\n // `connectorOptions` drops `session` when a custom endpoint is used, so the\n // connector is plain Chromium there whatever the session options say.\n const isKitesurf = !options.cdpUrl && options.session?.browser === \"kitesurf\";\n const browserExecute = runtime.tool({\n connectorHints: {\n cdp: isKitesurf\n ? 'Kitesurf one-shot Browser CDP. Call codemode.describe(\"cdp\") for connector types and Kitesurf execution rules. codemode.search indexes connector methods and snippets, not underlying CDP commands. Complete the task in one execution and do not pause. Return screenshots as { type: \"browser_screenshot\", mediaType: \"image/png\", data: screenshot.data }.'\n : \"Browser CDP. Return screenshots as { type: 'browser_screenshot', mediaType: 'image/png', data: screenshot.data }; the UI keeps the image while the model receives a compact summary.\"\n }\n });\n const tools: ToolSet = {\n browser_execute: {\n ...browserExecute,\n toModelOutput: ({ output }: { output: unknown }) =>\n browserExecuteModelOutput(output)\n }\n };\n\n // Quick Actions ride the same `browser` binding, so they are on by default\n // for Chromium. The binding RPC cannot select Kitesurf, so selecting\n // Kitesurf disables the defaults rather than silently adding Chromium tools.\n // Callers can still request a mixed-engine toolset explicitly.\n const enableQuickActions =\n options.quickActions !== false &&\n (!isKitesurf || options.quickActions !== undefined);\n // `env.BROWSER` satisfies both the CDP `BrowserBinding` (fetch) and the\n // `QuickActionBinding` (quickAction) surfaces; our narrower option type only\n // sees the former, so reuse it here unless an explicit binding wins.\n if (enableQuickActions) {\n const qa =\n typeof options.quickActions === \"object\" ? options.quickActions : {};\n const quickActionBrowser =\n qa.browser ??\n (options.browser as unknown as QuickActionBinding | undefined);\n if (quickActionBrowser) {\n Object.assign(\n tools,\n createQuickActionTools({\n browser: quickActionBrowser,\n actions: qa.actions,\n maxChars: qa.maxChars,\n options: qa.options\n })\n );\n } else if (options.quickActions) {\n // Explicitly requested but no binding to back them.\n throw new Error(\n \"quickActions requires a Browser Run binding — set 'browser' (env.BROWSER) or 'quickActions.browser'\"\n );\n } else if (!didDebugQuickActionSkip) {\n // Defaulted on, but only `cdpUrl` is set: there is no binding to call\n // Quick Actions through, so they are skipped. Surface it once so a user\n // expecting `browser_markdown` et al. isn't left wondering.\n didDebugQuickActionSkip = true;\n console.debug(\n \"[agents/browser] Quick Action tools skipped — no Browser Run binding (only 'cdpUrl' is set). Pass 'browser' or 'quickActions.browser' to enable them.\"\n );\n }\n }\n\n return { runtime, connector, tools };\n}\n\n/**\n * Create AI SDK tools for browser automation via CDP code mode.\n *\n * Returns a `ToolSet` with a single durable `browser_execute` tool backed by\n * a codemode runtime: the model writes TypeScript against the `cdp` connector\n * (`cdp.send`, `cdp.attachToTarget`, `cdp.spec`, …), executions are recorded\n * for abort-and-replay, and browser sessions survive pauses.\n *\n * @example\n * ```ts\n * import { createBrowserTools } from \"agents/browser/ai\";\n * import { generateText } from \"ai\";\n *\n * // inside a Durable Object / Agent:\n * const browserTools = createBrowserTools({\n * ctx: this.ctx,\n * browser: this.env.BROWSER,\n * loader: this.env.LOADER,\n * });\n *\n * const result = await generateText({\n * model,\n * tools: { ...browserTools, ...otherTools },\n * messages,\n * });\n * ```\n */\nexport function createBrowserTools(\n options: CreateBrowserToolsOptions\n): ToolSet {\n return createBrowserRuntime(options).tools;\n}\n\n/** A Quick Action exposed as an AI SDK tool. */\nexport type QuickActionToolName =\n | \"markdown\"\n | \"extract\"\n | \"links\"\n | \"scrape\"\n | \"content\";\n\nexport interface CreateQuickActionToolsOptions {\n /**\n * Browser Run binding with Quick Actions support (`env.BROWSER`). Requires a\n * Worker `compatibility_date` of `2026-03-24`+ and `remote: true` for local\n * `wrangler dev`.\n */\n browser: QuickActionBinding;\n\n /**\n * Which tools to expose. Defaults to the text-returning, model-friendly set\n * (`markdown`, `extract`, `links`, `scrape`). `content` (raw HTML) is opt-in\n * since it is large and rarely what a model wants.\n */\n actions?: QuickActionToolName[];\n\n /**\n * Bound every result to roughly this many characters before returning it to\n * the model, to protect the context window, preserving each result's shape:\n * text (markdown/content) is truncated to a string, oversized arrays\n * (links/scrape) are trimmed but stay arrays, and only an opaque oversized\n * object degrades to a truncated-preview summary. Set to `0` to disable.\n * Defaults to 50000.\n */\n maxChars?: number;\n\n /**\n * Common Browser Run options merged into every request — e.g. `cookies`,\n * `authenticate`, or `setExtraHTTPHeaders` for authenticated pages, and\n * `gotoOptions` / `viewport` for JavaScript-heavy pages. The model only ever\n * supplies the page (`url`/`html`) and action-specific fields; these\n * host-supplied options are never exposed to it.\n */\n options?: QuickActionCommonOptions;\n}\n\nconst DEFAULT_QUICK_ACTION_TOOLS: QuickActionToolName[] = [\n \"markdown\",\n \"extract\",\n \"links\",\n \"scrape\"\n];\n\nconst DEFAULT_QUICK_ACTION_MAX_CHARS = 50_000;\n\nconst pageInputSchema = z\n .object({\n url: z.string().url().optional().describe(\"URL of the page to load\"),\n html: z\n .string()\n .optional()\n .describe(\"Raw HTML to render instead of loading a URL\")\n })\n .refine((value) => Boolean(value.url) || Boolean(value.html), {\n message: \"Provide either 'url' or 'html'\"\n });\n\nfunction toPage(\n input: { url?: string; html?: string },\n options?: QuickActionCommonOptions\n): QuickActionPage {\n const page = input.url ? { url: input.url } : { html: input.html as string };\n return { ...options, ...page } as QuickActionPage;\n}\n\nfunction truncate(text: string, maxChars: number): string {\n if (maxChars <= 0 || text.length <= maxChars) return text;\n return `${text.slice(0, maxChars)}\\n\\n[truncated ${text.length - maxChars} characters]`;\n}\n\n/**\n * Keep a tool result within a rough character budget so a single browse cannot\n * blow the model's context window — while preserving the result's shape so the\n * model sees a consistent type across calls:\n *\n * - strings (markdown/content) are truncated to a string;\n * - arrays (links/scrape) are trimmed from the end but stay arrays;\n * - only an opaque oversized object (e.g. a sprawling `extract`) degrades to a\n * `{ truncated, note, preview }` summary, since it cannot be trimmed safely.\n */\nfunction boundResult(value: unknown, maxChars: number): unknown {\n if (maxChars <= 0) return value;\n if (typeof value === \"string\") return truncate(value, maxChars);\n let json: string;\n try {\n json = JSON.stringify(value);\n } catch {\n return value;\n }\n if (json.length <= maxChars) return value;\n if (Array.isArray(value)) {\n const trimmed = boundArray(value, maxChars);\n // If even the first element overflows the budget, `trimmed` is empty —\n // returning `[]` would read as \"no results\" rather than \"too large\", so\n // fall through to the explicit truncated-preview summary instead.\n if (trimmed.length > 0) return trimmed;\n }\n return {\n truncated: true,\n note: `Result is too large (${json.length} characters); narrow the request.`,\n preview: `${json.slice(0, maxChars)}…`\n };\n}\n\n/**\n * Take as many leading items as fit within `maxChars` (measured against their\n * JSON length), returning a trimmed array of the same element type. Silent by\n * design: the model gets fewer, valid items rather than a reshaped result.\n */\nfunction boundArray(value: unknown[], maxChars: number): unknown[] {\n const out: unknown[] = [];\n let size = 2; // the enclosing \"[]\"\n for (const item of value) {\n const itemSize = JSON.stringify(item).length + 1; // + a separating comma\n if (size + itemSize > maxChars) break;\n out.push(item);\n size += itemSize;\n }\n return out;\n}\n\n/**\n * Create AI SDK tools for Browser Run [Quick Actions](https://developers.cloudflare.com/browser-run/quick-actions/):\n * stateless one-shot browsing (read a page as Markdown, extract structured\n * data with AI, list links, scrape elements). Unlike `createBrowserTools`,\n * these need only the `browser` binding — no Durable Object, loader, or\n * sandbox — so they work from any Worker.\n *\n * @example\n * ```ts\n * import { createQuickActionTools } from \"agents/browser/ai\";\n *\n * const tools = createQuickActionTools({ browser: this.env.BROWSER });\n * const result = await generateText({ model, tools, messages });\n * ```\n */\nexport function createQuickActionTools(\n options: CreateQuickActionToolsOptions\n): ToolSet {\n const { browser } = options;\n const requestOptions = options.options;\n const enabled = new Set(options.actions ?? DEFAULT_QUICK_ACTION_TOOLS);\n const maxChars = options.maxChars ?? DEFAULT_QUICK_ACTION_MAX_CHARS;\n const tools: ToolSet = {};\n\n if (enabled.has(\"markdown\")) {\n tools.browser_markdown = tool({\n description:\n \"Load a web page (or render raw HTML) and return its content as Markdown. Best for reading articles, docs, or any page as text.\",\n inputSchema: pageInputSchema,\n execute: async (input) =>\n boundResult(\n await browserMarkdown(browser, toPage(input, requestOptions)),\n maxChars\n )\n });\n }\n\n if (enabled.has(\"extract\")) {\n tools.browser_extract = tool({\n description:\n \"Extract structured data from a web page using AI. Describe what you want in 'prompt'. Passing a JSON Schema in 'schema' is strongly recommended — without one the extractor often fails to produce JSON.\",\n inputSchema: z\n .object({\n url: z.string().url().optional().describe(\"URL of the page to load\"),\n html: z\n .string()\n .optional()\n .describe(\"Raw HTML to render instead of loading a URL\"),\n prompt: z\n .string()\n .optional()\n .describe(\"What to extract, in natural language\"),\n schema: z\n .record(z.string(), z.unknown(), {\n error: \"Schema must be a JSON object\"\n })\n .optional()\n .describe(\"Optional JSON Schema describing the desired output\")\n })\n .refine((value) => Boolean(value.url) || Boolean(value.html), {\n message: \"Provide either 'url' or 'html'\"\n })\n .refine((value) => Boolean(value.prompt) || Boolean(value.schema), {\n message: \"Provide either 'prompt' or 'schema'\"\n }),\n execute: async (input) =>\n boundResult(\n await browserExtract(browser, {\n ...toPage(input, requestOptions),\n prompt: input.prompt,\n response_format: input.schema\n ? { type: \"json_schema\", json_schema: input.schema }\n : undefined\n }),\n maxChars\n )\n });\n }\n\n if (enabled.has(\"links\")) {\n tools.browser_links = tool({\n description:\n \"Return every link found on a web page (including ones not visible). Useful for discovering pages to follow.\",\n inputSchema: pageInputSchema,\n execute: async (input) =>\n boundResult(\n await browserLinks(browser, toPage(input, requestOptions)),\n maxChars\n )\n });\n }\n\n if (enabled.has(\"scrape\")) {\n tools.browser_scrape = tool({\n description:\n \"Scrape specific elements from a web page by CSS selector. Returns the matched elements' text, HTML, and attributes.\",\n inputSchema: z\n .object({\n url: z.string().url().optional().describe(\"URL of the page to load\"),\n html: z\n .string()\n .optional()\n .describe(\"Raw HTML to render instead of loading a URL\"),\n selectors: z\n .array(z.string())\n .min(1)\n .describe(\"CSS selectors to extract\")\n })\n .refine((value) => Boolean(value.url) || Boolean(value.html), {\n message: \"Provide either 'url' or 'html'\"\n }),\n execute: async (input) =>\n boundResult(\n await browserScrape(browser, {\n ...toPage(input, requestOptions),\n elements: input.selectors.map((selector) => ({ selector }))\n }),\n maxChars\n )\n });\n }\n\n if (enabled.has(\"content\")) {\n tools.browser_content = tool({\n description:\n \"Load a web page and return its fully rendered HTML (after JavaScript runs). Prefer 'browser_markdown' unless you need the raw HTML.\",\n inputSchema: pageInputSchema,\n execute: async (input) =>\n boundResult(\n await browserContent(browser, toPage(input, requestOptions)),\n maxChars\n )\n });\n }\n\n return tools;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-C9DAjZIY.js","names":[],"sources":["../src/websockets/capnweb-socket.ts","../src/client.ts"],"sourcesContent":["import { newWebSocketRpcSession, RpcTarget, type RpcStub } from \"capnweb\";\nimport {\n CAPNWEB_TRANSPORT_SEND,\n capnWebTransportUrl,\n type TransportClientEvents,\n type TransportHostPipe,\n type TransportMessage\n} from \"./transport-protocol\";\n\n/** Local root the host calls to deliver frames. */\nclass Inbox extends RpcTarget implements TransportClientEvents {\n constructor(private readonly socket: CapnWebSocket) {\n super();\n }\n\n message(value: TransportMessage): void {\n this.socket.dispatchEvent(new MessageEvent(\"message\", { data: value }));\n }\n}\n\n/**\n * A WebSocket-shaped client for the Cap'n Web connection transport.\n *\n * It has the constructor, `readyState`, `send()`, `close()`, and events of\n * a `WebSocket`, so PartySocket (and therefore `useAgent` and\n * `AgentClient`) can drive it as a drop-in socket implementation and keep\n * owning reconnection, buffering, and backoff. Frames sent here travel\n * through the host's pipe method; frames from the host arrive as\n * `message` events.\n *\n * @experimental The transport is experimental.\n */\nexport class CapnWebSocket extends EventTarget {\n static readonly CONNECTING = 0;\n static readonly OPEN = 1;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n readonly CONNECTING = 0;\n readonly OPEN = 1;\n readonly CLOSING = 2;\n readonly CLOSED = 3;\n\n readonly url: string;\n readyState = CapnWebSocket.CONNECTING;\n binaryType: BinaryType = \"arraybuffer\";\n bufferedAmount = 0;\n extensions = \"\";\n protocol = \"\";\n onopen: ((event: Event) => void) | null = null;\n onmessage: ((event: MessageEvent) => void) | null = null;\n onclose: ((event: CloseEvent) => void) | null = null;\n onerror: ((event: Event) => void) | null = null;\n\n readonly #socket: WebSocket;\n readonly #root: RpcStub<TransportHostPipe>;\n\n constructor(url: string | URL, protocols?: string | string[]) {\n super();\n this.url = capnWebTransportUrl(url);\n this.#socket = protocols\n ? new WebSocket(this.url, protocols)\n : new WebSocket(this.url);\n this.#root = newWebSocketRpcSession<TransportHostPipe>(\n this.#socket,\n new Inbox(this)\n );\n this.#socket.addEventListener(\"open\", () => {\n this.readyState = CapnWebSocket.OPEN;\n this.protocol = this.#socket.protocol;\n this.dispatchEvent(new Event(\"open\"));\n });\n this.#socket.addEventListener(\"close\", (event) => {\n this.readyState = CapnWebSocket.CLOSED;\n this.dispatchEvent(\n new CloseEvent(\"close\", {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean\n })\n );\n });\n this.#socket.addEventListener(\"error\", () => {\n this.dispatchEvent(new Event(\"error\"));\n });\n }\n\n override dispatchEvent(event: Event): boolean {\n const handler = Reflect.get(this, `on${event.type}`) as unknown;\n if (typeof handler === \"function\") Reflect.apply(handler, this, [event]);\n return super.dispatchEvent(event);\n }\n\n /**\n * Invoke one of the host's native callables on the session root. The\n * result keeps Cap'n Web semantics: an `RpcTarget` arrives as a live\n * stub, a `ReadableStream` streams, and chained calls pipeline.\n */\n invoke(method: string, args: unknown[]): Promise<unknown> {\n if (this.readyState !== CapnWebSocket.OPEN) {\n return Promise.reject(new Error(\"Connection closed\"));\n }\n // The root stub answers every property with a callable, so an unknown\n // method is only detected by the host, which rejects the call. The\n // result is an RpcPromise; resolve through a plain Promise so callers\n // hold nothing exotic.\n const root = this.#root as unknown as Record<\n string,\n (...a: unknown[]) => unknown\n >;\n return Promise.resolve(root[method](...args));\n }\n\n send(data: TransportMessage): void {\n if (this.readyState !== CapnWebSocket.OPEN) {\n throw new DOMException(\"WebSocket is not open\", \"InvalidStateError\");\n }\n void this.#root[CAPNWEB_TRANSPORT_SEND](data).catch(() => {\n this.dispatchEvent(new Event(\"error\"));\n });\n }\n\n close(code?: number, reason?: string): void {\n if (this.readyState >= CapnWebSocket.CLOSING) return;\n this.readyState = CapnWebSocket.CLOSING;\n try {\n this.#root[Symbol.dispose]();\n } catch {\n // The session is already gone; closing the socket is enough.\n }\n this.#socket.close(code, reason);\n }\n}\n\n/**\n * A `CapnWebSocket` subclass that reports each instance it constructs.\n * PartySocket instantiates the class it is given; this is how a client\n * gets hold of the live socket to call `invoke()` without reaching into\n * PartySocket internals.\n */\nexport function boundCapnWebSocket(\n onCreate: (socket: CapnWebSocket) => void\n): typeof CapnWebSocket {\n return class BoundCapnWebSocket extends CapnWebSocket {\n constructor(url: string | URL, protocols?: string | string[]) {\n super(url, protocols);\n onCreate(this);\n }\n };\n}\n","import {\n type PartyFetchOptions,\n PartySocket,\n type PartySocketOptions\n} from \"partysocket\";\nimport type { Agent, RPCRequest, RPCResponse } from \"./\";\nimport type {\n ClientParameters,\n Method,\n RPCMethod,\n SerializableReturnValue,\n SerializableValue\n} from \"./serializable\";\nimport { MessageType } from \"./types\";\nimport { camelCaseToKebabCase, isInternalJsStubProp } from \"./utils\";\nimport {\n boundCapnWebSocket,\n type CapnWebSocket\n} from \"./websockets/capnweb-socket\";\nimport type { AgentTransport } from \"./websockets/transport-protocol\";\n\nexport type { AgentTransport } from \"./websockets/transport-protocol\";\n\nexport class AgentConnectionError extends Error {\n code: number;\n reason: string;\n wasClean: boolean;\n\n constructor(event: CloseEvent) {\n const reason = event.reason || `WebSocket closed with code ${event.code}`;\n super(`Agent connection closed: ${reason}`);\n this.name = \"AgentConnectionError\";\n this.code = event.code;\n this.reason = event.reason;\n this.wasClean = event.wasClean;\n }\n}\n\nexport function isTerminalCloseEvent(event: CloseEvent): boolean {\n return event.code === 1008 || (event.code >= 4000 && event.code <= 4999);\n}\n\ntype TerminalReconnectOptions = {\n shouldReconnectOnClose?: (event: CloseEvent) => boolean;\n};\n\n/**\n * Options for creating an AgentClient\n */\nexport type AgentClientOptions<State = unknown> = Omit<\n PartySocketOptions,\n \"party\" | \"room\"\n> &\n TerminalReconnectOptions & {\n /**\n * Wire the connection travels on. `\"cf-websocket\"` (default) is a\n * hibernating WebSocket where `call()` sends JSON `rpc` frames.\n * `\"capnweb\"` carries protocol frames over a Cap'n Web session whose\n * root also serves the host's `callables` natively, so `call()` and\n * `stub` invoke them directly and an `RpcTarget` result is a live stub.\n * The Durable Object stays in memory while a capnweb connection is open.\n * @experimental The `\"capnweb\"` transport is experimental.\n */\n transport?: AgentTransport;\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the client connects to this path directly.\n * Server must handle routing manually (e.g., with getAgentByName + fetch).\n * @example\n * // Client connects to /user, server routes based on session\n * useAgent({ agent: \"UserAgent\", basePath: \"user\" })\n */\n basePath?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n /** Called when a state update fails (e.g., connection is readonly) */\n onStateUpdateError?: (error: string) => void;\n /**\n * Called when the server sends the agent's identity on connect.\n * Useful when using basePath, as the actual instance name is determined server-side.\n * @param name The actual agent instance name\n * @param agent The agent class name (kebab-case)\n */\n onIdentity?: (name: string, agent: string) => void;\n /**\n * Called when identity changes on reconnect (different instance than before).\n * If not provided and identity changes, a warning will be logged.\n * @param oldName Previous instance name\n * @param newName New instance name\n * @param oldAgent Previous agent class name\n * @param newAgent New agent class name\n */\n onIdentityChange?: (\n oldName: string,\n newName: string,\n oldAgent: string,\n newAgent: string\n ) => void;\n /**\n * Additional path to append to the URL.\n * Works with both standard routing and basePath.\n * @example\n * // With basePath: /user/settings\n * { basePath: \"user\", path: \"settings\" }\n * // Standard: /agents/my-agent/room/settings\n * { agent: \"MyAgent\", name: \"room\", path: \"settings\" }\n */\n path?: string;\n /**\n * Default timeout (in milliseconds) applied to non-streaming `call()`s\n * that don't pass an explicit `timeout`. Defaults to 30 000 ms.\n * Set to `0` to disable. Streaming calls never get a default timeout.\n */\n defaultCallTimeout?: number;\n /** Called when the connection closes with a terminal code and will not reconnect. */\n onConnectionError?: (error: AgentConnectionError) => void;\n };\n\n/**\n * Default timeout (in milliseconds) applied to non-streaming RPC calls\n * that don't pass an explicit `timeout`. Acts as a backstop so calls\n * whose response is lost (e.g. the connection drops mid-flight) reject\n * instead of hanging forever. Override per client via\n * `defaultCallTimeout`, or per call via `timeout` (0 disables).\n */\nexport const DEFAULT_CALL_TIMEOUT_MS = 30_000;\n\n/**\n * Options for streaming RPC calls\n */\nexport type StreamOptions = {\n /** Called when a chunk of data is received */\n onChunk?: (chunk: unknown) => void;\n /** Called when the stream ends */\n onDone?: (finalChunk: unknown) => void;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n};\n\n/**\n * Options for RPC calls\n */\nexport type CallOptions = {\n /** Timeout in milliseconds. If the call doesn't complete within this time, it will be rejected. */\n timeout?: number;\n /** Streaming options for handling streaming responses */\n stream?: StreamOptions;\n};\n\n/**\n * Normalize `call()` options. The legacy shape is the stream callbacks\n * themselves (`{ onChunk, onDone, onError }`); the current shape nests\n * them under `stream` beside `timeout`.\n */\nexport function splitCallOptions(\n options: CallOptions | StreamOptions | undefined\n): {\n stream: StreamOptions | undefined;\n timeout: number | undefined;\n} {\n const legacy =\n options !== undefined &&\n (\"onChunk\" in options || \"onDone\" in options || \"onError\" in options);\n return legacy\n ? { stream: options as StreamOptions, timeout: undefined }\n : {\n stream: (options as CallOptions | undefined)?.stream,\n timeout: (options as CallOptions | undefined)?.timeout\n };\n}\n\n/**\n * One native call on the Cap'n Web transport, with the timeout and\n * stream-callback contract `call()` has on the JSON wire. The timeout\n * covers the whole call, draining included: on expiry the stream reader is\n * cancelled and the promise rejects once. A `ReadableStream` result is\n * drained into the stream callbacks when they are given; any other value,\n * live stubs included, passes straight through.\n */\nexport async function nativeCall<T>(\n socket: CapnWebSocket,\n method: string,\n args: unknown[],\n options: CallOptions | StreamOptions | undefined,\n defaultTimeout: number\n): Promise<T> {\n const { stream, timeout } = splitCallOptions(options);\n const effectiveTimeout =\n timeout !== undefined ? timeout : stream ? undefined : defaultTimeout;\n let reader: ReadableStreamDefaultReader<unknown> | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const work = (async () => {\n const result = await socket.invoke(method, args);\n if (stream && result instanceof ReadableStream) {\n reader = (result as ReadableStream<unknown>).getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n stream.onChunk?.(value);\n }\n stream.onDone?.(undefined);\n return undefined as T;\n }\n return result as T;\n })();\n\n const expiry = effectiveTimeout\n ? new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n void reader?.cancel().catch(() => {});\n reject(\n new Error(\n `RPC call to ${method} timed out after ${effectiveTimeout}ms`\n )\n );\n }, effectiveTimeout);\n })\n : undefined;\n\n try {\n return await (expiry ? Promise.race([work, expiry]) : work);\n } catch (error) {\n // Keep the rejection observed on the losing side of the race.\n void work.catch(() => {});\n stream?.onError?.(error instanceof Error ? error.message : String(error));\n throw error;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/**\n * Native calls issued while the Cap'n Web socket is still connecting or\n * between reconnects. They must not fall back to JSON frames — that would\n * change which methods are reachable and lose return-by-reference — so\n * they wait here and run on the next open socket, or reject when the\n * connection ends for good. Their timeout starts when they are issued.\n */\nexport class NativeCallQueue {\n #pending: Array<{\n run: (socket: CapnWebSocket) => void;\n reject: (error: Error) => void;\n }> = [];\n\n enqueue<T>(\n method: string,\n args: unknown[],\n options: CallOptions | StreamOptions | undefined,\n defaultTimeout: number\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const { stream, timeout } = splitCallOptions(options);\n const effectiveTimeout =\n timeout !== undefined ? timeout : stream ? undefined : defaultTimeout;\n const startedAt = Date.now();\n const entry = {\n run: (socket: CapnWebSocket) => {\n // Spend the remaining budget, not a fresh one.\n const remaining =\n effectiveTimeout === undefined\n ? undefined\n : Math.max(1, effectiveTimeout - (Date.now() - startedAt));\n const opts =\n remaining === undefined ? options : { stream, timeout: remaining };\n nativeCall<T>(socket, method, args, opts, defaultTimeout).then(\n resolve,\n reject\n );\n },\n reject: (error: Error) => {\n stream?.onError?.(error.message);\n reject(error);\n }\n };\n this.#pending.push(entry);\n if (effectiveTimeout) {\n setTimeout(() => {\n const index = this.#pending.indexOf(entry);\n if (index === -1) return;\n this.#pending.splice(index, 1);\n entry.reject(\n new Error(\n `RPC call to ${method} timed out after ${effectiveTimeout}ms`\n )\n );\n }, effectiveTimeout);\n }\n });\n }\n\n /** Run everything queued on a socket that just opened. */\n flush(socket: CapnWebSocket): void {\n const pending = this.#pending;\n this.#pending = [];\n for (const entry of pending) entry.run(socket);\n }\n\n /** Reject everything queued; the connection will not come back. */\n rejectAll(reason: string): void {\n const pending = this.#pending;\n this.#pending = [];\n const error = new Error(reason);\n for (const entry of pending) entry.reject(error);\n }\n}\n\n/**\n * Options for the agentFetch function\n */\nexport type AgentClientFetchOptions = Omit<\n PartyFetchOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the request is made to this path directly.\n */\n basePath?: string;\n};\n\n// ---- Shared RPC Type Utilities ----\n\ntype AllOptional<T> = T extends [infer A, ...infer R]\n ? undefined extends A\n ? AllOptional<R>\n : false\n : true;\n\nexport type RPCMethods<T> = {\n [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;\n};\n\ntype OptionalParametersMethod<T extends RPCMethod> =\n AllOptional<ClientParameters<T>> extends true ? T : never;\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic agent type constraint\nexport type AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;\n\nexport type OptionalAgentMethods<T> = {\n [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<\n AgentMethods<T>[K]\n >\n ? K\n : never]: OptionalParametersMethod<AgentMethods<T>[K]>;\n};\n\nexport type RequiredAgentMethods<T> = Omit<\n AgentMethods<T>,\n keyof OptionalAgentMethods<T>\n>;\n\nexport type AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic promise return type\n ReturnType<AgentMethods<T>[K]> extends Promise<any>\n ? ReturnType<AgentMethods<T>[K]>\n : Promise<ReturnType<AgentMethods<T>[K]>>;\n\nexport type AgentStub<T> = {\n [K in keyof AgentMethods<T>]: (\n ...args: ClientParameters<AgentMethods<T>[K]>\n ) => AgentPromiseReturnType<AgentMethods<T>, K>;\n};\n\nexport type UntypedAgentStub = Record<string, Method>;\n\ntype AgentClientStub<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentStub\n : AgentStub<AgentT>;\n\ntype OptionalArgsAgentClientCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: ClientParameters<OptionalAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentClientCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: ClientParameters<RequiredAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype TypedAgentClientCall<AgentT> = OptionalArgsAgentClientCall<AgentT> &\n RequiredArgsAgentClientCall<AgentT>;\n\ntype UntypedAgentClientCall = {\n <T extends SerializableReturnValue>(\n method: string,\n args?: SerializableValue[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n <T = unknown>(\n method: string,\n args?: unknown[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n};\n\ntype AgentClientCall<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentClientCall\n : TypedAgentClientCall<AgentT>;\n\n/**\n * Creates a proxy that wraps RPC method calls.\n * Internal JS methods (toJSON, then, etc.) return undefined to avoid\n * triggering RPC calls during serialization (e.g., console.log)\n */\nexport function createStubProxy<T = Record<string, Method>>(\n call: (method: string, args: unknown[]) => unknown\n): T {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- proxy needs any for dynamic method access\n return new Proxy<any>(\n {},\n {\n get: (_target, method) => {\n if (isInternalJsStubProp(method)) {\n return undefined;\n }\n return (...args: unknown[]) => call(method as string, args);\n }\n }\n );\n}\n\n/**\n * WebSocket client for connecting to an Agent\n */\nexport class AgentClient<\n AgentT = unknown,\n State = AgentT extends { get state(): infer S } ? S : AgentT\n> extends PartySocket {\n /**\n * @deprecated Use agentFetch instead\n */\n static fetch(_opts: PartyFetchOptions): Promise<Response> {\n throw new Error(\n \"AgentClient.fetch is not implemented, use agentFetch instead\"\n );\n }\n agent: string;\n name: string;\n call: AgentClientCall<AgentT>;\n stub: AgentClientStub<AgentT>;\n\n /**\n * The current agent state, updated on server broadcasts and client setState calls.\n * Starts as undefined until the first state message is received from the server.\n */\n state: State | undefined = undefined;\n\n /**\n * Whether the client has received identity from the server.\n * Becomes true after the first identity message is received.\n * Resets to false on connection close.\n */\n identified = false;\n\n /**\n * Terminal connection error, if the server closed the socket with a code\n * that should not be retried automatically.\n */\n connectionError: AgentConnectionError | null = null;\n\n /**\n * Promise that resolves when identity has been received from the server.\n * Useful for waiting before making calls that depend on knowing the instance.\n * Resets on connection close so it can be awaited again after reconnect.\n */\n get ready(): Promise<void> {\n return this._readyPromise;\n }\n\n private options: AgentClientOptions<State>;\n private _pendingCalls = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n /**\n * Whether the request was actually transmitted to the server.\n * Requests issued while disconnected sit in PartySocket's internal\n * buffer (transmitted: false) and are flushed on the next open —\n * they survive a transient close instead of being rejected, since\n * the server never saw them and re-delivery can't double-execute.\n */\n transmitted: boolean;\n }\n >();\n private _readyPromise!: Promise<void>;\n private _resolveReady!: () => void;\n private _previousName: string | null = null;\n private _previousAgent: string | null = null;\n\n private _resetReady() {\n this._readyPromise = new Promise((resolve) => {\n this._resolveReady = resolve;\n });\n }\n\n /**\n * The live Cap'n Web socket on the `\"capnweb\"` transport. PartySocket\n * constructs a new one on every reconnect; the bound class reports each\n * into this holder, which exists before `super()` runs.\n */\n readonly #capnWeb: { current: CapnWebSocket | null };\n readonly #nativeQueue = new NativeCallQueue();\n\n constructor(options: AgentClientOptions<State>) {\n const capnWeb: { current: CapnWebSocket | null } = { current: null };\n const socketClass =\n options.transport === \"capnweb\"\n ? {\n WebSocket: boundCapnWebSocket((socket) => {\n capnWeb.current = socket;\n })\n }\n : {};\n const agentNamespace = camelCaseToKebabCase(options.agent);\n const shouldReconnectOnClose = options.shouldReconnectOnClose;\n const classifyReconnect = (event: CloseEvent) =>\n (shouldReconnectOnClose?.(event) ?? true) && !isTerminalCloseEvent(event);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? {\n basePath: options.basePath,\n path: options.path,\n ...options,\n ...socketClass,\n shouldReconnectOnClose: classifyReconnect\n }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: options.path,\n ...options,\n ...socketClass,\n shouldReconnectOnClose: classifyReconnect\n };\n\n super(socketOptions);\n this.#capnWeb = capnWeb;\n this.agent = agentNamespace;\n this.name = options.name || \"default\";\n this.options = options;\n\n // Initialize ready promise\n this._resetReady();\n\n this.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(event.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = this._previousName;\n const oldAgent = this._previousAgent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n // Resolve ready/identified\n this.identified = true;\n this._resolveReady();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (this.options.onIdentityChange) {\n this.options.onIdentityChange(\n oldName,\n newName,\n oldAgent,\n newAgent\n );\n } else {\n const agentChanged = oldAgent !== newAgent;\n const nameChanged = oldName !== newName;\n let changeDescription = \"\";\n if (agentChanged && nameChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\", instance \"${oldName}\" → \"${newName}\"`;\n } else if (agentChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\"`;\n } else {\n changeDescription = `instance \"${oldName}\" → \"${newName}\"`;\n }\n console.warn(\n `[agents] Identity changed on reconnect: ${changeDescription}. ` +\n \"This can happen with server-side routing (e.g., basePath with getAgentByName) \" +\n \"where the instance is determined by auth/session. \" +\n \"Provide onIdentityChange callback to handle this explicitly, \" +\n \"or ignore if this is expected for your routing pattern.\"\n );\n }\n }\n\n // Always update from server identity (server is authoritative)\n this._previousName = newName;\n this._previousAgent = newAgent;\n this.name = newName;\n this.agent = newAgent;\n\n // Call onIdentity callback\n this.options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n this.state = parsedMessage.state as State;\n this.options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE_ERROR) {\n this.options.onStateUpdateError?.(parsedMessage.error as string);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = this._pendingCalls.get(response.id);\n if (!pending) {\n console.warn(\n `[AgentClient] Discarded an RPC response with no matching pending call (id \"${response.id}\"). ` +\n \"The call likely timed out or was rejected when its connection closed before the response arrived.\"\n );\n return;\n }\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n this._pendingCalls.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n }\n }\n }\n });\n\n // PartySocket flushes its internal message buffer right before\n // dispatching \"open\" — anything queued has now been transmitted.\n this.addEventListener(\"open\", () => {\n this.connectionError = null;\n for (const pending of this._pendingCalls.values()) {\n pending.transmitted = true;\n }\n const native = this.#capnWeb.current;\n if (native) this.#nativeQueue.flush(native);\n });\n\n // Clean up pending calls and reset ready state when connection closes\n this.addEventListener(\"close\", (event) => {\n const terminalClose = isTerminalCloseEvent(event);\n // Reset ready state for next connection\n this.identified = false;\n this._resetReady();\n\n if (this.shouldReconnect) {\n // Transient disconnect: reject calls whose request was already\n // transmitted — their response can never arrive. Buffered calls\n // stay pending; PartySocket re-sends them on reconnect.\n this._rejectPendingCalls(\"Connection closed\", {\n onlyTransmitted: true\n });\n } else {\n // Permanent close (close() called or retries exhausted): nothing\n // will ever flush the buffer, so reject everything.\n this._rejectPendingCalls(\"Connection closed\");\n this.#nativeQueue.rejectAll(\"Connection closed\");\n if (terminalClose) {\n const error = new AgentConnectionError(event);\n this.connectionError = error;\n this.options.onConnectionError?.(error);\n }\n }\n });\n\n this.call = this._callImpl.bind(this) as AgentClientCall<AgentT>;\n this.stub = createStubProxy((method, args) =>\n this._callImpl(method, args)\n ) as AgentClientStub<AgentT>;\n }\n\n /**\n * Reject pending RPC calls with the given reason.\n * With `onlyTransmitted`, calls still sitting in the send buffer are\n * kept pending (they'll be flushed on reconnect).\n */\n private _rejectPendingCalls(\n reason: string,\n { onlyTransmitted = false }: { onlyTransmitted?: boolean } = {}\n ) {\n const error = new Error(reason);\n for (const [id, pending] of this._pendingCalls) {\n if (onlyTransmitted && !pending.transmitted) continue;\n this._pendingCalls.delete(id);\n pending.reject(error);\n pending.stream?.onError?.(reason);\n }\n }\n\n setState(state: State) {\n this.send(JSON.stringify({ state, type: MessageType.CF_AGENT_STATE }));\n this.state = state;\n this.options.onStateUpdate?.(state, \"client\");\n }\n\n /**\n * Close the connection and immediately reject all pending RPC calls.\n * This provides immediate feedback on intentional close rather than\n * waiting for the WebSocket close handshake to complete.\n *\n * Note: Any calls made after `close()` will be rejected when the\n * underlying WebSocket close event fires.\n */\n close(code?: number, reason?: string) {\n // Immediately reject all pending calls on intentional close\n this._rejectPendingCalls(\"Connection closed\");\n\n // Then close the underlying socket\n super.close(code, reason);\n }\n\n /**\n * Call a method on the Agent.\n * When AgentT is provided, method names are inferred from the agent's methods.\n * Falls back to untyped string-based calls when AgentT is not provided.\n */\n private async _callImpl(\n method: string,\n args: unknown[] = [],\n options?: CallOptions | StreamOptions\n ): Promise<unknown> {\n // On the Cap'n Web transport, callables are native methods on the\n // session root: invoke them directly so an RpcTarget result arrives as\n // a live stub. The JSON `rpc` frame below is the WebSocket wire's protocol.\n if (this.options.transport === \"capnweb\") {\n const timeout =\n this.options.defaultCallTimeout ?? DEFAULT_CALL_TIMEOUT_MS;\n const native = this.#capnWeb.current;\n if (native && this.readyState === this.OPEN) {\n return nativeCall(native, method, args, options, timeout);\n }\n if (this.connectionError && this.readyState === this.CLOSED) {\n throw new Error(\"Connection closed\");\n }\n // Connecting or between reconnects: hold the call as a native call\n // rather than queueing a JSON frame that would change its meaning.\n return this.#nativeQueue.enqueue(method, args, options, timeout);\n }\n if (this.connectionError && this.readyState === this.CLOSED) {\n throw new Error(\"Connection closed\");\n }\n\n return new Promise((resolve, reject) => {\n const id = crypto.randomUUID();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const { stream: streamOptions, timeout } = splitCallOptions(options);\n\n // Apply the default timeout as a backstop for non-streaming calls\n // so a lost response rejects instead of hanging forever. An\n // explicit `timeout` (including 0 = disabled) always wins.\n const effectiveTimeout =\n timeout !== undefined\n ? timeout\n : streamOptions\n ? undefined\n : (this.options.defaultCallTimeout ?? DEFAULT_CALL_TIMEOUT_MS);\n\n if (effectiveTimeout) {\n timeoutId = setTimeout(() => {\n const pending = this._pendingCalls.get(id);\n this._pendingCalls.delete(id);\n const errorMessage = `RPC call to ${method} timed out after ${effectiveTimeout}ms`;\n pending?.stream?.onError?.(errorMessage);\n reject(new Error(errorMessage));\n }, effectiveTimeout);\n }\n\n this._pendingCalls.set(id, {\n reject: (e: Error) => {\n if (timeoutId) clearTimeout(timeoutId);\n reject(e);\n },\n resolve: (value: unknown) => {\n if (timeoutId) clearTimeout(timeoutId);\n resolve(value);\n },\n stream: streamOptions,\n // If the socket is open, send() below transmits synchronously;\n // otherwise the request is buffered until the next open event\n // (the \"open\" listener then marks it transmitted).\n transmitted: this.readyState === this.OPEN\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n this.send(JSON.stringify(request));\n });\n }\n}\n\n/**\n * Make an HTTP request to an Agent\n * @param opts Connection options\n * @param init Request initialization options\n * @returns Promise resolving to a Response\n */\nexport function agentFetch(opts: AgentClientFetchOptions, init?: RequestInit) {\n const agentNamespace = camelCaseToKebabCase(opts.agent);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n // When basePath is set, room/party aren't used by PartySocket (basePath replaces the URL)\n if (opts.basePath) {\n return PartySocket.fetch(\n { basePath: opts.basePath, ...opts } as unknown as PartyFetchOptions,\n init\n );\n }\n\n return PartySocket.fetch(\n {\n party: agentNamespace,\n prefix: \"agents\",\n room: opts.name || \"default\",\n ...opts\n },\n init\n );\n}\n"],"mappings":"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"}
@@ -1,53 +0,0 @@
1
- import { JSONSchema7, Tool, ToolSet } from "ai";
2
-
3
- //#region src/chat/client-tools.d.ts
4
- /**
5
- * Wire-format tool schema sent from the client.
6
- * Uses `parameters` (JSONSchema7) rather than AI SDK's `inputSchema`
7
- * because Zod schemas cannot be serialized over the wire.
8
- */
9
- type ClientToolSchema = {
10
- /** Unique name for the tool */ name: string /** Human-readable description of what the tool does */;
11
- description?: Tool["description"] /** JSON Schema defining the tool's input parameters */;
12
- parameters?: JSONSchema7;
13
- };
14
- /**
15
- * Executes a client-defined tool and returns its output.
16
- *
17
- * Used for the RPC path (e.g. a parent agent delegating to a Think sub-agent)
18
- * where the caller can run the client tools itself, rather than the
19
- * browser/WebSocket path where results are sent back asynchronously.
20
- */
21
- type ClientToolExecutor = (call: {
22
- /** The name of the client tool the model called. */ toolName: string /** The model-generated input for the tool call. */;
23
- input: unknown /** The AI SDK tool-call id for the invocation. */;
24
- toolCallId: string;
25
- }) => unknown | Promise<unknown>;
26
- /**
27
- * Converts client tool schemas to AI SDK tool format.
28
- *
29
- * By default these tools have no `execute` function — when the AI model calls
30
- * them, the tool call is sent back to the client for execution.
31
- *
32
- * When `options.execute` is provided, each tool is built WITH an `execute` that
33
- * delegates to it. This is used by the RPC path (e.g. a parent agent driving a
34
- * Think sub-agent) so the model's client-tool call is resolved inline within
35
- * the same turn.
36
- *
37
- * @param clientTools - Array of tool schemas from the client
38
- * @param options - Optional `execute` delegate to run the tools inline
39
- * @returns Record of AI SDK tools that can be spread into your tools object
40
- */
41
- declare function createToolsFromClientSchemas(
42
- clientTools?: ClientToolSchema[],
43
- options?: {
44
- execute?: ClientToolExecutor;
45
- }
46
- ): ToolSet;
47
- //#endregion
48
- export {
49
- ClientToolSchema as n,
50
- createToolsFromClientSchemas as r,
51
- ClientToolExecutor as t
52
- };
53
- //# sourceMappingURL=client-tools-aIBO0Fk7.d.ts.map