agents 0.22.0 → 0.23.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 (186) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-DE5zmCQ8.d.ts} +1038 -394
  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-DtXMTDGM.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.map +1 -1
  15. package/dist/capability-runner-Be_-PLR1.d.ts +459 -0
  16. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  17. package/dist/channels/ai-sdk.d.ts +46 -0
  18. package/dist/channels/ai-sdk.js +120 -0
  19. package/dist/channels/ai-sdk.js.map +1 -0
  20. package/dist/channels/email.d.ts +95 -0
  21. package/dist/channels/email.js +323 -0
  22. package/dist/channels/email.js.map +1 -0
  23. package/dist/channels/index.d.ts +233 -0
  24. package/dist/channels/index.js +608 -0
  25. package/dist/channels/index.js.map +1 -0
  26. package/dist/channels/slack.d.ts +140 -0
  27. package/dist/channels/slack.js +614 -0
  28. package/dist/channels/slack.js.map +1 -0
  29. package/dist/channels/tanstack-ai.d.ts +39 -0
  30. package/dist/channels/tanstack-ai.js +17 -0
  31. package/dist/channels/tanstack-ai.js.map +1 -0
  32. package/dist/channels/telegram.d.ts +106 -0
  33. package/dist/channels/telegram.js +427 -0
  34. package/dist/channels/telegram.js.map +1 -0
  35. package/dist/channels/voice.d.ts +45 -0
  36. package/dist/channels/voice.js +122 -0
  37. package/dist/channels/voice.js.map +1 -0
  38. package/dist/chat/index.d.ts +2325 -2019
  39. package/dist/chat/index.js +888 -518
  40. package/dist/chat/index.js.map +1 -1
  41. package/dist/chat-sdk/index.d.ts +7 -7
  42. package/dist/chat-sdk/index.js +1 -1
  43. package/dist/client.d.ts +1 -1
  44. package/dist/context/index.d.ts +216 -0
  45. package/dist/context/index.js +454 -0
  46. package/dist/context/index.js.map +1 -0
  47. package/dist/{current-agent-CuMErtly.d.ts → current-agent-Da_C9a3b.d.ts} +90 -107
  48. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  49. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  50. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  51. package/dist/diagnostics-C4jcz3VK.js +360 -0
  52. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  53. package/dist/index-BB0kqhIz.d.ts +101 -0
  54. package/dist/index-BVVgDSdq.d.ts +1 -0
  55. package/dist/index-XDkuQ7zm.d.ts +89 -0
  56. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  57. package/dist/index.d.ts +91 -82
  58. package/dist/index.js +3 -2
  59. package/dist/ingress-BfetZbMO.js +83 -0
  60. package/dist/ingress-BfetZbMO.js.map +1 -0
  61. package/dist/internal-CYlgHl1l.js +59 -0
  62. package/dist/internal-CYlgHl1l.js.map +1 -0
  63. package/dist/internal_context.d.ts +1 -1
  64. package/dist/lifecycle/index.d.ts +35 -17
  65. package/dist/lifecycle/index.js +1 -1
  66. package/dist/lifecycle-CMRGjZdw.js +1299 -0
  67. package/dist/lifecycle-CMRGjZdw.js.map +1 -0
  68. package/dist/mcp/client/index.d.ts +20 -20
  69. package/dist/mcp/index.d.ts +35 -35
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/observability/index.d.ts +1 -1
  72. package/dist/observability/index.js +1 -1
  73. package/dist/react.d.ts +4 -4
  74. package/dist/{retries-CAvxtG9d.d.ts → retries-D9Ds-1lz.d.ts} +17 -6
  75. package/dist/retries.d.ts +8 -6
  76. package/dist/retries.js +13 -1
  77. package/dist/retries.js.map +1 -1
  78. package/dist/routing/index.d.ts +137 -0
  79. package/dist/routing/index.js +244 -0
  80. package/dist/routing/index.js.map +1 -0
  81. package/dist/sanitize-D9TujEK8.js +79 -0
  82. package/dist/sanitize-D9TujEK8.js.map +1 -0
  83. package/dist/scheduler-DD9NdYbF.js +665 -0
  84. package/dist/scheduler-DD9NdYbF.js.map +1 -0
  85. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-Dwh85ZGl.d.ts} +21 -22
  86. package/dist/schedules/index.d.ts +1 -1
  87. package/dist/schedules/index.js +1 -1
  88. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  89. package/dist/serializable.d.ts +1 -1
  90. package/dist/sessions/index.d.ts +441 -0
  91. package/dist/sessions/index.js +2063 -0
  92. package/dist/sessions/index.js.map +1 -0
  93. package/dist/skills/index.d.ts +99 -0
  94. package/dist/skills/index.js +254 -5
  95. package/dist/skills/index.js.map +1 -1
  96. package/dist/{src-5W6JNKVb.js → src-DlSHshb2.js} +1460 -1110
  97. package/dist/src-DlSHshb2.js.map +1 -0
  98. package/dist/streams/index.d.ts +120 -0
  99. package/dist/streams/index.js +107 -0
  100. package/dist/streams/index.js.map +1 -0
  101. package/dist/streams-D6tJ0NN9.d.ts +370 -0
  102. package/dist/streams-DZKgAj9b.js +709 -0
  103. package/dist/streams-DZKgAj9b.js.map +1 -0
  104. package/dist/sub-routing.d.ts +12 -12
  105. package/dist/surface-bZZJqBka.js +17 -0
  106. package/dist/surface-bZZJqBka.js.map +1 -0
  107. package/dist/tasks/index.d.ts +64 -0
  108. package/dist/tasks/index.js +2 -0
  109. package/dist/tasks-BRJ5zgya.d.ts +517 -0
  110. package/dist/tasks-ylZgBjhj.js +1656 -0
  111. package/dist/tasks-ylZgBjhj.js.map +1 -0
  112. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  113. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  114. package/dist/text-stream-CpdiKrJB.js +272 -0
  115. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  116. package/dist/tokens-nHAKcN6M.js +52 -0
  117. package/dist/tokens-nHAKcN6M.js.map +1 -0
  118. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  119. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  120. package/dist/types-B7LojTe4.d.ts +202 -0
  121. package/dist/types-_Faxb570.d.ts +439 -0
  122. package/dist/voice/client.d.ts +226 -0
  123. package/dist/voice/client.js +932 -0
  124. package/dist/voice/client.js.map +1 -0
  125. package/dist/voice/errors.d.ts +43 -0
  126. package/dist/voice/errors.js +41 -0
  127. package/dist/voice/errors.js.map +1 -0
  128. package/dist/voice/index.d.ts +271 -0
  129. package/dist/voice/index.js +1812 -0
  130. package/dist/voice/index.js.map +1 -0
  131. package/dist/voice/react.d.ts +167 -0
  132. package/dist/voice/react.js +234 -0
  133. package/dist/voice/react.js.map +1 -0
  134. package/dist/voice/sfu.d.ts +71 -0
  135. package/dist/voice/sfu.js +157 -0
  136. package/dist/voice/sfu.js.map +1 -0
  137. package/dist/voice/text.d.ts +6 -0
  138. package/dist/voice/text.js +2 -0
  139. package/dist/voice/types.d.ts +58 -0
  140. package/dist/voice/types.js +18 -0
  141. package/dist/voice/types.js.map +1 -0
  142. package/dist/voice/workers-ai.d.ts +136 -0
  143. package/dist/voice/workers-ai.js +568 -0
  144. package/dist/voice/workers-ai.js.map +1 -0
  145. package/dist/websockets/index.d.ts +192 -0
  146. package/dist/websockets/index.js +2 -0
  147. package/dist/websockets-DUfRHPRq.js +502 -0
  148. package/dist/websockets-DUfRHPRq.js.map +1 -0
  149. package/dist/workflow-types.d.ts +25 -25
  150. package/dist/workflows.d.ts +21 -21
  151. package/dist/workflows.js +1 -1
  152. package/docs/agent-class.md +2 -2
  153. package/docs/agent-tools.md +2 -1
  154. package/docs/channels.md +323 -0
  155. package/docs/chat-agents.md +6 -13
  156. package/docs/context.md +131 -0
  157. package/docs/index.md +15 -12
  158. package/docs/lifecycle.md +102 -55
  159. package/docs/long-running-agents.md +2 -2
  160. package/docs/mcp-servers.md +5 -1
  161. package/docs/resumable-streaming.md +1 -1
  162. package/docs/routing.md +105 -0
  163. package/docs/sessions.md +237 -871
  164. package/docs/streams.md +213 -0
  165. package/docs/sub-agents.md +184 -124
  166. package/docs/tasks.md +246 -0
  167. package/docs/voice.md +745 -0
  168. package/package.json +115 -13
  169. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  170. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  171. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  172. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  173. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  174. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  175. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  176. package/dist/experimental/memory/session/index.d.ts +0 -671
  177. package/dist/experimental/memory/session/index.js +0 -2379
  178. package/dist/experimental/memory/session/index.js.map +0 -1
  179. package/dist/experimental/memory/utils/index.d.ts +0 -96
  180. package/dist/experimental/memory/utils/index.js +0 -79
  181. package/dist/experimental/memory/utils/index.js.map +0 -1
  182. package/dist/scheduler-CR9RHGos.js +0 -857
  183. package/dist/scheduler-CR9RHGos.js.map +0 -1
  184. package/dist/src-5W6JNKVb.js.map +0 -1
  185. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  186. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -4,7 +4,7 @@ import {
4
4
  n as AgentOptions,
5
5
  r as RoutingRetryOptions,
6
6
  t as AgentGetOptions
7
- } from "./agent-routing-CnkaHb-v.js";
7
+ } from "./agent-routing-DE5zmCQ8.js";
8
8
  export {
9
9
  AgentGetOptions,
10
10
  AgentOptions,
@@ -1,30 +1,30 @@
1
1
  import {
2
- $ as AgentToolRunPart,
3
- B as AgentToolChildAdapter,
4
- G as AgentToolFailure,
5
- H as AgentToolEvent,
6
- J as AgentToolMilestone,
7
- K as AgentToolInterruptedReason,
8
- Q as AgentToolRunInspection,
9
- R as AGENT_TOOL_MILESTONE_PART,
10
- U as AgentToolEventMessage,
11
- V as AgentToolDisplayMetadata,
12
- W as AgentToolEventState,
13
- X as AgentToolProgressSnapshot,
14
- Y as AgentToolProgress,
15
- Z as AgentToolRunInfo,
16
- at as DetachedAgentToolConfig,
17
- ct as RunAgentToolResult,
18
- et as AgentToolRunState,
19
- it as ChatCapableAgentClass,
20
- nt as AgentToolStoredChunk,
21
- ot as DetachedRunAgentToolResult,
22
- q as AgentToolLifecycleResult,
23
- rt as AgentToolTerminalStatus,
24
- st as RunAgentToolOptions,
25
- tt as AgentToolRunStatus,
26
- z as AGENT_TOOL_PROGRESS_PART
27
- } from "./agent-routing-CnkaHb-v.js";
2
+ $ as ChatCapableAgentClass,
3
+ B as AgentToolFailure,
4
+ F as AgentToolChildAdapter,
5
+ G as AgentToolProgressSnapshot,
6
+ H as AgentToolLifecycleResult,
7
+ I as AgentToolDisplayMetadata,
8
+ J as AgentToolRunPart,
9
+ K as AgentToolRunInfo,
10
+ L as AgentToolEvent,
11
+ N as AGENT_TOOL_MILESTONE_PART,
12
+ P as AGENT_TOOL_PROGRESS_PART,
13
+ Q as AgentToolTerminalStatus,
14
+ R as AgentToolEventMessage,
15
+ U as AgentToolMilestone,
16
+ V as AgentToolInterruptedReason,
17
+ W as AgentToolProgress,
18
+ X as AgentToolRunStatus,
19
+ Y as AgentToolRunState,
20
+ Z as AgentToolStoredChunk,
21
+ et as DetachedAgentToolConfig,
22
+ nt as RunAgentToolOptions,
23
+ q as AgentToolRunInspection,
24
+ rt as RunAgentToolResult,
25
+ tt as DetachedRunAgentToolResult,
26
+ z as AgentToolEventState
27
+ } from "./agent-routing-DE5zmCQ8.js";
28
28
  export {
29
29
  AGENT_TOOL_MILESTONE_PART,
30
30
  AGENT_TOOL_PROGRESS_PART,
@@ -1,10 +1,10 @@
1
1
  import {
2
- $ as AgentToolRunPart,
3
- U as AgentToolEventMessage,
4
- W as AgentToolEventState,
5
- Y as AgentToolProgress,
6
- nt as AgentToolStoredChunk
7
- } from "./agent-routing-CnkaHb-v.js";
2
+ J as AgentToolRunPart,
3
+ R as AgentToolEventMessage,
4
+ W as AgentToolProgress,
5
+ Z as AgentToolStoredChunk,
6
+ z as AgentToolEventState
7
+ } from "./agent-routing-DE5zmCQ8.js";
8
8
 
9
9
  //#region src/chat/agent-tools.d.ts
10
10
  type AgentToolProgressEmitResult = "emitted" | "coalesced" | "inactive";
@@ -130,4 +130,4 @@ export {
130
130
  interceptAgentToolBroadcast as s,
131
131
  AgentToolBroadcastHooks as t
132
132
  };
133
- //# sourceMappingURL=agent-tools-C0XJqWzB.d.ts.map
133
+ //# sourceMappingURL=agent-tools-DtXMTDGM.d.ts.map
@@ -1,25 +1,25 @@
1
1
  import {
2
- $ as AgentToolRunPart,
3
- B as AgentToolChildAdapter,
4
- G as AgentToolFailure,
5
- H as AgentToolEvent,
6
- K as AgentToolInterruptedReason,
7
- Q as AgentToolRunInspection,
8
- U as AgentToolEventMessage,
9
- V as AgentToolDisplayMetadata,
10
- W as AgentToolEventState,
11
- Z as AgentToolRunInfo,
12
- at as DetachedAgentToolConfig,
13
- ct as RunAgentToolResult,
14
- et as AgentToolRunState,
15
- it as ChatCapableAgentClass,
16
- nt as AgentToolStoredChunk,
17
- ot as DetachedRunAgentToolResult,
18
- q as AgentToolLifecycleResult,
19
- rt as AgentToolTerminalStatus,
20
- st as RunAgentToolOptions,
21
- tt as AgentToolRunStatus
22
- } from "./agent-routing-CnkaHb-v.js";
2
+ $ as ChatCapableAgentClass,
3
+ B as AgentToolFailure,
4
+ F as AgentToolChildAdapter,
5
+ H as AgentToolLifecycleResult,
6
+ I as AgentToolDisplayMetadata,
7
+ J as AgentToolRunPart,
8
+ K as AgentToolRunInfo,
9
+ L as AgentToolEvent,
10
+ Q as AgentToolTerminalStatus,
11
+ R as AgentToolEventMessage,
12
+ V as AgentToolInterruptedReason,
13
+ X as AgentToolRunStatus,
14
+ Y as AgentToolRunState,
15
+ Z as AgentToolStoredChunk,
16
+ et as DetachedAgentToolConfig,
17
+ nt as RunAgentToolOptions,
18
+ q as AgentToolRunInspection,
19
+ rt as RunAgentToolResult,
20
+ tt as DetachedRunAgentToolResult,
21
+ z as AgentToolEventState
22
+ } from "./agent-routing-DE5zmCQ8.js";
23
23
  import { FlexibleSchema, InferSchema, Tool } from "ai";
24
24
 
25
25
  //#region src/agent-tools.d.ts
@@ -68,7 +68,10 @@ function browserExecuteModelOutput(output) {
68
68
  value: `Screenshot captured successfully (${screenshot.mediaType}, approximately ${approximateBytes.toLocaleString()} bytes); the image is kept for the UI and omitted here.`
69
69
  };
70
70
  }
71
- const redacted = redactBase64Payloads(output);
71
+ const redacted = redactBase64Payloads(typeof output === "object" && output !== null && !Array.isArray(output) ? (({ calls: _calls, ...rest }) => ({
72
+ ...rest,
73
+ ...Array.isArray(rest.logs) ? { logs: truncateResult(rest.logs) } : {}
74
+ }))(output) : output);
72
75
  try {
73
76
  const serialized = JSON.stringify(redacted);
74
77
  return {
@@ -1 +1 @@
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 const redacted = redactBase64Payloads(output);\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
+ {"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":";;;;;;;AA8IA,IAAI,sBAAsB;AAC1B,IAAI,0BAA0B;AAQ9B,SAAS,wBACP,OACgC;CAChC,MAAM,QACJ,OAAO,UAAU,YAAY,UAAU,OAClC,QACD;CACN,MAAM,SACJ,SAAS,OAAO,MAAM,WAAW,YAAY,MAAM,WAAW,OACzD,MAAM,SACP;CACN,IACE,QAAQ,SAAS,wBACjB,OAAO,OAAO,cAAc,YAC5B,OAAO,OAAO,SAAS,UAEvB,OAAO;CAET,OAAO;AACT;AAEA,MAAM,6BAA6B;AACnC,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAE5B,SAAS,cACP,OACA,gBAAgB,4BAKT;CACP,IAAI,MAAM,SAAS,eAAe,OAAO;CAEzC,MAAM,UACJ,6DAA6D,KAAK,KAAK;CACzE,MAAM,UAAU,UAAU,MAAM;CAChC,IAAI,QAAQ,SAAS,MAAM,KAAK,CAAC,yBAAyB,KAAK,OAAO,GACpE,OAAO;CAGT,MAAM,UAAU,QAAQ,SAAS,IAAI,IAAI,IAAI,QAAQ,SAAS,GAAG,IAAI,IAAI;CACzE,OAAO;EACL,WAAW,UAAU;EACrB,OAAO,QAAQ;EACf,OAAQ,QAAQ,SAAS,IAAK,IAAI;CACpC;AACF;AAEA,SAAS,gBACP,OACA,WACA,eACQ;CACR,MAAM,UAAU,cAAc,OAAO,aAAa;CAClD,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,OAAO,aAAa,QAAQ;CAClC,OAAO,UAAU,OAAO,IAAI,SAAS,GAAG,iBAAiB,QAAQ,MAAM,eAAe,EAAE,wBAAwB,QAAQ,MAAM,eAAe,EAAE;AACjJ;AAEA,SAAS,qBAAqB,OAAyB;CACrD,MAAM,4BAAY,IAAI,QAAgB;CACtC,IAAI,QAAQ;CAEZ,SAAS,MAAM,SAAkB,OAAwB;EACvD,IAAI,QAAQ,qBAAqB,OAAO;EACxC,IAAI,EAAE,QAAQ,qBAAqB,OAAO;EAC1C,IAAI,OAAO,YAAY,UAAU,OAAO,gBAAgB,OAAO;EAC/D,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM,OAAO;EAI5D,IACE,mBAAmB,eACnB,YAAY,OAAO,OAAO,KAC1B,mBAAmB,QACnB,mBAAmB,OACnB,mBAAmB,KAEnB,OAAO;EAET,IAAI,UAAU,IAAI,OAAO,GAAG,OAAO;EAEnC,UAAU,IAAI,OAAO;EACrB,IAAI;GACF,IAAI,MAAM,QAAQ,OAAO,GACvB,OAAO,QAAQ,KAAK,UAAU,MAAM,OAAO,QAAQ,CAAC,CAAC;GAGvD,MAAM,SAAS;GACf,MAAM,aACJ,OAAO,SAAS,wBAChB,OAAO,OAAO,cAAc;GAC9B,OAAO,OAAO,YACZ,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,CAC3C,KACA,cAAc,QAAQ,UAAU,OAAO,UAAU,WAC7C,gBAAgB,OAAO,OAAO,WAAqB,CAAC,IACpD,MAAM,OAAO,QAAQ,CAAC,CAC5B,CAAC,CACH;EACF,UAAU;GACR,UAAU,OAAO,OAAO;EAC1B;CACF;CAEA,OAAO,MAAM,OAAO,CAAC;AACvB;AAEA,SAAS,uBAAuB,OAAyB;CAIvD,OAAO,wBAAwB,KAAK,IAChC,QACA,eAAe,qBAAqB,KAAK,CAAC;AAChD;AAEA,SAAS,0BACP,QACsE;CACtE,MAAM,aAAa,wBAAwB,MAAM;CACjD,IAAI,YAAY;EACd,MAAM,mBAAmB,KAAK,MAAO,WAAW,KAAK,SAAS,IAAK,CAAC;EACpE,OAAO;GACL,MAAM;GACN,OAAO,qCAAqC,WAAW,UAAU,kBAAkB,iBAAiB,eAAe,EAAE;EACvH;CACF;CAcA,MAAM,WAAW,qBARf,OAAO,WAAW,YAAY,WAAW,QAAQ,CAAC,MAAM,QAAQ,MAAM,MAChE,EAAE,OAAO,QAAQ,GAAG,YAAiD;EACrE,GAAG;EACH,GAAI,MAAM,QAAQ,KAAK,IAAI,IACvB,EAAE,MAAM,eAAe,KAAK,IAAI,EAAE,IAClC,CAAC;CACP,GAAA,CAAI,MAAM,IACV,MAC2C;CACjD,IAAI;EACF,MAAM,aAAa,KAAK,UAAU,QAAQ;EAC1C,OAAO;GACL,MAAM;GACN,OACE,eAAe,KAAA,IAAY,OAAQ,KAAK,MAAM,UAAU;EAC5D;CACF,QAAQ;EACN,OAAO;GACL,MAAM;GACN,OACE;EACJ;CACF;AACF;;;;;;;AAQA,SAAS,WACP,SACgC;CAChC,IAAI,QAAQ,KAAK,OAAO,QAAQ;CAIhC,QAHcA,sCAAa,SAAS,CAAC,EAAE,MAAA,EAGzB;AAChB;AAEA,SAAS,iBACP,SACA,KACyB;CACzB,IAAI,QAAQ,QACV,OAAO;EACL,QAAQ,QAAQ;EAChB,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB;CAEF,IAAI,CAAC,QAAQ,SACX,MAAM,IAAI,MACR,iEACF;CAEF,OAAO;EACL,SAAS,QAAQ;EACjB,OAAO,QAAQ,SAAS,IAAI,2BAA2B,IAAI,OAAO;EAClE,SAAS,QAAQ;EACjB,SAAS,QAAQ;CACnB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,qBACd,SACgB;CAChB,IAAI,CAAC,qBAAqB;EACxB,sBAAsB;EACtB,QAAQ,KACN,qFACF;CACF;CAEA,MAAM,MAAM,WAAW,OAAO;CAC9B,IAAI,CAAC,KACH,MAAM,IAAI,MACR,qJACF;CAGF,MAAM,YAAY,IAAI,iBAAiB,KAAK,iBAAiB,SAAS,GAAG,CAAC;CAC1E,MAAM,UAAU,sBAAsB;EACpC;EACA,UAAU,IAAI,sBAAsB;GAClC,QAAQ,QAAQ;GAChB,SAAS,QAAQ;EACnB,CAAC;EACD,YAAY,CAAC,SAAS;EACtB,MAAM,QAAQ,QAAQ;EACtB,iBAAiB;CACnB,CAAC;CAID,MAAM,aAAa,CAAC,QAAQ,UAAU,QAAQ,SAAS,YAAY;CAQnE,MAAM,QAAiB,EACrB,iBAAiB;EACf,GATmB,QAAQ,KAAK,EAClC,gBAAgB,EACd,KAAK,aACD,wWACA,uLACN,EACF,CAGoB;EAChB,gBAAgB,EAAE,aAChB,0BAA0B,MAAM;CACpC,EACF;CAYA,IALE,QAAQ,iBAAiB,UACxB,CAAC,cAAc,QAAQ,iBAAiB,KAAA,IAInB;EACtB,MAAM,KACJ,OAAO,QAAQ,iBAAiB,WAAW,QAAQ,eAAe,CAAC;EACrE,MAAM,qBACJ,GAAG,WACF,QAAQ;EACX,IAAI,oBACF,OAAO,OACL,OACA,uBAAuB;GACrB,SAAS;GACT,SAAS,GAAG;GACZ,UAAU,GAAG;GACb,SAAS,GAAG;EACd,CAAC,CACH;OACK,IAAI,QAAQ,cAEjB,MAAM,IAAI,MACR,qGACF;OACK,IAAI,CAAC,yBAAyB;GAInC,0BAA0B;GAC1B,QAAQ,MACN,uJACF;EACF;CACF;CAEA,OAAO;EAAE;EAAS;EAAW;CAAM;AACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,mBACd,SACS;CACT,OAAO,qBAAqB,OAAO,CAAC,CAAC;AACvC;AA6CA,MAAM,6BAAoD;CACxD;CACA;CACA;CACA;AACF;AAEA,MAAM,iCAAiC;AAEvC,MAAM,kBAAkB,EACrB,OAAO;CACN,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,yBAAyB;CACnE,MAAM,EACH,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,6CAA6C;AAC3D,CAAC,CAAC,CACD,QAAQ,UAAU,QAAQ,MAAM,GAAG,KAAK,QAAQ,MAAM,IAAI,GAAG,EAC5D,SAAS,iCACX,CAAC;AAEH,SAAS,OACP,OACA,SACiB;CACjB,MAAM,OAAO,MAAM,MAAM,EAAE,KAAK,MAAM,IAAI,IAAI,EAAE,MAAM,MAAM,KAAe;CAC3E,OAAO;EAAE,GAAG;EAAS,GAAG;CAAK;AAC/B;AAEA,SAAS,SAAS,MAAc,UAA0B;CACxD,IAAI,YAAY,KAAK,KAAK,UAAU,UAAU,OAAO;CACrD,OAAO,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE,iBAAiB,KAAK,SAAS,SAAS;AAC5E;;;;;;;;;;;AAYA,SAAS,YAAY,OAAgB,UAA2B;CAC9D,IAAI,YAAY,GAAG,OAAO;CAC1B,IAAI,OAAO,UAAU,UAAU,OAAO,SAAS,OAAO,QAAQ;CAC9D,IAAI;CACJ,IAAI;EACF,OAAO,KAAK,UAAU,KAAK;CAC7B,QAAQ;EACN,OAAO;CACT;CACA,IAAI,KAAK,UAAU,UAAU,OAAO;CACpC,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,MAAM,UAAU,WAAW,OAAO,QAAQ;EAI1C,IAAI,QAAQ,SAAS,GAAG,OAAO;CACjC;CACA,OAAO;EACL,WAAW;EACX,MAAM,wBAAwB,KAAK,OAAO;EAC1C,SAAS,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE;CACtC;AACF;;;;;;AAOA,SAAS,WAAW,OAAkB,UAA6B;CACjE,MAAM,MAAiB,CAAC;CACxB,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,UAAU,IAAI,CAAC,CAAC,SAAS;EAC/C,IAAI,OAAO,WAAW,UAAU;EAChC,IAAI,KAAK,IAAI;EACb,QAAQ;CACV;CACA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,uBACd,SACS;CACT,MAAM,EAAE,YAAY;CACpB,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,UAAU,IAAI,IAAI,QAAQ,WAAW,0BAA0B;CACrE,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,QAAiB,CAAC;CAExB,IAAI,QAAQ,IAAI,UAAU,GACxB,MAAM,mBAAmB,KAAK;EAC5B,aACE;EACF,aAAa;EACb,SAAS,OAAO,UACd,YACE,MAAM,gBAAgB,SAAS,OAAO,OAAO,cAAc,CAAC,GAC5D,QACF;CACJ,CAAC;CAGH,IAAI,QAAQ,IAAI,SAAS,GACvB,MAAM,kBAAkB,KAAK;EAC3B,aACE;EACF,aAAa,EACV,OAAO;GACN,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,yBAAyB;GACnE,MAAM,EACH,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,6CAA6C;GACzD,QAAQ,EACL,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,sCAAsC;GAClD,QAAQ,EACL,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,GAAG,EAC/B,OAAO,+BACT,CAAC,CAAC,CACD,SAAS,CAAC,CACV,SAAS,oDAAoD;EAClE,CAAC,CAAC,CACD,QAAQ,UAAU,QAAQ,MAAM,GAAG,KAAK,QAAQ,MAAM,IAAI,GAAG,EAC5D,SAAS,iCACX,CAAC,CAAC,CACD,QAAQ,UAAU,QAAQ,MAAM,MAAM,KAAK,QAAQ,MAAM,MAAM,GAAG,EACjE,SAAS,sCACX,CAAC;EACH,SAAS,OAAO,UACd,YACE,MAAM,eAAe,SAAS;GAC5B,GAAG,OAAO,OAAO,cAAc;GAC/B,QAAQ,MAAM;GACd,iBAAiB,MAAM,SACnB;IAAE,MAAM;IAAe,aAAa,MAAM;GAAO,IACjD,KAAA;EACN,CAAC,GACD,QACF;CACJ,CAAC;CAGH,IAAI,QAAQ,IAAI,OAAO,GACrB,MAAM,gBAAgB,KAAK;EACzB,aACE;EACF,aAAa;EACb,SAAS,OAAO,UACd,YACE,MAAM,aAAa,SAAS,OAAO,OAAO,cAAc,CAAC,GACzD,QACF;CACJ,CAAC;CAGH,IAAI,QAAQ,IAAI,QAAQ,GACtB,MAAM,iBAAiB,KAAK;EAC1B,aACE;EACF,aAAa,EACV,OAAO;GACN,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,yBAAyB;GACnE,MAAM,EACH,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,6CAA6C;GACzD,WAAW,EACR,MAAM,EAAE,OAAO,CAAC,CAAC,CACjB,IAAI,CAAC,CAAC,CACN,SAAS,0BAA0B;EACxC,CAAC,CAAC,CACD,QAAQ,UAAU,QAAQ,MAAM,GAAG,KAAK,QAAQ,MAAM,IAAI,GAAG,EAC5D,SAAS,iCACX,CAAC;EACH,SAAS,OAAO,UACd,YACE,MAAM,cAAc,SAAS;GAC3B,GAAG,OAAO,OAAO,cAAc;GAC/B,UAAU,MAAM,UAAU,KAAK,cAAc,EAAE,SAAS,EAAE;EAC5D,CAAC,GACD,QACF;CACJ,CAAC;CAGH,IAAI,QAAQ,IAAI,SAAS,GACvB,MAAM,kBAAkB,KAAK;EAC3B,aACE;EACF,aAAa;EACb,SAAS,OAAO,UACd,YACE,MAAM,eAAe,SAAS,OAAO,OAAO,cAAc,CAAC,GAC3D,QACF;CACJ,CAAC;CAGH,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack-ai.js","names":[],"sources":["../../src/browser/tanstack-ai.ts"],"sourcesContent":["import { toolDefinition } from \"@tanstack/ai\";\nimport type { ServerTool } from \"@tanstack/ai\";\nimport type { ProxyToolOutput } from \"@cloudflare/codemode\";\nimport { z } from \"zod\";\nimport { createBrowserRuntime, type CreateBrowserToolsOptions } from \"./ai\";\n\nexport type { CreateBrowserToolsOptions } from \"./ai\";\n\n/**\n * Create TanStack AI tools for browser automation via CDP code mode.\n *\n * Returns an array with a single durable `browser_execute` `ServerTool`\n * backed by the same codemode runtime as `agents/browser/ai` — the model\n * writes TypeScript against the `cdp` connector and browser sessions\n * survive pauses.\n *\n * The stateless Quick Action tools are not surfaced through this TanStack\n * wrapper (it exposes only `browser_execute`); use `createQuickActionTools`\n * from `agents/browser/ai` if you want them.\n *\n * @example\n * ```ts\n * import { createBrowserTools } from \"agents/browser/tanstack-ai\";\n * import { chat } from \"@tanstack/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 stream = chat({\n * adapter: openaiText(\"gpt-4o\"),\n * tools: [...browserTools, ...otherTools],\n * messages,\n * });\n * ```\n */\nexport function createBrowserTools(\n options: CreateBrowserToolsOptions\n): ServerTool[] {\n // This wrapper only surfaces `browser_execute`, so don't build the default-on\n // Quick Action tools just to discard them.\n const { tools } = createBrowserRuntime({ ...options, quickActions: false });\n const executeTool = tools.browser_execute;\n\n const execute = toolDefinition({\n name: \"browser_execute\" as const,\n description:\n typeof executeTool.description === \"function\"\n ? \"\"\n : (executeTool.description ?? \"\"),\n inputSchema: z.object({\n code: z.string().meta({\n description:\n \"TypeScript async arrow function that uses the cdp connector\"\n })\n })\n }).server(async ({ code }) => {\n if (!executeTool.execute) {\n throw new Error(\"browser_execute tool is not executable\");\n }\n const result = (await executeTool.execute({ code }, {\n toolCallId: crypto.randomUUID(),\n messages: [],\n context: {}\n } as never)) as ProxyToolOutput;\n // TanStack has a single return channel, so what the host sees is what the\n // model sees: apply the AI SDK path's `toModelOutput` projection so a\n // screenshot's base64 cannot reach the model. The execution envelope\n // (status, executionId, calls) is preserved either way.\n const modelOutput = await executeTool.toModelOutput?.({\n toolCallId: crypto.randomUUID(),\n input: { code },\n output: result\n });\n if (modelOutput?.type === \"error-text\") {\n throw new Error(modelOutput.value);\n }\n if (modelOutput?.type === \"text\") {\n return { ...result, result: modelOutput.value };\n }\n if (modelOutput?.type === \"json\") {\n return modelOutput.value;\n }\n return result;\n });\n\n return [execute];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,mBACd,SACc;CAGd,MAAM,EAAE,UAAU,qBAAqB;EAAE,GAAG;EAAS,cAAc;CAAM,CAAC;CAC1E,MAAM,cAAc,MAAM;CA4C1B,OAAO,CA1CS,eAAe;EAC7B,MAAM;EACN,aACE,OAAO,YAAY,gBAAgB,aAC/B,KACC,YAAY,eAAe;EAClC,aAAa,EAAE,OAAO,EACpB,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,EACpB,aACE,8DACJ,CAAC,EACH,CAAC;CACH,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,WAAW;EAC5B,IAAI,CAAC,YAAY,SACf,MAAM,IAAI,MAAM,wCAAwC;EAE1D,MAAM,SAAU,MAAM,YAAY,QAAQ,EAAE,KAAK,GAAG;GAClD,YAAY,OAAO,WAAW;GAC9B,UAAU,CAAC;GACX,SAAS,CAAC;EACZ,CAAU;EAKV,MAAM,cAAc,MAAM,YAAY,gBAAgB;GACpD,YAAY,OAAO,WAAW;GAC9B,OAAO,EAAE,KAAK;GACd,QAAQ;EACV,CAAC;EACD,IAAI,aAAa,SAAS,cACxB,MAAM,IAAI,MAAM,YAAY,KAAK;EAEnC,IAAI,aAAa,SAAS,QACxB,OAAO;GAAE,GAAG;GAAQ,QAAQ,YAAY;EAAM;EAEhD,IAAI,aAAa,SAAS,QACxB,OAAO,YAAY;EAErB,OAAO;CACT,CAEc,CAAC;AACjB"}
1
+ {"version":3,"file":"tanstack-ai.js","names":[],"sources":["../../src/browser/tanstack-ai.ts"],"sourcesContent":["import { toolDefinition } from \"@tanstack/ai\";\nimport type { ServerTool } from \"@tanstack/ai\";\nimport type { ProxyToolOutput } from \"@cloudflare/codemode\";\nimport { z } from \"zod\";\nimport { createBrowserRuntime, type CreateBrowserToolsOptions } from \"./ai\";\n\nexport type { CreateBrowserToolsOptions } from \"./ai\";\n\n/**\n * Create TanStack AI tools for browser automation via CDP code mode.\n *\n * Returns an array with a single durable `browser_execute` `ServerTool`\n * backed by the same codemode runtime as `agents/browser/ai` — the model\n * writes TypeScript against the `cdp` connector and browser sessions\n * survive pauses.\n *\n * The stateless Quick Action tools are not surfaced through this TanStack\n * wrapper (it exposes only `browser_execute`); use `createQuickActionTools`\n * from `agents/browser/ai` if you want them.\n *\n * @example\n * ```ts\n * import { createBrowserTools } from \"agents/browser/tanstack-ai\";\n * import { chat } from \"@tanstack/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 stream = chat({\n * adapter: openaiText(\"gpt-4o\"),\n * tools: [...browserTools, ...otherTools],\n * messages,\n * });\n * ```\n */\nexport function createBrowserTools(\n options: CreateBrowserToolsOptions\n): ServerTool[] {\n // This wrapper only surfaces `browser_execute`, so don't build the default-on\n // Quick Action tools just to discard them.\n const { tools } = createBrowserRuntime({ ...options, quickActions: false });\n const executeTool = tools.browser_execute;\n\n const execute = toolDefinition({\n name: \"browser_execute\" as const,\n description:\n typeof executeTool.description === \"function\"\n ? \"\"\n : (executeTool.description ?? \"\"),\n inputSchema: z.object({\n code: z.string().meta({\n description:\n \"TypeScript async arrow function that uses the cdp connector\"\n })\n })\n }).server(async ({ code }) => {\n if (!executeTool.execute) {\n throw new Error(\"browser_execute tool is not executable\");\n }\n const result = (await executeTool.execute({ code }, {\n toolCallId: crypto.randomUUID(),\n messages: [],\n context: {}\n } as never)) as ProxyToolOutput;\n // TanStack has a single return channel, so what the host sees is what the\n // model sees: apply the AI SDK path's `toModelOutput` projection so a\n // screenshot's base64 cannot reach the model and the durable `calls` log\n // stays out of its context. The execution envelope (status, executionId)\n // is preserved either way.\n const modelOutput = await executeTool.toModelOutput?.({\n toolCallId: crypto.randomUUID(),\n input: { code },\n output: result\n });\n if (modelOutput?.type === \"error-text\") {\n throw new Error(modelOutput.value);\n }\n if (modelOutput?.type === \"text\") {\n return { ...result, result: modelOutput.value };\n }\n if (modelOutput?.type === \"json\") {\n return modelOutput.value;\n }\n return result;\n });\n\n return [execute];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,mBACd,SACc;CAGd,MAAM,EAAE,UAAU,qBAAqB;EAAE,GAAG;EAAS,cAAc;CAAM,CAAC;CAC1E,MAAM,cAAc,MAAM;CA6C1B,OAAO,CA3CS,eAAe;EAC7B,MAAM;EACN,aACE,OAAO,YAAY,gBAAgB,aAC/B,KACC,YAAY,eAAe;EAClC,aAAa,EAAE,OAAO,EACpB,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,EACpB,aACE,8DACJ,CAAC,EACH,CAAC;CACH,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,WAAW;EAC5B,IAAI,CAAC,YAAY,SACf,MAAM,IAAI,MAAM,wCAAwC;EAE1D,MAAM,SAAU,MAAM,YAAY,QAAQ,EAAE,KAAK,GAAG;GAClD,YAAY,OAAO,WAAW;GAC9B,UAAU,CAAC;GACX,SAAS,CAAC;EACZ,CAAU;EAMV,MAAM,cAAc,MAAM,YAAY,gBAAgB;GACpD,YAAY,OAAO,WAAW;GAC9B,OAAO,EAAE,KAAK;GACd,QAAQ;EACV,CAAC;EACD,IAAI,aAAa,SAAS,cACxB,MAAM,IAAI,MAAM,YAAY,KAAK;EAEnC,IAAI,aAAa,SAAS,QACxB,OAAO;GAAE,GAAG;GAAQ,QAAQ,YAAY;EAAM;EAEhD,IAAI,aAAa,SAAS,QACxB,OAAO,YAAY;EAErB,OAAO;CACT,CAEc,CAAC;AACjB"}
@@ -0,0 +1,72 @@
1
+ //#region src/callable-decorator.d.ts
2
+ /**
3
+ * The `@callable()` method decorator and its metadata registry.
4
+ *
5
+ * Consumed by Agent's legacy JSON RPC protocol and, as a fallback
6
+ * interface source, by the WebSockets capability's Cap'n Web callables
7
+ * endpoint. Kept dependency-free so both can import it without cycles.
8
+ */
9
+ /**
10
+ * Metadata for a callable method
11
+ */
12
+ type CallableMetadata = {
13
+ /** Optional description of what the method does */ description?: string /** Whether the method supports streaming responses */;
14
+ streaming?: boolean;
15
+ };
16
+ /**
17
+ * Decorator that marks a method as callable by clients
18
+ * @param metadata Optional metadata about the callable method
19
+ */
20
+ declare function callable(
21
+ metadata?: CallableMetadata
22
+ ): <This, Args extends unknown[], Return>(
23
+ target: (this: This, ...args: Args) => Return,
24
+ _context: ClassMethodDecoratorContext
25
+ ) => (this: This, ...args: Args) => Return;
26
+ /**
27
+ * Decorator that marks a method as callable by clients
28
+ * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version
29
+ * @param metadata Optional metadata about the callable method
30
+ */
31
+ declare const unstable_callable: (
32
+ metadata?: CallableMetadata
33
+ ) => <This, Args extends unknown[], Return>(
34
+ target: (this: This, ...args: Args) => Return,
35
+ _context: ClassMethodDecoratorContext
36
+ ) => (this: This, ...args: Args) => Return;
37
+ /** @internal Read the metadata registered for a decorated method. */
38
+ declare function getCallableMetadata(
39
+ method: Function
40
+ ): CallableMetadata | undefined;
41
+ /** @internal Whether a method was registered with `@callable()`. */
42
+ declare function isCallableMethod(method: Function): boolean;
43
+ /**
44
+ * @internal Preserve registration when a framework wraps a decorated
45
+ * method (e.g. Agent's context auto-wrapping).
46
+ */
47
+ declare function copyCallableMetadata(source: Function, target: Function): void;
48
+ /**
49
+ * Every `@callable()`-registered method reachable on a host's prototype
50
+ * chain, with its metadata. The nearest declaration wins when a
51
+ * subclass overrides a decorated parent method.
52
+ *
53
+ * The canonical decorator scan — Agent introspection and the WebSockets
54
+ * capability's decorator-fallback target both consume it.
55
+ *
56
+ * @param host - The object whose prototype chain is scanned.
57
+ * @returns Method names mapped to their registered metadata.
58
+ */
59
+ declare function decoratedMethods(
60
+ host: object
61
+ ): ReadonlyMap<string, CallableMetadata>;
62
+ //#endregion
63
+ export {
64
+ getCallableMetadata as a,
65
+ decoratedMethods as i,
66
+ callable as n,
67
+ isCallableMethod as o,
68
+ copyCallableMetadata as r,
69
+ unstable_callable as s,
70
+ CallableMetadata as t
71
+ };
72
+ //# sourceMappingURL=callable-decorator-DP__HhBA.d.ts.map
@@ -0,0 +1,18 @@
1
+ import {
2
+ a as getCallableMetadata,
3
+ i as decoratedMethods,
4
+ n as callable,
5
+ o as isCallableMethod,
6
+ r as copyCallableMetadata,
7
+ s as unstable_callable,
8
+ t as CallableMetadata
9
+ } from "./callable-decorator-DP__HhBA.js";
10
+ export {
11
+ CallableMetadata,
12
+ callable,
13
+ copyCallableMetadata,
14
+ decoratedMethods,
15
+ getCallableMetadata,
16
+ isCallableMethod,
17
+ unstable_callable
18
+ };
@@ -0,0 +1,71 @@
1
+ //#region src/callable-decorator.ts
2
+ const callableMetadata = /* @__PURE__ */ new WeakMap();
3
+ /**
4
+ * Decorator that marks a method as callable by clients
5
+ * @param metadata Optional metadata about the callable method
6
+ */
7
+ function callable(metadata = {}) {
8
+ return function callableDecorator(target, _context) {
9
+ if (!callableMetadata.has(target)) callableMetadata.set(target, metadata);
10
+ return target;
11
+ };
12
+ }
13
+ let didWarnAboutUnstableCallable = false;
14
+ /**
15
+ * Decorator that marks a method as callable by clients
16
+ * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version
17
+ * @param metadata Optional metadata about the callable method
18
+ */
19
+ const unstable_callable = (metadata = {}) => {
20
+ if (!didWarnAboutUnstableCallable) {
21
+ didWarnAboutUnstableCallable = true;
22
+ console.warn("unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version.");
23
+ }
24
+ return callable(metadata);
25
+ };
26
+ /** @internal Read the metadata registered for a decorated method. */
27
+ function getCallableMetadata(method) {
28
+ return callableMetadata.get(method);
29
+ }
30
+ /** @internal Whether a method was registered with `@callable()`. */
31
+ function isCallableMethod(method) {
32
+ return callableMetadata.has(method);
33
+ }
34
+ /**
35
+ * @internal Preserve registration when a framework wraps a decorated
36
+ * method (e.g. Agent's context auto-wrapping).
37
+ */
38
+ function copyCallableMetadata(source, target) {
39
+ const metadata = callableMetadata.get(source);
40
+ if (metadata) callableMetadata.set(target, metadata);
41
+ }
42
+ /**
43
+ * Every `@callable()`-registered method reachable on a host's prototype
44
+ * chain, with its metadata. The nearest declaration wins when a
45
+ * subclass overrides a decorated parent method.
46
+ *
47
+ * The canonical decorator scan — Agent introspection and the WebSockets
48
+ * capability's decorator-fallback target both consume it.
49
+ *
50
+ * @param host - The object whose prototype chain is scanned.
51
+ * @returns Method names mapped to their registered metadata.
52
+ */
53
+ function decoratedMethods(host) {
54
+ const result = /* @__PURE__ */ new Map();
55
+ let prototype = Object.getPrototypeOf(host);
56
+ while (prototype && prototype !== Object.prototype) {
57
+ for (const name of Object.getOwnPropertyNames(prototype)) {
58
+ if (name === "constructor" || result.has(name)) continue;
59
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, name);
60
+ if (!descriptor || typeof descriptor.value !== "function") continue;
61
+ const metadata = getCallableMetadata(descriptor.value);
62
+ if (metadata) result.set(name, metadata);
63
+ }
64
+ prototype = Object.getPrototypeOf(prototype);
65
+ }
66
+ return result;
67
+ }
68
+ //#endregion
69
+ export { callable, copyCallableMetadata, decoratedMethods, getCallableMetadata, isCallableMethod, unstable_callable };
70
+
71
+ //# sourceMappingURL=callable-decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callable-decorator.js","names":[],"sources":["../src/callable-decorator.ts"],"sourcesContent":["/**\n * The `@callable()` method decorator and its metadata registry.\n *\n * Consumed by Agent's legacy JSON RPC protocol and, as a fallback\n * interface source, by the WebSockets capability's Cap'n Web callables\n * endpoint. Kept dependency-free so both can import it without cycles.\n */\n\n/**\n * Metadata for a callable method\n */\nexport type CallableMetadata = {\n /** Optional description of what the method does */\n description?: string;\n /** Whether the method supports streaming responses */\n streaming?: boolean;\n};\n\nconst callableMetadata = new WeakMap<Function, CallableMetadata>();\n\n/**\n * Decorator that marks a method as callable by clients\n * @param metadata Optional metadata about the callable method\n */\nexport function callable(metadata: CallableMetadata = {}) {\n return function callableDecorator<This, Args extends unknown[], Return>(\n target: (this: This, ...args: Args) => Return,\n _context: ClassMethodDecoratorContext\n ) {\n if (!callableMetadata.has(target)) {\n callableMetadata.set(target, metadata);\n }\n\n return target;\n };\n}\n\nlet didWarnAboutUnstableCallable = false;\n\n/**\n * Decorator that marks a method as callable by clients\n * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version\n * @param metadata Optional metadata about the callable method\n */\nexport const unstable_callable = (metadata: CallableMetadata = {}) => {\n if (!didWarnAboutUnstableCallable) {\n didWarnAboutUnstableCallable = true;\n console.warn(\n \"unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version.\"\n );\n }\n return callable(metadata);\n};\n\n/** @internal Read the metadata registered for a decorated method. */\nexport function getCallableMetadata(\n method: Function\n): CallableMetadata | undefined {\n return callableMetadata.get(method);\n}\n\n/** @internal Whether a method was registered with `@callable()`. */\nexport function isCallableMethod(method: Function): boolean {\n return callableMetadata.has(method);\n}\n\n/**\n * @internal Preserve registration when a framework wraps a decorated\n * method (e.g. Agent's context auto-wrapping).\n */\nexport function copyCallableMetadata(source: Function, target: Function): void {\n const metadata = callableMetadata.get(source);\n if (metadata) callableMetadata.set(target, metadata);\n}\n\n/**\n * Every `@callable()`-registered method reachable on a host's prototype\n * chain, with its metadata. The nearest declaration wins when a\n * subclass overrides a decorated parent method.\n *\n * The canonical decorator scan — Agent introspection and the WebSockets\n * capability's decorator-fallback target both consume it.\n *\n * @param host - The object whose prototype chain is scanned.\n * @returns Method names mapped to their registered metadata.\n */\nexport function decoratedMethods(\n host: object\n): ReadonlyMap<string, CallableMetadata> {\n const result = new Map<string, CallableMetadata>();\n let prototype: object | null = Object.getPrototypeOf(host);\n while (prototype && prototype !== Object.prototype) {\n for (const name of Object.getOwnPropertyNames(prototype)) {\n if (name === \"constructor\" || result.has(name)) continue;\n const descriptor = Object.getOwnPropertyDescriptor(prototype, name);\n if (!descriptor || typeof descriptor.value !== \"function\") continue;\n const metadata = getCallableMetadata(descriptor.value);\n if (metadata) result.set(name, metadata);\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n return result;\n}\n"],"mappings":";AAkBA,MAAM,mCAAmB,IAAI,QAAoC;;;;;AAMjE,SAAgB,SAAS,WAA6B,CAAC,GAAG;CACxD,OAAO,SAAS,kBACd,QACA,UACA;EACA,IAAI,CAAC,iBAAiB,IAAI,MAAM,GAC9B,iBAAiB,IAAI,QAAQ,QAAQ;EAGvC,OAAO;CACT;AACF;AAEA,IAAI,+BAA+B;;;;;;AAOnC,MAAa,qBAAqB,WAA6B,CAAC,MAAM;CACpE,IAAI,CAAC,8BAA8B;EACjC,+BAA+B;EAC/B,QAAQ,KACN,qHACF;CACF;CACA,OAAO,SAAS,QAAQ;AAC1B;;AAGA,SAAgB,oBACd,QAC8B;CAC9B,OAAO,iBAAiB,IAAI,MAAM;AACpC;;AAGA,SAAgB,iBAAiB,QAA2B;CAC1D,OAAO,iBAAiB,IAAI,MAAM;AACpC;;;;;AAMA,SAAgB,qBAAqB,QAAkB,QAAwB;CAC7E,MAAM,WAAW,iBAAiB,IAAI,MAAM;CAC5C,IAAI,UAAU,iBAAiB,IAAI,QAAQ,QAAQ;AACrD;;;;;;;;;;;;AAaA,SAAgB,iBACd,MACuC;CACvC,MAAM,yBAAS,IAAI,IAA8B;CACjD,IAAI,YAA2B,OAAO,eAAe,IAAI;CACzD,OAAO,aAAa,cAAc,OAAO,WAAW;EAClD,KAAK,MAAM,QAAQ,OAAO,oBAAoB,SAAS,GAAG;GACxD,IAAI,SAAS,iBAAiB,OAAO,IAAI,IAAI,GAAG;GAChD,MAAM,aAAa,OAAO,yBAAyB,WAAW,IAAI;GAClE,IAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;GAC3D,MAAM,WAAW,oBAAoB,WAAW,KAAK;GACrD,IAAI,UAAU,OAAO,IAAI,MAAM,QAAQ;EACzC;EACA,YAAY,OAAO,eAAe,SAAS;CAC7C;CACA,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"capability-BjSKYpzg.js","names":[],"sources":["../src/lifecycle/capability.ts"],"sourcesContent":["import type {\n CapabilityStartContext,\n DurableObjectCapability\n} from \"./capability-runner\";\n\n/** Opaque address understood by a Lifecycle routing transport. */\nexport type LifecycleRouteAddress = {\n /** Stable equality and storage key. */\n readonly key: string;\n /** Transport-owned serialized address. */\n readonly data: string;\n};\n\n/** Context supplied with a routed capability message. */\nexport type LifecycleRouteContext = {\n /** Address of the sending Lifecycle, or undefined for an unrouted root. */\n readonly source: LifecycleRouteAddress | undefined;\n /** Capability-owned message payload. */\n readonly payload: unknown;\n};\n\n/** Alarm coordination available to every Lifecycle capability. */\nexport type LifecycleAlarms = {\n /** Recompute the physical alarm from installed capability state. */\n readonly rearm: () => Promise<void>;\n /**\n * True once explicit host teardown permanently disabled alarm arming.\n * Capabilities stop dispatching durable work when this reports true.\n */\n readonly disabled: () => boolean;\n};\n\n/** Best-effort telemetry available to every Lifecycle capability. */\nexport type LifecycleEvents = {\n /** Publish an event under this capability's stable identity. */\n readonly emit: (type: string, payload: unknown) => void;\n};\n\n/** Routing available to every Lifecycle capability. */\nexport type LifecycleRoutes = {\n /** This Lifecycle's transport address, or undefined at the route root. */\n readonly source: LifecycleRouteAddress | undefined;\n /** Route a capability-owned message to the root Lifecycle. */\n readonly toRoot: (payload: unknown) => Promise<unknown>;\n /** Route a capability-owned message to another Lifecycle. */\n readonly to: (\n target: LifecycleRouteAddress,\n payload: unknown\n ) => Promise<unknown>;\n};\n\n/**\n * Standard services granted to every installed Lifecycle capability.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport type LifecycleServices = {\n readonly storage: DurableObjectStorage;\n readonly ready: () => Promise<void>;\n /** True while capability and host startup hooks are still running. */\n readonly starting: () => boolean;\n readonly alarms: LifecycleAlarms;\n /**\n * Run a capability-held user callback inside the host invocation context.\n * Capability hooks run outside host context; this is the one boundary for\n * entering it, and a host composition root may substitute its own wrapper\n * (Agent adds tracing span scope).\n */\n readonly runInHostContext: (fn: () => unknown) => Promise<unknown>;\n readonly events: LifecycleEvents;\n readonly routes: LifecycleRoutes;\n};\n\nconst installedServices = new WeakMap<object, LifecycleServices>();\n\n/**\n * Base class for capabilities that consume standard Lifecycle services.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport abstract class LifecycleCapability<Props extends object = object> {\n readonly capabilityId: string;\n\n protected constructor(capabilityId: string) {\n if (capabilityId.trim() === \"\") {\n throw new Error(\"Lifecycle capability IDs must be non-empty\");\n }\n this.capabilityId = capabilityId;\n }\n\n /** Default startup hook; capabilities override when they own startup work. */\n onStart(_context: CapabilityStartContext<Props>): void {}\n\n /** Standard services when installed, or undefined in isolated unit tests. */\n protected get lifecycleServices(): LifecycleServices | undefined {\n return installedServices.get(this);\n }\n\n /** Standard services supplied when Lifecycle installs this capability. */\n protected get lifecycle(): LifecycleServices {\n const services = this.lifecycleServices;\n if (!services) {\n throw new Error(\n `${this.constructor.name} must be installed with Lifecycle.use() before use`\n );\n }\n return services;\n }\n}\n\n/**\n * @internal Bind the standard service surface to one capability instance.\n * `Lifecycle.use()` calls this during installation. Test a capability by\n * installing it on a minimal Durable Object with a real Lifecycle rather\n * than binding fake services.\n */\nexport function bindLifecycleCapability(\n capability: LifecycleCapability,\n services: LifecycleServices\n): void {\n installedServices.set(capability, services);\n}\n\n/** @internal Read a capability ID without exposing installation internals. */\nexport function lifecycleCapabilityId(\n capability: DurableObjectCapability\n): string | undefined {\n return capability instanceof LifecycleCapability\n ? capability.capabilityId\n : undefined;\n}\n"],"mappings":";AAyEA,MAAM,oCAAoB,IAAI,QAAmC;;;;;;AAOjE,IAAsB,sBAAtB,MAAyE;CAGvE,YAAsB,cAAsB;EAC1C,IAAI,aAAa,KAAK,MAAM,IAC1B,MAAM,IAAI,MAAM,4CAA4C;EAE9D,KAAK,eAAe;CACtB;;CAGA,QAAQ,UAA+C,CAAC;;CAGxD,IAAc,oBAAmD;EAC/D,OAAO,kBAAkB,IAAI,IAAI;CACnC;;CAGA,IAAc,YAA+B;EAC3C,MAAM,WAAW,KAAK;EACtB,IAAI,CAAC,UACH,MAAM,IAAI,MACR,GAAG,KAAK,YAAY,KAAK,mDAC3B;EAEF,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,wBACd,YACA,UACM;CACN,kBAAkB,IAAI,YAAY,QAAQ;AAC5C;;AAGA,SAAgB,sBACd,YACoB;CACpB,OAAO,sBAAsB,sBACzB,WAAW,eACX,KAAA;AACN"}
1
+ {"version":3,"file":"capability-BjSKYpzg.js","names":[],"sources":["../src/lifecycle/capability.ts"],"sourcesContent":["import type {\n CapabilityStartContext,\n DurableObjectCapability\n} from \"./capability-runner\";\nimport type { Connection } from \"./types\";\nimport type { LifecycleJobs } from \"./job-queue\";\n\n/** Opaque address understood by a Lifecycle routing transport. */\nexport type LifecycleRouteAddress = {\n /** Stable equality and storage key. */\n readonly key: string;\n /** Transport-owned serialized address. */\n readonly data: string;\n};\n\n/** Context supplied with a routed capability message. */\nexport type LifecycleRouteContext = {\n /** Address of the sending Lifecycle, or undefined for an unrouted root. */\n readonly source: LifecycleRouteAddress | undefined;\n /** Capability-owned message payload. */\n readonly payload: unknown;\n};\n\n/** Best-effort telemetry available to every Lifecycle capability. */\nexport type LifecycleEvents = {\n /** Publish an event under this capability's stable identity. */\n readonly emit: (type: string, payload: unknown) => void;\n};\n\n/** Routing available to every Lifecycle capability. */\nexport type LifecycleRoutes = {\n /** This Lifecycle's transport address, or undefined at the route root. */\n readonly source: LifecycleRouteAddress | undefined;\n /** Route a capability-owned message to the root Lifecycle. */\n readonly toRoot: (payload: unknown) => Promise<unknown>;\n /** Route a capability-owned message to another Lifecycle. */\n readonly to: (\n target: LifecycleRouteAddress,\n payload: unknown\n ) => Promise<unknown>;\n};\n\n/**\n * Ambient scope a capability supplies when entering host context on\n * behalf of a live connection or request.\n */\nexport type LifecycleHostContextScope = {\n /** The connection the callback runs on behalf of, when there is one. */\n readonly connection?: Connection;\n /** The request the callback runs on behalf of, when there is one. */\n readonly request?: Request;\n};\n\n/**\n * The platform's hibernatable-socket surface, exposed narrowly so a\n * capability that owns connections (e.g. WebSockets) can accept and\n * enumerate them without holding the whole `DurableObjectState`.\n * These are workerd API names, not Lifecycle modeling sockets.\n */\nexport type LifecycleSockets = {\n /** Accept a socket into hibernation under the given tags. */\n readonly accept: (ws: WebSocket, tags: string[]) => void;\n /** Every hibernated socket on the object, optionally by tag. */\n readonly get: (tag?: string) => WebSocket[];\n};\n\n/**\n * Standard services granted to every installed Lifecycle capability.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport type LifecycleServices = {\n readonly storage: DurableObjectStorage;\n readonly sockets: LifecycleSockets;\n readonly ready: () => Promise<void>;\n /** True while capability and host startup hooks are still running. */\n readonly starting: () => boolean;\n /**\n * This capability's scoped access to the Lifecycle-owned work queue.\n * Pushed items are dispatched to `onJob` when due; every queue mutation\n * re-arms the physical alarm automatically.\n */\n readonly jobs: LifecycleJobs;\n /**\n * Keep work this capability hands off at a bounded `onJob` return inside\n * the current alarm's memory-limit breaker domain (#1825). Returns false,\n * tracking nothing, outside an alarm invocation.\n */\n readonly trackAlarmWork: (work: Promise<unknown>) => boolean;\n /**\n * Run a capability-held user callback inside the host invocation context.\n * Capability hooks run outside host context; this is the one boundary for\n * entering it, and a host composition root may substitute its own wrapper\n * (Agent adds tracing span scope). Pass `scope` to make a live\n * connection or request ambient for the callback.\n */\n readonly runInHostContext: (\n fn: () => unknown,\n scope?: LifecycleHostContextScope\n ) => Promise<unknown>;\n readonly events: LifecycleEvents;\n readonly routes: LifecycleRoutes;\n};\n\nconst installedServices = new WeakMap<object, LifecycleServices>();\n\n/**\n * Base class for capabilities that consume standard Lifecycle services.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport abstract class LifecycleCapability<Props extends object = object> {\n readonly capabilityId: string;\n\n protected constructor(capabilityId: string) {\n if (capabilityId.trim() === \"\") {\n throw new Error(\"Lifecycle capability IDs must be non-empty\");\n }\n this.capabilityId = capabilityId;\n }\n\n /** Default startup hook; capabilities override when they own startup work. */\n onStart(_context: CapabilityStartContext<Props>): void {}\n\n /** Standard services when installed, or undefined in isolated unit tests. */\n protected get lifecycleServices(): LifecycleServices | undefined {\n return installedServices.get(this);\n }\n\n /** Standard services supplied when Lifecycle installs this capability. */\n protected get lifecycle(): LifecycleServices {\n const services = this.lifecycleServices;\n if (!services) {\n throw new Error(\n `${this.constructor.name} must be installed with Lifecycle.use() before use`\n );\n }\n return services;\n }\n}\n\n/**\n * @internal Bind the standard service surface to one capability instance.\n * `Lifecycle.use()` calls this during installation. Test a capability by\n * installing it on a minimal Durable Object with a real Lifecycle rather\n * than binding fake services.\n */\nexport function bindLifecycleCapability(\n capability: LifecycleCapability,\n services: LifecycleServices\n): void {\n installedServices.set(capability, services);\n}\n\n/** @internal Read a capability ID without exposing installation internals. */\nexport function lifecycleCapabilityId(\n capability: DurableObjectCapability\n): string | undefined {\n return capability instanceof LifecycleCapability\n ? capability.capabilityId\n : undefined;\n}\n"],"mappings":";AAwGA,MAAM,oCAAoB,IAAI,QAAmC;;;;;;AAOjE,IAAsB,sBAAtB,MAAyE;CAGvE,YAAsB,cAAsB;EAC1C,IAAI,aAAa,KAAK,MAAM,IAC1B,MAAM,IAAI,MAAM,4CAA4C;EAE9D,KAAK,eAAe;CACtB;;CAGA,QAAQ,UAA+C,CAAC;;CAGxD,IAAc,oBAAmD;EAC/D,OAAO,kBAAkB,IAAI,IAAI;CACnC;;CAGA,IAAc,YAA+B;EAC3C,MAAM,WAAW,KAAK;EACtB,IAAI,CAAC,UACH,MAAM,IAAI,MACR,GAAG,KAAK,YAAY,KAAK,mDAC3B;EAEF,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,wBACd,YACA,UACM;CACN,kBAAkB,IAAI,YAAY,QAAQ;AAC5C;;AAGA,SAAgB,sBACd,YACoB;CACpB,OAAO,sBAAsB,sBACzB,WAAW,eACX,KAAA;AACN"}