agents 0.30.0 → 0.31.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 (130) hide show
  1. package/README.md +4 -2
  2. package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-wS1TimZ_.d.ts} +64 -603
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +1 -1
  5. package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-Bamxxb6Y.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
  8. package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
  9. package/dist/ai-sdk-Kon40i0q.js.map +1 -0
  10. package/dist/ai-sdk-hW3vntnk.d.ts +72 -0
  11. package/dist/browser/ai.d.ts +1 -1
  12. package/dist/browser/ai.js +16 -3
  13. package/dist/browser/ai.js.map +1 -1
  14. package/dist/browser/index.d.ts +64 -16
  15. package/dist/browser/index.js +4 -4
  16. package/dist/browser/tools/ai-sdk.d.ts +7 -70
  17. package/dist/browser/tools/ai-sdk.js +4 -4
  18. package/dist/browser/tools/ai-sdk.js.map +1 -1
  19. package/dist/browser/tools/pi.d.ts +9 -15
  20. package/dist/browser/tools/pi.js +6 -14
  21. package/dist/browser/tools/pi.js.map +1 -1
  22. package/dist/browser/tools/tanstack-ai.d.ts +46 -23
  23. package/dist/browser/tools/tanstack-ai.js +8 -4
  24. package/dist/browser/tools/tanstack-ai.js.map +1 -1
  25. package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
  26. package/dist/browser-1eUbPvC2.js.map +1 -0
  27. package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
  28. package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
  29. package/dist/browser-tool-lGnvEBLJ.js +497 -0
  30. package/dist/browser-tool-lGnvEBLJ.js.map +1 -0
  31. package/dist/capability-id-B3J8Nok_.js +13 -0
  32. package/dist/capability-id-B3J8Nok_.js.map +1 -0
  33. package/dist/chat/index.d.ts +2 -2
  34. package/dist/chat-sdk/index.d.ts +3 -3
  35. package/dist/chat-sdk/index.js +1 -1
  36. package/dist/client-4OlMIJx-.js.map +1 -1
  37. package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
  38. package/dist/client-DMWujQJ1.js.map +1 -0
  39. package/dist/{client-C27CtRZr.d.ts → client-wn4-yqGz.d.ts} +9 -7
  40. package/dist/client.d.ts +1 -1
  41. package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
  42. package/dist/connector-CM-uuxKM.js.map +1 -0
  43. package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
  44. package/dist/experimental/webmcp.js +1 -1
  45. package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
  46. package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
  47. package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
  48. package/dist/harness/container/index.d.ts +15 -15
  49. package/dist/harness/opencode/index.js.map +1 -1
  50. package/dist/harness/pi/index.d.ts +7 -3
  51. package/dist/harness/pi/index.js +46 -15
  52. package/dist/harness/pi/index.js.map +1 -1
  53. package/dist/harness/think/index.d.ts +2 -1
  54. package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
  55. package/dist/images-CfuRCjwq.js.map +1 -0
  56. package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
  57. package/dist/index.d.ts +14 -14
  58. package/dist/index.js +2 -2
  59. package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
  60. package/dist/internal-kmw70xwR.js.map +1 -1
  61. package/dist/invoker-BC1SZ3q1.js +26 -0
  62. package/dist/invoker-BC1SZ3q1.js.map +1 -0
  63. package/dist/invoker-DoLFPJZV.d.ts +21 -0
  64. package/dist/mcp/client/index.d.ts +15 -1
  65. package/dist/mcp/client/index.js +2 -2
  66. package/dist/mcp/client/x402.d.ts +7 -5
  67. package/dist/mcp/client/x402.js +34 -1
  68. package/dist/mcp/client/x402.js.map +1 -1
  69. package/dist/mcp/index.d.ts +561 -27
  70. package/dist/mcp/index.js +180 -3
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/mcp/server/index.d.ts +1 -1
  73. package/dist/mcp/server/index.js +1 -1
  74. package/dist/models/ai-sdk/index.d.ts +2 -2
  75. package/dist/models/ai-sdk/index.js +1 -1
  76. package/dist/models/opencode/index.d.ts +2 -2
  77. package/dist/models/opencode/index.js +1 -1
  78. package/dist/models/pi-ai/index.d.ts +3 -28
  79. package/dist/models/pi-ai/index.js +31 -16
  80. package/dist/models/pi-ai/index.js.map +1 -1
  81. package/dist/protocol-BEgrJYC5.d.ts +29 -29
  82. package/dist/react.d.ts +2 -2
  83. package/dist/routing/index.d.ts +1 -1
  84. package/dist/serializable.d.ts +1 -1
  85. package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
  86. package/dist/session-7CDgVE0z.js.map +1 -0
  87. package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
  88. package/dist/settings-Dk2il2Hf.js.map +1 -1
  89. package/dist/{src-DfLzdwlK.js → src-BGolXG_H.js} +18 -2
  90. package/dist/src-BGolXG_H.js.map +1 -0
  91. package/dist/sub-routing.d.ts +12 -12
  92. package/dist/tool-CTp72Jb_.d.ts +10 -10
  93. package/dist/tool-DoVberpN.d.ts +22 -22
  94. package/dist/tool-helpers-BodWi4gd.js +256 -0
  95. package/dist/tool-helpers-BodWi4gd.js.map +1 -0
  96. package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
  97. package/dist/types-D2naO3rA.d.ts +49 -0
  98. package/dist/voice/index.d.ts +1 -1
  99. package/dist/workflow-types.d.ts +1 -1
  100. package/dist/workflows.d.ts +1 -1
  101. package/dist/workflows.js +1 -1
  102. package/docs/browse-the-web.md +247 -413
  103. package/docs/get-current-agent.md +4 -7
  104. package/docs/harnesses/pi.md +28 -28
  105. package/docs/human-in-the-loop.md +3 -7
  106. package/docs/index.md +6 -6
  107. package/docs/mcp-client.md +4 -28
  108. package/docs/mcp-servers.md +137 -411
  109. package/docs/mcp-transports.md +30 -289
  110. package/docs/models-pi-ai.md +9 -11
  111. package/docs/models.md +1 -8
  112. package/docs/routing.md +0 -2
  113. package/docs/securing-mcp-servers.md +120 -304
  114. package/package.json +8 -3
  115. package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
  116. package/dist/browser-DccPw_wW.js.map +0 -1
  117. package/dist/browser-tool-B1mhifin.js +0 -616
  118. package/dist/browser-tool-B1mhifin.js.map +0 -1
  119. package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
  120. package/dist/client-BnYbNT3z.js.map +0 -1
  121. package/dist/connector-DAXBOIIi.js.map +0 -1
  122. package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
  123. package/dist/images-xaDv2Fqe.js.map +0 -1
  124. package/dist/invoker-CG0_p_Wq.d.ts +0 -20
  125. package/dist/invoker-CHMnoxIA.js +0 -57
  126. package/dist/invoker-CHMnoxIA.js.map +0 -1
  127. package/dist/session-store-yvwq1f9x.js.map +0 -1
  128. package/dist/src-DfLzdwlK.js.map +0 -1
  129. package/dist/tool-helpers-O5BDVEAY.js +0 -58
  130. package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","names":[],"sources":["../../src/browser/ai.ts"],"sourcesContent":["import { tool, type ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport {\n createCodemodeRuntime,\n DynamicWorkerExecutor,\n type CodemodeRuntimeHandle\n} from \"@cloudflare/codemode\";\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-store\";\nimport {\n browserExecuteModelOutput,\n resolveCtx,\n transformBrowserResult\n} from \"./tool-helpers\";\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\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":[],"sources":["../../src/browser/ai.ts"],"sourcesContent":["import { tool, type ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport {\n createCodemodeRuntime,\n DynamicWorkerExecutor,\n type CodemodeRuntimeHandle\n} from \"@cloudflare/codemode\";\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-store\";\nimport {\n browserExecuteModelOutput,\n resolveCtx,\n transformBrowserResult\n} from \"./tool-helpers\";\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\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 *\n * @deprecated Use `browserTool` from `agents/browser/ai-sdk`,\n * `agents/browser/tanstack-ai` or `agents/browser/pi`. See\n * https://github.com/cloudflare/agents/blob/main/docs/agents/browse-the-web.md#persistent-browser\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 *\n * @deprecated Use `browserTool` from `agents/browser/ai-sdk`,\n * `agents/browser/tanstack-ai` or `agents/browser/pi`. See\n * https://github.com/cloudflare/agents/blob/main/docs/agents/browse-the-web.md#persistent-browser\n */\nexport function createBrowserTools(\n options: CreateBrowserToolsOptions\n): ToolSet {\n return createBrowserRuntime(options).tools;\n}\n\n/**\n * A Quick Action exposed as an AI SDK tool.\n *\n * @deprecated Quick Actions are deprecated and won't change. Use\n * `browserTool` to drive a browser, the `web_fetch` tool from\n * `agents/webfetch` to read a page, or call the binding's\n * `quickAction()` directly.\n */\nexport type QuickActionToolName =\n | \"markdown\"\n | \"extract\"\n | \"links\"\n | \"scrape\"\n | \"content\";\n\n/**\n * @deprecated Quick Actions are deprecated and won't change. Use\n * `browserTool` to drive a browser, the `web_fetch` tool from\n * `agents/webfetch` to read a page, or call the binding's\n * `quickAction()` directly.\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 *\n * @deprecated Quick Actions are deprecated and won't change. Use\n * `browserTool` to drive a browser, the `web_fetch` tool from\n * `agents/webfetch` to read a page, or call the binding's\n * `quickAction()` directly.\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,3 +1,18 @@
1
+ import {
2
+ a as InternalHostRouterLoopback,
3
+ c as InternalWorkerHost,
4
+ d as TargetOf,
5
+ f as TargetSchema,
6
+ i as InternalHostRouter,
7
+ l as JsonSchemaObject,
8
+ n as InternalHostInfo,
9
+ o as InternalHostRouterProps,
10
+ p as TypedTargetSchema,
11
+ r as InternalHostMessage,
12
+ s as InternalHostsOptions,
13
+ t as InternalHost,
14
+ u as MAX_INTERNAL_HOSTS
15
+ } from "../internal-hosts-Kfp5A392.js";
1
16
  import {
2
17
  A as CdpSendOptions,
3
18
  C as createBrowserSession,
@@ -31,7 +46,7 @@ import {
31
46
  w as deleteBrowserSession,
32
47
  x as connectBrowser,
33
48
  y as ConnectChromiumBrowserOptions
34
- } from "../session-store-_IK6dV-w.js";
49
+ } from "../session-store-B7Ca-u1t.js";
35
50
  import {
36
51
  C as browserScrape,
37
52
  E as runQuickAction,
@@ -59,28 +74,40 @@ import {
59
74
  w as browserScreenshot,
60
75
  x as browserMarkdown,
61
76
  y as browserExtract
62
- } from "../connector-20DJ6p4k.js";
77
+ } from "../connector-DZ71EjE-.js";
63
78
  import {
64
- a as BrowserProvider,
65
- c as ResolvedBrowser,
66
- d as browserRun,
67
- f as CdpField,
68
- g as loadCdpSpec,
69
- h as SearchableCdpSpec,
70
- i as BrowserOptions,
71
- l as BrowserRunOptions,
72
- m as CdpSpecSource,
79
+ C as CdpItems,
80
+ E as loadCdpSpec,
81
+ S as CdpField,
82
+ T as SearchableCdpSpec,
83
+ _ as BrowserSessionReport,
84
+ a as BrowserOptions,
85
+ b as BrowserRunProvider,
86
+ c as MAX_BROWSER_SCOPES,
87
+ d as BrowserAttachInput,
88
+ f as BrowserDebugLogInput,
89
+ g as BrowserSessionOptions,
90
+ h as BrowserSession,
91
+ i as BrowserInternalHosts,
92
+ l as ResolvedBrowser,
93
+ m as BrowserSendInput,
73
94
  n as BrowserConnectOptions,
74
- o as DEFAULT_BROWSER_SCOPE,
75
- p as CdpItems,
95
+ o as BrowserProvider,
96
+ p as BrowserNewTab,
76
97
  r as BrowserConnection,
77
- s as MAX_BROWSER_SCOPES,
98
+ s as DEFAULT_BROWSER_SCOPE,
78
99
  t as Browser,
79
- u as BrowserRunProvider
80
- } from "../browser-DlXhSAdf.js";
100
+ u as ACTIVE_PAGE_SESSION,
101
+ v as BrowserSource,
102
+ w as CdpSpecSource,
103
+ x as browserRun,
104
+ y as BrowserRunOptions
105
+ } from "../browser-D9RNpJuT.js";
81
106
  import { CodemodeRuntime } from "@cloudflare/codemode";
82
107
  export {
108
+ ACTIVE_PAGE_SESSION,
83
109
  Browser,
110
+ type BrowserAttachInput,
84
111
  type BrowserBinding,
85
112
  type BrowserConnectOptions,
86
113
  type BrowserConnection,
@@ -89,19 +116,27 @@ export {
89
116
  type BrowserConnectorSessionOptions,
90
117
  type BrowserConnectorSweepOptions,
91
118
  type BrowserConnectorSweepResult,
119
+ type BrowserDebugLogInput,
120
+ type BrowserInternalHosts,
92
121
  type BrowserLiveView,
93
122
  type BrowserLiveViewTarget,
94
123
  type BrowserLiveViewUrl,
124
+ type BrowserNewTab,
95
125
  type BrowserOptions,
96
126
  type BrowserProvider,
97
127
  type BrowserRecording,
98
128
  BrowserRenderingError,
99
129
  type BrowserRunOptions,
100
130
  type BrowserRunProvider,
131
+ type BrowserSendInput,
132
+ BrowserSession,
101
133
  type BrowserSessionGuardrails,
102
134
  type BrowserSessionInfo,
103
135
  type BrowserSessionLock,
136
+ type BrowserSessionOptions,
137
+ type BrowserSessionReport,
104
138
  type BrowserSessionStore,
139
+ type BrowserSource,
105
140
  type BrowserTargetInfo,
106
141
  type CdpAttachOptions,
107
142
  CdpConnection,
@@ -120,9 +155,19 @@ export {
120
155
  DEFAULT_EXEC_SWEEP_IDLE_MS,
121
156
  DEFAULT_SWEEP_IDLE_MS,
122
157
  DurableBrowserSessionStore,
158
+ type InternalHost,
159
+ type InternalHostInfo,
160
+ type InternalHostMessage,
161
+ InternalHostRouter,
162
+ type InternalHostRouterLoopback,
163
+ type InternalHostRouterProps,
164
+ type InternalHostsOptions,
165
+ type InternalWorkerHost,
166
+ type JsonSchemaObject,
123
167
  type ListableBrowserSessionStore,
124
168
  type LiveViewMode,
125
169
  MAX_BROWSER_SCOPES,
170
+ MAX_INTERNAL_HOSTS,
126
171
  type QuickAction,
127
172
  type QuickActionBinary,
128
173
  type QuickActionBinding,
@@ -137,6 +182,9 @@ export {
137
182
  type ResolvedBrowser,
138
183
  type SearchableCdpSpec,
139
184
  type StoredBrowserSession,
185
+ type TargetOf,
186
+ type TargetSchema,
187
+ type TypedTargetSchema,
140
188
  browserContent,
141
189
  browserExtract,
142
190
  browserLinks,
@@ -1,5 +1,5 @@
1
- import { S as connectUrl, _ as listBrowserTargets, c as BrowserRenderingError, d as connectBrowser, f as connectBrowserSession, h as getBrowserRecording, m as deleteBrowserSession, n as DurableBrowserSessionStore, p as createBrowserSession, r as loadCdpSpec, t as DEFAULT_SWEEP_IDLE_MS, x as CdpSession, y as CdpConnection } from "../session-store-yvwq1f9x.js";
2
- import { a as browserLinks, c as browserScrape, d as runQuickAction, i as browserExtract, l as browserScreenshot, n as DEFAULT_EXEC_SWEEP_IDLE_MS, o as browserMarkdown, r as browserContent, s as browserPdf, t as BrowserConnector, u as browserSnapshot } from "../connector-DAXBOIIi.js";
3
- import { i as browserRun, n as DEFAULT_BROWSER_SCOPE, r as MAX_BROWSER_SCOPES, t as Browser } from "../browser-DccPw_wW.js";
1
+ import { S as CdpConnection, T as connectUrl, _ as deleteBrowserSession, a as DEFAULT_SWEEP_IDLE_MS, b as listBrowserTargets, d as BrowserRenderingError, g as createBrowserSession, h as connectBrowserSession, m as connectBrowser, n as BrowserSession, o as DurableBrowserSessionStore, s as loadCdpSpec, t as ACTIVE_PAGE_SESSION, v as getBrowserRecording, w as CdpSession } from "../session-7CDgVE0z.js";
2
+ import { a as browserLinks, c as browserScrape, d as runQuickAction, i as browserExtract, l as browserScreenshot, n as DEFAULT_EXEC_SWEEP_IDLE_MS, o as browserMarkdown, r as browserContent, s as browserPdf, t as BrowserConnector, u as browserSnapshot } from "../connector-CM-uuxKM.js";
3
+ import { a as InternalHostRouter, i as browserRun, n as DEFAULT_BROWSER_SCOPE, o as MAX_INTERNAL_HOSTS, r as MAX_BROWSER_SCOPES, t as Browser } from "../browser-1eUbPvC2.js";
4
4
  import { CodemodeRuntime } from "@cloudflare/codemode";
5
- export { Browser, BrowserConnector, BrowserRenderingError, CdpConnection, CdpSession, CodemodeRuntime, DEFAULT_BROWSER_SCOPE, DEFAULT_EXEC_SWEEP_IDLE_MS, DEFAULT_SWEEP_IDLE_MS, DurableBrowserSessionStore, MAX_BROWSER_SCOPES, browserContent, browserExtract, browserLinks, browserMarkdown, browserPdf, browserRun, browserScrape, browserScreenshot, browserSnapshot, connectBrowser, connectBrowserSession, connectUrl, createBrowserSession, deleteBrowserSession, getBrowserRecording, listBrowserTargets, loadCdpSpec, runQuickAction };
5
+ export { ACTIVE_PAGE_SESSION, Browser, BrowserConnector, BrowserRenderingError, BrowserSession, CdpConnection, CdpSession, CodemodeRuntime, DEFAULT_BROWSER_SCOPE, DEFAULT_EXEC_SWEEP_IDLE_MS, DEFAULT_SWEEP_IDLE_MS, DurableBrowserSessionStore, InternalHostRouter, MAX_BROWSER_SCOPES, MAX_INTERNAL_HOSTS, browserContent, browserExtract, browserLinks, browserMarkdown, browserPdf, browserRun, browserScrape, browserScreenshot, browserSnapshot, connectBrowser, connectBrowserSession, connectUrl, createBrowserSession, deleteBrowserSession, getBrowserRecording, listBrowserTargets, loadCdpSpec, runQuickAction };
@@ -2,79 +2,17 @@ import {
2
2
  i as QuickActionToolName,
3
3
  r as CreateQuickActionToolsOptions,
4
4
  s as createQuickActionTools
5
- } from "../../ai-iXw0uOGj.js";
5
+ } from "../../ai-CDn3Abax.js";
6
+ import {
7
+ p as BrowserNewTab,
8
+ v as BrowserSource
9
+ } from "../../browser-D9RNpJuT.js";
6
10
  import {
7
- a as BrowserSource,
8
- i as BrowserNewTab,
9
11
  n as BrowserToolOptions,
10
12
  r as BrowserToolOutput,
11
13
  t as BrowserToolInput
12
- } from "../../browser-tool-Cxjk5sgG.js";
13
- import { FlexibleSchema, JSONValue } from "ai";
14
-
15
- //#region src/browser/tool-helpers.d.ts
16
- /** What the model sees in place of a browser tool's output. */
17
- type BrowserModelOutput =
18
- | {
19
- type: "text";
20
- value: string;
21
- }
22
- | {
23
- type: "json";
24
- value: JSONValue;
25
- };
26
- //#endregion
27
- //#region src/browser/tools/ai-sdk.d.ts
28
- /**
29
- * The AI SDK tool {@link browserTool} returns. Assignable to the AI SDK's
30
- * `Tool`, and `execute` / `toModelOutput` are always present.
31
- */
32
- interface BrowserTool {
33
- description: string;
34
- inputSchema: FlexibleSchema<BrowserToolInput>;
35
- execute(
36
- input: BrowserToolInput,
37
- options: unknown
38
- ): Promise<BrowserToolOutput>;
39
- toModelOutput(options: { output: BrowserToolOutput }): BrowserModelOutput;
40
- }
41
- /**
42
- * Create an AI SDK tool that lets the model drive a persistent browser with
43
- * JavaScript and the Chrome DevTools Protocol.
44
- *
45
- * The browser outlives each run: tabs, cookies, and logins carry over. The
46
- * model never starts, closes, or resets it, and `sessionId: "active"`
47
- * addresses the tab it last worked in. If the browser had to be replaced
48
- * (it expired or was closed), the code still runs in the new browser and the
49
- * result says `restarted: true`.
50
- *
51
- * Browser Run only (Chromium). Guardrails, `keepAliveMs`, and recording are
52
- * set on the `Browser`'s provider.
53
- *
54
- * @example
55
- * ```ts
56
- * import { Browser, browserRun } from "agents/browser";
57
- * import { browserTool } from "agents/browser/ai-sdk";
58
- *
59
- * export class MyAgent extends Agent<Env> {
60
- * browser = new Browser({ provider: browserRun(this.env.BROWSER) });
61
- *
62
- * constructor(ctx: AgentContext, env: Env) {
63
- * super(ctx, env);
64
- * this.lifecycle.use(this.browser);
65
- * }
66
- *
67
- * async onChatMessage() {
68
- * const tools = {
69
- * browser: browserTool({ browser: this.browser, loader: this.env.LOADER })
70
- * };
71
- * // …pass `tools` to streamText / generateText
72
- * }
73
- * }
74
- * ```
75
- */
76
- declare function browserTool(options: BrowserToolOptions): BrowserTool;
77
- //#endregion
14
+ } from "../../browser-tool-BhjCcNVE.js";
15
+ import { n as browserTool, t as BrowserTool } from "../../ai-sdk-hW3vntnk.js";
78
16
  export {
79
17
  type BrowserNewTab,
80
18
  type BrowserSource,
@@ -87,4 +25,3 @@ export {
87
25
  browserTool,
88
26
  createQuickActionTools
89
27
  };
90
- //# sourceMappingURL=ai-sdk.d.ts.map
@@ -1,6 +1,6 @@
1
- import { t as browserExecuteModelOutput } from "../../tool-helpers-O5BDVEAY.js";
1
+ import { t as browserExecuteModelOutput } from "../../tool-helpers-BodWi4gd.js";
2
2
  import { createQuickActionTools } from "../ai.js";
3
- import { n as createBrowserToolCore, t as browserReportNotes } from "../../browser-tool-B1mhifin.js";
3
+ import { t as createBrowserToolCore } from "../../browser-tool-lGnvEBLJ.js";
4
4
  //#region src/browser/tools/ai-sdk.ts
5
5
  /**
6
6
  * Create an AI SDK tool that lets the model drive a persistent browser with
@@ -10,7 +10,7 @@ import { n as createBrowserToolCore, t as browserReportNotes } from "../../brows
10
10
  * model never starts, closes, or resets it, and `sessionId: "active"`
11
11
  * addresses the tab it last worked in. If the browser had to be replaced
12
12
  * (it expired or was closed), the code still runs in the new browser and the
13
- * result says `restarted: true`.
13
+ * result's `notice` says so.
14
14
  *
15
15
  * Browser Run only (Chromium). Guardrails, `keepAliveMs`, and recording are
16
16
  * set on the `Browser`'s provider.
@@ -43,7 +43,7 @@ function browserTool(options) {
43
43
  description: core.description,
44
44
  inputSchema: core.inputSchema,
45
45
  execute: (input) => core.execute(input),
46
- toModelOutput: ({ output }) => browserExecuteModelOutput(output, browserReportNotes(output))
46
+ toModelOutput: ({ output }) => browserExecuteModelOutput(output, output.notice ? [output.notice] : [])
47
47
  };
48
48
  }
49
49
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"ai-sdk.js","names":[],"sources":["../../../src/browser/tools/ai-sdk.ts"],"sourcesContent":["/**\n * `agents/browser/ai-sdk` — the AI SDK tool for a persistent `Browser`.\n *\n * The older `createBrowserTools` stays in `agents/browser/ai`.\n */\nimport type { FlexibleSchema } from \"ai\";\nimport {\n browserReportNotes,\n createBrowserToolCore,\n type BrowserToolInput,\n type BrowserToolOptions,\n type BrowserToolOutput\n} from \"../browser-tool\";\nimport {\n browserExecuteModelOutput,\n type BrowserModelOutput\n} from \"../tool-helpers\";\n\nexport type {\n BrowserToolInput,\n BrowserToolOptions,\n BrowserToolOutput\n} from \"../browser-tool\";\nexport type { BrowserNewTab, BrowserSource } from \"../session-connector\";\n\n// Stateless Quick Action tools, so one import covers both.\nexport {\n createQuickActionTools,\n type CreateQuickActionToolsOptions,\n type QuickActionToolName\n} from \"../ai\";\n\n/**\n * The AI SDK tool {@link browserTool} returns. Assignable to the AI SDK's\n * `Tool`, and `execute` / `toModelOutput` are always present.\n */\nexport interface BrowserTool {\n description: string;\n inputSchema: FlexibleSchema<BrowserToolInput>;\n execute(\n input: BrowserToolInput,\n options: unknown\n ): Promise<BrowserToolOutput>;\n toModelOutput(options: { output: BrowserToolOutput }): BrowserModelOutput;\n}\n\n/**\n * Create an AI SDK tool that lets the model drive a persistent browser with\n * JavaScript and the Chrome DevTools Protocol.\n *\n * The browser outlives each run: tabs, cookies, and logins carry over. The\n * model never starts, closes, or resets it, and `sessionId: \"active\"`\n * addresses the tab it last worked in. If the browser had to be replaced\n * (it expired or was closed), the code still runs in the new browser and the\n * result says `restarted: true`.\n *\n * Browser Run only (Chromium). Guardrails, `keepAliveMs`, and recording are\n * set on the `Browser`'s provider.\n *\n * @example\n * ```ts\n * import { Browser, browserRun } from \"agents/browser\";\n * import { browserTool } from \"agents/browser/ai-sdk\";\n *\n * export class MyAgent extends Agent<Env> {\n * browser = new Browser({ provider: browserRun(this.env.BROWSER) });\n *\n * constructor(ctx: AgentContext, env: Env) {\n * super(ctx, env);\n * this.lifecycle.use(this.browser);\n * }\n *\n * async onChatMessage() {\n * const tools = {\n * browser: browserTool({ browser: this.browser, loader: this.env.LOADER })\n * };\n * // …pass `tools` to streamText / generateText\n * }\n * }\n * ```\n */\nexport function browserTool(options: BrowserToolOptions): BrowserTool {\n const core = createBrowserToolCore(options, {\n screenshotHint:\n \"To show a screenshot, return { type: 'browser_screenshot', mediaType, data } with data from Page.captureScreenshot and mediaType 'image/png', or 'image/jpeg' if you captured with format: 'jpeg'. The user sees the image; you get a short text summary.\"\n });\n return {\n description: core.description,\n inputSchema: core.inputSchema,\n execute: (input) => core.execute(input),\n toModelOutput: ({ output }) =>\n browserExecuteModelOutput(output, browserReportNotes(output))\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiFA,SAAgB,YAAY,SAA0C;CACpE,MAAM,OAAO,sBAAsB,SAAS,EAC1C,gBACE,4PACJ,CAAC;CACD,OAAO;EACL,aAAa,KAAK;EAClB,aAAa,KAAK;EAClB,UAAU,UAAU,KAAK,QAAQ,KAAK;EACtC,gBAAgB,EAAE,aAChB,0BAA0B,QAAQ,mBAAmB,MAAM,CAAC;CAChE;AACF"}
1
+ {"version":3,"file":"ai-sdk.js","names":[],"sources":["../../../src/browser/tools/ai-sdk.ts"],"sourcesContent":["/**\n * `agents/browser/ai-sdk` — the AI SDK tool for a persistent `Browser`.\n *\n * The older `createBrowserTools` stays in `agents/browser/ai`.\n */\nimport type { FlexibleSchema } from \"ai\";\nimport {\n createBrowserToolCore,\n type BrowserToolInput,\n type BrowserToolOptions,\n type BrowserToolOutput\n} from \"../browser-tool\";\nimport {\n browserExecuteModelOutput,\n type BrowserModelOutput\n} from \"../tool-helpers\";\n\nexport type {\n BrowserToolInput,\n BrowserToolOptions,\n BrowserToolOutput\n} from \"../browser-tool\";\nexport type { BrowserNewTab, BrowserSource } from \"../session\";\n\n// Stateless Quick Action tools, so one import covers both.\nexport {\n createQuickActionTools,\n type CreateQuickActionToolsOptions,\n type QuickActionToolName\n} from \"../ai\";\n\n/**\n * The AI SDK tool {@link browserTool} returns. Assignable to the AI SDK's\n * `Tool`, and `execute` / `toModelOutput` are always present.\n */\nexport interface BrowserTool {\n description: string;\n inputSchema: FlexibleSchema<BrowserToolInput>;\n execute(\n input: BrowserToolInput,\n options: unknown\n ): Promise<BrowserToolOutput>;\n toModelOutput(options: { output: BrowserToolOutput }): BrowserModelOutput;\n}\n\n/**\n * Create an AI SDK tool that lets the model drive a persistent browser with\n * JavaScript and the Chrome DevTools Protocol.\n *\n * The browser outlives each run: tabs, cookies, and logins carry over. The\n * model never starts, closes, or resets it, and `sessionId: \"active\"`\n * addresses the tab it last worked in. If the browser had to be replaced\n * (it expired or was closed), the code still runs in the new browser and the\n * result's `notice` says so.\n *\n * Browser Run only (Chromium). Guardrails, `keepAliveMs`, and recording are\n * set on the `Browser`'s provider.\n *\n * @example\n * ```ts\n * import { Browser, browserRun } from \"agents/browser\";\n * import { browserTool } from \"agents/browser/ai-sdk\";\n *\n * export class MyAgent extends Agent<Env> {\n * browser = new Browser({ provider: browserRun(this.env.BROWSER) });\n *\n * constructor(ctx: AgentContext, env: Env) {\n * super(ctx, env);\n * this.lifecycle.use(this.browser);\n * }\n *\n * async onChatMessage() {\n * const tools = {\n * browser: browserTool({ browser: this.browser, loader: this.env.LOADER })\n * };\n * // …pass `tools` to streamText / generateText\n * }\n * }\n * ```\n */\nexport function browserTool(options: BrowserToolOptions): BrowserTool {\n const core = createBrowserToolCore(options, {\n screenshotHint:\n \"To show a screenshot, return { type: 'browser_screenshot', mediaType, data } with data from Page.captureScreenshot and mediaType 'image/png', or 'image/jpeg' if you captured with format: 'jpeg'. The user sees the image; you get a short text summary.\"\n });\n return {\n description: core.description,\n inputSchema: core.inputSchema,\n execute: (input) => core.execute(input),\n toModelOutput: ({ output }) =>\n browserExecuteModelOutput(output, output.notice ? [output.notice] : [])\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFA,SAAgB,YAAY,SAA0C;CACpE,MAAM,OAAO,sBAAsB,SAAS,EAC1C,gBACE,4PACJ,CAAC;CACD,OAAO;EACL,aAAa,KAAK;EAClB,aAAa,KAAK;EAClB,UAAU,UAAU,KAAK,QAAQ,KAAK;EACtC,gBAAgB,EAAE,aAChB,0BAA0B,QAAQ,OAAO,SAAS,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC;CAC1E;AACF"}
@@ -1,10 +1,12 @@
1
1
  import {
2
- a as BrowserSource,
3
- i as BrowserNewTab,
2
+ p as BrowserNewTab,
3
+ v as BrowserSource
4
+ } from "../../browser-D9RNpJuT.js";
5
+ import {
4
6
  n as BrowserToolOptions,
5
7
  r as BrowserToolOutput,
6
8
  t as BrowserToolInput
7
- } from "../../browser-tool-Cxjk5sgG.js";
9
+ } from "../../browser-tool-BhjCcNVE.js";
8
10
  import { Type } from "@earendil-works/pi-ai";
9
11
  import { ToolExecutionApi, ToolRegistration } from "@earendil-works/pi-durable";
10
12
 
@@ -28,18 +30,12 @@ declare const browserToolParameters: Type.TObject<{
28
30
  code: Type.TString;
29
31
  }>;
30
32
  /**
31
- * What a UI can show about a run without reading the content: the run's
32
- * outcome and what happened to the browser.
33
+ * What a UI can show about a run without reading the content: its id and
34
+ * outcome.
33
35
  */
34
36
  type PiBrowserToolDetails = {
35
37
  executionId: string;
36
38
  status: BrowserToolOutput["status"];
37
- restarted?: true;
38
- newTabs?: {
39
- targetId: string;
40
- url?: string;
41
- title?: string;
42
- }[];
43
39
  };
44
40
  type PiBrowserTool<TName extends string = "browser"> = ToolRegistration<
45
41
  typeof browserToolParameters,
@@ -53,8 +49,8 @@ type PiBrowserTool<TName extends string = "browser"> = ToolRegistration<
53
49
  *
54
50
  * Works like `browserTool` in `agents/browser/ai-sdk`: tabs, cookies, and
55
51
  * logins carry over between runs, `sessionId: "active"` addresses the tab the
56
- * model last worked in, and a replaced browser is reported as
57
- * `restarted: true`. A returned screenshot comes back as an image part that
52
+ * model last worked in, and a replaced browser is reported in the
53
+ * result's `notice`. A returned screenshot comes back as an image part that
58
54
  * the model sees, when its model accepts images.
59
55
  *
60
56
  * Each conversation gets its own active tab (see
@@ -62,7 +58,6 @@ type PiBrowserTool<TName extends string = "browser"> = ToolRegistration<
62
58
  * time, since they share its tab, and the tool doesn't rerun after an
63
59
  * eviction (its code may have clicked or
64
60
  * submitted something): pi gives the model an interrupted result instead.
65
- * Pass `ctx` unless the tool is built inside an Agent.
66
61
  *
67
62
  * @example
68
63
  * ```ts
@@ -78,7 +73,6 @@ type PiBrowserTool<TName extends string = "browser"> = ToolRegistration<
78
73
  * name: "browser",
79
74
  * tools: [
80
75
  * browserTool({
81
- * ctx: this.ctx,
82
76
  * browser: this.browser,
83
77
  * loader: this.env.LOADER
84
78
  * })
@@ -1,18 +1,12 @@
1
- import { n as browserScreenshotOutput, t as browserExecuteModelOutput } from "../../tool-helpers-O5BDVEAY.js";
2
- import { n as createBrowserToolCore } from "../../browser-tool-B1mhifin.js";
1
+ import { n as browserScreenshotOutput, t as browserExecuteModelOutput } from "../../tool-helpers-BodWi4gd.js";
2
+ import { t as createBrowserToolCore } from "../../browser-tool-lGnvEBLJ.js";
3
3
  import { Type } from "@earendil-works/pi-ai";
4
4
  //#region src/browser/tools/pi.ts
5
- const browserToolParameters = Type.Object({ code: Type.String({ description: "An async arrow function that drives the browser with `cdp`" }) });
5
+ const browserToolParameters = Type.Object({ code: Type.String({ description: "An async arrow function that drives the browser with `browser`" }) });
6
6
  function details(output) {
7
7
  return {
8
8
  executionId: output.executionId,
9
- status: output.status,
10
- ...output.restarted ? { restarted: true } : {},
11
- ...output.newTabs ? { newTabs: output.newTabs.map((tab) => ({
12
- targetId: tab.targetId,
13
- ...tab.url === void 0 ? {} : { url: tab.url },
14
- ...tab.title === void 0 ? {} : { title: tab.title }
15
- })) } : {}
9
+ status: output.status
16
10
  };
17
11
  }
18
12
  function text(value) {
@@ -58,8 +52,8 @@ function conversationScope(api) {
58
52
  *
59
53
  * Works like `browserTool` in `agents/browser/ai-sdk`: tabs, cookies, and
60
54
  * logins carry over between runs, `sessionId: "active"` addresses the tab the
61
- * model last worked in, and a replaced browser is reported as
62
- * `restarted: true`. A returned screenshot comes back as an image part that
55
+ * model last worked in, and a replaced browser is reported in the
56
+ * result's `notice`. A returned screenshot comes back as an image part that
63
57
  * the model sees, when its model accepts images.
64
58
  *
65
59
  * Each conversation gets its own active tab (see
@@ -67,7 +61,6 @@ function conversationScope(api) {
67
61
  * time, since they share its tab, and the tool doesn't rerun after an
68
62
  * eviction (its code may have clicked or
69
63
  * submitted something): pi gives the model an interrupted result instead.
70
- * Pass `ctx` unless the tool is built inside an Agent.
71
64
  *
72
65
  * @example
73
66
  * ```ts
@@ -83,7 +76,6 @@ function conversationScope(api) {
83
76
  * name: "browser",
84
77
  * tools: [
85
78
  * browserTool({
86
- * ctx: this.ctx,
87
79
  * browser: this.browser,
88
80
  * loader: this.env.LOADER
89
81
  * })
@@ -1 +1 @@
1
- {"version":3,"file":"pi.js","names":[],"sources":["../../../src/browser/tools/pi.ts"],"sourcesContent":["import {\n Type,\n type ImageContent,\n type TextContent\n} from \"@earendil-works/pi-ai\";\nimport type {\n ToolExecutionApi,\n ToolExecutionResult,\n ToolRegistration\n} from \"@earendil-works/pi-durable\";\nimport {\n createBrowserToolCore,\n type BrowserToolOptions,\n type BrowserToolOutput\n} from \"../browser-tool\";\nimport type { BrowserNewTab } from \"../session-connector\";\nimport {\n browserExecuteModelOutput,\n browserScreenshotOutput\n} from \"../tool-helpers\";\n\nexport type {\n BrowserToolInput,\n BrowserToolOptions,\n BrowserToolOutput\n} from \"../browser-tool\";\nexport type { BrowserNewTab, BrowserSource } from \"../session-connector\";\n\nexport interface PiBrowserToolOptions<\n TName extends string = \"browser\"\n> extends Omit<BrowserToolOptions, \"scope\"> {\n /** The tool's name. Default `\"browser\"`. */\n name?: TName;\n /**\n * Which calls share an active tab: a string for every call, or a function\n * of the call. Defaults to `conversation:<id>` for the calling\n * conversation, so each\n * conversation (and each fork or subagent) on the Durable Object keeps its\n * own tab, while cookies and logins stay shared.\n */\n scope?: string | ((api: ToolExecutionApi) => string);\n}\n\nconst browserToolParameters = Type.Object({\n code: Type.String({\n description: \"An async arrow function that drives the browser with `cdp`\"\n })\n});\n\n/**\n * What a UI can show about a run without reading the content: the run's\n * outcome and what happened to the browser.\n */\nexport type PiBrowserToolDetails = {\n executionId: string;\n status: BrowserToolOutput[\"status\"];\n restarted?: true;\n newTabs?: { targetId: string; url?: string; title?: string }[];\n};\n\nexport type PiBrowserTool<TName extends string = \"browser\"> = ToolRegistration<\n typeof browserToolParameters,\n PiBrowserToolDetails\n> & {\n readonly name: TName;\n};\n\nfunction details(output: BrowserToolOutput): PiBrowserToolDetails {\n return {\n executionId: output.executionId,\n status: output.status,\n ...(output.restarted ? { restarted: true as const } : {}),\n ...(output.newTabs\n ? {\n newTabs: output.newTabs.map((tab: BrowserNewTab) => ({\n targetId: tab.targetId,\n ...(tab.url === undefined ? {} : { url: tab.url }),\n ...(tab.title === undefined ? {} : { title: tab.title })\n }))\n }\n : {})\n };\n}\n\nfunction text(value: unknown): TextContent {\n return {\n type: \"text\",\n text: typeof value === \"string\" ? value : JSON.stringify(value)\n };\n}\n\n/**\n * The tool result pi stores and sends: the model projection of the run as\n * JSON (no `calls` log, bounded `logs`), and a screenshot as an image part\n * after it. pi-ai only sends the image to models that accept images.\n */\nfunction browserToolResult(\n output: BrowserToolOutput\n): ToolExecutionResult<PiBrowserToolDetails> {\n const isError = output.status === \"error\";\n const screenshot = browserScreenshotOutput(output);\n if (!screenshot) {\n return {\n output: [text(browserExecuteModelOutput(output).value)],\n details: details(output),\n ...(isError ? { isError } : {})\n };\n }\n\n // No size check: a screenshot comes from one cdp.send result, which\n // codemode caps at 1 MB, well under what model providers accept.\n const bytes = Math.floor((screenshot.data.length * 3) / 4).toLocaleString();\n // Keep the rest of the result (status, restarted, notice, newTabs) around\n // the sentence that replaces the screenshot.\n const summary = browserExecuteModelOutput({\n ...output,\n result: `Screenshot attached as an image (${screenshot.mediaType}, approximately ${bytes} bytes). If you can't see it, read the page with Runtime.evaluate instead.`\n }).value;\n const image: ImageContent = {\n type: \"image\",\n data: screenshot.data,\n mimeType: screenshot.mediaType\n };\n return {\n output: [text(summary), image],\n details: details(output)\n };\n}\n\nfunction conversationScope(api: ToolExecutionApi): string {\n return `conversation:${api.conversationId}`;\n}\n\n/**\n * Create a pi-durable tool that lets the model drive a persistent browser\n * with JavaScript and the Chrome DevTools Protocol.\n *\n * Works like `browserTool` in `agents/browser/ai-sdk`: tabs, cookies, and\n * logins carry over between runs, `sessionId: \"active\"` addresses the tab the\n * model last worked in, and a replaced browser is reported as\n * `restarted: true`. A returned screenshot comes back as an image part that\n * the model sees, when its model accepts images.\n *\n * Each conversation gets its own active tab (see\n * {@link PiBrowserToolOptions.scope}). A conversation's calls run one at a\n * time, since they share its tab, and the tool doesn't rerun after an\n * eviction (its code may have clicked or\n * submitted something): pi gives the model an interrupted result instead.\n * Pass `ctx` unless the tool is built inside an Agent.\n *\n * @example\n * ```ts\n * import { Browser, browserRun } from \"agents/browser\";\n * import { browserTool } from \"agents/browser/pi\";\n *\n * export class MyAgent extends DurableObject<Env> {\n * readonly browser = new Browser({ provider: browserRun(this.env.BROWSER) });\n * readonly registry = createRegistry();\n * readonly harness = new PiHarness({\n * harness: ({ storage, context, onWake }) => {\n * this.registry.install({\n * name: \"browser\",\n * tools: [\n * browserTool({\n * ctx: this.ctx,\n * browser: this.browser,\n * loader: this.env.LOADER\n * })\n * ]\n * });\n * return Harness.open(\n * storage,\n * { models, registry: this.registry, onWake },\n * context\n * );\n * }\n * });\n * readonly lifecycle = Lifecycle.install(this)\n * .use(this.browser)\n * .use(this.harness);\n * }\n * ```\n */\nexport function browserTool<TName extends string = \"browser\">(\n options: PiBrowserToolOptions<TName>\n): PiBrowserTool<TName> {\n const { scope = conversationScope, ...coreOptions } = options;\n const core = createBrowserToolCore(coreOptions, {\n screenshotHint:\n \"To see a screenshot, return { type: 'browser_screenshot', mediaType, data } with data from Page.captureScreenshot and mediaType 'image/png', or 'image/jpeg' if you captured with format: 'jpeg'. The image is attached to the result.\"\n });\n return {\n name: options.name ?? (\"browser\" as TName),\n description: core.description,\n parameters: browserToolParameters,\n // A conversation's calls share its tab, so they must not interleave.\n executionMode: \"sequential\",\n // The code may have clicked or submitted something; don't run it twice.\n replay: \"unsafe\",\n async execute(args, api) {\n const callScope = typeof scope === \"string\" ? scope : scope(api);\n return browserToolResult(\n await core.execute({ code: args.code }, callScope)\n );\n }\n };\n}\n"],"mappings":";;;;AA2CA,MAAM,wBAAwB,KAAK,OAAO,EACxC,MAAM,KAAK,OAAO,EAChB,aAAa,6DACf,CAAC,EACH,CAAC;AAoBD,SAAS,QAAQ,QAAiD;CAChE,OAAO;EACL,aAAa,OAAO;EACpB,QAAQ,OAAO;EACf,GAAI,OAAO,YAAY,EAAE,WAAW,KAAc,IAAI,CAAC;EACvD,GAAI,OAAO,UACP,EACE,SAAS,OAAO,QAAQ,KAAK,SAAwB;GACnD,UAAU,IAAI;GACd,GAAI,IAAI,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI;GAChD,GAAI,IAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,IAAI,MAAM;EACxD,EAAE,EACJ,IACA,CAAC;CACP;AACF;AAEA,SAAS,KAAK,OAA6B;CACzC,OAAO;EACL,MAAM;EACN,MAAM,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;CAChE;AACF;;;;;;AAOA,SAAS,kBACP,QAC2C;CAC3C,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,aAAa,wBAAwB,MAAM;CACjD,IAAI,CAAC,YACH,OAAO;EACL,QAAQ,CAAC,KAAK,0BAA0B,MAAM,CAAC,CAAC,KAAK,CAAC;EACtD,SAAS,QAAQ,MAAM;EACvB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC/B;CAKF,MAAM,QAAQ,KAAK,MAAO,WAAW,KAAK,SAAS,IAAK,CAAC,CAAC,CAAC,eAAe;CAG1E,MAAM,UAAU,0BAA0B;EACxC,GAAG;EACH,QAAQ,oCAAoC,WAAW,UAAU,kBAAkB,MAAM;CAC3F,CAAC,CAAC,CAAC;CACH,MAAM,QAAsB;EAC1B,MAAM;EACN,MAAM,WAAW;EACjB,UAAU,WAAW;CACvB;CACA,OAAO;EACL,QAAQ,CAAC,KAAK,OAAO,GAAG,KAAK;EAC7B,SAAS,QAAQ,MAAM;CACzB;AACF;AAEA,SAAS,kBAAkB,KAA+B;CACxD,OAAO,gBAAgB,IAAI;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,YACd,SACsB;CACtB,MAAM,EAAE,QAAQ,mBAAmB,GAAG,gBAAgB;CACtD,MAAM,OAAO,sBAAsB,aAAa,EAC9C,gBACE,yOACJ,CAAC;CACD,OAAO;EACL,MAAM,QAAQ,QAAS;EACvB,aAAa,KAAK;EAClB,YAAY;EAEZ,eAAe;EAEf,QAAQ;EACR,MAAM,QAAQ,MAAM,KAAK;GACvB,MAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,MAAM,GAAG;GAC/D,OAAO,kBACL,MAAM,KAAK,QAAQ,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,CACnD;EACF;CACF;AACF"}
1
+ {"version":3,"file":"pi.js","names":[],"sources":["../../../src/browser/tools/pi.ts"],"sourcesContent":["import {\n Type,\n type ImageContent,\n type TextContent\n} from \"@earendil-works/pi-ai\";\nimport type {\n ToolExecutionApi,\n ToolExecutionResult,\n ToolRegistration\n} from \"@earendil-works/pi-durable\";\nimport {\n createBrowserToolCore,\n type BrowserToolOptions,\n type BrowserToolOutput\n} from \"../browser-tool\";\nimport {\n browserExecuteModelOutput,\n browserScreenshotOutput\n} from \"../tool-helpers\";\n\nexport type {\n BrowserToolInput,\n BrowserToolOptions,\n BrowserToolOutput\n} from \"../browser-tool\";\nexport type { BrowserNewTab, BrowserSource } from \"../session\";\n\nexport interface PiBrowserToolOptions<\n TName extends string = \"browser\"\n> extends Omit<BrowserToolOptions, \"scope\"> {\n /** The tool's name. Default `\"browser\"`. */\n name?: TName;\n /**\n * Which calls share an active tab: a string for every call, or a function\n * of the call. Defaults to `conversation:<id>` for the calling\n * conversation, so each\n * conversation (and each fork or subagent) on the Durable Object keeps its\n * own tab, while cookies and logins stay shared.\n */\n scope?: string | ((api: ToolExecutionApi) => string);\n}\n\nconst browserToolParameters = Type.Object({\n code: Type.String({\n description:\n \"An async arrow function that drives the browser with `browser`\"\n })\n});\n\n/**\n * What a UI can show about a run without reading the content: its id and\n * outcome.\n */\nexport type PiBrowserToolDetails = {\n executionId: string;\n status: BrowserToolOutput[\"status\"];\n};\n\nexport type PiBrowserTool<TName extends string = \"browser\"> = ToolRegistration<\n typeof browserToolParameters,\n PiBrowserToolDetails\n> & {\n readonly name: TName;\n};\n\nfunction details(output: BrowserToolOutput): PiBrowserToolDetails {\n return {\n executionId: output.executionId,\n status: output.status\n };\n}\n\nfunction text(value: unknown): TextContent {\n return {\n type: \"text\",\n text: typeof value === \"string\" ? value : JSON.stringify(value)\n };\n}\n\n/**\n * The tool result pi stores and sends: the model projection of the run as\n * JSON (no `calls` log, bounded `logs`), and a screenshot as an image part\n * after it. pi-ai only sends the image to models that accept images.\n */\nfunction browserToolResult(\n output: BrowserToolOutput\n): ToolExecutionResult<PiBrowserToolDetails> {\n const isError = output.status === \"error\";\n const screenshot = browserScreenshotOutput(output);\n if (!screenshot) {\n return {\n output: [text(browserExecuteModelOutput(output).value)],\n details: details(output),\n ...(isError ? { isError } : {})\n };\n }\n\n // No size check: browserScreenshotOutput only accepts images up to 1 MB,\n // well under what model providers accept.\n const bytes = Math.floor((screenshot.data.length * 3) / 4).toLocaleString();\n // Keep the rest of the result (status, notice) around\n // the sentence that replaces the screenshot.\n const summary = browserExecuteModelOutput({\n ...output,\n result: `Screenshot attached as an image (${screenshot.mediaType}, approximately ${bytes} bytes). If you can't see it, read the page with Runtime.evaluate instead.`\n }).value;\n const image: ImageContent = {\n type: \"image\",\n data: screenshot.data,\n mimeType: screenshot.mediaType\n };\n return {\n output: [text(summary), image],\n details: details(output)\n };\n}\n\nfunction conversationScope(api: ToolExecutionApi): string {\n return `conversation:${api.conversationId}`;\n}\n\n/**\n * Create a pi-durable tool that lets the model drive a persistent browser\n * with JavaScript and the Chrome DevTools Protocol.\n *\n * Works like `browserTool` in `agents/browser/ai-sdk`: tabs, cookies, and\n * logins carry over between runs, `sessionId: \"active\"` addresses the tab the\n * model last worked in, and a replaced browser is reported in the\n * result's `notice`. A returned screenshot comes back as an image part that\n * the model sees, when its model accepts images.\n *\n * Each conversation gets its own active tab (see\n * {@link PiBrowserToolOptions.scope}). A conversation's calls run one at a\n * time, since they share its tab, and the tool doesn't rerun after an\n * eviction (its code may have clicked or\n * submitted something): pi gives the model an interrupted result instead.\n *\n * @example\n * ```ts\n * import { Browser, browserRun } from \"agents/browser\";\n * import { browserTool } from \"agents/browser/pi\";\n *\n * export class MyAgent extends DurableObject<Env> {\n * readonly browser = new Browser({ provider: browserRun(this.env.BROWSER) });\n * readonly registry = createRegistry();\n * readonly harness = new PiHarness({\n * harness: ({ storage, context, onWake }) => {\n * this.registry.install({\n * name: \"browser\",\n * tools: [\n * browserTool({\n * browser: this.browser,\n * loader: this.env.LOADER\n * })\n * ]\n * });\n * return Harness.open(\n * storage,\n * { models, registry: this.registry, onWake },\n * context\n * );\n * }\n * });\n * readonly lifecycle = Lifecycle.install(this)\n * .use(this.browser)\n * .use(this.harness);\n * }\n * ```\n */\nexport function browserTool<TName extends string = \"browser\">(\n options: PiBrowserToolOptions<TName>\n): PiBrowserTool<TName> {\n const { scope = conversationScope, ...coreOptions } = options;\n const core = createBrowserToolCore(coreOptions, {\n screenshotHint:\n \"To see a screenshot, return { type: 'browser_screenshot', mediaType, data } with data from Page.captureScreenshot and mediaType 'image/png', or 'image/jpeg' if you captured with format: 'jpeg'. The image is attached to the result.\"\n });\n return {\n name: options.name ?? (\"browser\" as TName),\n description: core.description,\n parameters: browserToolParameters,\n // A conversation's calls share its tab, so they must not interleave.\n executionMode: \"sequential\",\n // The code may have clicked or submitted something; don't run it twice.\n replay: \"unsafe\",\n async execute(args, api) {\n const callScope = typeof scope === \"string\" ? scope : scope(api);\n return browserToolResult(\n await core.execute({ code: args.code }, callScope)\n );\n }\n };\n}\n"],"mappings":";;;;AA0CA,MAAM,wBAAwB,KAAK,OAAO,EACxC,MAAM,KAAK,OAAO,EAChB,aACE,iEACJ,CAAC,EACH,CAAC;AAkBD,SAAS,QAAQ,QAAiD;CAChE,OAAO;EACL,aAAa,OAAO;EACpB,QAAQ,OAAO;CACjB;AACF;AAEA,SAAS,KAAK,OAA6B;CACzC,OAAO;EACL,MAAM;EACN,MAAM,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;CAChE;AACF;;;;;;AAOA,SAAS,kBACP,QAC2C;CAC3C,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,aAAa,wBAAwB,MAAM;CACjD,IAAI,CAAC,YACH,OAAO;EACL,QAAQ,CAAC,KAAK,0BAA0B,MAAM,CAAC,CAAC,KAAK,CAAC;EACtD,SAAS,QAAQ,MAAM;EACvB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC/B;CAKF,MAAM,QAAQ,KAAK,MAAO,WAAW,KAAK,SAAS,IAAK,CAAC,CAAC,CAAC,eAAe;CAG1E,MAAM,UAAU,0BAA0B;EACxC,GAAG;EACH,QAAQ,oCAAoC,WAAW,UAAU,kBAAkB,MAAM;CAC3F,CAAC,CAAC,CAAC;CACH,MAAM,QAAsB;EAC1B,MAAM;EACN,MAAM,WAAW;EACjB,UAAU,WAAW;CACvB;CACA,OAAO;EACL,QAAQ,CAAC,KAAK,OAAO,GAAG,KAAK;EAC7B,SAAS,QAAQ,MAAM;CACzB;AACF;AAEA,SAAS,kBAAkB,KAA+B;CACxD,OAAO,gBAAgB,IAAI;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,YACd,SACsB;CACtB,MAAM,EAAE,QAAQ,mBAAmB,GAAG,gBAAgB;CACtD,MAAM,OAAO,sBAAsB,aAAa,EAC9C,gBACE,yOACJ,CAAC;CACD,OAAO;EACL,MAAM,QAAQ,QAAS;EACvB,aAAa,KAAK;EAClB,YAAY;EAEZ,eAAe;EAEf,QAAQ;EACR,MAAM,QAAQ,MAAM,KAAK;GACvB,MAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,MAAM,GAAG;GAC/D,OAAO,kBACL,MAAM,KAAK,QAAQ,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,CACnD;EACF;CACF;AACF"}