agents 0.16.2 → 0.17.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 (122) hide show
  1. package/README.md +11 -8
  2. package/dist/{agent-tool-types-CTw3UJUP.d.ts → agent-tool-types-Cd1TZPfB.d.ts} +587 -137
  3. package/dist/agent-tool-types.d.ts +34 -18
  4. package/dist/agent-tool-types.js +20 -1
  5. package/dist/agent-tool-types.js.map +1 -0
  6. package/dist/agent-tools-BXlsuX0d.js +304 -0
  7. package/dist/agent-tools-BXlsuX0d.js.map +1 -0
  8. package/dist/agent-tools-_E8wxUIK.d.ts +119 -0
  9. package/dist/agent-tools.d.ts +24 -18
  10. package/dist/agent-tools.js.map +1 -1
  11. package/dist/ai-chat-agent.d.ts +1 -1
  12. package/dist/ai-chat-agent.js +1 -2
  13. package/dist/ai-chat-agent.js.map +1 -1
  14. package/dist/ai-chat-v5-migration.d.ts +1 -1
  15. package/dist/ai-chat-v5-migration.js +1 -2
  16. package/dist/ai-chat-v5-migration.js.map +1 -1
  17. package/dist/ai-react.d.ts +1 -1
  18. package/dist/ai-react.js +1 -2
  19. package/dist/ai-react.js.map +1 -1
  20. package/dist/ai-types.d.ts +1 -7
  21. package/dist/ai-types.js +2 -8
  22. package/dist/ai-types.js.map +1 -1
  23. package/dist/browser/ai.js +1 -1
  24. package/dist/browser/index.js +1 -1
  25. package/dist/chat/index.d.ts +1918 -72
  26. package/dist/chat/index.js +1730 -245
  27. package/dist/chat/index.js.map +1 -1
  28. package/dist/chat/react.d.ts +602 -0
  29. package/dist/chat/react.js +1506 -0
  30. package/dist/chat/react.js.map +1 -0
  31. package/dist/chat-sdk/index.d.ts +4 -4
  32. package/dist/{classPrivateFieldGet2-CZ7QjTXN.js → classPrivateFieldGet2-DZBYAB34.js} +5 -5
  33. package/dist/{classPrivateMethodInitSpec-D-0__zd9.js → classPrivateMethodInitSpec-qMjJ6sHQ.js} +2 -2
  34. package/dist/{client-BXJ9n2f7.js → client-BZ-B3NhC.js} +2 -2
  35. package/dist/client-BZ-B3NhC.js.map +1 -0
  36. package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
  37. package/dist/client.d.ts +76 -57
  38. package/dist/client.js +33 -5
  39. package/dist/client.js.map +1 -1
  40. package/dist/{connector-CrKhowfD.js → connector-CdldGF3h.js} +5 -5
  41. package/dist/{connector-CrKhowfD.js.map → connector-CdldGF3h.js.map} +1 -1
  42. package/dist/email.js +1 -1
  43. package/dist/email.js.map +1 -1
  44. package/dist/{index-B7IbEeze.d.ts → index-CcbnKkNh.d.ts} +188 -14
  45. package/dist/index.d.ts +91 -71
  46. package/dist/index.js +562 -24
  47. package/dist/index.js.map +1 -1
  48. package/dist/mcp/client.d.ts +18 -14
  49. package/dist/mcp/client.js +1 -1
  50. package/dist/mcp/index.d.ts +30 -30
  51. package/dist/mcp/index.js +7 -7
  52. package/dist/mcp/index.js.map +1 -1
  53. package/dist/{agent-tools-3zLG7MgA.js → message-builder-BymO4N_D.js} +45 -126
  54. package/dist/message-builder-BymO4N_D.js.map +1 -0
  55. package/dist/observability/index.d.ts +1 -1
  56. package/dist/observability/index.js +4 -2
  57. package/dist/observability/index.js.map +1 -1
  58. package/dist/react.d.ts +123 -110
  59. package/dist/react.js +44 -11
  60. package/dist/react.js.map +1 -1
  61. package/dist/serializable.d.ts +1 -1
  62. package/dist/skills/compile.js +1 -1
  63. package/dist/skills/compile.js.map +1 -1
  64. package/dist/skills/index.js +5 -5
  65. package/dist/skills/index.js.map +1 -1
  66. package/dist/sub-routing.d.ts +6 -6
  67. package/dist/utils.js +1 -1
  68. package/dist/utils.js.map +1 -1
  69. package/dist/vite.js +5 -5
  70. package/dist/vite.js.map +1 -1
  71. package/dist/wire-types-nflOzNuU.js +240 -0
  72. package/dist/wire-types-nflOzNuU.js.map +1 -0
  73. package/dist/{workflow-types-SrZK_o9p.d.ts → workflow-types-Baz_PO5v.d.ts} +42 -22
  74. package/dist/workflow-types.d.ts +25 -21
  75. package/dist/workflow-types.js.map +1 -1
  76. package/dist/workflows.d.ts +22 -21
  77. package/dist/workflows.js +31 -7
  78. package/dist/workflows.js.map +1 -1
  79. package/docs/adding-to-existing-project.md +450 -0
  80. package/docs/agent-class.md +503 -0
  81. package/docs/agent-tools.md +552 -0
  82. package/docs/browse-the-web.md +430 -0
  83. package/docs/callable-methods.md +627 -0
  84. package/docs/chat-agents.md +1687 -0
  85. package/docs/chat-sdk.md +181 -0
  86. package/docs/client-sdk.md +520 -0
  87. package/docs/client-tools-continuation.md +177 -0
  88. package/docs/codemode.md +440 -0
  89. package/docs/configuration.md +775 -0
  90. package/docs/cross-domain-authentication.md +171 -0
  91. package/docs/durable-execution.md +537 -0
  92. package/docs/email.md +663 -0
  93. package/docs/get-current-agent.md +204 -0
  94. package/docs/getting-started.md +305 -0
  95. package/docs/http-websockets.md +668 -0
  96. package/docs/human-in-the-loop.md +661 -0
  97. package/docs/index.md +151 -0
  98. package/docs/long-running-agents.md +730 -0
  99. package/docs/mcp-client.md +620 -0
  100. package/docs/mcp-servers.md +526 -0
  101. package/docs/mcp-transports.md +308 -0
  102. package/docs/migration-to-ai-sdk-v5.md +96 -0
  103. package/docs/migration-to-ai-sdk-v6.md +163 -0
  104. package/docs/observability.md +261 -0
  105. package/docs/push-notifications.md +367 -0
  106. package/docs/queue.md +329 -0
  107. package/docs/readonly-connections.md +278 -0
  108. package/docs/resumable-streaming.md +127 -0
  109. package/docs/retries.md +444 -0
  110. package/docs/routing.md +749 -0
  111. package/docs/scheduling.md +898 -0
  112. package/docs/securing-mcp-servers.md +359 -0
  113. package/docs/server-driven-messages.md +477 -0
  114. package/docs/sessions.md +1024 -0
  115. package/docs/state.md +512 -0
  116. package/docs/sub-agents.md +389 -0
  117. package/docs/webhooks.md +604 -0
  118. package/docs/workflows.md +877 -0
  119. package/package.json +41 -14
  120. package/dist/agent-tools-3zLG7MgA.js.map +0 -1
  121. package/dist/agent-tools-DZhI5F6Q.d.ts +0 -14
  122. package/dist/client-BXJ9n2f7.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"connector-CrKhowfD.js","names":[],"sources":["../src/browser/cdp-session.ts","../src/browser/browser-run.ts","../src/browser/quick-actions.ts","../src/browser/spec.ts","../src/browser/session-manager.ts","../src/browser/connector.ts"],"sourcesContent":["interface PendingCommand {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n method: string;\n sessionId?: string;\n startedAt: number;\n}\n\ninterface DebugEntry {\n at: string;\n type: string;\n [key: string]: unknown;\n}\n\nexport interface CdpSendOptions {\n timeoutMs?: number;\n sessionId?: string;\n}\n\nexport interface CdpAttachOptions {\n timeoutMs?: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst MAX_DEBUG_ENTRIES = 400;\n\n/**\n * A CDP session over an open WebSocket. Manages command correlation,\n * timeouts, target sessions, and a debug event ring buffer.\n *\n * Used host-side (not in the sandbox) — the sandbox calls into this\n * via DynamicWorkerExecutor's ToolDispatcher RPC.\n */\nexport class CdpSession {\n #socket: WebSocket;\n #nextId = 1;\n #pending = new Map<number, PendingCommand>();\n #debugLog: DebugEntry[] = [];\n #defaultTimeoutMs: number;\n #dispose?: () => void;\n readonly sessionId?: string;\n\n constructor(\n socket: WebSocket,\n defaultTimeoutMs = DEFAULT_TIMEOUT_MS,\n dispose?: () => void,\n sessionId?: string\n ) {\n this.#socket = socket;\n this.#defaultTimeoutMs = defaultTimeoutMs;\n this.#dispose = dispose;\n this.sessionId = sessionId;\n\n socket.addEventListener(\"message\", (event) => this.#handleMessage(event));\n socket.addEventListener(\"error\", () => {\n this.#rejectAll(new Error(\"CDP socket error\"));\n });\n socket.addEventListener(\"close\", () => {\n this.#rejectAll(new Error(\"CDP connection closed\"));\n });\n }\n\n send(\n method: string,\n params?: unknown,\n options: CdpSendOptions = {}\n ): Promise<unknown> {\n const id = this.#nextId++;\n const timeoutMs = options.timeoutMs ?? this.#defaultTimeoutMs;\n const sessionId =\n typeof options.sessionId === \"string\" && options.sessionId.length > 0\n ? options.sessionId\n : undefined;\n\n const domain = typeof method === \"string\" ? method.split(\".\")[0] : \"\";\n if (!sessionId && domain && ![\"Browser\", \"Target\"].includes(domain)) {\n this.#recordDebug(\"warning\", {\n id,\n method,\n reason: \"target-scoped method sent without sessionId\"\n });\n }\n\n const result = new Promise<unknown>((resolve, reject) => {\n const startedAt = performance.now();\n const timeoutId = setTimeout(() => {\n this.#pending.delete(id);\n reject(\n new Error(`CDP command timed out after ${timeoutMs}ms: ${method}`)\n );\n }, timeoutMs);\n this.#pending.set(id, {\n resolve,\n reject,\n timeoutId,\n method,\n sessionId,\n startedAt\n });\n });\n\n this.#recordDebug(\"send\", { id, method, sessionId, timeoutMs });\n this.#socket.send(JSON.stringify({ id, method, params, sessionId }));\n return result;\n }\n\n async attachToTarget(\n targetId: string,\n options: CdpAttachOptions = {}\n ): Promise<string> {\n if (typeof targetId !== \"string\" || !targetId) {\n throw new Error(\n \"attachToTarget requires a targetId — list open tabs with \" +\n \"send('Target.getTargets') or create one with \" +\n \"send('Target.createTarget', { url })\"\n );\n }\n\n const result = (await this.send(\n \"Target.attachToTarget\",\n {\n targetId,\n flatten: true\n },\n { timeoutMs: options.timeoutMs }\n )) as { sessionId?: string };\n\n const sessionId = result?.sessionId ?? \"\";\n if (!sessionId) {\n throw new Error(\n `Target.attachToTarget did not return a sessionId for target ${targetId}`\n );\n }\n\n this.#recordDebug(\"attach\", { targetId, sessionId });\n return sessionId;\n }\n\n getDebugLog(limit = 50): DebugEntry[] {\n const normalized = Number.isFinite(limit)\n ? Math.max(1, Math.floor(limit))\n : 50;\n return this.#debugLog.slice(-normalized);\n }\n\n clearDebugLog(): void {\n this.#debugLog = [];\n }\n\n disconnect(): void {\n this.#rejectAll(new Error(\"CDP session disconnected\"));\n try {\n this.#socket.close(1000, \"Done\");\n } catch {\n // socket may already be closed\n }\n }\n\n close(): void {\n this.disconnect();\n this.#dispose?.();\n }\n\n #rejectAll(error: Error): void {\n for (const [id, pending] of this.#pending.entries()) {\n clearTimeout(pending.timeoutId);\n this.#pending.delete(id);\n pending.reject(error);\n }\n }\n\n #handleMessage(event: MessageEvent): void {\n if (typeof event.data !== \"string\") {\n return;\n }\n\n let payload: Record<string, unknown>;\n try {\n payload = JSON.parse(event.data) as Record<string, unknown>;\n } catch {\n return;\n }\n\n this.#recordDebug(\"receive\", {\n id: payload.id,\n method: payload.method,\n sessionId: payload.sessionId,\n hasError: !!payload.error\n });\n\n if (typeof payload.id !== \"number\") {\n return;\n }\n\n const pending = this.#pending.get(payload.id);\n if (!pending) {\n return;\n }\n\n clearTimeout(pending.timeoutId);\n this.#pending.delete(payload.id);\n\n if (payload.error) {\n const err = payload.error as { code?: unknown; message?: string };\n const code = err.code ?? \"unknown\";\n const message = err.message ?? \"CDP error\";\n pending.reject(\n new Error(`CDP error ${code}: ${message} for ${pending.method}`)\n );\n return;\n }\n\n pending.resolve(payload.result);\n }\n\n #recordDebug(type: string, data: Record<string, unknown>): void {\n this.#debugLog.push({\n at: new Date().toISOString(),\n type,\n ...data\n });\n if (this.#debugLog.length > MAX_DEBUG_ENTRIES) {\n this.#debugLog.splice(0, this.#debugLog.length - MAX_DEBUG_ENTRIES);\n }\n }\n}\n\nconst LOCALHOST_HOSTS = new Set([\n \"localhost\",\n \"127.0.0.1\",\n \"0.0.0.0\",\n \"::1\",\n \"[::1]\"\n]);\n\n/**\n * Connect to a browser via a CDP base URL (e.g. http://localhost:9222).\n * Discovers the WebSocket debugger URL via /json/version,\n * rewrites localhost URLs to the base URL host, and opens the WebSocket.\n *\n * Useful for local development with `chrome --remote-debugging-port=9222`\n * or when connecting through a tunnel.\n */\nexport async function connectUrl(\n baseUrl: string,\n options?: { timeoutMs?: number; headers?: Record<string, string> }\n): Promise<CdpSession> {\n const endpoint = new URL(\"/json/version\", baseUrl).toString();\n const response = await fetch(endpoint, {\n headers: options?.headers\n });\n if (!response.ok) {\n throw new Error(\n `Failed to discover CDP endpoint at ${endpoint}: ${response.status}`\n );\n }\n\n const payload = (await response.json()) as {\n webSocketDebuggerUrl?: string;\n };\n if (!payload.webSocketDebuggerUrl) {\n throw new Error(\"CDP /json/version did not include webSocketDebuggerUrl\");\n }\n\n let wsUrl = payload.webSocketDebuggerUrl;\n const parsed = new URL(wsUrl);\n if (LOCALHOST_HOSTS.has(parsed.hostname)) {\n const base = new URL(baseUrl);\n parsed.hostname = base.hostname;\n parsed.port = base.port;\n parsed.protocol = base.protocol;\n } else {\n // Workers runtime requires fetch + Upgrade header for outbound WebSockets\n parsed.protocol = parsed.protocol === \"wss:\" ? \"https:\" : \"http:\";\n }\n const fetchUrl = parsed.toString();\n\n const wsResponse = await fetch(fetchUrl, {\n headers: { ...options?.headers, Upgrade: \"websocket\" }\n });\n const ws = wsResponse.webSocket;\n if (!ws) {\n throw new Error(\n `Failed to establish CDP WebSocket at ${fetchUrl} (status ${wsResponse.status})`\n );\n }\n ws.accept();\n\n return new CdpSession(ws, options?.timeoutMs);\n}\n","import { CdpSession } from \"./cdp-session\";\n\n/**\n * A Browser Rendering binding. Structural so it accepts both the classic\n * `Fetcher`-typed binding and the newer `BrowserRun` type generated by\n * `wrangler types` — we only ever use its `fetch` surface.\n */\nexport interface BrowserBinding {\n fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n}\n\nexport interface BrowserTargetInfo {\n id: string;\n type?: string;\n url?: string;\n title?: string;\n description?: string;\n devtoolsFrontendUrl?: string;\n webSocketDebuggerUrl?: string;\n}\n\nexport interface BrowserSessionInfo {\n sessionId: string;\n targets?: BrowserTargetInfo[];\n webSocketDebuggerUrl?: string;\n}\n\nexport interface ConnectBrowserOptions {\n timeoutMs?: number;\n keepAliveMs?: number;\n includeTargets?: boolean;\n /**\n * Opt into Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/):\n * an rrweb capture of DOM changes, input, and navigation, finalized when the\n * session closes. Set at session-launch time. Retrieve later with\n * {@link getBrowserRecording}.\n */\n recording?: boolean;\n}\n\n/** An rrweb session recording for a closed Browser Run session. */\nexport interface BrowserRecording {\n sessionId: string;\n /** Recording length in milliseconds. */\n duration: number;\n /**\n * rrweb event arrays keyed by CDP target id (one per tab). Each value can be\n * passed directly to `rrweb-player` to replay that tab.\n */\n events: Record<string, unknown[]>;\n}\n\nexport class BrowserRenderingError extends Error {\n constructor(\n message: string,\n readonly status: number\n ) {\n super(message);\n this.name = \"BrowserRenderingError\";\n }\n}\n\nfunction browserSessionEndpoint(\n sessionId?: string,\n options?: {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n }\n): string {\n const path = sessionId\n ? `/v1/devtools/browser/${sessionId}`\n : \"/v1/devtools/browser\";\n const url = new URL(`https://localhost${path}`);\n\n if (options?.keepAliveMs !== undefined) {\n url.searchParams.set(\"keep_alive\", String(options.keepAliveMs));\n }\n if (options?.includeTargets) {\n url.searchParams.set(\"targets\", \"true\");\n }\n if (options?.recording) {\n url.searchParams.set(\"recording\", \"true\");\n }\n\n return url.toString();\n}\n\nasync function parseBrowserSessionInfo(\n response: Response\n): Promise<BrowserSessionInfo> {\n const payload = (await response.json()) as {\n sessionId?: unknown;\n targets?: unknown;\n webSocketDebuggerUrl?: unknown;\n };\n const sessionId =\n typeof payload.sessionId === \"string\" ? payload.sessionId : \"\";\n\n if (!sessionId) {\n throw new Error(\"Browser Rendering response did not include a sessionId\");\n }\n\n return {\n sessionId,\n targets: Array.isArray(payload.targets)\n ? (payload.targets as BrowserTargetInfo[])\n : undefined,\n webSocketDebuggerUrl:\n typeof payload.webSocketDebuggerUrl === \"string\"\n ? payload.webSocketDebuggerUrl\n : undefined\n };\n}\n\nexport async function createBrowserSession(\n browser: BrowserBinding,\n options?: {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n }\n): Promise<BrowserSessionInfo> {\n const response = await browser.fetch(\n browserSessionEndpoint(undefined, options),\n { method: \"POST\" }\n );\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to create Browser Rendering session: ${response.status}`,\n response.status\n );\n }\n\n return parseBrowserSessionInfo(response);\n}\n\nexport async function listBrowserTargets(\n browser: BrowserBinding,\n sessionId: string\n): Promise<BrowserTargetInfo[]> {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}/json/list`\n );\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to list Browser Rendering targets for ${sessionId}: ${response.status}`,\n response.status\n );\n }\n\n const payload = (await response.json()) as unknown;\n return Array.isArray(payload) ? (payload as BrowserTargetInfo[]) : [];\n}\n\nexport async function deleteBrowserSession(\n browser: BrowserBinding,\n sessionId: string\n): Promise<void> {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}`,\n { method: \"DELETE\" }\n );\n\n if (!response.ok && response.status !== 404) {\n throw new BrowserRenderingError(\n `Failed to delete Browser Rendering session ${sessionId}: ${response.status}`,\n response.status\n );\n }\n}\n\n/**\n * Connect to a Browser Rendering session and delete it when closed.\n */\nexport async function connectBrowser(\n browser: BrowserBinding,\n options?: number | ConnectBrowserOptions\n): Promise<CdpSession> {\n const normalizedOptions =\n typeof options === \"number\" ? { timeoutMs: options } : (options ?? {});\n const response = await browser.fetch(\n browserSessionEndpoint(undefined, {\n keepAliveMs: normalizedOptions.keepAliveMs,\n includeTargets: normalizedOptions.includeTargets,\n recording: normalizedOptions.recording\n }),\n { headers: { Upgrade: \"websocket\" } }\n );\n\n const ws = response.webSocket;\n if (!ws) {\n throw new Error(\n \"Browser Rendering binding did not return a WebSocket. \" +\n \"Ensure the 'browser' binding is configured in wrangler.jsonc.\"\n );\n }\n\n const sessionId = response.headers.get(\"cf-browser-session-id\");\n if (!sessionId) {\n throw new Error(\n \"Browser Rendering binding did not include a session ID when opening the CDP WebSocket\"\n );\n }\n\n ws.accept();\n return new CdpSession(\n ws,\n normalizedOptions.timeoutMs,\n () => {\n deleteBrowserSession(browser, sessionId).catch((error: unknown) => {\n console.warn(\n `[agents/browser] Failed to delete one-shot Browser Run session ${sessionId}`,\n error\n );\n });\n },\n sessionId\n );\n}\n\n/**\n * Fetch a Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/)\n * by session id, via the Browser Rendering REST API.\n *\n * A recording is only available **after** the session closes (explicit\n * `closeSession()`, idle `keep_alive` expiry, or sweep) and is retained for 30\n * days. Capture the session id while the session is alive — e.g. from\n * `connector.liveView()`/`sessionInfo()` — then call this once it has ended.\n *\n * Unlike the binding-based helpers, this hits `api.cloudflare.com` directly, so\n * it needs an account id and an API token with `Browser Rendering` read access\n * (the Workers Browser Run binding cannot read recordings).\n */\nexport async function getBrowserRecording(options: {\n accountId: string;\n apiToken: string;\n sessionId: string;\n /** Override for testing; defaults to the global `fetch`. */\n fetchImpl?: typeof fetch;\n}): Promise<BrowserRecording> {\n const { accountId, apiToken, sessionId } = options;\n const fetchImpl = options.fetchImpl ?? fetch;\n const endpoint = `https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/recording/${sessionId}`;\n\n const response = await fetchImpl(endpoint, {\n headers: { Authorization: `Bearer ${apiToken}` }\n });\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to fetch Browser Run recording for ${sessionId}: ${response.status}`,\n response.status\n );\n }\n\n // The recording endpoint returns the recording object directly; tolerate a\n // standard v4 `{ result }` envelope in case that changes.\n const payload = (await response.json()) as\n | BrowserRecording\n | { result?: BrowserRecording };\n const recording =\n \"result\" in payload && payload.result ? payload.result : payload;\n\n return recording as BrowserRecording;\n}\n\n/**\n * Connect to an existing Browser Rendering session without deleting it on close.\n */\nexport async function connectBrowserSession(\n browser: BrowserBinding,\n sessionId: string,\n timeoutMs?: number\n): Promise<CdpSession> {\n const response = await browser.fetch(browserSessionEndpoint(sessionId), {\n headers: { Upgrade: \"websocket\" }\n });\n\n const ws = response.webSocket;\n if (!ws) {\n throw new Error(\n `Browser Rendering binding did not return a WebSocket for session ${sessionId}`\n );\n }\n\n ws.accept();\n return new CdpSession(ws, timeoutMs, undefined, sessionId);\n}\n","import { BrowserRenderingError } from \"./browser-run\";\n\n/**\n * A Browser Run binding that supports [Quick Actions](https://developers.cloudflare.com/browser-run/quick-actions/).\n *\n * This is the `quickAction()` surface of the `BrowserRun` binding generated by\n * `wrangler types`. Quick Actions are stateless one-shot tasks (screenshot,\n * PDF, markdown, structured extraction, …) — no session, no token, just the\n * binding.\n *\n * Requires a Worker `compatibility_date` of `2026-03-24` or later, and\n * `remote: true` on the browser binding for local `wrangler dev`.\n */\nexport interface QuickActionBinding {\n // `options: unknown` (declared as a method, so parameters are checked\n // bivariantly) lets the real `BrowserRun` binding — whose `quickAction` is a\n // set of per-action typed overloads — satisfy this structural type.\n quickAction(action: string, options: unknown): Promise<Response>;\n}\n\n/** The Quick Action endpoints exposed by Browser Run. */\nexport type QuickAction =\n | \"content\"\n | \"screenshot\"\n | \"pdf\"\n | \"markdown\"\n | \"snapshot\"\n | \"scrape\"\n | \"json\"\n | \"links\"\n | \"crawl\";\n\ntype GotoOptions = {\n waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle0\" | \"networkidle2\";\n timeout?: number;\n};\n\n/** Options accepted by every Quick Action endpoint. */\nexport interface QuickActionCommonOptions {\n gotoOptions?: GotoOptions;\n viewport?: { width: number; height: number; deviceScaleFactor?: number };\n cookies?: unknown[];\n authenticate?: { username: string; password: string };\n setExtraHTTPHeaders?: Record<string, string>;\n userAgent?: string;\n /** Regex strings for requests to drop before render (e.g. `[\"/\\\\.css$/\"]`). */\n rejectRequestPattern?: string[];\n}\n\n/**\n * The page a Quick Action operates on: a `url` to load, or raw `html` to\n * render. Exactly one is required.\n */\nexport type QuickActionPage =\n | ({ url: string; html?: never } & QuickActionCommonOptions)\n | ({ html: string; url?: never } & QuickActionCommonOptions);\n\n/** Input for the AI-powered `/json` extraction endpoint. */\nexport type QuickActionExtractInput = QuickActionPage & {\n /** Natural-language instruction for what to extract. */\n prompt?: string;\n /** A JSON Schema describing the desired output shape. */\n response_format?: { type: \"json_schema\"; schema: unknown };\n /** Bring-your-own model(s), tried in order, for extraction. */\n custom_ai?: { model: string; authorization: string }[];\n};\n\n/** Input for the `/scrape` endpoint. */\nexport type QuickActionScrapeInput = QuickActionPage & {\n elements: { selector: string }[];\n};\n\n/** Input for the `/screenshot` endpoint. */\nexport type QuickActionScreenshotInput = QuickActionPage & {\n screenshotOptions?: Record<string, unknown>;\n selector?: string;\n};\n\n/** Binary output (screenshot or PDF) with its reported content type. */\nexport interface QuickActionBinary {\n data: Uint8Array;\n contentType: string;\n}\n\n/** Any Quick Action input accepted by the typed helpers. */\nexport type QuickActionInput =\n | QuickActionPage\n | QuickActionExtractInput\n | QuickActionScrapeInput\n | QuickActionScreenshotInput;\n\n/** Elements matched by one selector via `/scrape`. */\nexport interface QuickActionScrapeResult {\n selector: string;\n results: {\n html: string;\n text: string;\n width: number;\n height: number;\n top: number;\n left: number;\n attributes: { name: string; value: string }[];\n }[];\n}\n\n/** Result of a `/snapshot` request: rendered HTML plus a base64 screenshot. */\nexport interface QuickActionSnapshot {\n /** HTML content of the page. */\n content: string;\n /** Base64-encoded screenshot image. */\n screenshot: string;\n}\n\n/**\n * Run a Quick Action and return the raw {@link Response} from the binding.\n *\n * Most callers want a typed helper ({@link browserMarkdown},\n * {@link browserExtract}, …) instead; reach for this only when you need an\n * endpoint or option not yet wrapped. The per-action overloads type `params`\n * against the action when it is a string literal (e.g. `\"json\"` requires a\n * {@link QuickActionExtractInput}); any {@link QuickActionInput} is accepted\n * otherwise.\n */\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"json\",\n params: QuickActionExtractInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"scrape\",\n params: QuickActionScrapeInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"screenshot\",\n params: QuickActionScreenshotInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<Response> {\n return browser.quickAction(action, params);\n}\n\n/** Build an error that includes the service's explanation, if the body has one. */\nasync function quickActionError(\n action: QuickAction,\n response: Response\n): Promise<BrowserRenderingError> {\n let detail = \"\";\n try {\n const text = await response.text();\n try {\n const body = JSON.parse(text) as {\n errors?: { message?: string }[];\n rawAiResponse?: string;\n };\n const messages = (body.errors ?? [])\n .map((e) => e.message)\n .filter((m): m is string => Boolean(m));\n if (messages.length > 0) detail = `: ${messages.join(\"; \")}`;\n else if (body.rawAiResponse) detail = `: ${body.rawAiResponse}`;\n else if (text) detail = `: ${text.slice(0, 200)}`;\n } catch {\n if (text) detail = `: ${text.slice(0, 200)}`;\n }\n } catch {\n // Body unreadable — fall back to the status code alone.\n }\n return new BrowserRenderingError(\n `Browser Run ${action} failed (${response.status})${detail}`,\n response.status\n );\n}\n\nasync function quickActionJson<T>(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<T> {\n const response = await runQuickAction(browser, action, params);\n if (!response.ok) throw await quickActionError(action, response);\n const payload = (await response.json()) as {\n success?: boolean;\n result?: T;\n errors?: { message?: string }[];\n };\n if (payload.success === false || payload.result === undefined) {\n const messages = (payload.errors ?? [])\n .map((e) => e.message)\n .filter((m): m is string => Boolean(m));\n throw new BrowserRenderingError(\n `Browser Run ${action} returned no result${messages.length > 0 ? `: ${messages.join(\"; \")}` : \"\"}`,\n response.status\n );\n }\n return payload.result;\n}\n\nasync function quickActionBinary(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<QuickActionBinary> {\n const response = await runQuickAction(browser, action, params);\n if (!response.ok) throw await quickActionError(action, response);\n const buffer = await response.arrayBuffer();\n return {\n data: new Uint8Array(buffer),\n contentType:\n response.headers.get(\"content-type\") ?? \"application/octet-stream\"\n };\n}\n\n/** Fetch a page's fully rendered HTML via `/content`. */\nexport function browserContent(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string> {\n return quickActionJson<string>(browser, \"content\", input);\n}\n\n/** Convert a page (or raw HTML) to Markdown via `/markdown`. */\nexport function browserMarkdown(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string> {\n return quickActionJson<string>(browser, \"markdown\", input);\n}\n\n/**\n * Extract structured data from a page with AI via `/json`. Provide a `prompt`,\n * a `response_format` JSON Schema, or both.\n */\nexport function browserExtract<T = unknown>(\n browser: QuickActionBinding,\n input: QuickActionExtractInput\n): Promise<T> {\n return quickActionJson<T>(browser, \"json\", input);\n}\n\n/** Retrieve every link on a page via `/links`. */\nexport function browserLinks(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string[]> {\n return quickActionJson<string[]>(browser, \"links\", input);\n}\n\n/** Scrape specific elements (by CSS selector) via `/scrape`. */\nexport function browserScrape(\n browser: QuickActionBinding,\n input: QuickActionScrapeInput\n): Promise<QuickActionScrapeResult[]> {\n return quickActionJson<QuickActionScrapeResult[]>(browser, \"scrape\", input);\n}\n\n/** Capture rendered HTML plus a base64 screenshot in one request via `/snapshot`. */\nexport function browserSnapshot(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<QuickActionSnapshot> {\n return quickActionJson<QuickActionSnapshot>(browser, \"snapshot\", input);\n}\n\n/**\n * Render a screenshot via `/screenshot`. Returns the raw bytes and their\n * content type — by default a PNG (`image/png`). Note that passing\n * `screenshotOptions.encoding: \"base64\"` makes the service return a `text/plain`\n * data-URI string instead of binary, which this helper hands back verbatim.\n */\nexport function browserScreenshot(\n browser: QuickActionBinding,\n input: QuickActionScreenshotInput\n): Promise<QuickActionBinary> {\n return quickActionBinary(browser, \"screenshot\", input);\n}\n\n/** Render a PDF via `/pdf`. Returns the PDF bytes. */\nexport function browserPdf(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<QuickActionBinary> {\n return quickActionBinary(browser, \"pdf\", input);\n}\n","/**\n * Chrome DevTools Protocol spec fetching + caching.\n *\n * The raw `/json/protocol` payload is normalized into a searchable shape and\n * cached per source: `cdpUrl` specs by endpoint + headers, Browser Rendering\n * specs by the binding itself (a WeakMap) so two different bindings in the\n * same isolate don't share an entry. The CDP protocol is identical across\n * bindings, but per-binding keys avoid surprising cross-binding cache reads.\n */\n\nimport type { BrowserBinding } from \"./browser-run\";\n\ninterface RawCdpCommand {\n name: string;\n description?: string;\n}\n\ninterface RawCdpEvent {\n name: string;\n description?: string;\n}\n\ninterface RawCdpType {\n id: string;\n description?: string;\n}\n\n/** Raw CDP protocol domain from `/json/protocol` */\ninterface RawCdpDomain {\n domain: string;\n description?: string;\n commands?: RawCdpCommand[];\n events?: RawCdpEvent[];\n types?: RawCdpType[];\n}\n\nexport interface SearchableCdpSpec {\n domains: Array<{\n name: string;\n description?: string;\n commands: Array<{ name: string; method: string; description?: string }>;\n events: Array<{ name: string; event: string; description?: string }>;\n types: Array<{ id: string; name: string; description?: string }>;\n }>;\n}\n\nexport interface CdpSpecSource {\n /** Browser Rendering binding (Fetcher) — used in production */\n browser?: BrowserBinding;\n /** CDP base URL override (e.g. http://localhost:9222) */\n cdpUrl?: string;\n /** Headers to send with CDP URL discovery requests */\n cdpHeaders?: Record<string, string>;\n}\n\nconst MISSING_BROWSER_CONFIG =\n \"Either 'browser' (Fetcher binding) or 'cdpUrl' must be provided\";\n\ninterface SpecCacheEntry {\n spec: SearchableCdpSpec;\n cachedAt: number;\n}\n\nconst urlSpecCache = new Map<string, SpecCacheEntry>();\nconst bindingSpecCache = new WeakMap<BrowserBinding, SpecCacheEntry>();\n\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction normalizeCdpSpec(spec: {\n domains?: RawCdpDomain[];\n}): SearchableCdpSpec {\n return {\n domains: (spec.domains ?? []).map((domain) => ({\n name: domain.domain,\n description: domain.description,\n commands: (domain.commands ?? []).map((command) => ({\n name: command.name,\n method: `${domain.domain}.${command.name}`,\n description: command.description\n })),\n events: (domain.events ?? []).map((event) => ({\n name: event.name,\n event: `${domain.domain}.${event.name}`,\n description: event.description\n })),\n types: (domain.types ?? []).map((type) => ({\n id: type.id,\n name: `${domain.domain}.${type.id}`,\n description: type.description\n }))\n }))\n };\n}\n\nfunction getSpecCacheKey(\n source: string,\n headers?: Record<string, string>\n): string {\n const headerEntries = Object.entries(headers ?? {}).sort(([a], [b]) =>\n a.localeCompare(b)\n );\n return `${source}:${JSON.stringify(headerEntries)}`;\n}\n\nasync function getCachedSpec<K>(\n cache: {\n get(key: K): SpecCacheEntry | undefined;\n set(key: K, entry: SpecCacheEntry): void;\n },\n key: K,\n load: () => Promise<{ domains?: RawCdpDomain[] }>\n): Promise<SearchableCdpSpec> {\n const cached = cache.get(key);\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {\n return cached.spec;\n }\n\n const spec = normalizeCdpSpec(await load());\n cache.set(key, { spec, cachedAt: Date.now() });\n return spec;\n}\n\nasync function fetchCdpSpecFromUrl(\n cdpBaseUrl: string,\n headers?: Record<string, string>\n): Promise<SearchableCdpSpec> {\n const endpoint = new URL(\"/json/protocol\", cdpBaseUrl).toString();\n\n return getCachedSpec(\n urlSpecCache,\n getSpecCacheKey(endpoint, headers),\n async () => {\n const response = await fetch(endpoint, { headers });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch CDP spec from ${endpoint}: ${response.status}`\n );\n }\n\n return (await response.json()) as { domains?: RawCdpDomain[] };\n }\n );\n}\n\nasync function fetchCdpSpecFromBrowser(\n browser: BrowserBinding\n): Promise<SearchableCdpSpec> {\n return getCachedSpec(bindingSpecCache, browser, async () => {\n const createResponse = await browser.fetch(\n \"https://localhost/v1/devtools/browser\",\n {\n method: \"POST\"\n }\n );\n\n if (!createResponse.ok) {\n throw new Error(\n \"Failed to create Browser Rendering session for protocol fetch: \" +\n `${createResponse.status}`\n );\n }\n\n const payload = (await createResponse.json()) as { sessionId?: string };\n const sessionId = payload.sessionId;\n if (!sessionId) {\n throw new Error(\n \"Browser Rendering session response did not include a sessionId\"\n );\n }\n\n try {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}/json/protocol`\n );\n\n if (!response.ok) {\n throw new Error(\n \"Failed to fetch CDP spec from Browser Rendering: \" +\n `${response.status}`\n );\n }\n\n return (await response.json()) as { domains?: RawCdpDomain[] };\n } finally {\n try {\n await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}`,\n {\n method: \"DELETE\"\n }\n );\n } catch {\n // Cleanup failure should not mask the original result or error\n }\n }\n });\n}\n\n/** Load the (cached) searchable CDP spec for a browser source. */\nexport async function loadCdpSpec(\n source: CdpSpecSource\n): Promise<SearchableCdpSpec> {\n if (source.cdpUrl) {\n return fetchCdpSpecFromUrl(source.cdpUrl, source.cdpHeaders);\n }\n if (source.browser) {\n return fetchCdpSpecFromBrowser(source.browser);\n }\n throw new Error(MISSING_BROWSER_CONFIG);\n}\n","type MaybePromise<T> = T | Promise<T>;\n\nexport interface StoredBrowserSession {\n sessionId: string;\n createdAt: number;\n updatedAt: number;\n /**\n * Set when a sweep closed this entry's Browser Run session but kept the\n * entry as a tombstone, so a later resume of the owning execution fails\n * loudly instead of silently continuing in a fresh browser.\n */\n closedAt?: number;\n}\n\nexport interface BrowserSessionLock {\n release(): MaybePromise<void>;\n}\n\nexport interface BrowserSessionStore {\n /**\n * Acquire an exclusive lock for this session key. The lock must serialize\n * all holders using the same key. Held only around storage reads/writes —\n * never across Browser Rendering network calls.\n */\n acquireLock(key: string): MaybePromise<BrowserSessionLock>;\n get(key: string): MaybePromise<StoredBrowserSession | undefined>;\n set(key: string, session: StoredBrowserSession): MaybePromise<void>;\n delete(key: string): MaybePromise<void>;\n /**\n * List stored sessions by key prefix. Optional — used by sweeps to find\n * orphaned per-execution sessions; without it only the shared session key\n * is swept.\n */\n list?(prefix: string): MaybePromise<Map<string, StoredBrowserSession>>;\n}\n\nexport class DurableBrowserSessionStore implements BrowserSessionStore {\n static #queues = new WeakMap<\n DurableObjectStorage,\n Map<string, Promise<void>>\n >();\n\n constructor(private readonly storage: DurableObjectStorage) {}\n\n async acquireLock(key: string): Promise<BrowserSessionLock> {\n let queues = DurableBrowserSessionStore.#queues.get(this.storage);\n if (!queues) {\n queues = new Map();\n DurableBrowserSessionStore.#queues.set(this.storage, queues);\n }\n\n const previous = queues.get(key) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = previous.then(\n () =>\n new Promise<void>((resolve) => {\n releaseQueue = resolve;\n })\n );\n queues.set(key, current);\n await previous;\n\n let released = false;\n return {\n release: () => {\n if (released) return;\n released = true;\n if (queues.get(key) === current) {\n queues.delete(key);\n }\n releaseQueue();\n }\n };\n }\n\n async get(key: string): Promise<StoredBrowserSession | undefined> {\n return this.storage.get<StoredBrowserSession>(this.#storageKey(key));\n }\n\n async set(key: string, session: StoredBrowserSession): Promise<void> {\n await this.storage.put(this.#storageKey(key), session);\n }\n\n async delete(key: string): Promise<void> {\n await this.storage.delete(this.#storageKey(key));\n }\n\n async list(prefix: string): Promise<Map<string, StoredBrowserSession>> {\n const storagePrefix = this.#storageKey(prefix);\n const entries = await this.storage.list<StoredBrowserSession>({\n prefix: storagePrefix\n });\n const result = new Map<string, StoredBrowserSession>();\n for (const [storageKey, value] of entries) {\n result.set(storageKey.slice(\"browser-session:\".length), value);\n }\n return result;\n }\n\n #storageKey(key: string): string {\n return `browser-session:${key}`;\n }\n}\n\n/**\n * Default idle window used by {@link BrowserConnector.sweep} for the shared\n * (reuse/promoted) session entry.\n */\nexport const DEFAULT_SWEEP_IDLE_MS = 10 * 60 * 1000;\n","import {\n CodemodeConnector,\n type ConnectorTools,\n type ExecutionEndStatus,\n type PassEndStatus,\n type ToolExecuteContext\n} from \"@cloudflare/codemode\";\nimport { CdpSession, connectUrl } from \"./cdp-session\";\nimport {\n connectBrowserSession,\n createBrowserSession,\n deleteBrowserSession,\n listBrowserTargets,\n BrowserRenderingError,\n type BrowserBinding,\n type BrowserSessionInfo,\n type BrowserTargetInfo\n} from \"./browser-run\";\nimport { loadCdpSpec, type SearchableCdpSpec } from \"./spec\";\nimport type {\n BrowserSessionStore,\n StoredBrowserSession\n} from \"./session-manager\";\nimport { DEFAULT_SWEEP_IDLE_MS } from \"./session-manager\";\n\n/** Browser session lifecycle for the connector (binding-backed only). */\nexport interface BrowserConnectorSessionOptions {\n /**\n * - `\"one-shot\"` (default) — one Browser Run session per codemode\n * execution, deleted when the execution ends.\n * - `\"reuse\"` — all executions share one stored session under `key`.\n * - `\"dynamic\"` — per-execution sessions by default; the model can call\n * `cdp.startSession()` to promote the current session into the shared\n * slot so later executions reuse it.\n */\n mode?: \"one-shot\" | \"reuse\" | \"dynamic\";\n /** Logical owner key for the shared (reuse/promoted) session. Default `\"default\"`. */\n key?: string;\n /** Browser Run inactivity timeout. Browser Run currently caps this server-side. */\n keepAliveMs?: number;\n /**\n * Opt into Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/)\n * for sessions this connector creates: an rrweb capture of everything the\n * agent did, finalized when the session closes. Retrieve it afterward with\n * {@link getBrowserRecording} using the session id from\n * {@link BrowserConnector.liveView}/`sessionInfo()`.\n */\n recording?: boolean;\n}\n\nexport type BrowserConnectorOptions = (\n | {\n /** Browser Rendering binding (Fetcher) — used in production. */\n browser: BrowserBinding;\n /**\n * Durable store for Browser Run session ids. Required with the binding:\n * a session must survive a pause (approval) and resume on a fresh\n * instance, so its id cannot live in connector memory.\n */\n store: BrowserSessionStore;\n session?: BrowserConnectorSessionOptions;\n cdpUrl?: never;\n cdpHeaders?: never;\n }\n | {\n /**\n * CDP base URL override (e.g. http://localhost:9222). The browser is\n * externally managed: no Browser Run sessions are created or deleted,\n * and session modes don't apply.\n */\n cdpUrl: string;\n /** Headers to send with CDP URL discovery requests (e.g. Access headers). */\n cdpHeaders?: Record<string, string>;\n browser?: never;\n store?: never;\n session?: never;\n }\n) & {\n /** CDP command timeout in milliseconds (default: 10000). */\n timeout?: number;\n};\n\nexport interface BrowserConnectorSweepOptions {\n /**\n * Close the shared (reuse/promoted) session when idle for at least this\n * many milliseconds. Defaults to the connector's `keepAliveMs`, or\n * {@link DEFAULT_SWEEP_IDLE_MS}.\n */\n maxIdleMs?: number;\n /**\n * Close *per-execution* sessions when idle for at least this many\n * milliseconds. Defaults to {@link DEFAULT_EXEC_SWEEP_IDLE_MS} (24h) —\n * deliberately at least as long as the codemode runtime's default paused\n * TTL, so a run awaiting approval is normally expired (and disposed) by\n * `expirePaused` before the sweep backstop ever touches its browser.\n */\n maxExecIdleMs?: number;\n}\n\nexport interface BrowserConnectorSweepResult {\n /** Store keys (and their Browser Run session ids) closed by this sweep. */\n swept: Array<{ key: string; sessionId: string }>;\n}\n\n/**\n * Live View rendering mode (the `mode` query param the hosted UI at\n * `live.browser.run` understands):\n *\n * - `\"tab\"` — a standalone, interactive page view (best for handing control\n * to a human).\n * - `\"devtools\"` — the full DevTools inspector panel (Elements, Console,\n * Network, …).\n *\n * Omit it to use whatever mode the binding's `devtoolsFrontendUrl` defaults\n * to.\n */\nexport type LiveViewMode = \"tab\" | \"devtools\";\n\n/** A single tab's Live View URL. */\nexport interface BrowserLiveViewUrl {\n /** Open this in a browser to watch/control the tab in real time. */\n url: string;\n /** CDP target (tab) id the URL points at. */\n targetId: string;\n /** Milliseconds the URL stays valid from when it was generated (~5 min). */\n expiresInMs: number;\n}\n\nexport interface BrowserLiveViewTarget {\n targetId: string;\n /** Embeddable Live View URL (the `devtoolsFrontendUrl`) for this tab. */\n url: string;\n /** The page the tab is currently showing (e.g. `https://example.com`). */\n pageUrl?: string;\n title?: string;\n type?: string;\n}\n\n/** Live View URLs for every tab in a (shared) session. */\nexport interface BrowserLiveView {\n sessionId: string;\n targets: BrowserLiveViewTarget[];\n /** Milliseconds the URLs stay valid from when they were generated (~5 min). */\n expiresInMs: number;\n}\n\nconst EXEC_KEY_PREFIX = \"cdp:exec:\";\nconst REUSE_KEY_PREFIX = \"cdp:reuse:\";\n\n/**\n * Default idle window before {@link BrowserConnector.sweep} reclaims a\n * per-execution session. Matches the codemode runtime's default paused TTL\n * (24h): an execution paused for approval keeps its browser until the run\n * itself is expired.\n */\nexport const DEFAULT_EXEC_SWEEP_IDLE_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Minimum interval between `updatedAt` bumps on a per-execution store entry.\n * Touching on every CDP call would write-amplify; once a minute is enough to\n * keep an active or recently-resumed execution out of sweep range.\n */\nconst EXEC_TOUCH_INTERVAL_MS = 60 * 1000;\n\n/**\n * Browser Run mints `devtoolsFrontendUrl`s (the Live View links) that are\n * valid for ~5 minutes. We surface the window so callers can decide how long\n * a shared link is good for before re-listing targets.\n */\nconst LIVE_VIEW_URL_TTL_MS = 5 * 60 * 1000;\n\nfunction isMissingBrowserSession(error: unknown): boolean {\n return error instanceof BrowserRenderingError && error.status === 404;\n}\n\n/**\n * Rewrite the hosted Live View UI's `mode` query param (`tab` | `devtools`).\n * The raw `devtoolsFrontendUrl` is returned unchanged when no mode is asked\n * for or the URL can't be parsed.\n */\nfunction applyLiveViewMode(rawUrl: string, mode?: LiveViewMode): string {\n if (!mode) return rawUrl;\n try {\n const url = new URL(rawUrl);\n url.searchParams.set(\"mode\", mode === \"devtools\" ? \"devtools\" : \"tab\");\n return url.toString();\n } catch {\n return rawUrl;\n }\n}\n\ninterface CachedSocket {\n session: CdpSession;\n /** Browser Run session id the socket is attached to (undefined for cdpUrl). */\n browserSessionId?: string;\n /**\n * Live CDP session id per attach handle, valid for this socket only.\n * Rebuilt lazily after a reconnect (sockets are per-pass).\n */\n attached: Map<string, string>;\n}\n\n/**\n * `cdp.attachToTarget` returns `{ sessionId: \"target:<targetId>\" }` — a stable\n * handle instead of the raw CDP session id. (The object shape mirrors the real\n * `Target.attachToTarget` response, which is what models reach for.) Raw ids\n * are connection-scoped: a run that pauses\n * for approval resumes on a fresh WebSocket where the old id is invalid, and\n * the durable replay log would otherwise pin the stale value. The handle is a\n * pure function of the target, so replayed code computes identical arguments,\n * and `send` resolves it to a live session id on the current socket —\n * re-attaching lazily after a reconnect.\n */\nconst ATTACH_HANDLE_PREFIX = \"target:\";\n\n/**\n * Codemode connector exposing a live browser over the Chrome DevTools\n * Protocol as the `cdp` global.\n *\n * Per-execution resources are keyed by the codemode `executionId`:\n *\n * - The Browser Run session id is stored durably under `cdp:exec:<id>`, so a\n * run that pauses for approval reconnects to the *same* browser when it\n * resumes — even on a fresh instance.\n * - The CDP WebSocket is per-pass: `onPassEnd` disconnects it (a paused run\n * holds no socket), and the next pass reconnects from the stored id.\n * - `disposeExecution` deletes the session unless it was promoted to the\n * shared slot via `cdp.startSession()` (dynamic mode).\n *\n * Locks on the session store are held only around store reads/writes, never\n * across network calls to Browser Run or while a socket is open.\n */\nexport class BrowserConnector extends CodemodeConnector {\n #options: BrowserConnectorOptions;\n #sockets = new Map<string, CachedSocket>();\n #connecting = new Map<string, Promise<CdpSession>>();\n\n constructor(\n ctx: DurableObjectState | ExecutionContext,\n options: BrowserConnectorOptions\n ) {\n super(ctx, {});\n if (!options.cdpUrl && !options.browser) {\n throw new Error(\n \"BrowserConnector requires either 'browser' (Fetcher binding) or 'cdpUrl'\"\n );\n }\n if (options.browser && !options.store) {\n throw new Error(\n \"BrowserConnector requires 'store' when using the Browser Rendering binding\"\n );\n }\n this.#options = options;\n }\n\n name(): string {\n return \"cdp\";\n }\n\n protected instructions(): string {\n const mode = this.#mode();\n const lines = [\n \"Issue CDP calls sequentially — never in parallel (no Promise.all): call order is recorded for durable replay.\",\n \"Browser-/Target-scoped commands (Target.createTarget, Target.getTargets) need no sessionId. Page-scoped commands (Page.navigate, Runtime.evaluate) require one: `const { sessionId } = await cdp.attachToTarget({ targetId });` then pass it to every page-scoped send.\",\n \"Write large outputs (screenshots, page dumps) to a file or workspace immediately and pass around small references — large return values fail to record.\",\n \"Use cdp.spec() to discover commands, events, and types when unsure.\",\n \"If a command fails or times out, check cdp.getDebugLog() for recent protocol traffic.\",\n \"When a step needs a human (login, MFA, CAPTCHA, sensitive input), call cdp.getLiveViewUrl() to get a link they can open to control the browser live — surface it, then make an approval-gated call so the run pauses until they're done.\"\n ];\n if (mode === \"one-shot\") {\n lines.push(\n \"The browser session lasts for this execution only and is closed when it ends.\"\n );\n } else if (mode === \"reuse\") {\n lines.push(\n \"The browser session is shared and persists across executions — tabs and state you leave behind will still be there next time.\"\n );\n } else {\n lines.push(\n \"The browser session is one-shot by default. If browser state must persist after this execution (e.g. a logged-in page), call cdp.startSession() to keep it alive for later executions.\"\n );\n }\n return lines.join(\"\\n\");\n }\n\n protected tools(): ConnectorTools {\n const tools: ConnectorTools = {\n send: {\n description:\n \"Send a CDP command and return its result. Page-scoped commands require a sessionId — pass the handle returned by attachToTarget.\",\n inputSchema: {\n type: \"object\",\n properties: {\n method: {\n type: \"string\",\n description: 'CDP method, e.g. \"Target.createTarget\"'\n },\n params: {\n type: \"object\",\n description: \"CDP command parameters\"\n },\n sessionId: {\n type: \"string\",\n description:\n \"Session handle from attachToTarget, for page-scoped commands\"\n },\n timeoutMs: {\n type: \"number\",\n description: \"Per-command timeout override in milliseconds\"\n }\n },\n required: [\"method\"]\n },\n execute: async (args, ctx) => {\n const { method, params, sessionId, timeoutMs } = args as {\n method: string;\n params?: unknown;\n sessionId?: string;\n timeoutMs?: number;\n };\n const executionId = this.#executionId(ctx);\n const socket = await this.#socket(executionId);\n const resolved = await this.#resolveSessionHandle(\n executionId,\n sessionId\n );\n try {\n return await socket.send(method, params, {\n sessionId: resolved,\n timeoutMs\n });\n } catch (err) {\n // \"Method wasn't found\" is almost always one of two model\n // mistakes. Teach the fix instead of leaving a bare protocol\n // error: either the method is actually an event (events can't be\n // sent), or a page-scoped command went to the browser-level\n // session because no sessionId was passed.\n if (\n err instanceof Error &&\n /-32601|wasn't found/.test(err.message)\n ) {\n if (await this.#isSpecEvent(method)) {\n throw new Error(\n `${err.message}. '${method}' is a CDP *event*, not a ` +\n `command — it cannot be called via cdp.send. To wait for ` +\n `page state, poll instead (e.g. Runtime.evaluate of ` +\n `document.readyState until \"complete\").`\n );\n }\n if (!sessionId) {\n throw new Error(\n `${err.message}. Page-scoped commands need a sessionId: ` +\n `const { sessionId } = await cdp.attachToTarget({ targetId }); ` +\n `then pass sessionId to cdp.send.`\n );\n }\n }\n throw err;\n }\n }\n },\n\n attachToTarget: {\n description:\n \"Attach to a target (tab) and return { sessionId } — a stable session handle to pass as sessionId in page-scoped send calls. The handle stays valid across pauses/resumes.\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: {\n type: \"string\",\n description: \"Target id from Target.createTarget/getTargets\"\n },\n timeoutMs: { type: \"number\" }\n },\n required: [\"targetId\"]\n },\n outputSchema: {\n type: \"object\",\n properties: {\n sessionId: {\n type: \"string\",\n description:\n \"Stable session handle for page-scoped send calls (valid across pauses/resumes)\"\n }\n },\n required: [\"sessionId\"]\n },\n execute: async (args, ctx) => {\n const { targetId, timeoutMs } = args as {\n targetId: string;\n timeoutMs?: number;\n };\n const executionId = this.#executionId(ctx);\n await this.#attach(executionId, targetId, timeoutMs);\n return { sessionId: `${ATTACH_HANDLE_PREFIX}${targetId}` };\n }\n },\n\n spec: {\n description:\n \"Return the searchable Chrome DevTools Protocol spec: domains with their commands, events, and types. Use it to discover method names and capabilities.\",\n replay: \"reexecute\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (): Promise<SearchableCdpSpec> =>\n loadCdpSpec(this.#options)\n },\n\n getDebugLog: {\n description:\n \"Return recent CDP protocol traffic (sends, receives, warnings) for this execution's connection — useful to diagnose failures and timeouts.\",\n replay: \"reexecute\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Max entries to return (default 50)\"\n }\n }\n },\n execute: async (args, ctx) => {\n const { limit } = (args ?? {}) as { limit?: number };\n const socket = await this.#socket(this.#executionId(ctx));\n return socket.getDebugLog(limit);\n }\n },\n\n clearDebugLog: {\n description: \"Clear the CDP debug log for this execution's connection.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) => {\n const socket = await this.#socket(this.#executionId(ctx));\n socket.clearDebugLog();\n return null;\n }\n },\n\n getLiveViewUrl: {\n description:\n \"Return a Live View URL for a tab — a link a human can open in a \" +\n \"browser to watch and control this session in real time. Use it \" +\n \"for human-in-the-loop steps (login, MFA, CAPTCHA, sensitive \" +\n \"input): get the URL, surface it to the user, then make a call \" +\n \"that pauses for approval so they can act before the run \" +\n \"continues. The URL is valid for ~5 minutes.\",\n replay: \"reexecute\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: {\n type: \"string\",\n description:\n \"Target (tab) id to view; defaults to the first open page\"\n },\n mode: {\n type: \"string\",\n enum: [\"tab\", \"devtools\"],\n description:\n \"tab = standalone interactive page view (best for handoff); \" +\n \"devtools = full DevTools inspector panel\"\n }\n }\n },\n execute: async (args, ctx) => {\n const { targetId, mode } = (args ?? {}) as {\n targetId?: string;\n mode?: LiveViewMode;\n };\n return this.#liveViewUrl(this.#executionId(ctx), { targetId, mode });\n }\n }\n };\n\n const mode = this.#mode();\n if (mode === \"reuse\" || mode === \"dynamic\") {\n tools.startSession = {\n description:\n mode === \"dynamic\"\n ? \"Promote the current browser session into the shared slot so it persists after this execution. Later executions reuse it. Returns the session info.\"\n : \"Ensure the shared browser session exists and return its info.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) =>\n this.#startSession(this.#executionId(ctx))\n };\n tools.sessionInfo = {\n description:\n \"Return info about the shared browser session (id and open targets), or null when none exists.\",\n replay: \"reexecute\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async () => (await this.sessionInfo()) ?? null\n };\n tools.closeSession = {\n description:\n \"Close the shared browser session, discarding its tabs and state.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) => {\n await this.#closeReusableFor(this.#executionId(ctx));\n return null;\n }\n };\n tools.resetSession = {\n description:\n \"Close the shared browser session and start a fresh one. Returns the new session info.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) =>\n this.#resetSession(this.#executionId(ctx))\n };\n }\n\n return tools;\n }\n\n // ---------------------------------------------------------------------\n // Lifecycle hooks\n // ---------------------------------------------------------------------\n\n /**\n * A pass is over (completed, errored, or paused awaiting approval) — drop\n * the CDP socket. The Browser Run session itself stays alive; a resume\n * reconnects from the durably stored session id.\n */\n override async onPassEnd(\n executionId: string,\n _status: PassEndStatus\n ): Promise<void> {\n this.#dropSocket(executionId);\n }\n\n /**\n * The execution is terminal — delete its Browser Run session unless it was\n * promoted to the shared slot via `cdp.startSession()`.\n */\n override async disposeExecution(\n executionId: string,\n _status: ExecutionEndStatus\n ): Promise<void> {\n this.#dropSocket(executionId);\n if (!this.#options.browser) return;\n\n const store = this.#options.store;\n const execKey = this.#execKey(executionId);\n const lock = await store.acquireLock(execKey);\n // Decide and update storage under the lock; the Browser Rendering delete\n // happens after release (locks wrap storage only).\n let toClose: StoredBrowserSession | undefined;\n try {\n const stored = await store.get(execKey);\n if (!stored) return;\n\n let promoted = false;\n if (this.#mode() === \"dynamic\") {\n const shared = await store.get(this.#reuseKey());\n promoted = shared?.sessionId === stored.sessionId;\n }\n\n if (!promoted && stored.closedAt === undefined) {\n toClose = stored;\n }\n await store.delete(execKey);\n } finally {\n await lock.release();\n }\n\n if (toClose) {\n try {\n await deleteBrowserSession(this.#options.browser, toClose.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete Browser Run session ${toClose.sessionId} for execution ${executionId}`,\n error\n );\n }\n }\n }\n\n // ---------------------------------------------------------------------\n // Host-side helpers — for callables and scheduled tasks on the agent.\n // ---------------------------------------------------------------------\n\n /** Info about the shared (reuse/promoted) session, if one exists. */\n async sessionInfo(): Promise<BrowserSessionInfo | undefined> {\n if (!this.#options.browser) return undefined;\n const store = this.#options.store;\n const key = this.#reuseKey();\n const lock = await store.acquireLock(key);\n let stored: StoredBrowserSession | undefined;\n try {\n stored = await store.get(key);\n } finally {\n await lock.release();\n }\n if (!stored) return undefined;\n try {\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(\n this.#options.browser,\n stored.sessionId\n )\n };\n } catch (error) {\n if (isMissingBrowserSession(error)) {\n await this.#deleteStoredEntry(key, stored.sessionId);\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * Live View URLs for the shared (reuse/promoted) session's tabs, or\n * `undefined` when no shared session exists. Each URL opens an interactive,\n * real-time view of the browser — surface them in your UI (or send them via\n * Slack/email) to let a human watch or take over a running session\n * (human-in-the-loop). URLs are valid for ~5 minutes; call again for fresh\n * ones. Only meaningful with the Browser Rendering binding in\n * `reuse`/`dynamic` mode.\n */\n async liveView(options?: {\n mode?: LiveViewMode;\n }): Promise<BrowserLiveView | undefined> {\n const info = await this.sessionInfo();\n if (!info) return undefined;\n const targets = (info.targets ?? [])\n .filter((target) => target.devtoolsFrontendUrl)\n .map((target) => ({\n targetId: target.id,\n url: applyLiveViewMode(target.devtoolsFrontendUrl!, options?.mode),\n pageUrl: target.url,\n title: target.title,\n type: target.type\n }));\n return {\n sessionId: info.sessionId,\n targets,\n expiresInMs: LIVE_VIEW_URL_TTL_MS\n };\n }\n\n /** Close the shared (reuse/promoted) session, if one exists. */\n async closeSession(): Promise<void> {\n if (!this.#options.browser) return;\n await this.#closeStoredSession(this.#reuseKey());\n }\n\n /**\n * Close stored sessions (shared and per-execution) idle past the threshold.\n * Per-execution entries normally die with `disposeExecution` (or the\n * codemode runtime's `expirePaused`); the sweep is the backstop for crashed\n * hosts. Call it from a recurring alarm/scheduled task.\n *\n * Active executions bump their entry's `updatedAt` on use, so only runs\n * idle past `maxExecIdleMs` (default 24h) are reclaimed. A swept\n * per-execution entry is kept as a tombstone (`closedAt`) rather than\n * deleted, so a later resume fails with a clear \"session expired\" error\n * instead of silently continuing in a fresh browser; tombstones are\n * deleted once they age past the threshold again.\n */\n async sweep(\n options?: BrowserConnectorSweepOptions\n ): Promise<BrowserConnectorSweepResult> {\n if (!this.#options.browser) return { swept: [] };\n const store = this.#options.store;\n const maxIdleMs =\n options?.maxIdleMs ??\n this.#options.session?.keepAliveMs ??\n DEFAULT_SWEEP_IDLE_MS;\n const maxExecIdleMs = options?.maxExecIdleMs ?? DEFAULT_EXEC_SWEEP_IDLE_MS;\n\n const keys = new Set<string>([this.#reuseKey()]);\n if (store.list) {\n for (const key of (await store.list(\"cdp:\")).keys()) {\n keys.add(key);\n }\n }\n\n const swept: Array<{ key: string; sessionId: string }> = [];\n for (const key of keys) {\n const isExec = key.startsWith(EXEC_KEY_PREFIX);\n const idleMs = isExec ? maxExecIdleMs : maxIdleMs;\n const lock = await store.acquireLock(key);\n let toClose: StoredBrowserSession | undefined;\n try {\n const stored = await store.get(key);\n if (!stored) continue;\n const now = Date.now();\n if (stored.closedAt !== undefined) {\n // Tombstone from a previous sweep — its session is already gone.\n // Drop it once it has aged past the threshold again.\n if (now - stored.closedAt >= idleMs) await store.delete(key);\n continue;\n }\n if (now - stored.updatedAt < idleMs) continue;\n if (isExec) {\n await store.set(key, { ...stored, closedAt: now });\n } else {\n await store.delete(key);\n }\n toClose = stored;\n } finally {\n await lock.release();\n }\n try {\n await deleteBrowserSession(this.#options.browser, toClose.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Sweep failed to delete Browser Run session ${toClose.sessionId}`,\n error\n );\n }\n swept.push({ key, sessionId: toClose.sessionId });\n }\n return { swept };\n }\n\n // ---------------------------------------------------------------------\n // Session + socket resolution\n // ---------------------------------------------------------------------\n\n #mode(): \"one-shot\" | \"reuse\" | \"dynamic\" {\n return this.#options.session?.mode ?? \"one-shot\";\n }\n\n #execKey(executionId: string): string {\n return `${EXEC_KEY_PREFIX}${executionId}`;\n }\n\n #reuseKey(): string {\n return `${REUSE_KEY_PREFIX}${this.#options.session?.key ?? \"default\"}`;\n }\n\n #executionId(ctx?: ToolExecuteContext): string {\n if (!ctx?.executionId) {\n throw new Error(\n \"BrowserConnector requires an execution context — use it through createCodemodeRuntime\"\n );\n }\n return ctx.executionId;\n }\n\n #dropSocket(executionId: string): void {\n const cached = this.#sockets.get(executionId);\n if (!cached) return;\n this.#sockets.delete(executionId);\n cached.session.disconnect();\n }\n\n /** Attach the current socket to a target, caching the live CDP session id. */\n async #attach(\n executionId: string,\n targetId: string,\n timeoutMs?: number\n ): Promise<string> {\n const socket = await this.#socket(executionId);\n const cached = this.#sockets.get(executionId);\n const handle = `${ATTACH_HANDLE_PREFIX}${targetId}`;\n const existing = cached?.attached.get(handle);\n if (existing) return existing;\n const live = await socket.attachToTarget(targetId, { timeoutMs });\n cached?.attached.set(handle, live);\n return live;\n }\n\n /**\n * List the current tabs (targets) for this execution's browser, including\n * their `devtoolsFrontendUrl` (the Live View link). For the binding this is\n * the current Browser Run session; for an externally-managed `cdpUrl` it is\n * the standard CDP `/json/list`.\n */\n async #liveTargets(executionId: string): Promise<BrowserTargetInfo[]> {\n if (this.#options.cdpUrl) {\n const endpoint = new URL(\"/json/list\", this.#options.cdpUrl).toString();\n const response = await fetch(endpoint, {\n headers: this.#options.cdpHeaders\n });\n if (!response.ok) {\n throw new Error(\n `Failed to list targets at ${endpoint}: ${response.status}`\n );\n }\n const payload = (await response.json()) as unknown;\n return Array.isArray(payload) ? (payload as BrowserTargetInfo[]) : [];\n }\n\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n // Ensure a session + socket exist, then read the resolved Browser Run id.\n await this.#socket(executionId);\n const sessionId = this.#sockets.get(executionId)?.browserSessionId;\n if (!sessionId) return [];\n return listBrowserTargets(browser, sessionId);\n }\n\n /** Build a Live View URL for one tab in this execution's browser. */\n async #liveViewUrl(\n executionId: string,\n options: { targetId?: string; mode?: LiveViewMode }\n ): Promise<BrowserLiveViewUrl> {\n const targets = await this.#liveTargets(executionId);\n const target = options.targetId\n ? targets.find((candidate) => candidate.id === options.targetId)\n : (targets.find(\n (candidate) =>\n candidate.type === \"page\" && candidate.devtoolsFrontendUrl\n ) ?? targets.find((candidate) => candidate.devtoolsFrontendUrl));\n\n if (!target) {\n throw new Error(\n options.targetId\n ? `No target ${options.targetId} found. List tabs with Target.getTargets or open one with Target.createTarget.`\n : \"No browser tab is open yet. Create one (Target.createTarget) before requesting a Live View URL.\"\n );\n }\n if (!target.devtoolsFrontendUrl) {\n throw new Error(\n `Target ${target.id} has no Live View URL (devtoolsFrontendUrl). Live View needs the Browser Rendering binding.`\n );\n }\n\n return {\n url: applyLiveViewMode(target.devtoolsFrontendUrl, options.mode),\n targetId: target.id,\n expiresInMs: LIVE_VIEW_URL_TTL_MS\n };\n }\n\n /**\n * Resolve a model-facing session handle to the live CDP session id on the\n * current socket, re-attaching lazily after a reconnect. Raw CDP session\n * ids (from manual Target.attachToTarget sends) pass through untouched.\n */\n /**\n * True when `method` is a CDP *event* (e.g. `Page.loadEventFired`) rather\n * than a command. Used only on the `send` failure path to produce a better\n * error; any spec-loading failure just means no extra hint.\n */\n async #isSpecEvent(method: string): Promise<boolean> {\n try {\n const spec = await loadCdpSpec(this.#options);\n const domain = method.split(\".\")[0];\n return spec.domains.some(\n (d) => d.name === domain && d.events.some((e) => e.event === method)\n );\n } catch {\n return false;\n }\n }\n\n async #resolveSessionHandle(\n executionId: string,\n sessionId?: string\n ): Promise<string | undefined> {\n if (!sessionId?.startsWith(ATTACH_HANDLE_PREFIX)) return sessionId;\n const targetId = sessionId.slice(ATTACH_HANDLE_PREFIX.length);\n return this.#attach(executionId, targetId);\n }\n\n /**\n * Get or open the CDP socket for an execution. Concurrent calls for the\n * same execution (model code that ignores the \"sequential calls\" rule and\n * uses Promise.all) share one in-flight connect instead of racing and\n * leaking the loser's WebSocket.\n */\n #socket(executionId: string): Promise<CdpSession> {\n const inFlight = this.#connecting.get(executionId);\n if (inFlight) return inFlight;\n const promise = this.#socketInner(executionId).finally(() => {\n if (this.#connecting.get(executionId) === promise) {\n this.#connecting.delete(executionId);\n }\n });\n this.#connecting.set(executionId, promise);\n return promise;\n }\n\n async #socketInner(executionId: string): Promise<CdpSession> {\n if (this.#options.cdpUrl) {\n const cached = this.#sockets.get(executionId);\n if (cached) return cached.session;\n const session = await connectUrl(this.#options.cdpUrl, {\n timeoutMs: this.#options.timeout,\n headers: this.#options.cdpHeaders\n });\n this.#sockets.set(executionId, { session, attached: new Map() });\n return session;\n }\n\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const stored = await this.#resolveSession(executionId);\n const cached = this.#sockets.get(executionId);\n if (cached?.browserSessionId === stored.sessionId) {\n return cached.session;\n }\n if (cached) this.#dropSocket(executionId);\n\n const session = await connectBrowserSession(\n browser,\n stored.sessionId,\n this.#options.timeout\n );\n this.#sockets.set(executionId, {\n session,\n browserSessionId: stored.sessionId,\n attached: new Map()\n });\n return session;\n }\n\n /**\n * Resolve the Browser Run session for an execution:\n *\n * - An existing `cdp:exec:<id>` entry wins. If its session is gone (e.g.\n * expired while the run was paused), the run fails with a clear error\n * rather than silently continuing in a fresh browser.\n * - In `reuse` mode the shared session is used (created if missing).\n * - In `dynamic` mode an alive shared session is used; otherwise a fresh\n * per-execution session is created.\n * - In `one-shot` mode a fresh per-execution session is created.\n */\n async #resolveSession(executionId: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const mode = this.#mode();\n const execKey = this.#execKey(executionId);\n\n if (mode === \"reuse\") {\n return this.#ensureStoredSession(this.#reuseKey());\n }\n\n // one-shot / dynamic: a session this execution already opened wins.\n const existing = await this.#readStored(execKey);\n if (existing) {\n if (existing.closedAt === undefined && (await this.#isAlive(existing))) {\n // Keep the entry fresh so the sweep backstop never reclaims an\n // active (or recently resumed) execution's session.\n if (Date.now() - existing.updatedAt >= EXEC_TOUCH_INTERVAL_MS) {\n await this.#touchStored(execKey, existing);\n }\n return existing;\n }\n await this.#deleteStoredEntry(execKey, existing.sessionId);\n throw new Error(\n `Browser session ${existing.sessionId} expired or was swept while this execution was paused — the run cannot continue. Start a new execution.`\n );\n }\n\n if (mode === \"dynamic\") {\n const shared = await this.#readStored(this.#reuseKey());\n if (shared) {\n if (await this.#isAlive(shared)) {\n await this.#touchStored(this.#reuseKey(), shared);\n return shared;\n }\n await this.#deleteStoredEntry(this.#reuseKey(), shared.sessionId);\n }\n }\n\n // Create a fresh per-execution session. The Browser Rendering call\n // happens outside the store lock; the lock only guards the commit, so\n // two concurrent tool calls for the same execution don't double-create\n // (the loser's session is deleted).\n return this.#createAndCommit(execKey);\n }\n\n /**\n * Get the stored session under `key`, validating and creating as needed.\n *\n * Network calls (the liveness probe, session creation) happen OUTSIDE the\n * store lock — locks wrap storage only, so a hung Browser Rendering call\n * can't serialize every other operation on this key. The lock is\n * re-acquired to commit, with a sessionId re-check to detect a concurrent\n * swap; on a swap the new entry is re-validated from the top.\n */\n async #ensureStoredSession(key: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const store = this.#store;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const existing = await store.get(key);\n if (!existing) return this.#createAndCommit(key);\n\n const alive = await this.#isAlive(existing);\n const lock = await store.acquireLock(key);\n try {\n const current = await store.get(key);\n if (current?.sessionId !== existing.sessionId) {\n // Entry was swapped while we probed — validate the new one.\n continue;\n }\n if (alive) {\n const refreshed = { ...current, updatedAt: Date.now() };\n await store.set(key, refreshed);\n return refreshed;\n }\n await store.delete(key);\n } finally {\n await lock.release();\n }\n // Dead entry deleted — the next iteration creates a fresh session.\n }\n throw new Error(\n `Browser session entry ${key} kept changing concurrently — retry`\n );\n }\n\n /**\n * Create a Browser Run session (outside any lock) and commit it under\n * `key`. If a concurrent caller committed first, their entry wins and the\n * redundant session is deleted best-effort.\n */\n async #createAndCommit(key: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const store = this.#store;\n\n const info = await createBrowserSession(browser, {\n keepAliveMs: this.#options.session?.keepAliveMs,\n recording: this.#options.session?.recording\n });\n const now = Date.now();\n const stored: StoredBrowserSession = {\n sessionId: info.sessionId,\n createdAt: now,\n updatedAt: now\n };\n\n const lock = await store.acquireLock(key);\n let winner: StoredBrowserSession | undefined;\n try {\n const raced = await store.get(key);\n if (raced) {\n winner = raced;\n } else {\n await store.set(key, stored);\n }\n } finally {\n await lock.release();\n }\n\n if (winner) {\n try {\n await deleteBrowserSession(browser, stored.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete redundant Browser Run session ${stored.sessionId}`,\n error\n );\n }\n return winner;\n }\n return stored;\n }\n\n async #isAlive(stored: StoredBrowserSession): Promise<boolean> {\n const browser = this.#options.browser;\n if (!browser) return false;\n try {\n await listBrowserTargets(browser, stored.sessionId);\n return true;\n } catch (error) {\n if (isMissingBrowserSession(error)) return false;\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------\n // Session tools (reuse/dynamic)\n // ---------------------------------------------------------------------\n\n async #startSession(executionId: string): Promise<BrowserSessionInfo> {\n const browser = this.#options.browser;\n if (!browser) {\n throw new Error(\"startSession requires the Browser Rendering binding\");\n }\n const store = this.#options.store;\n const reuseKey = this.#reuseKey();\n\n if (this.#mode() === \"dynamic\") {\n // Promote this execution's session into the shared slot, if it has one.\n const exec = await this.#readStored(this.#execKey(executionId));\n if (exec && exec.closedAt === undefined) {\n const lock = await store.acquireLock(reuseKey);\n let replaced: StoredBrowserSession | undefined;\n try {\n const shared = await store.get(reuseKey);\n if (shared?.sessionId !== exec.sessionId) {\n replaced = shared;\n await store.set(reuseKey, { ...exec, updatedAt: Date.now() });\n }\n } finally {\n await lock.release();\n }\n if (replaced) {\n try {\n await deleteBrowserSession(browser, replaced.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete replaced Browser Run session ${replaced.sessionId}`,\n error\n );\n }\n }\n return {\n sessionId: exec.sessionId,\n targets: await listBrowserTargets(browser, exec.sessionId)\n };\n }\n }\n\n const stored = await this.#ensureStoredSession(reuseKey);\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(browser, stored.sessionId)\n };\n }\n\n async #resetSession(executionId: string): Promise<BrowserSessionInfo> {\n const browser = this.#options.browser;\n if (!browser) {\n throw new Error(\"resetSession requires the Browser Rendering binding\");\n }\n await this.#closeReusableFor(executionId);\n const stored = await this.#ensureStoredSession(this.#reuseKey());\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(browser, stored.sessionId)\n };\n }\n\n /**\n * Close the shared session from inside an execution. If this execution's\n * socket is attached to that session, drop it first.\n */\n async #closeReusableFor(executionId: string): Promise<void> {\n const reuseKey = this.#reuseKey();\n const stored = await this.#readStored(reuseKey);\n if (!stored) return;\n const cached = this.#sockets.get(executionId);\n if (cached?.browserSessionId === stored.sessionId) {\n this.#dropSocket(executionId);\n }\n await this.#closeStoredSession(reuseKey);\n // In reuse mode the execution continues against a fresh shared session on\n // the next send. In dynamic mode the exec entry (if any) still points at\n // the closed session; clear it so the next send fails loudly instead of\n // silently targeting a deleted browser.\n const exec = await this.#readStored(this.#execKey(executionId));\n if (exec?.sessionId === stored.sessionId) {\n await this.#deleteStoredEntry(this.#execKey(executionId), exec.sessionId);\n }\n }\n\n // ---------------------------------------------------------------------\n // Store access — locks held only around the store operation itself.\n // ---------------------------------------------------------------------\n\n get #store(): BrowserSessionStore {\n const store = this.#options.store;\n if (!store) {\n throw new Error(\n \"BrowserConnector session storage requires the Browser Rendering binding\"\n );\n }\n return store;\n }\n\n async #readStored(key: string): Promise<StoredBrowserSession | undefined> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n return await store.get(key);\n } finally {\n await lock.release();\n }\n }\n\n async #writeStored(key: string, value: StoredBrowserSession): Promise<void> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n await store.set(key, value);\n } finally {\n await lock.release();\n }\n }\n\n async #touchStored(key: string, value: StoredBrowserSession): Promise<void> {\n await this.#writeStored(key, { ...value, updatedAt: Date.now() });\n }\n\n /** Delete the store entry only if it still points at `sessionId`. */\n async #deleteStoredEntry(key: string, sessionId: string): Promise<void> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n const current = await store.get(key);\n if (current?.sessionId === sessionId) {\n await store.delete(key);\n }\n } finally {\n await lock.release();\n }\n }\n\n /** Delete the stored entry under `key` and its Browser Run session. */\n async #closeStoredSession(key: string): Promise<void> {\n const browser = this.#options.browser;\n if (!browser) return;\n const store = this.#options.store;\n const lock = await store.acquireLock(key);\n let stored: StoredBrowserSession | undefined;\n try {\n stored = await store.get(key);\n if (stored) await store.delete(key);\n } finally {\n await lock.release();\n }\n if (stored) {\n await deleteBrowserSession(browser, stored.sessionId);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"connector-CdldGF3h.js","names":[],"sources":["../src/browser/cdp-session.ts","../src/browser/browser-run.ts","../src/browser/quick-actions.ts","../src/browser/spec.ts","../src/browser/session-manager.ts","../src/browser/connector.ts"],"sourcesContent":["interface PendingCommand {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n method: string;\n sessionId?: string;\n startedAt: number;\n}\n\ninterface DebugEntry {\n at: string;\n type: string;\n [key: string]: unknown;\n}\n\nexport interface CdpSendOptions {\n timeoutMs?: number;\n sessionId?: string;\n}\n\nexport interface CdpAttachOptions {\n timeoutMs?: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst MAX_DEBUG_ENTRIES = 400;\n\n/**\n * A CDP session over an open WebSocket. Manages command correlation,\n * timeouts, target sessions, and a debug event ring buffer.\n *\n * Used host-side (not in the sandbox) — the sandbox calls into this\n * via DynamicWorkerExecutor's ToolDispatcher RPC.\n */\nexport class CdpSession {\n #socket: WebSocket;\n #nextId = 1;\n #pending = new Map<number, PendingCommand>();\n #debugLog: DebugEntry[] = [];\n #defaultTimeoutMs: number;\n #dispose?: () => void;\n readonly sessionId?: string;\n\n constructor(\n socket: WebSocket,\n defaultTimeoutMs = DEFAULT_TIMEOUT_MS,\n dispose?: () => void,\n sessionId?: string\n ) {\n this.#socket = socket;\n this.#defaultTimeoutMs = defaultTimeoutMs;\n this.#dispose = dispose;\n this.sessionId = sessionId;\n\n socket.addEventListener(\"message\", (event) => this.#handleMessage(event));\n socket.addEventListener(\"error\", () => {\n this.#rejectAll(new Error(\"CDP socket error\"));\n });\n socket.addEventListener(\"close\", () => {\n this.#rejectAll(new Error(\"CDP connection closed\"));\n });\n }\n\n send(\n method: string,\n params?: unknown,\n options: CdpSendOptions = {}\n ): Promise<unknown> {\n const id = this.#nextId++;\n const timeoutMs = options.timeoutMs ?? this.#defaultTimeoutMs;\n const sessionId =\n typeof options.sessionId === \"string\" && options.sessionId.length > 0\n ? options.sessionId\n : undefined;\n\n const domain = typeof method === \"string\" ? method.split(\".\")[0] : \"\";\n if (!sessionId && domain && ![\"Browser\", \"Target\"].includes(domain)) {\n this.#recordDebug(\"warning\", {\n id,\n method,\n reason: \"target-scoped method sent without sessionId\"\n });\n }\n\n const result = new Promise<unknown>((resolve, reject) => {\n const startedAt = performance.now();\n const timeoutId = setTimeout(() => {\n this.#pending.delete(id);\n reject(\n new Error(`CDP command timed out after ${timeoutMs}ms: ${method}`)\n );\n }, timeoutMs);\n this.#pending.set(id, {\n resolve,\n reject,\n timeoutId,\n method,\n sessionId,\n startedAt\n });\n });\n\n this.#recordDebug(\"send\", { id, method, sessionId, timeoutMs });\n this.#socket.send(JSON.stringify({ id, method, params, sessionId }));\n return result;\n }\n\n async attachToTarget(\n targetId: string,\n options: CdpAttachOptions = {}\n ): Promise<string> {\n if (typeof targetId !== \"string\" || !targetId) {\n throw new Error(\n \"attachToTarget requires a targetId — list open tabs with \" +\n \"send('Target.getTargets') or create one with \" +\n \"send('Target.createTarget', { url })\"\n );\n }\n\n const result = (await this.send(\n \"Target.attachToTarget\",\n {\n targetId,\n flatten: true\n },\n { timeoutMs: options.timeoutMs }\n )) as { sessionId?: string };\n\n const sessionId = result?.sessionId ?? \"\";\n if (!sessionId) {\n throw new Error(\n `Target.attachToTarget did not return a sessionId for target ${targetId}`\n );\n }\n\n this.#recordDebug(\"attach\", { targetId, sessionId });\n return sessionId;\n }\n\n getDebugLog(limit = 50): DebugEntry[] {\n const normalized = Number.isFinite(limit)\n ? Math.max(1, Math.floor(limit))\n : 50;\n return this.#debugLog.slice(-normalized);\n }\n\n clearDebugLog(): void {\n this.#debugLog = [];\n }\n\n disconnect(): void {\n this.#rejectAll(new Error(\"CDP session disconnected\"));\n try {\n this.#socket.close(1000, \"Done\");\n } catch {\n // socket may already be closed\n }\n }\n\n close(): void {\n this.disconnect();\n this.#dispose?.();\n }\n\n #rejectAll(error: Error): void {\n for (const [id, pending] of this.#pending.entries()) {\n clearTimeout(pending.timeoutId);\n this.#pending.delete(id);\n pending.reject(error);\n }\n }\n\n #handleMessage(event: MessageEvent): void {\n if (typeof event.data !== \"string\") {\n return;\n }\n\n let payload: Record<string, unknown>;\n try {\n payload = JSON.parse(event.data) as Record<string, unknown>;\n } catch {\n return;\n }\n\n this.#recordDebug(\"receive\", {\n id: payload.id,\n method: payload.method,\n sessionId: payload.sessionId,\n hasError: !!payload.error\n });\n\n if (typeof payload.id !== \"number\") {\n return;\n }\n\n const pending = this.#pending.get(payload.id);\n if (!pending) {\n return;\n }\n\n clearTimeout(pending.timeoutId);\n this.#pending.delete(payload.id);\n\n if (payload.error) {\n const err = payload.error as { code?: unknown; message?: string };\n const code = err.code ?? \"unknown\";\n const message = err.message ?? \"CDP error\";\n pending.reject(\n new Error(`CDP error ${code}: ${message} for ${pending.method}`)\n );\n return;\n }\n\n pending.resolve(payload.result);\n }\n\n #recordDebug(type: string, data: Record<string, unknown>): void {\n this.#debugLog.push({\n at: new Date().toISOString(),\n type,\n ...data\n });\n if (this.#debugLog.length > MAX_DEBUG_ENTRIES) {\n this.#debugLog.splice(0, this.#debugLog.length - MAX_DEBUG_ENTRIES);\n }\n }\n}\n\nconst LOCALHOST_HOSTS = new Set([\n \"localhost\",\n \"127.0.0.1\",\n \"0.0.0.0\",\n \"::1\",\n \"[::1]\"\n]);\n\n/**\n * Connect to a browser via a CDP base URL (e.g. http://localhost:9222).\n * Discovers the WebSocket debugger URL via /json/version,\n * rewrites localhost URLs to the base URL host, and opens the WebSocket.\n *\n * Useful for local development with `chrome --remote-debugging-port=9222`\n * or when connecting through a tunnel.\n */\nexport async function connectUrl(\n baseUrl: string,\n options?: { timeoutMs?: number; headers?: Record<string, string> }\n): Promise<CdpSession> {\n const endpoint = new URL(\"/json/version\", baseUrl).toString();\n const response = await fetch(endpoint, {\n headers: options?.headers\n });\n if (!response.ok) {\n throw new Error(\n `Failed to discover CDP endpoint at ${endpoint}: ${response.status}`\n );\n }\n\n const payload = (await response.json()) as {\n webSocketDebuggerUrl?: string;\n };\n if (!payload.webSocketDebuggerUrl) {\n throw new Error(\"CDP /json/version did not include webSocketDebuggerUrl\");\n }\n\n let wsUrl = payload.webSocketDebuggerUrl;\n const parsed = new URL(wsUrl);\n if (LOCALHOST_HOSTS.has(parsed.hostname)) {\n const base = new URL(baseUrl);\n parsed.hostname = base.hostname;\n parsed.port = base.port;\n parsed.protocol = base.protocol;\n } else {\n // Workers runtime requires fetch + Upgrade header for outbound WebSockets\n parsed.protocol = parsed.protocol === \"wss:\" ? \"https:\" : \"http:\";\n }\n const fetchUrl = parsed.toString();\n\n const wsResponse = await fetch(fetchUrl, {\n headers: { ...options?.headers, Upgrade: \"websocket\" }\n });\n const ws = wsResponse.webSocket;\n if (!ws) {\n throw new Error(\n `Failed to establish CDP WebSocket at ${fetchUrl} (status ${wsResponse.status})`\n );\n }\n ws.accept();\n\n return new CdpSession(ws, options?.timeoutMs);\n}\n","import { CdpSession } from \"./cdp-session\";\n\n/**\n * A Browser Rendering binding. Structural so it accepts both the classic\n * `Fetcher`-typed binding and the newer `BrowserRun` type generated by\n * `wrangler types` — we only ever use its `fetch` surface.\n */\nexport interface BrowserBinding {\n fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n}\n\nexport interface BrowserTargetInfo {\n id: string;\n type?: string;\n url?: string;\n title?: string;\n description?: string;\n devtoolsFrontendUrl?: string;\n webSocketDebuggerUrl?: string;\n}\n\nexport interface BrowserSessionInfo {\n sessionId: string;\n targets?: BrowserTargetInfo[];\n webSocketDebuggerUrl?: string;\n}\n\nexport interface ConnectBrowserOptions {\n timeoutMs?: number;\n keepAliveMs?: number;\n includeTargets?: boolean;\n /**\n * Opt into Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/):\n * an rrweb capture of DOM changes, input, and navigation, finalized when the\n * session closes. Set at session-launch time. Retrieve later with\n * {@link getBrowserRecording}.\n */\n recording?: boolean;\n}\n\n/** An rrweb session recording for a closed Browser Run session. */\nexport interface BrowserRecording {\n sessionId: string;\n /** Recording length in milliseconds. */\n duration: number;\n /**\n * rrweb event arrays keyed by CDP target id (one per tab). Each value can be\n * passed directly to `rrweb-player` to replay that tab.\n */\n events: Record<string, unknown[]>;\n}\n\nexport class BrowserRenderingError extends Error {\n constructor(\n message: string,\n readonly status: number\n ) {\n super(message);\n this.name = \"BrowserRenderingError\";\n }\n}\n\nfunction browserSessionEndpoint(\n sessionId?: string,\n options?: {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n }\n): string {\n const path = sessionId\n ? `/v1/devtools/browser/${sessionId}`\n : \"/v1/devtools/browser\";\n const url = new URL(`https://localhost${path}`);\n\n if (options?.keepAliveMs !== undefined) {\n url.searchParams.set(\"keep_alive\", String(options.keepAliveMs));\n }\n if (options?.includeTargets) {\n url.searchParams.set(\"targets\", \"true\");\n }\n if (options?.recording) {\n url.searchParams.set(\"recording\", \"true\");\n }\n\n return url.toString();\n}\n\nasync function parseBrowserSessionInfo(\n response: Response\n): Promise<BrowserSessionInfo> {\n const payload = (await response.json()) as {\n sessionId?: unknown;\n targets?: unknown;\n webSocketDebuggerUrl?: unknown;\n };\n const sessionId =\n typeof payload.sessionId === \"string\" ? payload.sessionId : \"\";\n\n if (!sessionId) {\n throw new Error(\"Browser Rendering response did not include a sessionId\");\n }\n\n return {\n sessionId,\n targets: Array.isArray(payload.targets)\n ? (payload.targets as BrowserTargetInfo[])\n : undefined,\n webSocketDebuggerUrl:\n typeof payload.webSocketDebuggerUrl === \"string\"\n ? payload.webSocketDebuggerUrl\n : undefined\n };\n}\n\nexport async function createBrowserSession(\n browser: BrowserBinding,\n options?: {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n }\n): Promise<BrowserSessionInfo> {\n const response = await browser.fetch(\n browserSessionEndpoint(undefined, options),\n { method: \"POST\" }\n );\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to create Browser Rendering session: ${response.status}`,\n response.status\n );\n }\n\n return parseBrowserSessionInfo(response);\n}\n\nexport async function listBrowserTargets(\n browser: BrowserBinding,\n sessionId: string\n): Promise<BrowserTargetInfo[]> {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}/json/list`\n );\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to list Browser Rendering targets for ${sessionId}: ${response.status}`,\n response.status\n );\n }\n\n const payload = (await response.json()) as unknown;\n return Array.isArray(payload) ? (payload as BrowserTargetInfo[]) : [];\n}\n\nexport async function deleteBrowserSession(\n browser: BrowserBinding,\n sessionId: string\n): Promise<void> {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}`,\n { method: \"DELETE\" }\n );\n\n if (!response.ok && response.status !== 404) {\n throw new BrowserRenderingError(\n `Failed to delete Browser Rendering session ${sessionId}: ${response.status}`,\n response.status\n );\n }\n}\n\n/**\n * Connect to a Browser Rendering session and delete it when closed.\n */\nexport async function connectBrowser(\n browser: BrowserBinding,\n options?: number | ConnectBrowserOptions\n): Promise<CdpSession> {\n const normalizedOptions =\n typeof options === \"number\" ? { timeoutMs: options } : (options ?? {});\n const response = await browser.fetch(\n browserSessionEndpoint(undefined, {\n keepAliveMs: normalizedOptions.keepAliveMs,\n includeTargets: normalizedOptions.includeTargets,\n recording: normalizedOptions.recording\n }),\n { headers: { Upgrade: \"websocket\" } }\n );\n\n const ws = response.webSocket;\n if (!ws) {\n throw new Error(\n \"Browser Rendering binding did not return a WebSocket. \" +\n \"Ensure the 'browser' binding is configured in wrangler.jsonc.\"\n );\n }\n\n const sessionId = response.headers.get(\"cf-browser-session-id\");\n if (!sessionId) {\n throw new Error(\n \"Browser Rendering binding did not include a session ID when opening the CDP WebSocket\"\n );\n }\n\n ws.accept();\n return new CdpSession(\n ws,\n normalizedOptions.timeoutMs,\n () => {\n deleteBrowserSession(browser, sessionId).catch((error: unknown) => {\n console.warn(\n `[agents/browser] Failed to delete one-shot Browser Run session ${sessionId}`,\n error\n );\n });\n },\n sessionId\n );\n}\n\n/**\n * Fetch a Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/)\n * by session id, via the Browser Rendering REST API.\n *\n * A recording is only available **after** the session closes (explicit\n * `closeSession()`, idle `keep_alive` expiry, or sweep) and is retained for 30\n * days. Capture the session id while the session is alive — e.g. from\n * `connector.liveView()`/`sessionInfo()` — then call this once it has ended.\n *\n * Unlike the binding-based helpers, this hits `api.cloudflare.com` directly, so\n * it needs an account id and an API token with `Browser Rendering` read access\n * (the Workers Browser Run binding cannot read recordings).\n */\nexport async function getBrowserRecording(options: {\n accountId: string;\n apiToken: string;\n sessionId: string;\n /** Override for testing; defaults to the global `fetch`. */\n fetchImpl?: typeof fetch;\n}): Promise<BrowserRecording> {\n const { accountId, apiToken, sessionId } = options;\n const fetchImpl = options.fetchImpl ?? fetch;\n const endpoint = `https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/recording/${sessionId}`;\n\n const response = await fetchImpl(endpoint, {\n headers: { Authorization: `Bearer ${apiToken}` }\n });\n\n if (!response.ok) {\n throw new BrowserRenderingError(\n `Failed to fetch Browser Run recording for ${sessionId}: ${response.status}`,\n response.status\n );\n }\n\n // The recording endpoint returns the recording object directly; tolerate a\n // standard v4 `{ result }` envelope in case that changes.\n const payload = (await response.json()) as\n | BrowserRecording\n | { result?: BrowserRecording };\n const recording =\n \"result\" in payload && payload.result ? payload.result : payload;\n\n return recording as BrowserRecording;\n}\n\n/**\n * Connect to an existing Browser Rendering session without deleting it on close.\n */\nexport async function connectBrowserSession(\n browser: BrowserBinding,\n sessionId: string,\n timeoutMs?: number\n): Promise<CdpSession> {\n const response = await browser.fetch(browserSessionEndpoint(sessionId), {\n headers: { Upgrade: \"websocket\" }\n });\n\n const ws = response.webSocket;\n if (!ws) {\n throw new Error(\n `Browser Rendering binding did not return a WebSocket for session ${sessionId}`\n );\n }\n\n ws.accept();\n return new CdpSession(ws, timeoutMs, undefined, sessionId);\n}\n","import { BrowserRenderingError } from \"./browser-run\";\n\n/**\n * A Browser Run binding that supports [Quick Actions](https://developers.cloudflare.com/browser-run/quick-actions/).\n *\n * This is the `quickAction()` surface of the `BrowserRun` binding generated by\n * `wrangler types`. Quick Actions are stateless one-shot tasks (screenshot,\n * PDF, markdown, structured extraction, …) — no session, no token, just the\n * binding.\n *\n * Requires a Worker `compatibility_date` of `2026-03-24` or later, and\n * `remote: true` on the browser binding for local `wrangler dev`.\n */\nexport interface QuickActionBinding {\n // `options: unknown` (declared as a method, so parameters are checked\n // bivariantly) lets the real `BrowserRun` binding — whose `quickAction` is a\n // set of per-action typed overloads — satisfy this structural type.\n quickAction(action: string, options: unknown): Promise<Response>;\n}\n\n/** The Quick Action endpoints exposed by Browser Run. */\nexport type QuickAction =\n | \"content\"\n | \"screenshot\"\n | \"pdf\"\n | \"markdown\"\n | \"snapshot\"\n | \"scrape\"\n | \"json\"\n | \"links\"\n | \"crawl\";\n\ntype GotoOptions = {\n waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle0\" | \"networkidle2\";\n timeout?: number;\n};\n\n/** Options accepted by every Quick Action endpoint. */\nexport interface QuickActionCommonOptions {\n gotoOptions?: GotoOptions;\n viewport?: { width: number; height: number; deviceScaleFactor?: number };\n cookies?: unknown[];\n authenticate?: { username: string; password: string };\n setExtraHTTPHeaders?: Record<string, string>;\n userAgent?: string;\n /** Regex strings for requests to drop before render (e.g. `[\"/\\\\.css$/\"]`). */\n rejectRequestPattern?: string[];\n}\n\n/**\n * The page a Quick Action operates on: a `url` to load, or raw `html` to\n * render. Exactly one is required.\n */\nexport type QuickActionPage =\n | ({ url: string; html?: never } & QuickActionCommonOptions)\n | ({ html: string; url?: never } & QuickActionCommonOptions);\n\n/** Input for the AI-powered `/json` extraction endpoint. */\nexport type QuickActionExtractInput = QuickActionPage & {\n /** Natural-language instruction for what to extract. */\n prompt?: string;\n /** A JSON Schema describing the desired output shape. */\n response_format?: { type: \"json_schema\"; schema: unknown };\n /** Bring-your-own model(s), tried in order, for extraction. */\n custom_ai?: { model: string; authorization: string }[];\n};\n\n/** Input for the `/scrape` endpoint. */\nexport type QuickActionScrapeInput = QuickActionPage & {\n elements: { selector: string }[];\n};\n\n/** Input for the `/screenshot` endpoint. */\nexport type QuickActionScreenshotInput = QuickActionPage & {\n screenshotOptions?: Record<string, unknown>;\n selector?: string;\n};\n\n/** Binary output (screenshot or PDF) with its reported content type. */\nexport interface QuickActionBinary {\n data: Uint8Array;\n contentType: string;\n}\n\n/** Any Quick Action input accepted by the typed helpers. */\nexport type QuickActionInput =\n | QuickActionPage\n | QuickActionExtractInput\n | QuickActionScrapeInput\n | QuickActionScreenshotInput;\n\n/** Elements matched by one selector via `/scrape`. */\nexport interface QuickActionScrapeResult {\n selector: string;\n results: {\n html: string;\n text: string;\n width: number;\n height: number;\n top: number;\n left: number;\n attributes: { name: string; value: string }[];\n }[];\n}\n\n/** Result of a `/snapshot` request: rendered HTML plus a base64 screenshot. */\nexport interface QuickActionSnapshot {\n /** HTML content of the page. */\n content: string;\n /** Base64-encoded screenshot image. */\n screenshot: string;\n}\n\n/**\n * Run a Quick Action and return the raw {@link Response} from the binding.\n *\n * Most callers want a typed helper ({@link browserMarkdown},\n * {@link browserExtract}, …) instead; reach for this only when you need an\n * endpoint or option not yet wrapped. The per-action overloads type `params`\n * against the action when it is a string literal (e.g. `\"json\"` requires a\n * {@link QuickActionExtractInput}); any {@link QuickActionInput} is accepted\n * otherwise.\n */\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"json\",\n params: QuickActionExtractInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"scrape\",\n params: QuickActionScrapeInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: \"screenshot\",\n params: QuickActionScreenshotInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<Response>;\nexport function runQuickAction(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<Response> {\n return browser.quickAction(action, params);\n}\n\n/** Build an error that includes the service's explanation, if the body has one. */\nasync function quickActionError(\n action: QuickAction,\n response: Response\n): Promise<BrowserRenderingError> {\n let detail = \"\";\n try {\n const text = await response.text();\n try {\n const body = JSON.parse(text) as {\n errors?: { message?: string }[];\n rawAiResponse?: string;\n };\n const messages = (body.errors ?? [])\n .map((e) => e.message)\n .filter((m): m is string => Boolean(m));\n if (messages.length > 0) detail = `: ${messages.join(\"; \")}`;\n else if (body.rawAiResponse) detail = `: ${body.rawAiResponse}`;\n else if (text) detail = `: ${text.slice(0, 200)}`;\n } catch {\n if (text) detail = `: ${text.slice(0, 200)}`;\n }\n } catch {\n // Body unreadable — fall back to the status code alone.\n }\n return new BrowserRenderingError(\n `Browser Run ${action} failed (${response.status})${detail}`,\n response.status\n );\n}\n\nasync function quickActionJson<T>(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<T> {\n const response = await runQuickAction(browser, action, params);\n if (!response.ok) throw await quickActionError(action, response);\n const payload = (await response.json()) as {\n success?: boolean;\n result?: T;\n errors?: { message?: string }[];\n };\n if (payload.success === false || payload.result === undefined) {\n const messages = (payload.errors ?? [])\n .map((e) => e.message)\n .filter((m): m is string => Boolean(m));\n throw new BrowserRenderingError(\n `Browser Run ${action} returned no result${messages.length > 0 ? `: ${messages.join(\"; \")}` : \"\"}`,\n response.status\n );\n }\n return payload.result;\n}\n\nasync function quickActionBinary(\n browser: QuickActionBinding,\n action: QuickAction,\n params: QuickActionInput\n): Promise<QuickActionBinary> {\n const response = await runQuickAction(browser, action, params);\n if (!response.ok) throw await quickActionError(action, response);\n const buffer = await response.arrayBuffer();\n return {\n data: new Uint8Array(buffer),\n contentType:\n response.headers.get(\"content-type\") ?? \"application/octet-stream\"\n };\n}\n\n/** Fetch a page's fully rendered HTML via `/content`. */\nexport function browserContent(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string> {\n return quickActionJson<string>(browser, \"content\", input);\n}\n\n/** Convert a page (or raw HTML) to Markdown via `/markdown`. */\nexport function browserMarkdown(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string> {\n return quickActionJson<string>(browser, \"markdown\", input);\n}\n\n/**\n * Extract structured data from a page with AI via `/json`. Provide a `prompt`,\n * a `response_format` JSON Schema, or both.\n */\nexport function browserExtract<T = unknown>(\n browser: QuickActionBinding,\n input: QuickActionExtractInput\n): Promise<T> {\n return quickActionJson<T>(browser, \"json\", input);\n}\n\n/** Retrieve every link on a page via `/links`. */\nexport function browserLinks(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<string[]> {\n return quickActionJson<string[]>(browser, \"links\", input);\n}\n\n/** Scrape specific elements (by CSS selector) via `/scrape`. */\nexport function browserScrape(\n browser: QuickActionBinding,\n input: QuickActionScrapeInput\n): Promise<QuickActionScrapeResult[]> {\n return quickActionJson<QuickActionScrapeResult[]>(browser, \"scrape\", input);\n}\n\n/** Capture rendered HTML plus a base64 screenshot in one request via `/snapshot`. */\nexport function browserSnapshot(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<QuickActionSnapshot> {\n return quickActionJson<QuickActionSnapshot>(browser, \"snapshot\", input);\n}\n\n/**\n * Render a screenshot via `/screenshot`. Returns the raw bytes and their\n * content type — by default a PNG (`image/png`). Note that passing\n * `screenshotOptions.encoding: \"base64\"` makes the service return a `text/plain`\n * data-URI string instead of binary, which this helper hands back verbatim.\n */\nexport function browserScreenshot(\n browser: QuickActionBinding,\n input: QuickActionScreenshotInput\n): Promise<QuickActionBinary> {\n return quickActionBinary(browser, \"screenshot\", input);\n}\n\n/** Render a PDF via `/pdf`. Returns the PDF bytes. */\nexport function browserPdf(\n browser: QuickActionBinding,\n input: QuickActionPage\n): Promise<QuickActionBinary> {\n return quickActionBinary(browser, \"pdf\", input);\n}\n","/**\n * Chrome DevTools Protocol spec fetching + caching.\n *\n * The raw `/json/protocol` payload is normalized into a searchable shape and\n * cached per source: `cdpUrl` specs by endpoint + headers, Browser Rendering\n * specs by the binding itself (a WeakMap) so two different bindings in the\n * same isolate don't share an entry. The CDP protocol is identical across\n * bindings, but per-binding keys avoid surprising cross-binding cache reads.\n */\n\nimport type { BrowserBinding } from \"./browser-run\";\n\ninterface RawCdpCommand {\n name: string;\n description?: string;\n}\n\ninterface RawCdpEvent {\n name: string;\n description?: string;\n}\n\ninterface RawCdpType {\n id: string;\n description?: string;\n}\n\n/** Raw CDP protocol domain from `/json/protocol` */\ninterface RawCdpDomain {\n domain: string;\n description?: string;\n commands?: RawCdpCommand[];\n events?: RawCdpEvent[];\n types?: RawCdpType[];\n}\n\nexport interface SearchableCdpSpec {\n domains: Array<{\n name: string;\n description?: string;\n commands: Array<{ name: string; method: string; description?: string }>;\n events: Array<{ name: string; event: string; description?: string }>;\n types: Array<{ id: string; name: string; description?: string }>;\n }>;\n}\n\nexport interface CdpSpecSource {\n /** Browser Rendering binding (Fetcher) — used in production */\n browser?: BrowserBinding;\n /** CDP base URL override (e.g. http://localhost:9222) */\n cdpUrl?: string;\n /** Headers to send with CDP URL discovery requests */\n cdpHeaders?: Record<string, string>;\n}\n\nconst MISSING_BROWSER_CONFIG =\n \"Either 'browser' (Fetcher binding) or 'cdpUrl' must be provided\";\n\ninterface SpecCacheEntry {\n spec: SearchableCdpSpec;\n cachedAt: number;\n}\n\nconst urlSpecCache = new Map<string, SpecCacheEntry>();\nconst bindingSpecCache = new WeakMap<BrowserBinding, SpecCacheEntry>();\n\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction normalizeCdpSpec(spec: {\n domains?: RawCdpDomain[];\n}): SearchableCdpSpec {\n return {\n domains: (spec.domains ?? []).map((domain) => ({\n name: domain.domain,\n description: domain.description,\n commands: (domain.commands ?? []).map((command) => ({\n name: command.name,\n method: `${domain.domain}.${command.name}`,\n description: command.description\n })),\n events: (domain.events ?? []).map((event) => ({\n name: event.name,\n event: `${domain.domain}.${event.name}`,\n description: event.description\n })),\n types: (domain.types ?? []).map((type) => ({\n id: type.id,\n name: `${domain.domain}.${type.id}`,\n description: type.description\n }))\n }))\n };\n}\n\nfunction getSpecCacheKey(\n source: string,\n headers?: Record<string, string>\n): string {\n const headerEntries = Object.entries(headers ?? {}).sort(([a], [b]) =>\n a.localeCompare(b)\n );\n return `${source}:${JSON.stringify(headerEntries)}`;\n}\n\nasync function getCachedSpec<K>(\n cache: {\n get(key: K): SpecCacheEntry | undefined;\n set(key: K, entry: SpecCacheEntry): void;\n },\n key: K,\n load: () => Promise<{ domains?: RawCdpDomain[] }>\n): Promise<SearchableCdpSpec> {\n const cached = cache.get(key);\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {\n return cached.spec;\n }\n\n const spec = normalizeCdpSpec(await load());\n cache.set(key, { spec, cachedAt: Date.now() });\n return spec;\n}\n\nasync function fetchCdpSpecFromUrl(\n cdpBaseUrl: string,\n headers?: Record<string, string>\n): Promise<SearchableCdpSpec> {\n const endpoint = new URL(\"/json/protocol\", cdpBaseUrl).toString();\n\n return getCachedSpec(\n urlSpecCache,\n getSpecCacheKey(endpoint, headers),\n async () => {\n const response = await fetch(endpoint, { headers });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch CDP spec from ${endpoint}: ${response.status}`\n );\n }\n\n return (await response.json()) as { domains?: RawCdpDomain[] };\n }\n );\n}\n\nasync function fetchCdpSpecFromBrowser(\n browser: BrowserBinding\n): Promise<SearchableCdpSpec> {\n return getCachedSpec(bindingSpecCache, browser, async () => {\n const createResponse = await browser.fetch(\n \"https://localhost/v1/devtools/browser\",\n {\n method: \"POST\"\n }\n );\n\n if (!createResponse.ok) {\n throw new Error(\n \"Failed to create Browser Rendering session for protocol fetch: \" +\n `${createResponse.status}`\n );\n }\n\n const payload = (await createResponse.json()) as { sessionId?: string };\n const sessionId = payload.sessionId;\n if (!sessionId) {\n throw new Error(\n \"Browser Rendering session response did not include a sessionId\"\n );\n }\n\n try {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}/json/protocol`\n );\n\n if (!response.ok) {\n throw new Error(\n \"Failed to fetch CDP spec from Browser Rendering: \" +\n `${response.status}`\n );\n }\n\n return (await response.json()) as { domains?: RawCdpDomain[] };\n } finally {\n try {\n await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}`,\n {\n method: \"DELETE\"\n }\n );\n } catch {\n // Cleanup failure should not mask the original result or error\n }\n }\n });\n}\n\n/** Load the (cached) searchable CDP spec for a browser source. */\nexport async function loadCdpSpec(\n source: CdpSpecSource\n): Promise<SearchableCdpSpec> {\n if (source.cdpUrl) {\n return fetchCdpSpecFromUrl(source.cdpUrl, source.cdpHeaders);\n }\n if (source.browser) {\n return fetchCdpSpecFromBrowser(source.browser);\n }\n throw new Error(MISSING_BROWSER_CONFIG);\n}\n","type MaybePromise<T> = T | Promise<T>;\n\nexport interface StoredBrowserSession {\n sessionId: string;\n createdAt: number;\n updatedAt: number;\n /**\n * Set when a sweep closed this entry's Browser Run session but kept the\n * entry as a tombstone, so a later resume of the owning execution fails\n * loudly instead of silently continuing in a fresh browser.\n */\n closedAt?: number;\n}\n\nexport interface BrowserSessionLock {\n release(): MaybePromise<void>;\n}\n\nexport interface BrowserSessionStore {\n /**\n * Acquire an exclusive lock for this session key. The lock must serialize\n * all holders using the same key. Held only around storage reads/writes —\n * never across Browser Rendering network calls.\n */\n acquireLock(key: string): MaybePromise<BrowserSessionLock>;\n get(key: string): MaybePromise<StoredBrowserSession | undefined>;\n set(key: string, session: StoredBrowserSession): MaybePromise<void>;\n delete(key: string): MaybePromise<void>;\n /**\n * List stored sessions by key prefix. Optional — used by sweeps to find\n * orphaned per-execution sessions; without it only the shared session key\n * is swept.\n */\n list?(prefix: string): MaybePromise<Map<string, StoredBrowserSession>>;\n}\n\nexport class DurableBrowserSessionStore implements BrowserSessionStore {\n static #queues = new WeakMap<\n DurableObjectStorage,\n Map<string, Promise<void>>\n >();\n\n constructor(private readonly storage: DurableObjectStorage) {}\n\n async acquireLock(key: string): Promise<BrowserSessionLock> {\n let queues = DurableBrowserSessionStore.#queues.get(this.storage);\n if (!queues) {\n queues = new Map();\n DurableBrowserSessionStore.#queues.set(this.storage, queues);\n }\n\n const previous = queues.get(key) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = previous.then(\n () =>\n new Promise<void>((resolve) => {\n releaseQueue = resolve;\n })\n );\n queues.set(key, current);\n await previous;\n\n let released = false;\n return {\n release: () => {\n if (released) return;\n released = true;\n if (queues.get(key) === current) {\n queues.delete(key);\n }\n releaseQueue();\n }\n };\n }\n\n async get(key: string): Promise<StoredBrowserSession | undefined> {\n return this.storage.get<StoredBrowserSession>(this.#storageKey(key));\n }\n\n async set(key: string, session: StoredBrowserSession): Promise<void> {\n await this.storage.put(this.#storageKey(key), session);\n }\n\n async delete(key: string): Promise<void> {\n await this.storage.delete(this.#storageKey(key));\n }\n\n async list(prefix: string): Promise<Map<string, StoredBrowserSession>> {\n const storagePrefix = this.#storageKey(prefix);\n const entries = await this.storage.list<StoredBrowserSession>({\n prefix: storagePrefix\n });\n const result = new Map<string, StoredBrowserSession>();\n for (const [storageKey, value] of entries) {\n result.set(storageKey.slice(\"browser-session:\".length), value);\n }\n return result;\n }\n\n #storageKey(key: string): string {\n return `browser-session:${key}`;\n }\n}\n\n/**\n * Default idle window used by {@link BrowserConnector.sweep} for the shared\n * (reuse/promoted) session entry.\n */\nexport const DEFAULT_SWEEP_IDLE_MS = 10 * 60 * 1000;\n","import {\n CodemodeConnector,\n type ConnectorTools,\n type ExecutionEndStatus,\n type PassEndStatus,\n type ToolExecuteContext\n} from \"@cloudflare/codemode\";\nimport { CdpSession, connectUrl } from \"./cdp-session\";\nimport {\n connectBrowserSession,\n createBrowserSession,\n deleteBrowserSession,\n listBrowserTargets,\n BrowserRenderingError,\n type BrowserBinding,\n type BrowserSessionInfo,\n type BrowserTargetInfo\n} from \"./browser-run\";\nimport { loadCdpSpec, type SearchableCdpSpec } from \"./spec\";\nimport type {\n BrowserSessionStore,\n StoredBrowserSession\n} from \"./session-manager\";\nimport { DEFAULT_SWEEP_IDLE_MS } from \"./session-manager\";\n\n/** Browser session lifecycle for the connector (binding-backed only). */\nexport interface BrowserConnectorSessionOptions {\n /**\n * - `\"one-shot\"` (default) — one Browser Run session per codemode\n * execution, deleted when the execution ends.\n * - `\"reuse\"` — all executions share one stored session under `key`.\n * - `\"dynamic\"` — per-execution sessions by default; the model can call\n * `cdp.startSession()` to promote the current session into the shared\n * slot so later executions reuse it.\n */\n mode?: \"one-shot\" | \"reuse\" | \"dynamic\";\n /** Logical owner key for the shared (reuse/promoted) session. Default `\"default\"`. */\n key?: string;\n /** Browser Run inactivity timeout. Browser Run currently caps this server-side. */\n keepAliveMs?: number;\n /**\n * Opt into Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/)\n * for sessions this connector creates: an rrweb capture of everything the\n * agent did, finalized when the session closes. Retrieve it afterward with\n * {@link getBrowserRecording} using the session id from\n * {@link BrowserConnector.liveView}/`sessionInfo()`.\n */\n recording?: boolean;\n}\n\nexport type BrowserConnectorOptions = (\n | {\n /** Browser Rendering binding (Fetcher) — used in production. */\n browser: BrowserBinding;\n /**\n * Durable store for Browser Run session ids. Required with the binding:\n * a session must survive a pause (approval) and resume on a fresh\n * instance, so its id cannot live in connector memory.\n */\n store: BrowserSessionStore;\n session?: BrowserConnectorSessionOptions;\n cdpUrl?: never;\n cdpHeaders?: never;\n }\n | {\n /**\n * CDP base URL override (e.g. http://localhost:9222). The browser is\n * externally managed: no Browser Run sessions are created or deleted,\n * and session modes don't apply.\n */\n cdpUrl: string;\n /** Headers to send with CDP URL discovery requests (e.g. Access headers). */\n cdpHeaders?: Record<string, string>;\n browser?: never;\n store?: never;\n session?: never;\n }\n) & {\n /** CDP command timeout in milliseconds (default: 10000). */\n timeout?: number;\n};\n\nexport interface BrowserConnectorSweepOptions {\n /**\n * Close the shared (reuse/promoted) session when idle for at least this\n * many milliseconds. Defaults to the connector's `keepAliveMs`, or\n * {@link DEFAULT_SWEEP_IDLE_MS}.\n */\n maxIdleMs?: number;\n /**\n * Close *per-execution* sessions when idle for at least this many\n * milliseconds. Defaults to {@link DEFAULT_EXEC_SWEEP_IDLE_MS} (24h) —\n * deliberately at least as long as the codemode runtime's default paused\n * TTL, so a run awaiting approval is normally expired (and disposed) by\n * `expirePaused` before the sweep backstop ever touches its browser.\n */\n maxExecIdleMs?: number;\n}\n\nexport interface BrowserConnectorSweepResult {\n /** Store keys (and their Browser Run session ids) closed by this sweep. */\n swept: Array<{ key: string; sessionId: string }>;\n}\n\n/**\n * Live View rendering mode (the `mode` query param the hosted UI at\n * `live.browser.run` understands):\n *\n * - `\"tab\"` — a standalone, interactive page view (best for handing control\n * to a human).\n * - `\"devtools\"` — the full DevTools inspector panel (Elements, Console,\n * Network, …).\n *\n * Omit it to use whatever mode the binding's `devtoolsFrontendUrl` defaults\n * to.\n */\nexport type LiveViewMode = \"tab\" | \"devtools\";\n\n/** A single tab's Live View URL. */\nexport interface BrowserLiveViewUrl {\n /** Open this in a browser to watch/control the tab in real time. */\n url: string;\n /** CDP target (tab) id the URL points at. */\n targetId: string;\n /** Milliseconds the URL stays valid from when it was generated (~5 min). */\n expiresInMs: number;\n}\n\nexport interface BrowserLiveViewTarget {\n targetId: string;\n /** Embeddable Live View URL (the `devtoolsFrontendUrl`) for this tab. */\n url: string;\n /** The page the tab is currently showing (e.g. `https://example.com`). */\n pageUrl?: string;\n title?: string;\n type?: string;\n}\n\n/** Live View URLs for every tab in a (shared) session. */\nexport interface BrowserLiveView {\n sessionId: string;\n targets: BrowserLiveViewTarget[];\n /** Milliseconds the URLs stay valid from when they were generated (~5 min). */\n expiresInMs: number;\n}\n\nconst EXEC_KEY_PREFIX = \"cdp:exec:\";\nconst REUSE_KEY_PREFIX = \"cdp:reuse:\";\n\n/**\n * Default idle window before {@link BrowserConnector.sweep} reclaims a\n * per-execution session. Matches the codemode runtime's default paused TTL\n * (24h): an execution paused for approval keeps its browser until the run\n * itself is expired.\n */\nexport const DEFAULT_EXEC_SWEEP_IDLE_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Minimum interval between `updatedAt` bumps on a per-execution store entry.\n * Touching on every CDP call would write-amplify; once a minute is enough to\n * keep an active or recently-resumed execution out of sweep range.\n */\nconst EXEC_TOUCH_INTERVAL_MS = 60 * 1000;\n\n/**\n * Browser Run mints `devtoolsFrontendUrl`s (the Live View links) that are\n * valid for ~5 minutes. We surface the window so callers can decide how long\n * a shared link is good for before re-listing targets.\n */\nconst LIVE_VIEW_URL_TTL_MS = 5 * 60 * 1000;\n\nfunction isMissingBrowserSession(error: unknown): boolean {\n return error instanceof BrowserRenderingError && error.status === 404;\n}\n\n/**\n * Rewrite the hosted Live View UI's `mode` query param (`tab` | `devtools`).\n * The raw `devtoolsFrontendUrl` is returned unchanged when no mode is asked\n * for or the URL can't be parsed.\n */\nfunction applyLiveViewMode(rawUrl: string, mode?: LiveViewMode): string {\n if (!mode) return rawUrl;\n try {\n const url = new URL(rawUrl);\n url.searchParams.set(\"mode\", mode === \"devtools\" ? \"devtools\" : \"tab\");\n return url.toString();\n } catch {\n return rawUrl;\n }\n}\n\ninterface CachedSocket {\n session: CdpSession;\n /** Browser Run session id the socket is attached to (undefined for cdpUrl). */\n browserSessionId?: string;\n /**\n * Live CDP session id per attach handle, valid for this socket only.\n * Rebuilt lazily after a reconnect (sockets are per-pass).\n */\n attached: Map<string, string>;\n}\n\n/**\n * `cdp.attachToTarget` returns `{ sessionId: \"target:<targetId>\" }` — a stable\n * handle instead of the raw CDP session id. (The object shape mirrors the real\n * `Target.attachToTarget` response, which is what models reach for.) Raw ids\n * are connection-scoped: a run that pauses\n * for approval resumes on a fresh WebSocket where the old id is invalid, and\n * the durable replay log would otherwise pin the stale value. The handle is a\n * pure function of the target, so replayed code computes identical arguments,\n * and `send` resolves it to a live session id on the current socket —\n * re-attaching lazily after a reconnect.\n */\nconst ATTACH_HANDLE_PREFIX = \"target:\";\n\n/**\n * Codemode connector exposing a live browser over the Chrome DevTools\n * Protocol as the `cdp` global.\n *\n * Per-execution resources are keyed by the codemode `executionId`:\n *\n * - The Browser Run session id is stored durably under `cdp:exec:<id>`, so a\n * run that pauses for approval reconnects to the *same* browser when it\n * resumes — even on a fresh instance.\n * - The CDP WebSocket is per-pass: `onPassEnd` disconnects it (a paused run\n * holds no socket), and the next pass reconnects from the stored id.\n * - `disposeExecution` deletes the session unless it was promoted to the\n * shared slot via `cdp.startSession()` (dynamic mode).\n *\n * Locks on the session store are held only around store reads/writes, never\n * across network calls to Browser Run or while a socket is open.\n */\nexport class BrowserConnector extends CodemodeConnector {\n #options: BrowserConnectorOptions;\n #sockets = new Map<string, CachedSocket>();\n #connecting = new Map<string, Promise<CdpSession>>();\n\n constructor(\n ctx: DurableObjectState | ExecutionContext,\n options: BrowserConnectorOptions\n ) {\n super(ctx, {});\n if (!options.cdpUrl && !options.browser) {\n throw new Error(\n \"BrowserConnector requires either 'browser' (Fetcher binding) or 'cdpUrl'\"\n );\n }\n if (options.browser && !options.store) {\n throw new Error(\n \"BrowserConnector requires 'store' when using the Browser Rendering binding\"\n );\n }\n this.#options = options;\n }\n\n name(): string {\n return \"cdp\";\n }\n\n protected instructions(): string {\n const mode = this.#mode();\n const lines = [\n \"Issue CDP calls sequentially — never in parallel (no Promise.all): call order is recorded for durable replay.\",\n \"Browser-/Target-scoped commands (Target.createTarget, Target.getTargets) need no sessionId. Page-scoped commands (Page.navigate, Runtime.evaluate) require one: `const { sessionId } = await cdp.attachToTarget({ targetId });` then pass it to every page-scoped send.\",\n \"Write large outputs (screenshots, page dumps) to a file or workspace immediately and pass around small references — large return values fail to record.\",\n \"Use cdp.spec() to discover commands, events, and types when unsure.\",\n \"If a command fails or times out, check cdp.getDebugLog() for recent protocol traffic.\",\n \"When a step needs a human (login, MFA, CAPTCHA, sensitive input), call cdp.getLiveViewUrl() to get a link they can open to control the browser live — surface it, then make an approval-gated call so the run pauses until they're done.\"\n ];\n if (mode === \"one-shot\") {\n lines.push(\n \"The browser session lasts for this execution only and is closed when it ends.\"\n );\n } else if (mode === \"reuse\") {\n lines.push(\n \"The browser session is shared and persists across executions — tabs and state you leave behind will still be there next time.\"\n );\n } else {\n lines.push(\n \"The browser session is one-shot by default. If browser state must persist after this execution (e.g. a logged-in page), call cdp.startSession() to keep it alive for later executions.\"\n );\n }\n return lines.join(\"\\n\");\n }\n\n protected tools(): ConnectorTools {\n const tools: ConnectorTools = {\n send: {\n description:\n \"Send a CDP command and return its result. Page-scoped commands require a sessionId — pass the handle returned by attachToTarget.\",\n inputSchema: {\n type: \"object\",\n properties: {\n method: {\n type: \"string\",\n description: 'CDP method, e.g. \"Target.createTarget\"'\n },\n params: {\n type: \"object\",\n description: \"CDP command parameters\"\n },\n sessionId: {\n type: \"string\",\n description:\n \"Session handle from attachToTarget, for page-scoped commands\"\n },\n timeoutMs: {\n type: \"number\",\n description: \"Per-command timeout override in milliseconds\"\n }\n },\n required: [\"method\"]\n },\n execute: async (args, ctx) => {\n const { method, params, sessionId, timeoutMs } = args as {\n method: string;\n params?: unknown;\n sessionId?: string;\n timeoutMs?: number;\n };\n const executionId = this.#executionId(ctx);\n const socket = await this.#socket(executionId);\n const resolved = await this.#resolveSessionHandle(\n executionId,\n sessionId\n );\n try {\n return await socket.send(method, params, {\n sessionId: resolved,\n timeoutMs\n });\n } catch (err) {\n // \"Method wasn't found\" is almost always one of two model\n // mistakes. Teach the fix instead of leaving a bare protocol\n // error: either the method is actually an event (events can't be\n // sent), or a page-scoped command went to the browser-level\n // session because no sessionId was passed.\n if (\n err instanceof Error &&\n /-32601|wasn't found/.test(err.message)\n ) {\n if (await this.#isSpecEvent(method)) {\n throw new Error(\n `${err.message}. '${method}' is a CDP *event*, not a ` +\n `command — it cannot be called via cdp.send. To wait for ` +\n `page state, poll instead (e.g. Runtime.evaluate of ` +\n `document.readyState until \"complete\").`\n );\n }\n if (!sessionId) {\n throw new Error(\n `${err.message}. Page-scoped commands need a sessionId: ` +\n `const { sessionId } = await cdp.attachToTarget({ targetId }); ` +\n `then pass sessionId to cdp.send.`\n );\n }\n }\n throw err;\n }\n }\n },\n\n attachToTarget: {\n description:\n \"Attach to a target (tab) and return { sessionId } — a stable session handle to pass as sessionId in page-scoped send calls. The handle stays valid across pauses/resumes.\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: {\n type: \"string\",\n description: \"Target id from Target.createTarget/getTargets\"\n },\n timeoutMs: { type: \"number\" }\n },\n required: [\"targetId\"]\n },\n outputSchema: {\n type: \"object\",\n properties: {\n sessionId: {\n type: \"string\",\n description:\n \"Stable session handle for page-scoped send calls (valid across pauses/resumes)\"\n }\n },\n required: [\"sessionId\"]\n },\n execute: async (args, ctx) => {\n const { targetId, timeoutMs } = args as {\n targetId: string;\n timeoutMs?: number;\n };\n const executionId = this.#executionId(ctx);\n await this.#attach(executionId, targetId, timeoutMs);\n return { sessionId: `${ATTACH_HANDLE_PREFIX}${targetId}` };\n }\n },\n\n spec: {\n description:\n \"Return the searchable Chrome DevTools Protocol spec: domains with their commands, events, and types. Use it to discover method names and capabilities.\",\n replay: \"reexecute\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (): Promise<SearchableCdpSpec> =>\n loadCdpSpec(this.#options)\n },\n\n getDebugLog: {\n description:\n \"Return recent CDP protocol traffic (sends, receives, warnings) for this execution's connection — useful to diagnose failures and timeouts.\",\n replay: \"reexecute\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Max entries to return (default 50)\"\n }\n }\n },\n execute: async (args, ctx) => {\n const { limit } = (args ?? {}) as { limit?: number };\n const socket = await this.#socket(this.#executionId(ctx));\n return socket.getDebugLog(limit);\n }\n },\n\n clearDebugLog: {\n description: \"Clear the CDP debug log for this execution's connection.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) => {\n const socket = await this.#socket(this.#executionId(ctx));\n socket.clearDebugLog();\n return null;\n }\n },\n\n getLiveViewUrl: {\n description:\n \"Return a Live View URL for a tab — a link a human can open in a \" +\n \"browser to watch and control this session in real time. Use it \" +\n \"for human-in-the-loop steps (login, MFA, CAPTCHA, sensitive \" +\n \"input): get the URL, surface it to the user, then make a call \" +\n \"that pauses for approval so they can act before the run \" +\n \"continues. The URL is valid for ~5 minutes.\",\n replay: \"reexecute\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: {\n type: \"string\",\n description:\n \"Target (tab) id to view; defaults to the first open page\"\n },\n mode: {\n type: \"string\",\n enum: [\"tab\", \"devtools\"],\n description:\n \"tab = standalone interactive page view (best for handoff); \" +\n \"devtools = full DevTools inspector panel\"\n }\n }\n },\n execute: async (args, ctx) => {\n const { targetId, mode } = (args ?? {}) as {\n targetId?: string;\n mode?: LiveViewMode;\n };\n return this.#liveViewUrl(this.#executionId(ctx), { targetId, mode });\n }\n }\n };\n\n const mode = this.#mode();\n if (mode === \"reuse\" || mode === \"dynamic\") {\n tools.startSession = {\n description:\n mode === \"dynamic\"\n ? \"Promote the current browser session into the shared slot so it persists after this execution. Later executions reuse it. Returns the session info.\"\n : \"Ensure the shared browser session exists and return its info.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) =>\n this.#startSession(this.#executionId(ctx))\n };\n tools.sessionInfo = {\n description:\n \"Return info about the shared browser session (id and open targets), or null when none exists.\",\n replay: \"reexecute\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async () => (await this.sessionInfo()) ?? null\n };\n tools.closeSession = {\n description:\n \"Close the shared browser session, discarding its tabs and state.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) => {\n await this.#closeReusableFor(this.#executionId(ctx));\n return null;\n }\n };\n tools.resetSession = {\n description:\n \"Close the shared browser session and start a fresh one. Returns the new session info.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) =>\n this.#resetSession(this.#executionId(ctx))\n };\n }\n\n return tools;\n }\n\n // ---------------------------------------------------------------------\n // Lifecycle hooks\n // ---------------------------------------------------------------------\n\n /**\n * A pass is over (completed, errored, or paused awaiting approval) — drop\n * the CDP socket. The Browser Run session itself stays alive; a resume\n * reconnects from the durably stored session id.\n */\n override async onPassEnd(\n executionId: string,\n _status: PassEndStatus\n ): Promise<void> {\n this.#dropSocket(executionId);\n }\n\n /**\n * The execution is terminal — delete its Browser Run session unless it was\n * promoted to the shared slot via `cdp.startSession()`.\n */\n override async disposeExecution(\n executionId: string,\n _status: ExecutionEndStatus\n ): Promise<void> {\n this.#dropSocket(executionId);\n if (!this.#options.browser) return;\n\n const store = this.#options.store;\n const execKey = this.#execKey(executionId);\n const lock = await store.acquireLock(execKey);\n // Decide and update storage under the lock; the Browser Rendering delete\n // happens after release (locks wrap storage only).\n let toClose: StoredBrowserSession | undefined;\n try {\n const stored = await store.get(execKey);\n if (!stored) return;\n\n let promoted = false;\n if (this.#mode() === \"dynamic\") {\n const shared = await store.get(this.#reuseKey());\n promoted = shared?.sessionId === stored.sessionId;\n }\n\n if (!promoted && stored.closedAt === undefined) {\n toClose = stored;\n }\n await store.delete(execKey);\n } finally {\n await lock.release();\n }\n\n if (toClose) {\n try {\n await deleteBrowserSession(this.#options.browser, toClose.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete Browser Run session ${toClose.sessionId} for execution ${executionId}`,\n error\n );\n }\n }\n }\n\n // ---------------------------------------------------------------------\n // Host-side helpers — for callables and scheduled tasks on the agent.\n // ---------------------------------------------------------------------\n\n /** Info about the shared (reuse/promoted) session, if one exists. */\n async sessionInfo(): Promise<BrowserSessionInfo | undefined> {\n if (!this.#options.browser) return undefined;\n const store = this.#options.store;\n const key = this.#reuseKey();\n const lock = await store.acquireLock(key);\n let stored: StoredBrowserSession | undefined;\n try {\n stored = await store.get(key);\n } finally {\n await lock.release();\n }\n if (!stored) return undefined;\n try {\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(\n this.#options.browser,\n stored.sessionId\n )\n };\n } catch (error) {\n if (isMissingBrowserSession(error)) {\n await this.#deleteStoredEntry(key, stored.sessionId);\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * Live View URLs for the shared (reuse/promoted) session's tabs, or\n * `undefined` when no shared session exists. Each URL opens an interactive,\n * real-time view of the browser — surface them in your UI (or send them via\n * Slack/email) to let a human watch or take over a running session\n * (human-in-the-loop). URLs are valid for ~5 minutes; call again for fresh\n * ones. Only meaningful with the Browser Rendering binding in\n * `reuse`/`dynamic` mode.\n */\n async liveView(options?: {\n mode?: LiveViewMode;\n }): Promise<BrowserLiveView | undefined> {\n const info = await this.sessionInfo();\n if (!info) return undefined;\n const targets = (info.targets ?? [])\n .filter((target) => target.devtoolsFrontendUrl)\n .map((target) => ({\n targetId: target.id,\n url: applyLiveViewMode(target.devtoolsFrontendUrl!, options?.mode),\n pageUrl: target.url,\n title: target.title,\n type: target.type\n }));\n return {\n sessionId: info.sessionId,\n targets,\n expiresInMs: LIVE_VIEW_URL_TTL_MS\n };\n }\n\n /** Close the shared (reuse/promoted) session, if one exists. */\n async closeSession(): Promise<void> {\n if (!this.#options.browser) return;\n await this.#closeStoredSession(this.#reuseKey());\n }\n\n /**\n * Close stored sessions (shared and per-execution) idle past the threshold.\n * Per-execution entries normally die with `disposeExecution` (or the\n * codemode runtime's `expirePaused`); the sweep is the backstop for crashed\n * hosts. Call it from a recurring alarm/scheduled task.\n *\n * Active executions bump their entry's `updatedAt` on use, so only runs\n * idle past `maxExecIdleMs` (default 24h) are reclaimed. A swept\n * per-execution entry is kept as a tombstone (`closedAt`) rather than\n * deleted, so a later resume fails with a clear \"session expired\" error\n * instead of silently continuing in a fresh browser; tombstones are\n * deleted once they age past the threshold again.\n */\n async sweep(\n options?: BrowserConnectorSweepOptions\n ): Promise<BrowserConnectorSweepResult> {\n if (!this.#options.browser) return { swept: [] };\n const store = this.#options.store;\n const maxIdleMs =\n options?.maxIdleMs ??\n this.#options.session?.keepAliveMs ??\n DEFAULT_SWEEP_IDLE_MS;\n const maxExecIdleMs = options?.maxExecIdleMs ?? DEFAULT_EXEC_SWEEP_IDLE_MS;\n\n const keys = new Set<string>([this.#reuseKey()]);\n if (store.list) {\n for (const key of (await store.list(\"cdp:\")).keys()) {\n keys.add(key);\n }\n }\n\n const swept: Array<{ key: string; sessionId: string }> = [];\n for (const key of keys) {\n const isExec = key.startsWith(EXEC_KEY_PREFIX);\n const idleMs = isExec ? maxExecIdleMs : maxIdleMs;\n const lock = await store.acquireLock(key);\n let toClose: StoredBrowserSession | undefined;\n try {\n const stored = await store.get(key);\n if (!stored) continue;\n const now = Date.now();\n if (stored.closedAt !== undefined) {\n // Tombstone from a previous sweep — its session is already gone.\n // Drop it once it has aged past the threshold again.\n if (now - stored.closedAt >= idleMs) await store.delete(key);\n continue;\n }\n if (now - stored.updatedAt < idleMs) continue;\n if (isExec) {\n await store.set(key, { ...stored, closedAt: now });\n } else {\n await store.delete(key);\n }\n toClose = stored;\n } finally {\n await lock.release();\n }\n try {\n await deleteBrowserSession(this.#options.browser, toClose.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Sweep failed to delete Browser Run session ${toClose.sessionId}`,\n error\n );\n }\n swept.push({ key, sessionId: toClose.sessionId });\n }\n return { swept };\n }\n\n // ---------------------------------------------------------------------\n // Session + socket resolution\n // ---------------------------------------------------------------------\n\n #mode(): \"one-shot\" | \"reuse\" | \"dynamic\" {\n return this.#options.session?.mode ?? \"one-shot\";\n }\n\n #execKey(executionId: string): string {\n return `${EXEC_KEY_PREFIX}${executionId}`;\n }\n\n #reuseKey(): string {\n return `${REUSE_KEY_PREFIX}${this.#options.session?.key ?? \"default\"}`;\n }\n\n #executionId(ctx?: ToolExecuteContext): string {\n if (!ctx?.executionId) {\n throw new Error(\n \"BrowserConnector requires an execution context — use it through createCodemodeRuntime\"\n );\n }\n return ctx.executionId;\n }\n\n #dropSocket(executionId: string): void {\n const cached = this.#sockets.get(executionId);\n if (!cached) return;\n this.#sockets.delete(executionId);\n cached.session.disconnect();\n }\n\n /** Attach the current socket to a target, caching the live CDP session id. */\n async #attach(\n executionId: string,\n targetId: string,\n timeoutMs?: number\n ): Promise<string> {\n const socket = await this.#socket(executionId);\n const cached = this.#sockets.get(executionId);\n const handle = `${ATTACH_HANDLE_PREFIX}${targetId}`;\n const existing = cached?.attached.get(handle);\n if (existing) return existing;\n const live = await socket.attachToTarget(targetId, { timeoutMs });\n cached?.attached.set(handle, live);\n return live;\n }\n\n /**\n * List the current tabs (targets) for this execution's browser, including\n * their `devtoolsFrontendUrl` (the Live View link). For the binding this is\n * the current Browser Run session; for an externally-managed `cdpUrl` it is\n * the standard CDP `/json/list`.\n */\n async #liveTargets(executionId: string): Promise<BrowserTargetInfo[]> {\n if (this.#options.cdpUrl) {\n const endpoint = new URL(\"/json/list\", this.#options.cdpUrl).toString();\n const response = await fetch(endpoint, {\n headers: this.#options.cdpHeaders\n });\n if (!response.ok) {\n throw new Error(\n `Failed to list targets at ${endpoint}: ${response.status}`\n );\n }\n const payload = (await response.json()) as unknown;\n return Array.isArray(payload) ? (payload as BrowserTargetInfo[]) : [];\n }\n\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n // Ensure a session + socket exist, then read the resolved Browser Run id.\n await this.#socket(executionId);\n const sessionId = this.#sockets.get(executionId)?.browserSessionId;\n if (!sessionId) return [];\n return listBrowserTargets(browser, sessionId);\n }\n\n /** Build a Live View URL for one tab in this execution's browser. */\n async #liveViewUrl(\n executionId: string,\n options: { targetId?: string; mode?: LiveViewMode }\n ): Promise<BrowserLiveViewUrl> {\n const targets = await this.#liveTargets(executionId);\n const target = options.targetId\n ? targets.find((candidate) => candidate.id === options.targetId)\n : (targets.find(\n (candidate) =>\n candidate.type === \"page\" && candidate.devtoolsFrontendUrl\n ) ?? targets.find((candidate) => candidate.devtoolsFrontendUrl));\n\n if (!target) {\n throw new Error(\n options.targetId\n ? `No target ${options.targetId} found. List tabs with Target.getTargets or open one with Target.createTarget.`\n : \"No browser tab is open yet. Create one (Target.createTarget) before requesting a Live View URL.\"\n );\n }\n if (!target.devtoolsFrontendUrl) {\n throw new Error(\n `Target ${target.id} has no Live View URL (devtoolsFrontendUrl). Live View needs the Browser Rendering binding.`\n );\n }\n\n return {\n url: applyLiveViewMode(target.devtoolsFrontendUrl, options.mode),\n targetId: target.id,\n expiresInMs: LIVE_VIEW_URL_TTL_MS\n };\n }\n\n /**\n * Resolve a model-facing session handle to the live CDP session id on the\n * current socket, re-attaching lazily after a reconnect. Raw CDP session\n * ids (from manual Target.attachToTarget sends) pass through untouched.\n */\n /**\n * True when `method` is a CDP *event* (e.g. `Page.loadEventFired`) rather\n * than a command. Used only on the `send` failure path to produce a better\n * error; any spec-loading failure just means no extra hint.\n */\n async #isSpecEvent(method: string): Promise<boolean> {\n try {\n const spec = await loadCdpSpec(this.#options);\n const domain = method.split(\".\")[0];\n return spec.domains.some(\n (d) => d.name === domain && d.events.some((e) => e.event === method)\n );\n } catch {\n return false;\n }\n }\n\n async #resolveSessionHandle(\n executionId: string,\n sessionId?: string\n ): Promise<string | undefined> {\n if (!sessionId?.startsWith(ATTACH_HANDLE_PREFIX)) return sessionId;\n const targetId = sessionId.slice(ATTACH_HANDLE_PREFIX.length);\n return this.#attach(executionId, targetId);\n }\n\n /**\n * Get or open the CDP socket for an execution. Concurrent calls for the\n * same execution (model code that ignores the \"sequential calls\" rule and\n * uses Promise.all) share one in-flight connect instead of racing and\n * leaking the loser's WebSocket.\n */\n #socket(executionId: string): Promise<CdpSession> {\n const inFlight = this.#connecting.get(executionId);\n if (inFlight) return inFlight;\n const promise = this.#socketInner(executionId).finally(() => {\n if (this.#connecting.get(executionId) === promise) {\n this.#connecting.delete(executionId);\n }\n });\n this.#connecting.set(executionId, promise);\n return promise;\n }\n\n async #socketInner(executionId: string): Promise<CdpSession> {\n if (this.#options.cdpUrl) {\n const cached = this.#sockets.get(executionId);\n if (cached) return cached.session;\n const session = await connectUrl(this.#options.cdpUrl, {\n timeoutMs: this.#options.timeout,\n headers: this.#options.cdpHeaders\n });\n this.#sockets.set(executionId, { session, attached: new Map() });\n return session;\n }\n\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const stored = await this.#resolveSession(executionId);\n const cached = this.#sockets.get(executionId);\n if (cached?.browserSessionId === stored.sessionId) {\n return cached.session;\n }\n if (cached) this.#dropSocket(executionId);\n\n const session = await connectBrowserSession(\n browser,\n stored.sessionId,\n this.#options.timeout\n );\n this.#sockets.set(executionId, {\n session,\n browserSessionId: stored.sessionId,\n attached: new Map()\n });\n return session;\n }\n\n /**\n * Resolve the Browser Run session for an execution:\n *\n * - An existing `cdp:exec:<id>` entry wins. If its session is gone (e.g.\n * expired while the run was paused), the run fails with a clear error\n * rather than silently continuing in a fresh browser.\n * - In `reuse` mode the shared session is used (created if missing).\n * - In `dynamic` mode an alive shared session is used; otherwise a fresh\n * per-execution session is created.\n * - In `one-shot` mode a fresh per-execution session is created.\n */\n async #resolveSession(executionId: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const mode = this.#mode();\n const execKey = this.#execKey(executionId);\n\n if (mode === \"reuse\") {\n return this.#ensureStoredSession(this.#reuseKey());\n }\n\n // one-shot / dynamic: a session this execution already opened wins.\n const existing = await this.#readStored(execKey);\n if (existing) {\n if (existing.closedAt === undefined && (await this.#isAlive(existing))) {\n // Keep the entry fresh so the sweep backstop never reclaims an\n // active (or recently resumed) execution's session.\n if (Date.now() - existing.updatedAt >= EXEC_TOUCH_INTERVAL_MS) {\n await this.#touchStored(execKey, existing);\n }\n return existing;\n }\n await this.#deleteStoredEntry(execKey, existing.sessionId);\n throw new Error(\n `Browser session ${existing.sessionId} expired or was swept while this execution was paused — the run cannot continue. Start a new execution.`\n );\n }\n\n if (mode === \"dynamic\") {\n const shared = await this.#readStored(this.#reuseKey());\n if (shared) {\n if (await this.#isAlive(shared)) {\n await this.#touchStored(this.#reuseKey(), shared);\n return shared;\n }\n await this.#deleteStoredEntry(this.#reuseKey(), shared.sessionId);\n }\n }\n\n // Create a fresh per-execution session. The Browser Rendering call\n // happens outside the store lock; the lock only guards the commit, so\n // two concurrent tool calls for the same execution don't double-create\n // (the loser's session is deleted).\n return this.#createAndCommit(execKey);\n }\n\n /**\n * Get the stored session under `key`, validating and creating as needed.\n *\n * Network calls (the liveness probe, session creation) happen OUTSIDE the\n * store lock — locks wrap storage only, so a hung Browser Rendering call\n * can't serialize every other operation on this key. The lock is\n * re-acquired to commit, with a sessionId re-check to detect a concurrent\n * swap; on a swap the new entry is re-validated from the top.\n */\n async #ensureStoredSession(key: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const store = this.#store;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const existing = await store.get(key);\n if (!existing) return this.#createAndCommit(key);\n\n const alive = await this.#isAlive(existing);\n const lock = await store.acquireLock(key);\n try {\n const current = await store.get(key);\n if (current?.sessionId !== existing.sessionId) {\n // Entry was swapped while we probed — validate the new one.\n continue;\n }\n if (alive) {\n const refreshed = { ...current, updatedAt: Date.now() };\n await store.set(key, refreshed);\n return refreshed;\n }\n await store.delete(key);\n } finally {\n await lock.release();\n }\n // Dead entry deleted — the next iteration creates a fresh session.\n }\n throw new Error(\n `Browser session entry ${key} kept changing concurrently — retry`\n );\n }\n\n /**\n * Create a Browser Run session (outside any lock) and commit it under\n * `key`. If a concurrent caller committed first, their entry wins and the\n * redundant session is deleted best-effort.\n */\n async #createAndCommit(key: string): Promise<StoredBrowserSession> {\n const browser = this.#options.browser;\n if (!browser) throw new Error(\"BrowserConnector has no browser binding\");\n const store = this.#store;\n\n const info = await createBrowserSession(browser, {\n keepAliveMs: this.#options.session?.keepAliveMs,\n recording: this.#options.session?.recording\n });\n const now = Date.now();\n const stored: StoredBrowserSession = {\n sessionId: info.sessionId,\n createdAt: now,\n updatedAt: now\n };\n\n const lock = await store.acquireLock(key);\n let winner: StoredBrowserSession | undefined;\n try {\n const raced = await store.get(key);\n if (raced) {\n winner = raced;\n } else {\n await store.set(key, stored);\n }\n } finally {\n await lock.release();\n }\n\n if (winner) {\n try {\n await deleteBrowserSession(browser, stored.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete redundant Browser Run session ${stored.sessionId}`,\n error\n );\n }\n return winner;\n }\n return stored;\n }\n\n async #isAlive(stored: StoredBrowserSession): Promise<boolean> {\n const browser = this.#options.browser;\n if (!browser) return false;\n try {\n await listBrowserTargets(browser, stored.sessionId);\n return true;\n } catch (error) {\n if (isMissingBrowserSession(error)) return false;\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------\n // Session tools (reuse/dynamic)\n // ---------------------------------------------------------------------\n\n async #startSession(executionId: string): Promise<BrowserSessionInfo> {\n const browser = this.#options.browser;\n if (!browser) {\n throw new Error(\"startSession requires the Browser Rendering binding\");\n }\n const store = this.#options.store;\n const reuseKey = this.#reuseKey();\n\n if (this.#mode() === \"dynamic\") {\n // Promote this execution's session into the shared slot, if it has one.\n const exec = await this.#readStored(this.#execKey(executionId));\n if (exec && exec.closedAt === undefined) {\n const lock = await store.acquireLock(reuseKey);\n let replaced: StoredBrowserSession | undefined;\n try {\n const shared = await store.get(reuseKey);\n if (shared?.sessionId !== exec.sessionId) {\n replaced = shared;\n await store.set(reuseKey, { ...exec, updatedAt: Date.now() });\n }\n } finally {\n await lock.release();\n }\n if (replaced) {\n try {\n await deleteBrowserSession(browser, replaced.sessionId);\n } catch (error) {\n console.warn(\n `[agents/browser] Failed to delete replaced Browser Run session ${replaced.sessionId}`,\n error\n );\n }\n }\n return {\n sessionId: exec.sessionId,\n targets: await listBrowserTargets(browser, exec.sessionId)\n };\n }\n }\n\n const stored = await this.#ensureStoredSession(reuseKey);\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(browser, stored.sessionId)\n };\n }\n\n async #resetSession(executionId: string): Promise<BrowserSessionInfo> {\n const browser = this.#options.browser;\n if (!browser) {\n throw new Error(\"resetSession requires the Browser Rendering binding\");\n }\n await this.#closeReusableFor(executionId);\n const stored = await this.#ensureStoredSession(this.#reuseKey());\n return {\n sessionId: stored.sessionId,\n targets: await listBrowserTargets(browser, stored.sessionId)\n };\n }\n\n /**\n * Close the shared session from inside an execution. If this execution's\n * socket is attached to that session, drop it first.\n */\n async #closeReusableFor(executionId: string): Promise<void> {\n const reuseKey = this.#reuseKey();\n const stored = await this.#readStored(reuseKey);\n if (!stored) return;\n const cached = this.#sockets.get(executionId);\n if (cached?.browserSessionId === stored.sessionId) {\n this.#dropSocket(executionId);\n }\n await this.#closeStoredSession(reuseKey);\n // In reuse mode the execution continues against a fresh shared session on\n // the next send. In dynamic mode the exec entry (if any) still points at\n // the closed session; clear it so the next send fails loudly instead of\n // silently targeting a deleted browser.\n const exec = await this.#readStored(this.#execKey(executionId));\n if (exec?.sessionId === stored.sessionId) {\n await this.#deleteStoredEntry(this.#execKey(executionId), exec.sessionId);\n }\n }\n\n // ---------------------------------------------------------------------\n // Store access — locks held only around the store operation itself.\n // ---------------------------------------------------------------------\n\n get #store(): BrowserSessionStore {\n const store = this.#options.store;\n if (!store) {\n throw new Error(\n \"BrowserConnector session storage requires the Browser Rendering binding\"\n );\n }\n return store;\n }\n\n async #readStored(key: string): Promise<StoredBrowserSession | undefined> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n return await store.get(key);\n } finally {\n await lock.release();\n }\n }\n\n async #writeStored(key: string, value: StoredBrowserSession): Promise<void> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n await store.set(key, value);\n } finally {\n await lock.release();\n }\n }\n\n async #touchStored(key: string, value: StoredBrowserSession): Promise<void> {\n await this.#writeStored(key, { ...value, updatedAt: Date.now() });\n }\n\n /** Delete the store entry only if it still points at `sessionId`. */\n async #deleteStoredEntry(key: string, sessionId: string): Promise<void> {\n const store = this.#store;\n const lock = await store.acquireLock(key);\n try {\n const current = await store.get(key);\n if (current?.sessionId === sessionId) {\n await store.delete(key);\n }\n } finally {\n await lock.release();\n }\n }\n\n /** Delete the stored entry under `key` and its Browser Run session. */\n async #closeStoredSession(key: string): Promise<void> {\n const browser = this.#options.browser;\n if (!browser) return;\n const store = this.#options.store;\n const lock = await store.acquireLock(key);\n let stored: StoredBrowserSession | undefined;\n try {\n stored = await store.get(key);\n if (stored) await store.delete(key);\n } finally {\n await lock.release();\n }\n if (stored) {\n await deleteBrowserSession(browser, stored.sessionId);\n }\n }\n}\n"],"mappings":"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"}
package/dist/email.js CHANGED
@@ -126,7 +126,7 @@ async function signAgentHeaders(secret, agentName, agentId) {
126
126
  * @throws Always throws an error with migration guidance.
127
127
  */
128
128
  function createHeaderBasedEmailResolver() {
129
- throw new Error("createHeaderBasedEmailResolver has been removed due to a security vulnerability. It trusted attacker-controlled email headers for routing, enabling IDOR attacks.\n\nMigration options:\n - For inbound mail: use createAddressBasedEmailResolver(agentName)\n - For reply flows: use createSecureReplyEmailResolver(secret) with signed headers\n\nSee https://github.com/cloudflare/agents/blob/main/docs/email.md for details.");
129
+ throw new Error("createHeaderBasedEmailResolver has been removed due to a security vulnerability. It trusted attacker-controlled email headers for routing, enabling IDOR attacks.\n\nMigration options:\n - For inbound mail: use createAddressBasedEmailResolver(agentName)\n - For reply flows: use createSecureReplyEmailResolver(secret) with signed headers\n\nSee https://github.com/cloudflare/agents/blob/main/docs/agents/email.md for details.");
130
130
  }
131
131
  /**
132
132
  * Create a resolver for routing email replies with signature verification.