agents 0.28.1 → 0.29.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.
- package/dist/{agent-routing-BMvWTFEp.d.ts → agent-routing-CDbpVjYq.d.ts} +7 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-ohoewW-B.d.ts → agent-tools-C8DH8Yii.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/{ai-ahruGw7e.d.ts → ai-iXw0uOGj.d.ts} +3 -3
- package/dist/{ai-sdk-C2iTAwUd.js → ai-sdk-DRPh2rRa.js} +185 -125
- package/dist/ai-sdk-DRPh2rRa.js.map +1 -0
- package/dist/browser/ai.d.ts +1 -1
- package/dist/browser/ai.js +2 -2
- package/dist/browser/index.d.ts +8 -8
- package/dist/browser/index.js +3 -3
- package/dist/browser/tools/ai-sdk.d.ts +2 -2
- package/dist/browser/tools/ai-sdk.js +1 -1
- package/dist/browser/tools/pi.d.ts +1 -1
- package/dist/browser/tools/pi.js +3 -3
- package/dist/browser/tools/pi.js.map +1 -1
- package/dist/browser/tools/tanstack-ai.d.ts +2 -2
- package/dist/browser/tools/tanstack-ai.js +1 -1
- package/dist/{browser-CEdNlsaD.js → browser-DccPw_wW.js} +130 -79
- package/dist/browser-DccPw_wW.js.map +1 -0
- package/dist/{browser-D30VlpcA.d.ts → browser-DlXhSAdf.d.ts} +41 -37
- package/dist/{browser-tool-4iomavs_.js → browser-tool-B1mhifin.js} +3 -3
- package/dist/{browser-tool-4iomavs_.js.map → browser-tool-B1mhifin.js.map} +1 -1
- package/dist/{browser-tool-vtrPOV8e.d.ts → browser-tool-Cxjk5sgG.d.ts} +2 -2
- package/dist/chat/index.d.ts +143 -71
- package/dist/chat/index.js +269 -110
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +33 -33
- package/dist/{client-Bp-JwL3p.d.ts → client-C27CtRZr.d.ts} +2 -2
- package/dist/client.d.ts +1 -1
- package/dist/{connector-DEXzVoaY.d.ts → connector-20DJ6p4k.d.ts} +2 -2
- package/dist/{connector-CtZylXdk.js → connector-DAXBOIIi.js} +2 -2
- package/dist/{connector-CtZylXdk.js.map → connector-DAXBOIIi.js.map} +1 -1
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/harness/container/index.js +1 -1
- package/dist/harness/container/index.js.map +1 -1
- package/dist/harness/opencode/index.js +1 -1
- package/dist/harness/pi/index.d.ts +13 -5
- package/dist/harness/pi/index.js +8 -214
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/{images-C4hiIexM.js → images-xaDv2Fqe.js} +636 -168
- package/dist/images-xaDv2Fqe.js.map +1 -0
- package/dist/index-DCxk3OSJ.d.ts +378 -0
- package/dist/{index-kbSUIer3.d.ts → index-iv9FTXX9.d.ts} +80 -112
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{input-schema-xBofjBKC.js → input-schema-B0Etuo-o.js} +2 -2
- package/dist/{input-schema-xBofjBKC.js.map → input-schema-B0Etuo-o.js.map} +1 -1
- package/dist/lifecycle/index.js +1 -1
- package/dist/{lifecycle-DGorpAmA.js → lifecycle-ClT4DmF2.js} +11 -3
- package/dist/lifecycle-ClT4DmF2.js.map +1 -0
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +29 -352
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +25 -13
- package/dist/models/opencode/index.js +16 -11
- package/dist/models/opencode/index.js.map +1 -1
- package/dist/models/pi-ai/index.d.ts +13 -14
- package/dist/models/pi-ai/index.js +85 -32
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{session-store-DoPY12xM.d.ts → session-store-_IK6dV-w.d.ts} +14 -2
- package/dist/{session-store-Do4xkDcf.js → session-store-yvwq1f9x.js} +55 -2
- package/dist/session-store-yvwq1f9x.js.map +1 -0
- package/dist/{settings-BjAiPd6Z.js → settings-Dk2il2Hf.js} +4 -1
- package/dist/settings-Dk2il2Hf.js.map +1 -0
- package/dist/skills/index.d.ts +22 -28
- package/dist/skills/index.js +183 -143
- package/dist/skills/index.js.map +1 -1
- package/dist/{src-CQxJFv4l.js → src-6lr7MtM_.js} +3 -3
- package/dist/src-6lr7MtM_.js.map +1 -0
- package/dist/sub-routing.d.ts +1 -1
- package/dist/{tool-VF0qiO7q.js → tool-DkT_DJBm.js} +2 -2
- package/dist/tool-DkT_DJBm.js.map +1 -0
- package/dist/transport-CPh7YGiw.d.ts +623 -0
- package/dist/voice/index.d.ts +1 -1
- package/dist/web/fetch/tools/pi.js +2 -2
- package/dist/web/fetch/tools/pi.js.map +1 -1
- package/dist/web/search/index.js +1 -1
- package/dist/web/search/tools/ai-sdk.js +2 -2
- package/dist/web/search/tools/pi.js +3 -3
- package/dist/web/search/tools/pi.js.map +1 -1
- package/dist/web/search/tools/tanstack-ai.js +2 -2
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-C3zy8YR0.js → websockets-CqxnntmE.js} +2 -2
- package/dist/{websockets-C3zy8YR0.js.map → websockets-CqxnntmE.js.map} +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +1 -1
- package/docs/chat-agents.md +19 -18
- package/docs/harnesses/pi.md +47 -18
- package/docs/models-pi-ai.md +62 -20
- package/docs/models.md +197 -172
- package/package.json +7 -7
- package/dist/ai-sdk-C2iTAwUd.js.map +0 -1
- package/dist/browser-CEdNlsaD.js.map +0 -1
- package/dist/images-C4hiIexM.js.map +0 -1
- package/dist/lifecycle-DGorpAmA.js.map +0 -1
- package/dist/session-store-Do4xkDcf.js.map +0 -1
- package/dist/settings-BjAiPd6Z.js.map +0 -1
- package/dist/settings-DnD__xuE.d.ts +0 -349
- package/dist/src-CQxJFv4l.js.map +0 -1
- package/dist/tool-VF0qiO7q.js.map +0 -1
- package/dist/transport-DCyarnwm.d.ts +0 -200
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-store-Do4xkDcf.js","names":[],"sources":["../src/browser/cdp-connection.ts","../src/browser/browser-run.ts","../src/browser/connector-validation.ts","../src/browser/live-view.ts","../src/browser/spec.ts","../src/browser/session-store.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\n/** Construction options for {@link CdpConnection}. */\nexport interface CdpConnectionOptions {\n /** Default per-command timeout. Defaults to 10 seconds. */\n timeoutMs?: number;\n /**\n * Invoked exactly once when the session reaches a terminal state — an\n * explicit `close()`, peer closure, or a socket error.\n */\n onClose?: () => void;\n /** Browser Run session id, when connected to a session-scoped browser. */\n sessionId?: string;\n /** Invoked on every CDP command sent — an activity signal for idle tracking. */\n onActivity?: () => void;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/** JSON-RPC's \"method not found\" code, which Chrome also uses for CDP. */\nexport const CDP_METHOD_NOT_FOUND = -32601;\n\n/** The browser answered a command with a JSON-RPC error. */\nexport class CdpProtocolError extends Error {\n override readonly name = \"CdpProtocolError\";\n /** JSON-RPC error code, e.g. {@link CDP_METHOD_NOT_FOUND}. */\n readonly code: number | undefined;\n /** The CDP method that failed. */\n readonly method: string;\n\n constructor(method: string, code: number | undefined, message: string) {\n super(`CDP error ${code ?? \"unknown\"}: ${message} for ${method}`);\n this.code = code;\n this.method = method;\n }\n}\nconst MAX_DEBUG_ENTRIES = 400;\n\n/**\n * One Chrome DevTools Protocol connection over an open WebSocket. Manages\n * command correlation, timeouts, per-tab CDP sessions, and a debug event\n * 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 CdpConnection {\n #socket: WebSocket;\n #nextId = 1;\n #pending = new Map<number, PendingCommand>();\n #debugLog: DebugEntry[] = [];\n #defaultTimeoutMs: number;\n #dispose?: () => void;\n #disposed = false;\n #onActivity?: () => void;\n readonly sessionId?: string;\n\n constructor(socket: WebSocket, options?: CdpConnectionOptions);\n /**\n * @deprecated Pass a {@link CdpConnectionOptions} object instead —\n * `new CdpConnection(socket, { timeoutMs, onClose, sessionId })`. The\n * positional form will be removed.\n */\n constructor(\n socket: WebSocket,\n timeoutMs?: number,\n onClose?: () => void,\n sessionId?: string\n );\n constructor(\n socket: WebSocket,\n optionsOrTimeoutMs?: CdpConnectionOptions | number,\n onClose?: () => void,\n sessionId?: string\n ) {\n const options: CdpConnectionOptions =\n typeof optionsOrTimeoutMs === \"object\"\n ? optionsOrTimeoutMs\n : { timeoutMs: optionsOrTimeoutMs, onClose, sessionId };\n this.#socket = socket;\n this.#defaultTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#dispose = options.onClose;\n this.sessionId = options.sessionId;\n this.#onActivity = options.onActivity;\n\n socket.addEventListener(\"message\", (event) => this.#handleMessage(event));\n socket.addEventListener(\"error\", () => {\n this.#rejectAll(new Error(\"CDP socket error\"));\n this.#runDispose();\n });\n socket.addEventListener(\"close\", () => {\n this.#rejectAll(new Error(\"CDP connection closed\"));\n this.#runDispose();\n });\n }\n\n send(\n method: string,\n params?: unknown,\n options: CdpSendOptions = {}\n ): Promise<unknown> {\n this.#onActivity?.();\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 try {\n this.#socket.send(JSON.stringify({ id, method, params, sessionId }));\n } catch (error) {\n // A closed socket throws on send: fail this command now rather than\n // leave it pending until it times out.\n const pending = this.#pending.get(id);\n if (pending) {\n clearTimeout(pending.timeoutId);\n this.#pending.delete(id);\n pending.reject(\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\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.#runDispose();\n }\n\n /**\n * Run the dispose callback exactly once, on the first terminal event —\n * an explicit {@link close}, peer closure, or a socket error.\n */\n #runDispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\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 pending.reject(\n new CdpProtocolError(\n pending.method,\n typeof err.code === \"number\" ? err.code : undefined,\n err.message ?? \"CDP error\"\n )\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<CdpConnection> {\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 CdpConnection(ws, { timeoutMs: options?.timeoutMs });\n}\n\n/** @deprecated Renamed to {@link CdpConnection}. */\nexport const CdpSession = CdpConnection;\n/** @deprecated Renamed to {@link CdpConnection}. */\nexport type CdpSession = CdpConnection;\n","import { CdpConnection } from \"./cdp-connection\";\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\n/**\n * Browser Run [hostname guardrails](https://developers.cloudflare.com/browser-run/features/guardrails/):\n * restrict which hostnames the session's HTTP/HTTPS requests may reach. Fixed\n * at session launch for every connection to the session, including Live View.\n * Omitted entirely, the platform default applies: all hostnames are allowed.\n * Not supported by Kitesurf.\n */\nexport interface BrowserSessionGuardrails {\n /**\n * Hostname patterns the browser may request — bare hostnames only (no\n * protocol, port, or path). `*.example.com` matches subdomains; add\n * `example.com` separately to allow the apex.\n */\n allowedDomains?: string[];\n /** Named Cloudflare-maintained domain sets, e.g. `\"common-cdns\"`. */\n allowedDomainSets?: string[];\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\n/** {@link connectBrowser} options for the default Chromium engine. */\nexport interface ConnectChromiumBrowserOptions {\n /** Select the browser engine. Defaults to Chromium. */\n browser?: \"chromium\";\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/**\n * {@link connectBrowser} options for Kitesurf, Cloudflare's connection-scoped,\n * agent-first browser engine. A Kitesurf browser lives and dies with its\n * WebSocket, so the Chromium-only options (`keepAliveMs`, `includeTargets`,\n * `recording`) do not exist on this arm.\n */\nexport interface ConnectKitesurfBrowserOptions {\n browser: \"kitesurf\";\n timeoutMs?: number;\n}\n\n/**\n * Engine-discriminated {@link connectBrowser} options: selecting\n * `browser: \"kitesurf\"` removes the Chromium-only options at the type level.\n */\nexport type ConnectBrowserOptions =\n | ConnectChromiumBrowserOptions\n | ConnectKitesurfBrowserOptions;\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\n/**\n * Whether an error means the platform session is gone: Browser Run uses 404\n * for unknown ids and 410 after `keep_alive` expiry.\n */\nexport function isMissingBrowserSession(error: unknown): boolean {\n return (\n error instanceof BrowserRenderingError &&\n (error.status === 404 || error.status === 410)\n );\n}\n\nfunction browserSessionEndpoint(\n sessionId?: string,\n options?: {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n browser?: \"kitesurf\";\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 if (options?.browser) {\n url.searchParams.set(\"browser\", options.browser);\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 guardrails?: BrowserSessionGuardrails;\n }\n): Promise<BrowserSessionInfo> {\n // Guardrails ride the acquire request's JSON body (the query string only\n // carries scalar options). The endpoint accepts an empty `{}` body —\n // verified against the live acquire API — so the request shape stays\n // uniform whether or not guardrails are set.\n const response = await browser.fetch(\n browserSessionEndpoint(undefined, options),\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(\n options?.guardrails ? { guardrails: options.guardrails } : {}\n )\n }\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<CdpConnection> {\n const normalizedOptions: ConnectBrowserOptions =\n typeof options === \"number\" ? { timeoutMs: options } : (options ?? {});\n if (normalizedOptions.browser === \"kitesurf\") {\n // The options union already rejects these at the type level for literal\n // call sites; plain-JS callers and spreads can still smuggle them in.\n // Explicitly disabled values are tolerated but never sent — `keep_alive=0`\n // is not a valid Kitesurf query parameter.\n const smuggled = normalizedOptions as {\n keepAliveMs?: number;\n includeTargets?: boolean;\n recording?: boolean;\n };\n if (smuggled.keepAliveMs || smuggled.includeTargets || smuggled.recording) {\n throw new Error(\n \"Kitesurf does not support keepAliveMs, includeTargets, or recording\"\n );\n }\n }\n\n const response = await browser.fetch(\n browserSessionEndpoint(\n undefined,\n normalizedOptions.browser === \"kitesurf\"\n ? { browser: \"kitesurf\" }\n : {\n keepAliveMs: normalizedOptions.keepAliveMs,\n includeTargets: normalizedOptions.includeTargets,\n recording: normalizedOptions.recording\n }\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 if (normalizedOptions.browser === \"kitesurf\") {\n // A Kitesurf browser is scoped to this WebSocket. Browser Run may return\n // an ID for analytics correlation, but it cannot be used with the\n // session-scoped reconnect or delete endpoints.\n ws.accept();\n return new CdpConnection(ws, { timeoutMs: normalizedOptions.timeoutMs });\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 CdpConnection(ws, {\n timeoutMs: normalizedOptions.timeoutMs,\n onClose: () => {\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\nexport interface ConnectBrowserSessionOptions {\n timeoutMs?: number;\n /**\n * Invoked once when the returned {@link CdpConnection} reaches a terminal\n * state — an explicit `close()`, peer closure, or a socket error. The\n * session itself is never deleted on close — pass an `onClose` that\n * deletes it for one-shot (create-and-close) semantics.\n */\n onClose?: () => void;\n /**\n * Invoked on every CDP command sent over the returned {@link CdpConnection} —\n * an activity signal for idle tracking. Keep it cheap and synchronous;\n * throttle any I/O it triggers.\n */\n onActivity?: () => void;\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 options?: ConnectBrowserSessionOptions\n): Promise<CdpConnection>;\n/**\n * @deprecated Pass `{ timeoutMs }` instead of a bare number — the numeric\n * form will be removed.\n */\nexport async function connectBrowserSession(\n browser: BrowserBinding,\n sessionId: string,\n timeoutMs?: number\n): Promise<CdpConnection>;\nexport async function connectBrowserSession(\n browser: BrowserBinding,\n sessionId: string,\n options?: number | ConnectBrowserSessionOptions\n): Promise<CdpConnection> {\n const normalized =\n typeof options === \"number\" ? { timeoutMs: options } : (options ?? {});\n const response = await browser.fetch(browserSessionEndpoint(sessionId), {\n headers: { Upgrade: \"websocket\" }\n });\n\n const ws = response.webSocket;\n if (!ws) {\n // Carry the upgrade status: a 404/410 here means the browser expired\n // after the caller last saw it alive (see isMissingBrowserSession).\n throw new BrowserRenderingError(\n `Browser Rendering binding did not return a WebSocket for session ${sessionId} (${response.status})`,\n response.status\n );\n }\n\n ws.accept();\n return new CdpConnection(ws, {\n timeoutMs: normalized.timeoutMs,\n onClose: normalized.onClose,\n sessionId,\n onActivity: normalized.onActivity\n });\n}\n\n/** One-shot session options for the default Chromium engine. */\nexport interface OneShotChromiumSessionOptions {\n /** Select the browser engine. Defaults to Chromium. */\n browser?: \"chromium\";\n timeoutMs?: number;\n /** Platform `keep_alive` in milliseconds. */\n keepAliveMs?: number;\n /** Opt into Browser Run session recording (rrweb capture). */\n recording?: boolean;\n /** Hostname guardrails, fixed at launch. */\n guardrails?: BrowserSessionGuardrails;\n}\n\n/**\n * One-shot session options for Kitesurf. The Chromium-only options —\n * `guardrails`, `keepAliveMs`, `recording` — do not exist on this arm:\n * Kitesurf does not support them.\n */\nexport interface OneShotKitesurfSessionOptions {\n browser: \"kitesurf\";\n timeoutMs?: number;\n}\n\n/**\n * Engine-discriminated {@link openOneShotBrowserSession} options: selecting\n * `browser: \"kitesurf\"` removes the Chromium-only options at the type level.\n */\nexport type OneShotBrowserSessionOptions =\n | OneShotChromiumSessionOptions\n | OneShotKitesurfSessionOptions;\n\n/**\n * Open a one-shot browser session: create, connect, and delete the platform\n * session when the returned {@link CdpConnection} closes. No store involved —\n * one-shot sessions have no name and no durability.\n */\nexport async function openOneShotBrowserSession(\n browser: BrowserBinding,\n options: OneShotBrowserSessionOptions = {}\n): Promise<CdpConnection> {\n if (options.browser === \"kitesurf\") {\n // The options union already rejects these at the type level for literal\n // call sites; plain-JS callers and spreads can still smuggle them in, so\n // fail loudly in one place with one message.\n const smuggled = options as {\n guardrails?: unknown;\n keepAliveMs?: unknown;\n recording?: unknown;\n };\n if (smuggled.guardrails || smuggled.keepAliveMs || smuggled.recording) {\n throw new Error(\n \"Kitesurf does not support guardrails, keepAliveMs, or recording\"\n );\n }\n // Kitesurf browsers are scoped to their WebSocket — connectBrowser is\n // already one-shot there.\n return connectBrowser(browser, {\n browser: \"kitesurf\",\n timeoutMs: options.timeoutMs\n });\n }\n\n const info = await createBrowserSession(browser, {\n keepAliveMs: options.keepAliveMs,\n recording: options.recording,\n guardrails: options.guardrails\n });\n try {\n return await connectBrowserSession(browser, info.sessionId, {\n timeoutMs: options.timeoutMs,\n onClose: () => {\n deleteBrowserSession(browser, info.sessionId).catch(\n (error: unknown) => {\n console.warn(\n `[agents/browser] Failed to delete one-shot Browser Run session ${info.sessionId}`,\n error\n );\n }\n );\n }\n });\n } catch (error) {\n // The session was allocated but never got its delete-on-close owner —\n // reclaim it now instead of leaving it to expire.\n try {\n await deleteBrowserSession(browser, info.sessionId);\n } catch {\n // Best-effort: keep_alive expiry reclaims it.\n }\n throw error;\n }\n}\n","import { Validator, type OutputUnit, type Schema } from \"@cfworker/json-schema\";\nimport type { ConnectorTool } from \"@cloudflare/codemode\";\n\nfunction formatToolValidationError(\n connector: string,\n tool: string,\n errors: OutputUnit[]\n): string {\n // A failing property emits both a generic parent `properties` error and a\n // specific child error. Prefer the latter so the model sees what to fix.\n const specific = errors.filter((error) => error.keyword !== \"properties\");\n const relevant = specific.length > 0 ? specific : errors;\n const details = relevant.map((error) => {\n const location = error.instanceLocation\n .replace(/^#\\/?/, \"\")\n .replaceAll(\"~1\", \"/\")\n .replaceAll(\"~0\", \"~\")\n .replaceAll(\"/\", \".\");\n return `${location ? ` at ${location}` : \"\"}: ${error.error}`;\n });\n return `Invalid arguments for ${connector}.${tool}${details.join(\";\")}`;\n}\n\n/**\n * Validate a connector tool's arguments against its input schema before it\n * runs, so the model gets a precise error instead of a failure deep inside\n * browser work. An omitted argument counts as `{}`: argumentless tools are\n * documented as `cdp.spec()`.\n */\nexport function validateConnectorArgs(\n connector: string,\n name: string,\n tool: ConnectorTool\n): ConnectorTool {\n if (!tool.inputSchema) return tool;\n\n // Both types describe draft-7 schemas, but @cfworker's `Schema` type is\n // narrower than JSONSchema7 around boolean subschemas.\n const schema = tool.inputSchema as unknown as Schema;\n const validator = new Validator(schema, \"7\", false);\n return {\n ...tool,\n execute: async (args, ctx) => {\n const input = args === undefined ? {} : args;\n const result = validator.validate(input);\n if (!result.valid) {\n throw new Error(\n formatToolValidationError(connector, name, result.errors)\n );\n }\n return await tool.execute(input, ctx);\n }\n };\n}\n","/**\n * Live View vocabulary shared by every host-side surface that mints links:\n * the connector's `getLiveViewUrl` tool and `Browser.liveView()`. Live View\n * URLs are bearer credentials — mint them fresh from a target listing when a\n * human is about to view, and never persist them.\n */\n\nimport type { BrowserTargetInfo } from \"./browser-run\";\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 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\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 */\nexport const LIVE_VIEW_URL_TTL_MS = 5 * 60 * 1000;\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 */\nexport function 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\n/**\n * Project a fresh target listing into Live View links — one per tab that has\n * a `devtoolsFrontendUrl`. Pure; the caller supplies just-listed targets.\n */\nexport function createLiveView(\n sessionId: string,\n targets: BrowserTargetInfo[],\n mode?: LiveViewMode\n): BrowserLiveView {\n return {\n sessionId,\n targets: targets\n .filter((target) => target.devtoolsFrontendUrl)\n .map((target) => ({\n targetId: target.id,\n url: applyLiveViewMode(target.devtoolsFrontendUrl!, mode),\n pageUrl: target.url,\n title: target.title,\n type: target.type\n })),\n expiresInMs: LIVE_VIEW_URL_TTL_MS\n };\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\n/** A parameter, return value, or type property in the raw protocol. */\ninterface RawCdpField {\n name: string;\n description?: string;\n optional?: boolean;\n experimental?: boolean;\n deprecated?: boolean;\n type?: string;\n $ref?: string;\n enum?: string[];\n items?: { type?: string; $ref?: string; enum?: string[] };\n}\n\ninterface RawCdpCommand {\n name: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n parameters?: RawCdpField[];\n returns?: RawCdpField[];\n}\n\ninterface RawCdpEvent {\n name: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n parameters?: RawCdpField[];\n}\n\ninterface RawCdpType {\n id: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n type?: string;\n enum?: string[];\n properties?: RawCdpField[];\n items?: { type?: string; $ref?: string; enum?: string[] };\n}\n\n/** Raw CDP protocol domain from `/json/protocol` */\ninterface RawCdpDomain {\n domain: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n commands?: RawCdpCommand[];\n events?: RawCdpEvent[];\n types?: RawCdpType[];\n}\n\n/**\n * The element type of an array field or type. `$ref` is always\n * domain-qualified (`\"Network.Cookie\"`), matching a type's `name`.\n */\nexport interface CdpItems {\n type?: string;\n $ref?: string;\n enum?: string[];\n}\n\n/**\n * A command parameter, return value, event parameter, or type property.\n * Either `type` (a JSON type such as `\"string\"` or `\"array\"`) or `$ref`\n * (a domain-qualified type name matching a type's `name`) is set.\n */\nexport interface CdpField {\n name: string;\n description?: string;\n optional?: boolean;\n experimental?: boolean;\n deprecated?: boolean;\n type?: string;\n $ref?: string;\n enum?: string[];\n items?: CdpItems;\n}\n\nexport interface SearchableCdpSpec {\n domains: Array<{\n name: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n commands: Array<{\n name: string;\n method: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n parameters: CdpField[];\n returns: CdpField[];\n }>;\n events: Array<{\n name: string;\n event: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n parameters: CdpField[];\n }>;\n types: Array<{\n id: string;\n name: string;\n description?: string;\n experimental?: boolean;\n deprecated?: boolean;\n /** JSON type of the value, e.g. `\"string\"`, `\"object\"`, `\"array\"`. */\n type?: string;\n enum?: string[];\n properties: CdpField[];\n items?: CdpItems;\n }>;\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 * An existing Browser Run session to read the protocol from. Without it,\n * loading through the binding creates (and deletes) a throwaway session.\n */\n sessionId?: 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\n/** Qualify a same-domain `$ref` (`\"FrameId\"` → `\"Page.FrameId\"`). */\nfunction qualifyRef(domain: string, ref: string | undefined) {\n if (ref === undefined) return undefined;\n return ref.includes(\".\") ? ref : `${domain}.${ref}`;\n}\n\nfunction normalizeItems(\n domain: string,\n items: RawCdpType[\"items\"]\n): CdpItems | undefined {\n if (!items) return undefined;\n return {\n type: items.type,\n $ref: qualifyRef(domain, items.$ref),\n enum: items.enum\n };\n}\n\nfunction normalizeFields(\n domain: string,\n fields: RawCdpField[] | undefined\n): CdpField[] {\n return (fields ?? []).map((field) => ({\n name: field.name,\n description: field.description,\n optional: field.optional,\n experimental: field.experimental,\n deprecated: field.deprecated,\n type: field.type,\n $ref: qualifyRef(domain, field.$ref),\n enum: field.enum,\n items: normalizeItems(domain, field.items)\n }));\n}\n\nfunction normalizeCdpSpec(spec: {\n domains?: RawCdpDomain[];\n}): SearchableCdpSpec {\n return {\n domains: (spec.domains ?? []).map(({ domain, ...raw }) => ({\n name: domain,\n description: raw.description,\n experimental: raw.experimental,\n deprecated: raw.deprecated,\n commands: (raw.commands ?? []).map((command) => ({\n name: command.name,\n method: `${domain}.${command.name}`,\n description: command.description,\n experimental: command.experimental,\n deprecated: command.deprecated,\n parameters: normalizeFields(domain, command.parameters),\n returns: normalizeFields(domain, command.returns)\n })),\n events: (raw.events ?? []).map((event) => ({\n name: event.name,\n event: `${domain}.${event.name}`,\n description: event.description,\n experimental: event.experimental,\n deprecated: event.deprecated,\n parameters: normalizeFields(domain, event.parameters)\n })),\n types: (raw.types ?? []).map((type) => ({\n id: type.id,\n name: `${domain}.${type.id}`,\n description: type.description,\n experimental: type.experimental,\n deprecated: type.deprecated,\n type: type.type,\n enum: type.enum,\n properties: normalizeFields(domain, type.properties),\n items: normalizeItems(domain, type.items)\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 fetchCdpSpecFromSession(\n browser: BrowserBinding,\n sessionId: string\n): Promise<SearchableCdpSpec> {\n return getCachedSpec(bindingSpecCache, browser, async () => {\n const response = await browser.fetch(\n `https://localhost/v1/devtools/browser/${sessionId}/json/protocol`\n );\n if (!response.ok) {\n throw new Error(\n `Failed to fetch CDP spec from Browser Rendering: ${response.status}`\n );\n }\n return (await response.json()) as { domains?: RawCdpDomain[] };\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 && source.sessionId) {\n return fetchCdpSpecFromSession(source.browser, source.sessionId);\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 * Browser scope records only: the tab (CDP `targetId`) the scope last\n * worked in, so `sessionId: \"active\"` in a later execution lands on the\n * same page. CDP session ids die with each connection; target ids live as\n * long as the tab.\n */\n activeTargetId?: string;\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\n/**\n * A {@link BrowserSessionStore} that can list by prefix, as `Browser` needs:\n * it lists a browser's scope records to cap them and to see which tabs\n * other scopes are working in.\n */\nexport type ListableBrowserSessionStore = BrowserSessionStore &\n Required<Pick<BrowserSessionStore, \"list\">>;\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"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"settings-BjAiPd6Z.js","names":[],"sources":["../src/models/core/settings.ts"],"sourcesContent":["import type { WorkersAIModelId } from \"./catalog\";\n\n/** The gateway id Cloudflare auto-creates on first use. */\nexport const DEFAULT_GATEWAY_ID = \"default\";\n\n/** Key that per-call options live under in a framework's per-call options bag. */\nexport const PROVIDER_OPTIONS_KEY = \"cloudflare\";\n\n/**\n * AI Gateway settings for a request. The gateway is an option, not a separate\n * product: every call goes through one, and `id` defaults to `\"default\"`,\n * which Cloudflare creates on first use.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface GatewayOptions {\n /** Gateway id. Defaults to `\"default\"` (auto-created on first use). */\n id?: string;\n /** Bypass the cache for this request. */\n skipCache?: boolean;\n /** Cache lifetime in seconds. */\n cacheTtl?: number;\n /** Explicit cache key, instead of the request-derived one. */\n cacheKey?: string;\n /** Whether the gateway stores the request/response in its log. */\n collectLog?: boolean;\n /** Arbitrary key/values attached to the gateway log entry. */\n metadata?: Record<string, string | number | boolean | null>;\n /** Correlates several requests into one gateway event. */\n eventId?: string;\n /** Upstream request timeout in milliseconds. */\n requestTimeoutMs?: number;\n /** Server-side retry policy for the upstream provider call. */\n retries?: {\n maxAttempts?: 1 | 2 | 3 | 4 | 5;\n retryDelayMs?: number;\n backoff?: \"constant\" | \"linear\" | \"exponential\";\n };\n /**\n * Zero Data Retention for this request, sent as `cf-aig-zdr`. `true` turns\n * it on and `false` turns it off, whatever the gateway's own setting. It\n * applies to vendor models routed through the gateway on unified billing.\n */\n zdr?: boolean;\n}\n\n/**\n * How `createAI` reaches Cloudflare: the Workers AI binding, and nothing else.\n * Workers AI models go through `env.AI.run`, vendor models through\n * `env.AI.gateway(id).run` — both are the binding, so there is no HTTP\n * transport, no account id and no API token to hold.\n *\n * @experimental This surface is experimental and may change.\n */\nexport type AISettings = {\n /** The `AI` binding from a Worker's env. */\n binding: Ai;\n} & ProviderGatewaySettings;\n\n/**\n * Provider-wide gateway defaults, in either spelling: nested under `gateway`,\n * or flat (`{ id: \"prod\", cacheTtl: 60 }`). Both merge, the flat key winning.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ProviderGatewaySettings extends GatewayOptions {\n /** Gateway id or full gateway options. */\n gateway?: string | GatewayOptions;\n}\n\n/**\n * Per-model and per-call options. The flat gateway keys are sugar for\n * `gateway: { ... }`; both forms merge, with the flat key winning.\n *\n * The same shape is accepted per call under\n * `providerOptions.cloudflare`, where it takes precedence over the per-model\n * options, which in turn take precedence over the `createAI` settings.\n *\n * `Leg` is what a framework module accepts as a fallback leg. Workers AI ids\n * are the only kind this module can resolve on its own, so they are the\n * default; a module whose legs may also be model objects says so\n * (`ModelOptions<WorkersAIModelId | LanguageModelV4>`) rather than rebuilding\n * the type.\n *\n * @experimental This surface is experimental and may change.\n */\nexport interface ModelOptions<\n Leg = WorkersAIModelId\n> extends ProviderGatewaySettings {\n /**\n * Models to try, in order, if the primary fails before any output is\n * produced. A leg travels with the chain's gateway options — those win over\n * a leg's own, and `metadata` merges — while everything a leg was built with\n * itself stays its own. Client-side today; becomes server-side when the\n * platform ships model-first routing.\n */\n fallback?: Leg[];\n /** Extra request headers, merged last. */\n headers?: Record<string, string>;\n /**\n * Workers AI only: route same-key requests to the same replica for\n * prefix-cache hits. Sent as the `x-session-affinity` header.\n */\n sessionAffinity?: string;\n /**\n * Explicit reasoning effort. `null` disables reasoning on models that\n * support toggling it. The unified AI SDK `reasoning` call option maps onto\n * this when this is not set.\n */\n reasoningEffort?: \"low\" | \"medium\" | \"high\" | null;\n /**\n * Workers AI only: forwarded verbatim as `chat_template_kwargs`, e.g.\n * `{ enable_thinking: false }`.\n */\n chatTemplateKwargs?: Record<string, unknown>;\n}\n\n/** A gateway config with the id filled in. */\nexport interface ResolvedGateway extends GatewayOptions {\n id: string;\n}\n\n/** Everything one request needs, after merging all three option layers. */\nexport interface ResolvedOptions {\n gateway: ResolvedGateway;\n headers: Record<string, string>;\n sessionAffinity: string | undefined;\n reasoningEffort: \"low\" | \"medium\" | \"high\" | null | undefined;\n chatTemplateKwargs: Record<string, unknown> | undefined;\n /**\n * The fallback legs given as ids. A module whose legs may also be model\n * objects keeps its own ordered list; this one is what the id-only callers\n * (embeddings, the other modalities) need.\n */\n fallback: string[];\n}\n\n/** The id legs of a fallback list; model objects are their module's business. */\nfunction idLegs(fallback: unknown[] | undefined): string[] {\n return (fallback ?? []).filter(\n (leg): leg is string => typeof leg === \"string\"\n );\n}\n\n/** Strips `undefined` values so a later layer never blanks an earlier one. */\nfunction defined<T extends object>(value: T): T {\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (entry !== undefined) result[key] = entry;\n }\n return result as T;\n}\n\nfunction normalizeGateway(\n gateway: string | GatewayOptions | undefined\n): GatewayOptions {\n if (gateway === undefined) return {};\n // An explicit `undefined` inside a gateway object means \"not set\", exactly\n // as the flat sugar does; it must not blank out a lower layer's value.\n return typeof gateway === \"string\" ? { id: gateway } : defined(gateway);\n}\n\n/**\n * Folds one layer's flat gateway sugar into its `gateway` object. The flat key\n * wins over the nested one, and an explicit `undefined` on either never blanks\n * a lower layer.\n */\nfunction layerGateway(\n options: ProviderGatewaySettings | undefined\n): GatewayOptions {\n if (options === undefined) return {};\n return {\n ...normalizeGateway(options.gateway),\n ...defined({\n cacheKey: options.cacheKey,\n cacheTtl: options.cacheTtl,\n collectLog: options.collectLog,\n eventId: options.eventId,\n id: options.id,\n metadata: options.metadata,\n requestTimeoutMs: options.requestTimeoutMs,\n retries: options.retries,\n skipCache: options.skipCache,\n zdr: options.zdr\n })\n };\n}\n\n/** The flat gateway sugar {@link layerGateway} folds into `gateway`. */\nconst FLAT_GATEWAY_KEYS = [\n \"cacheKey\",\n \"cacheTtl\",\n \"collectLog\",\n \"eventId\",\n \"gateway\",\n \"id\",\n \"metadata\",\n \"requestTimeoutMs\",\n \"retries\",\n \"skipCache\",\n \"zdr\"\n] as const;\n\n/**\n * One layer's gateway options as a single object, both spellings folded in.\n * Exported so a module that collapses two option layers into one bag (a\n * fallback leg inheriting a chain's gateway) can merge them field by field\n * rather than replacing one object with the other.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function gatewayLayerOf(\n options: ProviderGatewaySettings | undefined\n): GatewayOptions {\n return layerGateway(options);\n}\n\n/** An option bag without the gateway keys, whichever spelling they used. */\nfunction withoutGatewayKeys<Leg>(\n options: ModelOptions<Leg>\n): ModelOptions<Leg> {\n const rest: Record<string, unknown> = { ...options };\n for (const key of FLAT_GATEWAY_KEYS) delete rest[key];\n return defined(rest as ModelOptions<Leg>);\n}\n\n/**\n * Collapses two option layers into one bag, `override` winning field by field.\n *\n * The gateway keys of both are folded into a single `gateway` object, so\n * neither layer's flat sugar can out-rank the other's nested spelling when the\n * bag is resolved later, and `metadata` merges rather than replaces — the same\n * rules {@link resolveOptions} applies across its three layers.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function mergeModelOptions<Leg>(\n base: ModelOptions<Leg> | undefined,\n override: ModelOptions<Leg> | undefined\n): ModelOptions<Leg> | undefined {\n if (base === undefined) return override;\n if (override === undefined) return base;\n const layers = [layerGateway(base), layerGateway(override)];\n const gateway: GatewayOptions = Object.assign({}, ...layers);\n const metadata = Object.assign({}, ...layers.map((layer) => layer.metadata));\n const retries = mergeRetries(layers);\n // Headers merge field by field, as they do across `resolveOptions`' three\n // layers: replacing the object wholesale would drop a header the lower layer\n // was configured with. The spread comes after the override's own keys so it\n // wins over the `headers` that spread carried.\n const headers = { ...base.headers, ...override.headers };\n return {\n ...withoutGatewayKeys(base),\n ...withoutGatewayKeys(override),\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n gateway: {\n ...gateway,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n ...(retries === undefined ? {} : { retries })\n }\n };\n}\n\n/**\n * Merges the retry policies field by field, so a provider-wide `backoff` still\n * applies when a call only sets `maxAttempts`. `undefined` on any layer means\n * \"not set\" and never blanks a lower one.\n */\nfunction mergeRetries(\n layers: GatewayOptions[]\n): GatewayOptions[\"retries\"] | undefined {\n const merged = layers.reduce<NonNullable<GatewayOptions[\"retries\"]>>(\n (result, layer) => ({\n ...result,\n ...(layer.retries === undefined ? {} : defined(layer.retries))\n }),\n {}\n );\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Merges the option layers. Precedence is per-call\n * (`providerOptions.cloudflare`) > per-model (`ai(id, options)`) >\n * provider (`createAI({ ... })`).\n *\n * The provider layer takes the whole settings object as well as a bare\n * `gateway` value, so `createAI({ binding, id: \"prod\", cacheTtl: 60 })` reads\n * the same as `createAI({ binding, gateway: { id: \"prod\", cacheTtl: 60 } })`.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function resolveOptions(\n provider: string | ProviderGatewaySettings | undefined,\n model: ModelOptions<unknown> | undefined,\n call: ModelOptions<unknown> | undefined\n): ResolvedOptions {\n const layers =\n typeof provider === \"string\"\n ? [normalizeGateway(provider), layerGateway(model), layerGateway(call)]\n : [layerGateway(provider), layerGateway(model), layerGateway(call)];\n const gateway: GatewayOptions = Object.assign({}, ...layers);\n const metadata = Object.assign({}, ...layers.map((layer) => layer.metadata));\n const retries = mergeRetries(layers);\n return {\n chatTemplateKwargs: call?.chatTemplateKwargs ?? model?.chatTemplateKwargs,\n fallback: idLegs(call?.fallback ?? model?.fallback),\n gateway: {\n ...gateway,\n id: gateway.id ?? DEFAULT_GATEWAY_ID,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n ...(retries === undefined ? {} : { retries })\n },\n headers: { ...model?.headers, ...call?.headers },\n // `null` is a meaningful value here (it disables reasoning), so the call\n // layer wins on any value it actually set, not just on a truthy one.\n reasoningEffort:\n call?.reasoningEffort !== undefined\n ? call.reasoningEffort\n : model?.reasoningEffort,\n sessionAffinity: call?.sessionAffinity ?? model?.sessionAffinity\n };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction asStringRecord(value: unknown): Record<string, string> | undefined {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const result: Record<string, string> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (typeof entry === \"string\") result[key] = entry;\n }\n return result;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" ? value : undefined;\n}\n\nfunction asBoolean(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction asReasoningEffort(\n value: unknown\n): \"low\" | \"medium\" | \"high\" | null | undefined {\n if (value === null) return null;\n if (value === \"low\" || value === \"medium\" || value === \"high\") return value;\n return undefined;\n}\n\n/**\n * Metadata values the gateway accepts are scalars only; a nested object or\n * array would be rejected by the binding, so drop those rather than forward\n * them.\n */\nfunction asMetadata(value: unknown): GatewayOptions[\"metadata\"] {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const result: NonNullable<GatewayOptions[\"metadata\"]> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (\n entry === null ||\n typeof entry === \"string\" ||\n typeof entry === \"number\" ||\n typeof entry === \"boolean\"\n ) {\n result[key] = entry;\n }\n }\n return result;\n}\n\nconst BACKOFFS = [\"constant\", \"linear\", \"exponential\"] as const;\n\n/** Reads the retry policy field by field; the binding validates it strictly. */\nfunction asRetries(value: unknown): GatewayOptions[\"retries\"] {\n const record = asRecord(value);\n if (record === undefined) return undefined;\n const maxAttempts = asNumber(record.maxAttempts);\n const backoff = asString(record.backoff);\n const retries = defined({\n backoff: BACKOFFS.find((entry) => entry === backoff),\n maxAttempts:\n maxAttempts !== undefined &&\n Number.isInteger(maxAttempts) &&\n maxAttempts >= 1 &&\n maxAttempts <= 5\n ? (maxAttempts as 1 | 2 | 3 | 4 | 5)\n : undefined,\n retryDelayMs: asNumber(record.retryDelayMs)\n });\n // An empty policy is not a policy: returning `{}` would out-rank a lower\n // layer's real one when the layers merge.\n return Object.keys(retries).length > 0 ? retries : undefined;\n}\n\n/** Reads the shared gateway keys out of a loosely-typed record. */\nfunction parseGatewayFields(raw: Record<string, unknown>): GatewayOptions {\n return defined({\n cacheKey: asString(raw.cacheKey),\n cacheTtl: asNumber(raw.cacheTtl),\n collectLog: asBoolean(raw.collectLog),\n eventId: asString(raw.eventId),\n id: asString(raw.id),\n metadata: asMetadata(raw.metadata),\n requestTimeoutMs: asNumber(raw.requestTimeoutMs),\n retries: asRetries(raw.retries),\n skipCache: asBoolean(raw.skipCache),\n zdr: asBoolean(raw.zdr)\n });\n}\n\n/**\n * Reads per-call options out of a loosely-typed options bag (the value a\n * framework keeps under {@link PROVIDER_OPTIONS_KEY}).\n *\n * The bag is plain JSON, so every field is read defensively: anything of an\n * unexpected type is dropped rather than thrown, because a malformed\n * observability hint should never fail a generation.\n *\n * @experimental This surface is experimental and may change.\n */\nexport function parseModelOptions(value: unknown): ModelOptions | undefined {\n const raw = asRecord(value);\n if (raw === undefined) return undefined;\n\n const nested = asRecord(raw.gateway);\n const gateway: string | GatewayOptions | undefined =\n typeof raw.gateway === \"string\"\n ? raw.gateway\n : nested !== undefined\n ? parseGatewayFields(nested)\n : undefined;\n\n const fallback = Array.isArray(raw.fallback)\n ? raw.fallback.filter(\n (entry): entry is WorkersAIModelId => typeof entry === \"string\"\n )\n : undefined;\n\n return defined({\n ...parseGatewayFields(raw),\n chatTemplateKwargs: asRecord(raw.chatTemplateKwargs),\n fallback,\n gateway,\n headers: asStringRecord(raw.headers),\n reasoningEffort: asReasoningEffort(raw.reasoningEffort),\n sessionAffinity: asString(raw.sessionAffinity)\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
//#region src/models/core/catalog.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Keys of the ambient `AiModels` interface (from `@cloudflare/workers-types`)
|
|
4
|
-
* whose model type extends `T`. Kept in step with the installed workers-types
|
|
5
|
-
* version rather than hand-maintained here.
|
|
6
|
-
*/
|
|
7
|
-
type WorkersAIModelIdsExtending<T> = {
|
|
8
|
-
[K in keyof AiModels]: AiModels[K] extends T ? K : never;
|
|
9
|
-
}[keyof AiModels];
|
|
10
|
-
/** The `inputs` shape a catalog entry declares. */
|
|
11
|
-
type InputsOf<K extends keyof AiModels> = AiModels[K] extends {
|
|
12
|
-
inputs: infer I;
|
|
13
|
-
}
|
|
14
|
-
? I
|
|
15
|
-
: never;
|
|
16
|
-
/** The `postProcessedOutputs` shape a catalog entry declares. */
|
|
17
|
-
type OutputsOf<K extends keyof AiModels> = AiModels[K] extends {
|
|
18
|
-
postProcessedOutputs: infer O;
|
|
19
|
-
}
|
|
20
|
-
? O
|
|
21
|
-
: never;
|
|
22
|
-
/**
|
|
23
|
-
* Catalog keys whose input takes a required `messages` array — every current
|
|
24
|
-
* chat model. Newer entries get their own generated class rather than
|
|
25
|
-
* extending `BaseAiTextGeneration`, so the base-class arm alone misses them.
|
|
26
|
-
*/
|
|
27
|
-
type ChatCatalogId = {
|
|
28
|
-
[K in keyof AiModels]: Extract<
|
|
29
|
-
InputsOf<K>,
|
|
30
|
-
{
|
|
31
|
-
messages: unknown;
|
|
32
|
-
}
|
|
33
|
-
> extends never
|
|
34
|
-
? never
|
|
35
|
-
: K;
|
|
36
|
-
}[keyof AiModels];
|
|
37
|
-
/**
|
|
38
|
-
* Catalog keys that take text and answer with embedding vectors. Both halves
|
|
39
|
-
* matter: the input test alone also matches translation, classification and
|
|
40
|
-
* speech models, which take `text` but return something else entirely.
|
|
41
|
-
*/
|
|
42
|
-
type EmbeddingCatalogId = {
|
|
43
|
-
[K in keyof AiModels]: Extract<
|
|
44
|
-
InputsOf<K>,
|
|
45
|
-
{
|
|
46
|
-
text: unknown;
|
|
47
|
-
}
|
|
48
|
-
> extends never
|
|
49
|
-
? never
|
|
50
|
-
: Extract<
|
|
51
|
-
OutputsOf<K>,
|
|
52
|
-
{
|
|
53
|
-
data?: number[][];
|
|
54
|
-
}
|
|
55
|
-
> extends never
|
|
56
|
-
? never
|
|
57
|
-
: K;
|
|
58
|
-
}[keyof AiModels];
|
|
59
|
-
/**
|
|
60
|
-
* Catalog keys that take audio to transcribe. The `audio` key is required on
|
|
61
|
-
* every speech-recognition input and on no other input shape, so the test is
|
|
62
|
-
* exact rather than heuristic.
|
|
63
|
-
*/
|
|
64
|
-
type TranscriptionCatalogId = {
|
|
65
|
-
[K in keyof AiModels]: Extract<
|
|
66
|
-
InputsOf<K>,
|
|
67
|
-
{
|
|
68
|
-
audio: unknown;
|
|
69
|
-
}
|
|
70
|
-
> extends never
|
|
71
|
-
? never
|
|
72
|
-
: K;
|
|
73
|
-
}[keyof AiModels];
|
|
74
|
-
/**
|
|
75
|
-
* Catalog keys that score a list of contexts against a query — rerankers.
|
|
76
|
-
* `contexts` is required on exactly those inputs.
|
|
77
|
-
*/
|
|
78
|
-
type RerankingCatalogId = {
|
|
79
|
-
[K in keyof AiModels]: Extract<
|
|
80
|
-
InputsOf<K>,
|
|
81
|
-
{
|
|
82
|
-
contexts: unknown;
|
|
83
|
-
}
|
|
84
|
-
> extends never
|
|
85
|
-
? never
|
|
86
|
-
: K;
|
|
87
|
-
}[keyof AiModels];
|
|
88
|
-
/**
|
|
89
|
-
* A Workers AI model id.
|
|
90
|
-
*
|
|
91
|
-
* Workers AI is the one catalog this package keeps up with, so this is the
|
|
92
|
-
* only id shape it accepts: `@cf/<author>/<model>`. Autocomplete covers the
|
|
93
|
-
* text-generation catalog from the installed `@cloudflare/workers-types`; the
|
|
94
|
-
* template arm keeps every other `@cf/` slug assignable, because the catalog
|
|
95
|
-
* lives server-side and moves independently of these types.
|
|
96
|
-
*
|
|
97
|
-
* Third-party models are not ids here — they are model objects built by their
|
|
98
|
-
* own provider package and routed through AI Gateway.
|
|
99
|
-
*
|
|
100
|
-
* @experimental This surface is experimental and may change.
|
|
101
|
-
*/
|
|
102
|
-
type WorkersAIModelId =
|
|
103
|
-
| Extract<
|
|
104
|
-
| ChatCatalogId
|
|
105
|
-
| Exclude<
|
|
106
|
-
WorkersAIModelIdsExtending<BaseAiTextGeneration>,
|
|
107
|
-
WorkersAIModelIdsExtending<BaseAiTextToImage>
|
|
108
|
-
>,
|
|
109
|
-
`@cf/${string}`
|
|
110
|
-
>
|
|
111
|
-
| (`@cf/${string}` & {});
|
|
112
|
-
/**
|
|
113
|
-
* An AI Gateway dynamic route, by name: `dynamic/<route>`.
|
|
114
|
-
*
|
|
115
|
-
* A dynamic route is configured on the gateway — which models it tries, in
|
|
116
|
-
* which order, with what rate limits or budgets — and called through the
|
|
117
|
-
* Workers AI run path like a model. It answers in the OpenAI chat-completions
|
|
118
|
-
* shape whatever model served it, so it is a language model only.
|
|
119
|
-
*
|
|
120
|
-
* @experimental This surface is experimental and may change.
|
|
121
|
-
*/
|
|
122
|
-
type DynamicRouteId = `dynamic/${string}`;
|
|
123
|
-
/**
|
|
124
|
-
* A text-embedding model id accepted by `ai.embedding()`.
|
|
125
|
-
*
|
|
126
|
-
* The modality methods are Workers AI only — there is no vendor route for them
|
|
127
|
-
* — so, like {@link WorkersAIModelId}, they take `@cf/` ids and nothing else.
|
|
128
|
-
*
|
|
129
|
-
* @experimental This surface is experimental and may change.
|
|
130
|
-
*/
|
|
131
|
-
type CloudflareEmbeddingModelId =
|
|
132
|
-
| Extract<
|
|
133
|
-
EmbeddingCatalogId | WorkersAIModelIdsExtending<BaseAiTextEmbeddings>,
|
|
134
|
-
`@cf/${string}`
|
|
135
|
-
>
|
|
136
|
-
| (`@cf/${string}` & {});
|
|
137
|
-
/**
|
|
138
|
-
* Workers AI text-to-image ids that the generated `AiModels` entries do not
|
|
139
|
-
* classify as {@link BaseAiTextToImage} — the newer partner models get their
|
|
140
|
-
* own generated class instead. Curated for autocomplete only; the catalog
|
|
141
|
-
* lives server-side and any slug is accepted.
|
|
142
|
-
*
|
|
143
|
-
* The FLUX.2 family (`flux-2-dev`, `flux-2-klein-4b`, `flux-2-klein-9b`) is
|
|
144
|
-
* deliberately absent, for the reason {@link UnsupportedTranscriptionId}
|
|
145
|
-
* records for the Deepgram recognisers: its generated input takes a required
|
|
146
|
-
* `multipart` object body (`{ multipart: { body, contentType } }`) and no
|
|
147
|
-
* `prompt`, which the JSON run path cannot carry — live, the run path answers
|
|
148
|
-
* `400 Bad input: required properties at "/" are 'multipart'`. Suggesting an
|
|
149
|
-
* id that always 400s is worse than not suggesting it.
|
|
150
|
-
*
|
|
151
|
-
* @experimental This surface is experimental and may change.
|
|
152
|
-
*/
|
|
153
|
-
type KnownImageModelId =
|
|
154
|
-
| "@cf/black-forest-labs/flux-1-schnell"
|
|
155
|
-
| "@cf/leonardo/lucid-origin"
|
|
156
|
-
| "@cf/leonardo/phoenix-1.0";
|
|
157
|
-
/**
|
|
158
|
-
* An image model id accepted by `ai.image()`.
|
|
159
|
-
*
|
|
160
|
-
* @experimental This surface is experimental and may change.
|
|
161
|
-
*/
|
|
162
|
-
type CloudflareImageModelId =
|
|
163
|
-
| Extract<
|
|
164
|
-
WorkersAIModelIdsExtending<BaseAiTextToImage> | KnownImageModelId,
|
|
165
|
-
`@cf/${string}`
|
|
166
|
-
>
|
|
167
|
-
| (`@cf/${string}` & {});
|
|
168
|
-
/**
|
|
169
|
-
* Workers AI text-to-speech ids without a {@link BaseAiTextToSpeech} entry.
|
|
170
|
-
* Curated for autocomplete only.
|
|
171
|
-
*
|
|
172
|
-
* @experimental This surface is experimental and may change.
|
|
173
|
-
*/
|
|
174
|
-
type KnownSpeechModelId =
|
|
175
|
-
| "@cf/deepgram/aura-1"
|
|
176
|
-
| "@cf/deepgram/aura-2-en"
|
|
177
|
-
| "@cf/deepgram/aura-2-es";
|
|
178
|
-
/**
|
|
179
|
-
* A text-to-speech model id accepted by `ai.speech()`.
|
|
180
|
-
*
|
|
181
|
-
* @experimental This surface is experimental and may change.
|
|
182
|
-
*/
|
|
183
|
-
type CloudflareSpeechModelId =
|
|
184
|
-
| Extract<
|
|
185
|
-
WorkersAIModelIdsExtending<BaseAiTextToSpeech> | KnownSpeechModelId,
|
|
186
|
-
`@cf/${string}`
|
|
187
|
-
>
|
|
188
|
-
| (`@cf/${string}` & {});
|
|
189
|
-
/**
|
|
190
|
-
* Deepgram's recognition models want the audio as an object body
|
|
191
|
-
* (`audio: { body, contentType }`) rather than as base64, which the JSON run
|
|
192
|
-
* path cannot carry — every documented variant answered `400` live. They stay
|
|
193
|
-
* out of the suggested arm, and the transcription model answers a clear error
|
|
194
|
-
* for them.
|
|
195
|
-
*/
|
|
196
|
-
type UnsupportedTranscriptionId = "@cf/deepgram/nova-3" | "@cf/deepgram/flux";
|
|
197
|
-
/**
|
|
198
|
-
* A speech-recognition model id accepted by `ai.transcription()`.
|
|
199
|
-
*
|
|
200
|
-
* Deepgram's recognition models (`@cf/deepgram/nova-3`, `@cf/deepgram/flux`)
|
|
201
|
-
* are deliberately not suggested: the run path rejects their documented input
|
|
202
|
-
* shape, so this provider answers a clear error for them rather than a 400.
|
|
203
|
-
*
|
|
204
|
-
* @experimental This surface is experimental and may change.
|
|
205
|
-
*/
|
|
206
|
-
type CloudflareTranscriptionModelId =
|
|
207
|
-
| Extract<
|
|
208
|
-
| Exclude<TranscriptionCatalogId, UnsupportedTranscriptionId>
|
|
209
|
-
| Exclude<
|
|
210
|
-
WorkersAIModelIdsExtending<BaseAiAutomaticSpeechRecognition>,
|
|
211
|
-
UnsupportedTranscriptionId
|
|
212
|
-
>,
|
|
213
|
-
`@cf/${string}`
|
|
214
|
-
>
|
|
215
|
-
| (`@cf/${string}` & {});
|
|
216
|
-
/**
|
|
217
|
-
* A reranking model id accepted by `ai.reranking()`.
|
|
218
|
-
*
|
|
219
|
-
* @experimental This surface is experimental and may change.
|
|
220
|
-
*/
|
|
221
|
-
type CloudflareRerankingModelId =
|
|
222
|
-
| Extract<RerankingCatalogId, `@cf/${string}`>
|
|
223
|
-
| (`@cf/${string}` & {});
|
|
224
|
-
//#endregion
|
|
225
|
-
//#region src/models/core/settings.d.ts
|
|
226
|
-
/**
|
|
227
|
-
* AI Gateway settings for a request. The gateway is an option, not a separate
|
|
228
|
-
* product: every call goes through one, and `id` defaults to `"default"`,
|
|
229
|
-
* which Cloudflare creates on first use.
|
|
230
|
-
*
|
|
231
|
-
* @experimental This surface is experimental and may change.
|
|
232
|
-
*/
|
|
233
|
-
interface GatewayOptions {
|
|
234
|
-
/** Gateway id. Defaults to `"default"` (auto-created on first use). */
|
|
235
|
-
id?: string;
|
|
236
|
-
/** Bypass the cache for this request. */
|
|
237
|
-
skipCache?: boolean;
|
|
238
|
-
/** Cache lifetime in seconds. */
|
|
239
|
-
cacheTtl?: number;
|
|
240
|
-
/** Explicit cache key, instead of the request-derived one. */
|
|
241
|
-
cacheKey?: string;
|
|
242
|
-
/** Whether the gateway stores the request/response in its log. */
|
|
243
|
-
collectLog?: boolean;
|
|
244
|
-
/** Arbitrary key/values attached to the gateway log entry. */
|
|
245
|
-
metadata?: Record<string, string | number | boolean | null>;
|
|
246
|
-
/** Correlates several requests into one gateway event. */
|
|
247
|
-
eventId?: string;
|
|
248
|
-
/** Upstream request timeout in milliseconds. */
|
|
249
|
-
requestTimeoutMs?: number;
|
|
250
|
-
/** Server-side retry policy for the upstream provider call. */
|
|
251
|
-
retries?: {
|
|
252
|
-
maxAttempts?: 1 | 2 | 3 | 4 | 5;
|
|
253
|
-
retryDelayMs?: number;
|
|
254
|
-
backoff?: "constant" | "linear" | "exponential";
|
|
255
|
-
};
|
|
256
|
-
/**
|
|
257
|
-
* Zero Data Retention for this request, sent as `cf-aig-zdr`. `true` turns
|
|
258
|
-
* it on and `false` turns it off, whatever the gateway's own setting. It
|
|
259
|
-
* applies to vendor models routed through the gateway on unified billing.
|
|
260
|
-
*/
|
|
261
|
-
zdr?: boolean;
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* How `createAI` reaches Cloudflare: the Workers AI binding, and nothing else.
|
|
265
|
-
* Workers AI models go through `env.AI.run`, vendor models through
|
|
266
|
-
* `env.AI.gateway(id).run` — both are the binding, so there is no HTTP
|
|
267
|
-
* transport, no account id and no API token to hold.
|
|
268
|
-
*
|
|
269
|
-
* @experimental This surface is experimental and may change.
|
|
270
|
-
*/
|
|
271
|
-
type AISettings = {
|
|
272
|
-
/** The `AI` binding from a Worker's env. */ binding: Ai;
|
|
273
|
-
} & ProviderGatewaySettings;
|
|
274
|
-
/**
|
|
275
|
-
* Provider-wide gateway defaults, in either spelling: nested under `gateway`,
|
|
276
|
-
* or flat (`{ id: "prod", cacheTtl: 60 }`). Both merge, the flat key winning.
|
|
277
|
-
*
|
|
278
|
-
* @experimental This surface is experimental and may change.
|
|
279
|
-
*/
|
|
280
|
-
interface ProviderGatewaySettings extends GatewayOptions {
|
|
281
|
-
/** Gateway id or full gateway options. */
|
|
282
|
-
gateway?: string | GatewayOptions;
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
|
-
* Per-model and per-call options. The flat gateway keys are sugar for
|
|
286
|
-
* `gateway: { ... }`; both forms merge, with the flat key winning.
|
|
287
|
-
*
|
|
288
|
-
* The same shape is accepted per call under
|
|
289
|
-
* `providerOptions.cloudflare`, where it takes precedence over the per-model
|
|
290
|
-
* options, which in turn take precedence over the `createAI` settings.
|
|
291
|
-
*
|
|
292
|
-
* `Leg` is what a framework module accepts as a fallback leg. Workers AI ids
|
|
293
|
-
* are the only kind this module can resolve on its own, so they are the
|
|
294
|
-
* default; a module whose legs may also be model objects says so
|
|
295
|
-
* (`ModelOptions<WorkersAIModelId | LanguageModelV4>`) rather than rebuilding
|
|
296
|
-
* the type.
|
|
297
|
-
*
|
|
298
|
-
* @experimental This surface is experimental and may change.
|
|
299
|
-
*/
|
|
300
|
-
interface ModelOptions<Leg = WorkersAIModelId> extends ProviderGatewaySettings {
|
|
301
|
-
/**
|
|
302
|
-
* Models to try, in order, if the primary fails before any output is
|
|
303
|
-
* produced. A leg travels with the chain's gateway options — those win over
|
|
304
|
-
* a leg's own, and `metadata` merges — while everything a leg was built with
|
|
305
|
-
* itself stays its own. Client-side today; becomes server-side when the
|
|
306
|
-
* platform ships model-first routing.
|
|
307
|
-
*/
|
|
308
|
-
fallback?: Leg[];
|
|
309
|
-
/** Extra request headers, merged last. */
|
|
310
|
-
headers?: Record<string, string>;
|
|
311
|
-
/**
|
|
312
|
-
* Workers AI only: route same-key requests to the same replica for
|
|
313
|
-
* prefix-cache hits. Sent as the `x-session-affinity` header.
|
|
314
|
-
*/
|
|
315
|
-
sessionAffinity?: string;
|
|
316
|
-
/**
|
|
317
|
-
* Explicit reasoning effort. `null` disables reasoning on models that
|
|
318
|
-
* support toggling it. The unified AI SDK `reasoning` call option maps onto
|
|
319
|
-
* this when this is not set.
|
|
320
|
-
*/
|
|
321
|
-
reasoningEffort?: "low" | "medium" | "high" | null;
|
|
322
|
-
/**
|
|
323
|
-
* Workers AI only: forwarded verbatim as `chat_template_kwargs`, e.g.
|
|
324
|
-
* `{ enable_thinking: false }`.
|
|
325
|
-
*/
|
|
326
|
-
chatTemplateKwargs?: Record<string, unknown>;
|
|
327
|
-
}
|
|
328
|
-
/** A gateway config with the id filled in. */
|
|
329
|
-
interface ResolvedGateway extends GatewayOptions {
|
|
330
|
-
id: string;
|
|
331
|
-
}
|
|
332
|
-
//#endregion
|
|
333
|
-
export {
|
|
334
|
-
ResolvedGateway as a,
|
|
335
|
-
CloudflareRerankingModelId as c,
|
|
336
|
-
DynamicRouteId as d,
|
|
337
|
-
KnownImageModelId as f,
|
|
338
|
-
ProviderGatewaySettings as i,
|
|
339
|
-
CloudflareSpeechModelId as l,
|
|
340
|
-
WorkersAIModelId as m,
|
|
341
|
-
GatewayOptions as n,
|
|
342
|
-
CloudflareEmbeddingModelId as o,
|
|
343
|
-
KnownSpeechModelId as p,
|
|
344
|
-
ModelOptions as r,
|
|
345
|
-
CloudflareImageModelId as s,
|
|
346
|
-
AISettings as t,
|
|
347
|
-
CloudflareTranscriptionModelId as u
|
|
348
|
-
};
|
|
349
|
-
//# sourceMappingURL=settings-DnD__xuE.d.ts.map
|