agents 0.23.0 → 0.25.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-DE5zmCQ8.d.ts → agent-routing-0DR0Tk2v.d.ts} +270 -190
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-routing.js.map +1 -1
- package/dist/agent-tool-types.d.ts +13 -7
- package/dist/agent-tool-types.js +23 -1
- package/dist/agent-tool-types.js.map +1 -1
- package/dist/{agent-tools-y7zLfw4Q.js → agent-tools-CdJC-8Dc.js} +72 -9
- package/dist/agent-tools-CdJC-8Dc.js.map +1 -0
- package/dist/{agent-tools-DtXMTDGM.d.ts → agent-tools-YrATZJu2.d.ts} +29 -15
- package/dist/agent-tools.d.ts +6 -4
- package/dist/agent-tools.js.map +1 -1
- package/dist/ai-fm7xx1BK.js +312 -0
- package/dist/ai-fm7xx1BK.js.map +1 -0
- package/dist/base64-redaction-C1Uu29t5.js +59 -0
- package/dist/base64-redaction-C1Uu29t5.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +90 -0
- package/dist/browser/ai-sdk.js +51 -0
- package/dist/browser/ai-sdk.js.map +1 -0
- package/dist/browser/ai.d.ts +4 -4
- package/dist/browser/ai.js +1 -347
- package/dist/browser/index.d.ts +81 -79
- package/dist/browser/index.js +361 -2
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/tanstack-ai.d.ts +96 -1
- package/dist/browser/tanstack-ai.js +62 -2
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/browser-DE3d-RLk.d.ts +275 -0
- package/dist/browser-tool-CQ10e6Kj.js +480 -0
- package/dist/browser-tool-CQ10e6Kj.js.map +1 -0
- package/dist/browser-tool-DuNdlwZ9.d.ts +73 -0
- package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
- package/dist/capability-B4WbF81e.js.map +1 -0
- package/dist/{capability-runner-Be_-PLR1.d.ts → capability-runner-DBAnGr6L.d.ts} +45 -15
- package/dist/chat/index.d.ts +341 -232
- package/dist/chat/index.js +602 -72
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +42 -2
- package/dist/chat/react.js +191 -35
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/transport.d.ts +1 -1
- package/dist/chat/transport.js +1 -1
- package/dist/chat-sdk/index.d.ts +17 -3
- package/dist/chat-sdk/index.js +28 -2
- package/dist/chat-sdk/index.js.map +1 -1
- package/dist/client-4OlMIJx-.js +591 -0
- package/dist/client-4OlMIJx-.js.map +1 -0
- package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
- package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
- package/dist/client-je3koD9Z.d.ts +446 -0
- package/dist/client.d.ts +29 -283
- package/dist/client.js +2 -274
- package/dist/{connector-CptFKzRh.js → connector-58XDGvc3.js} +251 -120
- package/dist/connector-58XDGvc3.js.map +1 -0
- package/dist/{connector-CkQD4MK3.d.ts → connector-Cl-VqPmA.d.ts} +244 -146
- package/dist/context/index.d.ts +29 -0
- package/dist/context/index.js +64 -17
- package/dist/context/index.js.map +1 -1
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- package/dist/current-agent-vAk_5JMt.d.ts +93 -0
- package/dist/{current-agent-Da_C9a3b.d.ts → durable-object-lifecycle-HhgOMWq9.d.ts} +26 -127
- package/dist/harnesses/pi/index.d.ts +348 -0
- package/dist/harnesses/pi/index.js +754 -0
- package/dist/harnesses/pi/index.js.map +1 -0
- package/dist/images-iiTDSyRu.js +1631 -0
- package/dist/images-iiTDSyRu.js.map +1 -0
- package/dist/index-BreL0YrQ.d.ts +78 -0
- package/dist/index-kbSUIer3.d.ts +343 -0
- package/dist/index.d.ts +43 -41
- package/dist/index.js +2 -2
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +19 -17
- package/dist/lifecycle/index.js +2 -2
- package/dist/{lifecycle-CMRGjZdw.js → lifecycle-CFu6OV03.js} +73 -29
- package/dist/lifecycle-CFu6OV03.js.map +1 -0
- package/dist/mcp/client/index.d.ts +20 -20
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.js +21 -19
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +35 -35
- package/dist/mcp/index.js +2 -2
- package/dist/{message-builder-BymO4N_D.js → message-builder-DAl9AhHH.js} +89 -4
- package/dist/message-builder-DAl9AhHH.js.map +1 -0
- package/dist/models/ai-sdk/index.d.ts +353 -0
- package/dist/models/ai-sdk/index.js +2443 -0
- package/dist/models/ai-sdk/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +313 -0
- package/dist/models/pi-ai/index.js +1795 -0
- package/dist/models/pi-ai/index.js.map +1 -0
- package/dist/observability/ai/index.js +20 -4
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/{protocol-B0nh6KNf.js → protocol-kHsr-f0X.js} +26 -12
- package/dist/{protocol-B0nh6KNf.js.map → protocol-kHsr-f0X.js.map} +1 -1
- package/dist/queue/index.d.ts +123 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue-BB-zfIYF.js +406 -0
- package/dist/queue-BB-zfIYF.js.map +1 -0
- package/dist/react.d.ts +31 -13
- package/dist/react.js +190 -71
- package/dist/react.js.map +1 -1
- package/dist/{retries-D9Ds-1lz.d.ts → retries-CV6AkXmQ.d.ts} +23 -8
- package/dist/retries.d.ts +12 -8
- package/dist/retries.js +19 -1
- package/dist/retries.js.map +1 -1
- package/dist/routing/index.d.ts +2 -2
- package/dist/routing/index.js +1 -1
- package/dist/{scheduler-DD9NdYbF.js → scheduler-DZ3xQfeK.js} +4 -11
- package/dist/scheduler-DZ3xQfeK.js.map +1 -0
- package/dist/{scheduler-Dwh85ZGl.d.ts → scheduler-RdACNXDP.d.ts} +6 -6
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +70 -3
- package/dist/sessions/index.js +276 -67
- package/dist/sessions/index.js.map +1 -1
- package/dist/skills/index.d.ts +29 -314
- package/dist/socket-address.d.ts +16 -0
- package/dist/socket-address.js +19 -0
- package/dist/socket-address.js.map +1 -0
- package/dist/{src-DlSHshb2.js → src-BZeu-SCD.js} +541 -500
- package/dist/src-BZeu-SCD.js.map +1 -0
- package/dist/state/index.d.ts +6 -0
- package/dist/state/index.js +137 -0
- package/dist/state/index.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-D6tJ0NN9.d.ts → streams-Cmkj9QfW.d.ts} +4 -2
- package/dist/{streams-DZKgAj9b.js → streams-DW-UCOUc.js} +9 -2
- package/dist/streams-DW-UCOUc.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-ylZgBjhj.js → tasks-68DESxf0.js} +3 -3
- package/dist/{tasks-ylZgBjhj.js.map → tasks-68DESxf0.js.map} +1 -1
- package/dist/{tasks-BRJ5zgya.d.ts → tasks-9YxYtByh.d.ts} +5 -5
- package/dist/transport-PfFnt-Ld.d.ts +525 -0
- package/dist/transport-protocol-BxyngQ_R.js +25 -0
- package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
- package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
- package/dist/types-BA4anrjI.d.ts +70 -0
- package/dist/voice/index.d.ts +2 -2
- package/dist/websockets/index.d.ts +195 -69
- package/dist/websockets/index.js +3 -2
- package/dist/websockets-Ci-LZFHH.js +1030 -0
- package/dist/websockets-Ci-LZFHH.js.map +1 -0
- package/dist/wire-types-CnMt6_HR.js.map +1 -1
- package/dist/wire-types-CrjKvDyi.d.ts +300 -0
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflows.d.ts +21 -21
- package/dist/workflows.js +1 -1
- package/dist/{ws-chat-transport-UNRIS2xl.d.ts → ws-chat-transport-BbT1A5Lc.d.ts} +51 -2
- package/dist/{ws-chat-transport-rWwta645.js → ws-chat-transport-cqMKq3IY.js} +143 -16
- package/dist/ws-chat-transport-cqMKq3IY.js.map +1 -0
- package/docs/agent-class.md +2 -2
- package/docs/agent-tools.md +29 -4
- package/docs/browse-the-web.md +87 -5
- package/docs/chat-agents.md +124 -16
- package/docs/client-sdk.md +30 -0
- package/docs/context.md +27 -0
- package/docs/durable-execution.md +2 -0
- package/docs/harnesses/pi.md +91 -0
- package/docs/human-in-the-loop.md +4 -0
- package/docs/index.md +4 -1
- package/docs/lifecycle.md +114 -23
- package/docs/models-pi-ai.md +325 -0
- package/docs/models.md +504 -0
- package/docs/queue.md +135 -241
- package/docs/resumable-streaming.md +2 -0
- package/docs/retries.md +1 -1
- package/docs/routing.md +13 -13
- package/docs/sessions.md +36 -1
- package/docs/state.md +1 -0
- package/docs/sub-agents.md +12 -3
- package/package.json +51 -3
- package/dist/agent-tools-y7zLfw4Q.js.map +0 -1
- package/dist/browser/ai.js.map +0 -1
- package/dist/capability-BjSKYpzg.js.map +0 -1
- package/dist/client-tools-aIBO0Fk7.d.ts +0 -53
- package/dist/client.js.map +0 -1
- package/dist/connector-CptFKzRh.js.map +0 -1
- package/dist/lifecycle-CMRGjZdw.js.map +0 -1
- package/dist/message-builder-BymO4N_D.js.map +0 -1
- package/dist/scheduler-DD9NdYbF.js.map +0 -1
- package/dist/src-DlSHshb2.js.map +0 -1
- package/dist/streams-DZKgAj9b.js.map +0 -1
- package/dist/websockets-DUfRHPRq.js +0 -502
- package/dist/websockets-DUfRHPRq.js.map +0 -1
- package/dist/ws-chat-transport-rWwta645.js.map +0 -1
package/dist/agent-routing.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-routing.js","names":[],"sources":["../src/agent-routing.ts"],"sourcesContent":["import type { Agent } from \"./index\";\nimport { camelCaseToKebabCase } from \"./utils\";\n\nconst namespaceMapCache = new WeakMap<\n object,\n Record<string, DurableObjectNamespace>\n>();\nconst bindingNameCache = new WeakMap<object, Record<string, string>>();\n\nconst DEFAULT_ROUTING_RETRY_OPTIONS = {\n maxAttempts: 3,\n baseDelayMs: 100,\n maxDelayMs: 800\n};\n\ninterface RoutingRetryEvent {\n error: unknown;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n name: string;\n className?: string;\n}\n\n/** Retry policy for Agent routing infrastructure failures. */\nexport interface RoutingRetryOptions {\n /** Max number of attempts, including the first. Default: 3. */\n maxAttempts?: number;\n /** Base delay in milliseconds for exponential backoff. Default: 100. */\n baseDelayMs?: number;\n /** Maximum delay in milliseconds. Default: 800. */\n maxDelayMs?: number;\n /** Optional callback invoked before each retry delay. */\n onRetry?: (event: RoutingRetryEvent) => void | Promise<void>;\n}\n\ninterface AgentRouteMatch<Env = Cloudflare.Env> {\n /** The Durable Object environment binding name. */\n className: Extract<keyof Env, string>;\n /** The named Durable Object instance extracted from the URL. */\n name: string;\n}\n\ninterface AgentRouteOptions<\n Env = Cloudflare.Env,\n Props extends Record<string, unknown> = Record<string, unknown>\n> {\n /** URL prefix before the binding and instance name. Default: `agents`. */\n prefix?: string;\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n /** Properties supplied before lifecycle startup. */\n props?: Props;\n /**\n * Whether to enable CORS for matched routes.\n *\n * When `true`, uses default permissive CORS headers:\n * - Access-Control-Allow-Origin: *\n * - Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS\n * - Access-Control-Allow-Headers: *\n * - Access-Control-Max-Age: 86400\n *\n * For credentialed requests, pass explicit headers with a specific origin.\n * When set to a `HeadersInit` value, uses those as the CORS headers instead.\n * CORS preflight requests are handled automatically for matched routes.\n */\n cors?: boolean | HeadersInit;\n /**\n * Retry transient Durable Object infrastructure errors thrown while routing.\n * Enabled by default; pass `false` to disable.\n */\n routingRetry?: false | RoutingRetryOptions;\n onBeforeConnect?: (\n request: Request,\n route: AgentRouteMatch<Env>\n ) => Response | Request | void | Promise<Response | Request | void>;\n onBeforeRequest?: (\n request: Request,\n route: AgentRouteMatch<Env>\n ) =>\n | Response\n | Request\n | void\n | Promise<Response | Request | undefined | void>;\n}\n\n/** Configuration options for {@link routeAgentRequest}. */\nexport type AgentOptions<Env> = AgentRouteOptions<Env>;\n\n/** Options for resolving and starting a named Agent. */\nexport type AgentGetOptions<\n Env,\n Props extends Record<string, unknown> = Record<string, unknown>\n> = Pick<\n AgentRouteOptions<Env, Props>,\n \"jurisdiction\" | \"locationHint\" | \"props\" | \"routingRetry\"\n>;\n\ninterface ResolvedRoutingRetryOptions extends Required<\n Omit<RoutingRetryOptions, \"onRetry\">\n> {\n onRetry?: RoutingRetryOptions[\"onRetry\"];\n}\n\ninterface RoutingRetryContext {\n name: string;\n className?: string;\n}\n\nfunction durableObjectGetOptions(\n options: { locationHint?: DurableObjectLocationHint } | undefined\n) {\n return options?.locationHint\n ? { locationHint: options.locationHint }\n : undefined;\n}\n\nfunction validatePositiveInteger(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 1) {\n throw new Error(`${name} must be >= 1`);\n }\n if (!Number.isInteger(value)) {\n throw new Error(`${name} must be an integer`);\n }\n}\n\nfunction validatePositiveNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`${name} must be > 0`);\n }\n}\n\nfunction resolveRoutingRetryOptions(\n options: false | RoutingRetryOptions | undefined\n): ResolvedRoutingRetryOptions | null {\n if (options === false) return null;\n\n const resolved = {\n maxAttempts:\n options?.maxAttempts ?? DEFAULT_ROUTING_RETRY_OPTIONS.maxAttempts,\n baseDelayMs:\n options?.baseDelayMs ?? DEFAULT_ROUTING_RETRY_OPTIONS.baseDelayMs,\n maxDelayMs: options?.maxDelayMs ?? DEFAULT_ROUTING_RETRY_OPTIONS.maxDelayMs,\n onRetry: options?.onRetry\n };\n\n validatePositiveInteger(resolved.maxAttempts, \"routingRetry.maxAttempts\");\n validatePositiveNumber(resolved.baseDelayMs, \"routingRetry.baseDelayMs\");\n validatePositiveNumber(resolved.maxDelayMs, \"routingRetry.maxDelayMs\");\n if (resolved.baseDelayMs > resolved.maxDelayMs) {\n throw new Error(\"routingRetry.baseDelayMs must be <= maxDelayMs\");\n }\n\n return resolved;\n}\n\nfunction isRetryableDurableObjectError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) return false;\n // SAFETY: Cloudflare's retryable and overloaded error flags are optional\n // runtime properties not represented on the base Error type.\n const typed = error as { retryable?: boolean; overloaded?: boolean };\n return typed.retryable === true && typed.overloaded !== true;\n}\n\nfunction routingRetryDelayMs(\n attempt: number,\n options: ResolvedRoutingRetryOptions\n): number {\n const upperBoundMs = Math.min(\n options.maxDelayMs,\n options.baseDelayMs * 2 ** (attempt - 1)\n );\n return Math.floor(Math.random() * upperBoundMs);\n}\n\nasync function retryDurableObjectOperation<T>(\n operation: () => Promise<T>,\n context: RoutingRetryContext,\n retryOptions: false | RoutingRetryOptions | undefined\n): Promise<T> {\n const resolved = resolveRoutingRetryOptions(retryOptions);\n if (!resolved) return await operation();\n\n let attempt = 1;\n while (true) {\n try {\n return await operation();\n } catch (error) {\n const nextAttempt = attempt + 1;\n if (\n nextAttempt > resolved.maxAttempts ||\n !isRetryableDurableObjectError(error)\n ) {\n throw error;\n }\n\n const delayMs = routingRetryDelayMs(attempt, resolved);\n try {\n await resolved.onRetry?.({\n error,\n attempt,\n maxAttempts: resolved.maxAttempts,\n delayMs,\n name: context.name,\n className: context.className\n });\n } catch (callbackError) {\n console.warn(\n \"Durable Object routing retry callback failed:\",\n callbackError\n );\n }\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n attempt = nextAttempt;\n }\n }\n}\n\nfunction encodeLifecycleProps(props: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(props));\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nfunction mutableRequest(request: Request): Request {\n return new Request(request);\n}\n\nfunction cloneRequestForFetch(request: Request): Request {\n // SAFETY: Workers Types v5 preserves an unconstrained `cf` generic from\n // clone(). Cloning does not change the runtime Request representation.\n return request.clone() as Request;\n}\n\nfunction resolveCorsHeaders(\n cors: boolean | HeadersInit | undefined\n): Record<string, string> | null {\n if (cors === true) {\n return {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, HEAD, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\n \"Access-Control-Max-Age\": \"86400\"\n };\n }\n if (cors && typeof cors === \"object\") {\n const headers = new Headers(cors);\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key] = value;\n });\n return record;\n }\n return null;\n}\n\n/**\n * Route `/agents/:binding/:name` HTTP and WebSocket requests to a named\n * Durable Object. The target may extend `Agent` or compose `Lifecycle`\n * directly into a plain `DurableObject`.\n *\n * @param request - Incoming Worker request.\n * @param env - Worker environment containing Durable Object bindings.\n * @param options - Routing options.\n * @returns The matched response, or `null` when the path does not match.\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n): Promise<Response | null> {\n // SAFETY: Worker environments are object records. The unconstrained Env\n // generic is retained for compatibility with the previously published API.\n const environment = env as object;\n if (!namespaceMapCache.has(environment)) {\n const namespaceMap: Record<string, DurableObjectNamespace> = {};\n const bindingNames: Record<string, string> = {};\n for (const [key, value] of Object.entries(environment)) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n const kebab = camelCaseToKebabCase(key);\n // SAFETY: The structural idFromName check above identifies a Durable\n // Object namespace at the Worker environment boundary.\n namespaceMap[kebab] = value as DurableObjectNamespace;\n bindingNames[kebab] = key;\n }\n }\n namespaceMapCache.set(environment, namespaceMap);\n bindingNameCache.set(environment, bindingNames);\n }\n\n const map = namespaceMapCache.get(environment) as Record<\n string,\n DurableObjectNamespace\n >;\n const bindingNames = bindingNameCache.get(environment) as Record<\n string,\n string\n >;\n const prefixParts = (options?.prefix || \"agents\").split(\"/\");\n const parts = new URL(request.url).pathname.split(\"/\").filter(Boolean);\n const prefixMatches = prefixParts.every(\n (part, index) => parts[index] === part\n );\n if (!prefixMatches || parts.length < prefixParts.length + 2) return null;\n\n const namespaceName = parts[prefixParts.length];\n const name = parts[prefixParts.length + 1];\n if (!name || !namespaceName) return null;\n\n const boundNamespace = map[namespaceName];\n if (!boundNamespace) {\n console.error(\n `The URL ${request.url} with namespace \"${namespaceName}\" and name \"${name}\" does not match any Durable Object binding.`\n );\n return new Response(\"Invalid request\", { status: 400 });\n }\n\n const corsHeaders = resolveCorsHeaders(options?.cors);\n const isWebSocket =\n request.headers.get(\"Upgrade\")?.toLowerCase() === \"websocket\";\n const withCorsHeaders = (response: Response): Response => {\n if (!corsHeaders || isWebSocket) return response;\n const nextResponse = new Response(response.body, response);\n for (const [key, value] of Object.entries(corsHeaders)) {\n nextResponse.headers.set(key, value);\n }\n return nextResponse;\n };\n\n if (request.method === \"OPTIONS\" && corsHeaders) {\n return new Response(null, { headers: corsHeaders });\n }\n\n const namespace = options?.jurisdiction\n ? boundNamespace.jurisdiction(options.jurisdiction)\n : boundNamespace;\n const id = namespace.idFromName(name);\n const getOptions = durableObjectGetOptions(options);\n request = mutableRequest(request);\n\n // SAFETY: binding names come directly from Object.entries(env), so they are\n // string keys of Env.\n const className = bindingNames[namespaceName] as Extract<keyof Env, string>;\n const route: AgentRouteMatch<Env> = { className, name };\n\n if (isWebSocket) {\n const requestOrResponse = await options?.onBeforeConnect?.(request, route);\n if (requestOrResponse instanceof Request) {\n request = mutableRequest(requestOrResponse);\n } else if (requestOrResponse instanceof Response) {\n return requestOrResponse;\n }\n } else {\n const requestOrResponse = await options?.onBeforeRequest?.(request, route);\n if (requestOrResponse instanceof Request) {\n request = mutableRequest(requestOrResponse);\n } else if (requestOrResponse instanceof Response) {\n return withCorsHeaders(requestOrResponse);\n }\n }\n\n if (options?.props !== undefined) {\n request.headers.set(\n \"x-agents-lifecycle-props\",\n encodeLifecycleProps(options.props)\n );\n }\n\n const response = await retryDurableObjectOperation(\n () => namespace.get(id, getOptions).fetch(cloneRequestForFetch(request)),\n { name, className },\n options?.routingRetry\n );\n return isWebSocket ? response : withCorsHeaders(response);\n}\n\n/**\n * Get a named Agent stub after its lifecycle startup has completed.\n *\n * @param namespace - Agent Durable Object namespace.\n * @param name - Agent instance name.\n * @param options - Placement, startup properties, and retry options.\n * @returns The initialized Agent stub.\n */\nexport async function getAgentByName<\n Env extends Cloudflare.Env = Cloudflare.Env,\n T extends Agent<Env> = Agent<Env>,\n Props extends Record<string, unknown> = Record<string, unknown>\n>(\n namespace: DurableObjectNamespace<T>,\n name: string,\n options?: AgentGetOptions<Env, Props>\n): Promise<DurableObjectStub<T>> {\n const target = options?.jurisdiction\n ? namespace.jurisdiction(options.jurisdiction)\n : namespace;\n const id = target.idFromName(name);\n const stub = target.get(id, durableObjectGetOptions(options));\n\n // SAFETY: Agent exposes this internal initializer specifically for native\n // RPC calls, which bypass the lifecycle-installed fetch handler.\n const lifecycleStub = stub as unknown as {\n __unsafe_ensureInitialized(props?: Props): Promise<void>;\n };\n await retryDurableObjectOperation(\n () => lifecycleStub.__unsafe_ensureInitialized(options?.props),\n { name },\n options?.routingRetry\n );\n\n return stub;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-routing.js","names":[],"sources":["../src/agent-routing.ts"],"sourcesContent":["import type { Agent } from \"./index\";\nimport { camelCaseToKebabCase } from \"./utils\";\n\nconst namespaceMapCache = new WeakMap<\n object,\n Record<string, DurableObjectNamespace>\n>();\nconst bindingNameCache = new WeakMap<object, Record<string, string>>();\n\nconst DEFAULT_ROUTING_RETRY_OPTIONS = {\n maxAttempts: 3,\n baseDelayMs: 100,\n maxDelayMs: 800\n};\n\ninterface RoutingRetryEvent {\n error: unknown;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n name: string;\n className?: string;\n}\n\n/** Retry policy for Agent routing infrastructure failures. */\nexport interface RoutingRetryOptions {\n /** Max number of attempts, including the first. Default: 3. */\n maxAttempts?: number;\n /** Base delay in milliseconds for exponential backoff. Default: 100. */\n baseDelayMs?: number;\n /** Maximum delay in milliseconds. Default: 800. */\n maxDelayMs?: number;\n /** Optional callback invoked before each retry delay. */\n onRetry?: (event: RoutingRetryEvent) => void | Promise<void>;\n}\n\ninterface AgentRouteMatch<Env = Cloudflare.Env> {\n /** The Durable Object environment binding name. */\n className: Extract<keyof Env, string>;\n /** The named Durable Object instance extracted from the URL. */\n name: string;\n}\n\ninterface AgentRouteOptions<\n Env = Cloudflare.Env,\n Props extends object = object\n> {\n /** URL prefix before the binding and instance name. Default: `agents`. */\n prefix?: string;\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n /** Properties supplied before lifecycle startup. */\n props?: Props;\n /**\n * Whether to enable CORS for matched routes.\n *\n * When `true`, uses default permissive CORS headers:\n * - Access-Control-Allow-Origin: *\n * - Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS\n * - Access-Control-Allow-Headers: *\n * - Access-Control-Max-Age: 86400\n *\n * For credentialed requests, pass explicit headers with a specific origin.\n * When set to a `HeadersInit` value, uses those as the CORS headers instead.\n * CORS preflight requests are handled automatically for matched routes.\n */\n cors?: boolean | HeadersInit;\n /**\n * Retry transient Durable Object infrastructure errors thrown while routing.\n * Enabled by default; pass `false` to disable.\n */\n routingRetry?: false | RoutingRetryOptions;\n onBeforeConnect?: (\n request: Request,\n route: AgentRouteMatch<Env>\n ) => Response | Request | void | Promise<Response | Request | void>;\n onBeforeRequest?: (\n request: Request,\n route: AgentRouteMatch<Env>\n ) =>\n | Response\n | Request\n | void\n | Promise<Response | Request | undefined | void>;\n}\n\n/** Configuration options for {@link routeAgentRequest}. */\nexport type AgentOptions<Env> = AgentRouteOptions<Env>;\n\n/** Options for resolving and starting a named Agent. */\nexport type AgentGetOptions<Env, Props extends object = object> = Pick<\n AgentRouteOptions<Env, Props>,\n \"jurisdiction\" | \"locationHint\" | \"props\" | \"routingRetry\"\n>;\n\ninterface ResolvedRoutingRetryOptions extends Required<\n Omit<RoutingRetryOptions, \"onRetry\">\n> {\n onRetry?: RoutingRetryOptions[\"onRetry\"];\n}\n\ninterface RoutingRetryContext {\n name: string;\n className?: string;\n}\n\nfunction durableObjectGetOptions(\n options: { locationHint?: DurableObjectLocationHint } | undefined\n) {\n return options?.locationHint\n ? { locationHint: options.locationHint }\n : undefined;\n}\n\nfunction validatePositiveInteger(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 1) {\n throw new Error(`${name} must be >= 1`);\n }\n if (!Number.isInteger(value)) {\n throw new Error(`${name} must be an integer`);\n }\n}\n\nfunction validatePositiveNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`${name} must be > 0`);\n }\n}\n\nfunction resolveRoutingRetryOptions(\n options: false | RoutingRetryOptions | undefined\n): ResolvedRoutingRetryOptions | null {\n if (options === false) return null;\n\n const resolved = {\n maxAttempts:\n options?.maxAttempts ?? DEFAULT_ROUTING_RETRY_OPTIONS.maxAttempts,\n baseDelayMs:\n options?.baseDelayMs ?? DEFAULT_ROUTING_RETRY_OPTIONS.baseDelayMs,\n maxDelayMs: options?.maxDelayMs ?? DEFAULT_ROUTING_RETRY_OPTIONS.maxDelayMs,\n onRetry: options?.onRetry\n };\n\n validatePositiveInteger(resolved.maxAttempts, \"routingRetry.maxAttempts\");\n validatePositiveNumber(resolved.baseDelayMs, \"routingRetry.baseDelayMs\");\n validatePositiveNumber(resolved.maxDelayMs, \"routingRetry.maxDelayMs\");\n if (resolved.baseDelayMs > resolved.maxDelayMs) {\n throw new Error(\"routingRetry.baseDelayMs must be <= maxDelayMs\");\n }\n\n return resolved;\n}\n\nfunction isRetryableDurableObjectError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) return false;\n // SAFETY: Cloudflare's retryable and overloaded error flags are optional\n // runtime properties not represented on the base Error type.\n const typed = error as { retryable?: boolean; overloaded?: boolean };\n return typed.retryable === true && typed.overloaded !== true;\n}\n\nfunction routingRetryDelayMs(\n attempt: number,\n options: ResolvedRoutingRetryOptions\n): number {\n const upperBoundMs = Math.min(\n options.maxDelayMs,\n options.baseDelayMs * 2 ** (attempt - 1)\n );\n return Math.floor(Math.random() * upperBoundMs);\n}\n\nasync function retryDurableObjectOperation<T>(\n operation: () => Promise<T>,\n context: RoutingRetryContext,\n retryOptions: false | RoutingRetryOptions | undefined\n): Promise<T> {\n const resolved = resolveRoutingRetryOptions(retryOptions);\n if (!resolved) return await operation();\n\n let attempt = 1;\n while (true) {\n try {\n return await operation();\n } catch (error) {\n const nextAttempt = attempt + 1;\n if (\n nextAttempt > resolved.maxAttempts ||\n !isRetryableDurableObjectError(error)\n ) {\n throw error;\n }\n\n const delayMs = routingRetryDelayMs(attempt, resolved);\n try {\n await resolved.onRetry?.({\n error,\n attempt,\n maxAttempts: resolved.maxAttempts,\n delayMs,\n name: context.name,\n className: context.className\n });\n } catch (callbackError) {\n console.warn(\n \"Durable Object routing retry callback failed:\",\n callbackError\n );\n }\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n attempt = nextAttempt;\n }\n }\n}\n\nfunction encodeLifecycleProps(props: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(props));\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nfunction mutableRequest(request: Request): Request {\n return new Request(request);\n}\n\nfunction cloneRequestForFetch(request: Request): Request {\n // SAFETY: Workers Types v5 preserves an unconstrained `cf` generic from\n // clone(). Cloning does not change the runtime Request representation.\n return request.clone() as Request;\n}\n\nfunction resolveCorsHeaders(\n cors: boolean | HeadersInit | undefined\n): Record<string, string> | null {\n if (cors === true) {\n return {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, HEAD, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\n \"Access-Control-Max-Age\": \"86400\"\n };\n }\n if (cors && typeof cors === \"object\") {\n const headers = new Headers(cors);\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key] = value;\n });\n return record;\n }\n return null;\n}\n\n/**\n * Route `/agents/:binding/:name` HTTP and WebSocket requests to a named\n * Durable Object. The target may extend `Agent` or compose `Lifecycle`\n * directly into a plain `DurableObject`.\n *\n * @param request - Incoming Worker request.\n * @param env - Worker environment containing Durable Object bindings.\n * @param options - Routing options.\n * @returns The matched response, or `null` when the path does not match.\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n): Promise<Response | null> {\n // SAFETY: Worker environments are object records. The unconstrained Env\n // generic is retained for compatibility with the previously published API.\n const environment = env as object;\n if (!namespaceMapCache.has(environment)) {\n const namespaceMap: Record<string, DurableObjectNamespace> = {};\n const bindingNames: Record<string, string> = {};\n for (const [key, value] of Object.entries(environment)) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n const kebab = camelCaseToKebabCase(key);\n // SAFETY: The structural idFromName check above identifies a Durable\n // Object namespace at the Worker environment boundary.\n namespaceMap[kebab] = value as DurableObjectNamespace;\n bindingNames[kebab] = key;\n }\n }\n namespaceMapCache.set(environment, namespaceMap);\n bindingNameCache.set(environment, bindingNames);\n }\n\n const map = namespaceMapCache.get(environment) as Record<\n string,\n DurableObjectNamespace\n >;\n const bindingNames = bindingNameCache.get(environment) as Record<\n string,\n string\n >;\n const prefixParts = (options?.prefix || \"agents\").split(\"/\");\n const parts = new URL(request.url).pathname.split(\"/\").filter(Boolean);\n const prefixMatches = prefixParts.every(\n (part, index) => parts[index] === part\n );\n if (!prefixMatches || parts.length < prefixParts.length + 2) return null;\n\n const namespaceName = parts[prefixParts.length];\n const name = parts[prefixParts.length + 1];\n if (!name || !namespaceName) return null;\n\n const boundNamespace = map[namespaceName];\n if (!boundNamespace) {\n console.error(\n `The URL ${request.url} with namespace \"${namespaceName}\" and name \"${name}\" does not match any Durable Object binding.`\n );\n return new Response(\"Invalid request\", { status: 400 });\n }\n\n const corsHeaders = resolveCorsHeaders(options?.cors);\n const isWebSocket =\n request.headers.get(\"Upgrade\")?.toLowerCase() === \"websocket\";\n const withCorsHeaders = (response: Response): Response => {\n if (!corsHeaders || isWebSocket) return response;\n const nextResponse = new Response(response.body, response);\n for (const [key, value] of Object.entries(corsHeaders)) {\n nextResponse.headers.set(key, value);\n }\n return nextResponse;\n };\n\n if (request.method === \"OPTIONS\" && corsHeaders) {\n return new Response(null, { headers: corsHeaders });\n }\n\n const namespace = options?.jurisdiction\n ? boundNamespace.jurisdiction(options.jurisdiction)\n : boundNamespace;\n const id = namespace.idFromName(name);\n const getOptions = durableObjectGetOptions(options);\n request = mutableRequest(request);\n\n // SAFETY: binding names come directly from Object.entries(env), so they are\n // string keys of Env.\n const className = bindingNames[namespaceName] as Extract<keyof Env, string>;\n const route: AgentRouteMatch<Env> = { className, name };\n\n if (isWebSocket) {\n const requestOrResponse = await options?.onBeforeConnect?.(request, route);\n if (requestOrResponse instanceof Request) {\n request = mutableRequest(requestOrResponse);\n } else if (requestOrResponse instanceof Response) {\n return requestOrResponse;\n }\n } else {\n const requestOrResponse = await options?.onBeforeRequest?.(request, route);\n if (requestOrResponse instanceof Request) {\n request = mutableRequest(requestOrResponse);\n } else if (requestOrResponse instanceof Response) {\n return withCorsHeaders(requestOrResponse);\n }\n }\n\n if (options?.props !== undefined) {\n request.headers.set(\n \"x-agents-lifecycle-props\",\n encodeLifecycleProps(options.props)\n );\n }\n\n const response = await retryDurableObjectOperation(\n () => namespace.get(id, getOptions).fetch(cloneRequestForFetch(request)),\n { name, className },\n options?.routingRetry\n );\n return isWebSocket ? response : withCorsHeaders(response);\n}\n\n/**\n * Get a named Agent stub after its lifecycle startup has completed.\n *\n * @param namespace - Agent Durable Object namespace.\n * @param name - Agent instance name.\n * @param options - Placement, startup properties, and retry options.\n * @returns The initialized Agent stub.\n */\nexport async function getAgentByName<\n Env extends Cloudflare.Env = Cloudflare.Env,\n T extends Agent<Env> = Agent<Env>,\n Props extends object = object\n>(\n namespace: DurableObjectNamespace<T>,\n name: string,\n options?: AgentGetOptions<Env, Props>\n): Promise<DurableObjectStub<T>> {\n const target = options?.jurisdiction\n ? namespace.jurisdiction(options.jurisdiction)\n : namespace;\n const id = target.idFromName(name);\n const stub = target.get(id, durableObjectGetOptions(options));\n\n // SAFETY: Agent exposes this internal initializer specifically for native\n // RPC calls, which bypass the lifecycle-installed fetch handler.\n const lifecycleStub = stub as unknown as {\n __unsafe_ensureInitialized(props?: Props): Promise<void>;\n };\n await retryDurableObjectOperation(\n () => lifecycleStub.__unsafe_ensureInitialized(options?.props),\n { name },\n options?.routingRetry\n );\n\n return stub;\n}\n"],"mappings":";;AAGA,MAAM,oCAAoB,IAAI,QAG5B;AACF,MAAM,mCAAmB,IAAI,QAAwC;AAErE,MAAM,gCAAgC;CACpC,aAAa;CACb,aAAa;CACb,YAAY;AACd;AA6FA,SAAS,wBACP,SACA;CACA,OAAO,SAAS,eACZ,EAAE,cAAc,QAAQ,aAAa,IACrC,KAAA;AACN;AAEA,SAAS,wBAAwB,OAAe,MAAoB;CAClE,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,GAAG,KAAK,cAAc;CAExC,IAAI,CAAC,OAAO,UAAU,KAAK,GACzB,MAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB;AAEhD;AAEA,SAAS,uBAAuB,OAAe,MAAoB;CACjE,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACtC,MAAM,IAAI,MAAM,GAAG,KAAK,aAAa;AAEzC;AAEA,SAAS,2BACP,SACoC;CACpC,IAAI,YAAY,OAAO,OAAO;CAE9B,MAAM,WAAW;EACf,aACE,SAAS,eAAe,8BAA8B;EACxD,aACE,SAAS,eAAe,8BAA8B;EACxD,YAAY,SAAS,cAAc,8BAA8B;EACjE,SAAS,SAAS;CACpB;CAEA,wBAAwB,SAAS,aAAa,0BAA0B;CACxE,uBAAuB,SAAS,aAAa,0BAA0B;CACvE,uBAAuB,SAAS,YAAY,yBAAyB;CACrE,IAAI,SAAS,cAAc,SAAS,YAClC,MAAM,IAAI,MAAM,gDAAgD;CAGlE,OAAO;AACT;AAEA,SAAS,8BAA8B,OAAyB;CAC9D,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAGxD,MAAM,QAAQ;CACd,OAAO,MAAM,cAAc,QAAQ,MAAM,eAAe;AAC1D;AAEA,SAAS,oBACP,SACA,SACQ;CACR,MAAM,eAAe,KAAK,IACxB,QAAQ,YACR,QAAQ,cAAc,MAAM,UAAU,EACxC;CACA,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,YAAY;AAChD;AAEA,eAAe,4BACb,WACA,SACA,cACY;CACZ,MAAM,WAAW,2BAA2B,YAAY;CACxD,IAAI,CAAC,UAAU,OAAO,MAAM,UAAU;CAEtC,IAAI,UAAU;CACd,OAAO,MACL,IAAI;EACF,OAAO,MAAM,UAAU;CACzB,SAAS,OAAO;EACd,MAAM,cAAc,UAAU;EAC9B,IACE,cAAc,SAAS,eACvB,CAAC,8BAA8B,KAAK,GAEpC,MAAM;EAGR,MAAM,UAAU,oBAAoB,SAAS,QAAQ;EACrD,IAAI;GACF,MAAM,SAAS,UAAU;IACvB;IACA;IACA,aAAa,SAAS;IACtB;IACA,MAAM,QAAQ;IACd,WAAW,QAAQ;GACrB,CAAC;EACH,SAAS,eAAe;GACtB,QAAQ,KACN,iDACA,aACF;EACF;EACA,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,OAAO,CAAC;EAC3D,UAAU;CACZ;AAEJ;AAEA,SAAS,qBAAqB,OAAwB;CACpD,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,UAAU,KAAK,CAAC;CAC5D,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,UAAU,OAAO,aAAa,MAAM,EAAE;CAExC,OAAO,KAAK,MAAM;AACpB;AAEA,SAAS,eAAe,SAA2B;CACjD,OAAO,IAAI,QAAQ,OAAO;AAC5B;AAEA,SAAS,qBAAqB,SAA2B;CAGvD,OAAO,QAAQ,MAAM;AACvB;AAEA,SAAS,mBACP,MAC+B;CAC/B,IAAI,SAAS,MACX,OAAO;EACL,+BAA+B;EAC/B,gCAAgC;EAChC,gCAAgC;EAChC,0BAA0B;CAC5B;CAEF,IAAI,QAAQ,OAAO,SAAS,UAAU;EACpC,MAAM,UAAU,IAAI,QAAQ,IAAI;EAChC,MAAM,SAAiC,CAAC;EACxC,QAAQ,SAAS,OAAO,QAAQ;GAC9B,OAAO,OAAO;EAChB,CAAC;EACD,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;;;;AAYA,eAAsB,kBACpB,SACA,KACA,SAC0B;CAG1B,MAAM,cAAc;CACpB,IAAI,CAAC,kBAAkB,IAAI,WAAW,GAAG;EACvC,MAAM,eAAuD,CAAC;EAC9D,MAAM,eAAuC,CAAC;EAC9C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,GACnD,IACE,SACA,OAAO,UAAU,YACjB,gBAAgB,SAChB,OAAO,MAAM,eAAe,YAC5B;GACA,MAAM,QAAQ,qBAAqB,GAAG;GAGtC,aAAa,SAAS;GACtB,aAAa,SAAS;EACxB;EAEF,kBAAkB,IAAI,aAAa,YAAY;EAC/C,iBAAiB,IAAI,aAAa,YAAY;CAChD;CAEA,MAAM,MAAM,kBAAkB,IAAI,WAAW;CAI7C,MAAM,eAAe,iBAAiB,IAAI,WAAW;CAIrD,MAAM,eAAe,SAAS,UAAU,SAAA,CAAU,MAAM,GAAG;CAC3D,MAAM,QAAQ,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;CAIrE,IAAI,CAHkB,YAAY,OAC/B,MAAM,UAAU,MAAM,WAAW,IAEnB,KAAK,MAAM,SAAS,YAAY,SAAS,GAAG,OAAO;CAEpE,MAAM,gBAAgB,MAAM,YAAY;CACxC,MAAM,OAAO,MAAM,YAAY,SAAS;CACxC,IAAI,CAAC,QAAQ,CAAC,eAAe,OAAO;CAEpC,MAAM,iBAAiB,IAAI;CAC3B,IAAI,CAAC,gBAAgB;EACnB,QAAQ,MACN,WAAW,QAAQ,IAAI,mBAAmB,cAAc,cAAc,KAAK,6CAC7E;EACA,OAAO,IAAI,SAAS,mBAAmB,EAAE,QAAQ,IAAI,CAAC;CACxD;CAEA,MAAM,cAAc,mBAAmB,SAAS,IAAI;CACpD,MAAM,cACJ,QAAQ,QAAQ,IAAI,SAAS,CAAC,EAAE,YAAY,MAAM;CACpD,MAAM,mBAAmB,aAAiC;EACxD,IAAI,CAAC,eAAe,aAAa,OAAO;EACxC,MAAM,eAAe,IAAI,SAAS,SAAS,MAAM,QAAQ;EACzD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,GACnD,aAAa,QAAQ,IAAI,KAAK,KAAK;EAErC,OAAO;CACT;CAEA,IAAI,QAAQ,WAAW,aAAa,aAClC,OAAO,IAAI,SAAS,MAAM,EAAE,SAAS,YAAY,CAAC;CAGpD,MAAM,YAAY,SAAS,eACvB,eAAe,aAAa,QAAQ,YAAY,IAChD;CACJ,MAAM,KAAK,UAAU,WAAW,IAAI;CACpC,MAAM,aAAa,wBAAwB,OAAO;CAClD,UAAU,eAAe,OAAO;CAIhC,MAAM,YAAY,aAAa;CAC/B,MAAM,QAA8B;EAAE;EAAW;CAAK;CAEtD,IAAI,aAAa;EACf,MAAM,oBAAoB,MAAM,SAAS,kBAAkB,SAAS,KAAK;EACzE,IAAI,6BAA6B,SAC/B,UAAU,eAAe,iBAAiB;OACrC,IAAI,6BAA6B,UACtC,OAAO;CAEX,OAAO;EACL,MAAM,oBAAoB,MAAM,SAAS,kBAAkB,SAAS,KAAK;EACzE,IAAI,6BAA6B,SAC/B,UAAU,eAAe,iBAAiB;OACrC,IAAI,6BAA6B,UACtC,OAAO,gBAAgB,iBAAiB;CAE5C;CAEA,IAAI,SAAS,UAAU,KAAA,GACrB,QAAQ,QAAQ,IACd,4BACA,qBAAqB,QAAQ,KAAK,CACpC;CAGF,MAAM,WAAW,MAAM,kCACf,UAAU,IAAI,IAAI,UAAU,CAAC,CAAC,MAAM,qBAAqB,OAAO,CAAC,GACvE;EAAE;EAAM;CAAU,GAClB,SAAS,YACX;CACA,OAAO,cAAc,WAAW,gBAAgB,QAAQ;AAC1D;;;;;;;;;AAUA,eAAsB,eAKpB,WACA,MACA,SAC+B;CAC/B,MAAM,SAAS,SAAS,eACpB,UAAU,aAAa,QAAQ,YAAY,IAC3C;CACJ,MAAM,KAAK,OAAO,WAAW,IAAI;CACjC,MAAM,OAAO,OAAO,IAAI,IAAI,wBAAwB,OAAO,CAAC;CAI5D,MAAM,gBAAgB;CAGtB,MAAM,kCACE,cAAc,2BAA2B,SAAS,KAAK,GAC7D,EAAE,KAAK,GACP,SAAS,YACX;CAEA,OAAO;AACT"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
$ as ChatCapableAgentClass,
|
|
3
3
|
B as AgentToolFailure,
|
|
4
|
-
F as
|
|
4
|
+
F as AgentToolDisplayMetadata,
|
|
5
5
|
G as AgentToolProgressSnapshot,
|
|
6
6
|
H as AgentToolLifecycleResult,
|
|
7
|
-
I as
|
|
7
|
+
I as AgentToolEvent,
|
|
8
8
|
J as AgentToolRunPart,
|
|
9
9
|
K as AgentToolRunInfo,
|
|
10
|
-
L as
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
L as AgentToolEventDelivery,
|
|
11
|
+
M as AGENT_TOOL_MILESTONE_PART,
|
|
12
|
+
N as AGENT_TOOL_PROGRESS_PART,
|
|
13
|
+
P as AgentToolChildAdapter,
|
|
13
14
|
Q as AgentToolTerminalStatus,
|
|
14
15
|
R as AgentToolEventMessage,
|
|
15
16
|
U as AgentToolMilestone,
|
|
@@ -18,19 +19,22 @@ import {
|
|
|
18
19
|
X as AgentToolRunStatus,
|
|
19
20
|
Y as AgentToolRunState,
|
|
20
21
|
Z as AgentToolStoredChunk,
|
|
22
|
+
at as isPositionlessAgentToolChunk,
|
|
21
23
|
et as DetachedAgentToolConfig,
|
|
24
|
+
it as isAgentToolLifecycleChunk,
|
|
22
25
|
nt as RunAgentToolOptions,
|
|
23
26
|
q as AgentToolRunInspection,
|
|
24
27
|
rt as RunAgentToolResult,
|
|
25
28
|
tt as DetachedRunAgentToolResult,
|
|
26
29
|
z as AgentToolEventState
|
|
27
|
-
} from "./agent-routing-
|
|
30
|
+
} from "./agent-routing-0DR0Tk2v.js";
|
|
28
31
|
export {
|
|
29
32
|
AGENT_TOOL_MILESTONE_PART,
|
|
30
33
|
AGENT_TOOL_PROGRESS_PART,
|
|
31
34
|
AgentToolChildAdapter,
|
|
32
35
|
AgentToolDisplayMetadata,
|
|
33
36
|
AgentToolEvent,
|
|
37
|
+
AgentToolEventDelivery,
|
|
34
38
|
AgentToolEventMessage,
|
|
35
39
|
AgentToolEventState,
|
|
36
40
|
AgentToolFailure,
|
|
@@ -50,5 +54,7 @@ export {
|
|
|
50
54
|
DetachedAgentToolConfig,
|
|
51
55
|
DetachedRunAgentToolResult,
|
|
52
56
|
RunAgentToolOptions,
|
|
53
|
-
RunAgentToolResult
|
|
57
|
+
RunAgentToolResult,
|
|
58
|
+
isAgentToolLifecycleChunk,
|
|
59
|
+
isPositionlessAgentToolChunk
|
|
54
60
|
};
|
package/dist/agent-tool-types.js
CHANGED
|
@@ -14,7 +14,29 @@ const AGENT_TOOL_PROGRESS_PART = "data-agent-progress";
|
|
|
14
14
|
* re-resolves milestone waiters. See `design/rfc-detached-agent-tools.md`.
|
|
15
15
|
*/
|
|
16
16
|
const AGENT_TOOL_MILESTONE_PART = "data-agent-milestone";
|
|
17
|
+
/**
|
|
18
|
+
* Whether a chunk body is a progress or milestone frame. These are broadcast
|
|
19
|
+
* but never written to the child's chunk store, so they have no stored-chunk
|
|
20
|
+
* position and must not take part in stored-position numbering or dedupe.
|
|
21
|
+
*/
|
|
22
|
+
function isAgentToolLifecycleChunk(body) {
|
|
23
|
+
if (!body.includes("data-agent-progress") && !body.includes("data-agent-milestone")) return false;
|
|
24
|
+
try {
|
|
25
|
+
const type = JSON.parse(body)?.type;
|
|
26
|
+
return type === "data-agent-progress" || type === "data-agent-milestone";
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether a forwarded chunk has no stored-chunk position: a progress or
|
|
33
|
+
* milestone frame, or a chunk too large to store. Such chunks carry the next
|
|
34
|
+
* stored position without consuming it.
|
|
35
|
+
*/
|
|
36
|
+
function isPositionlessAgentToolChunk(chunk) {
|
|
37
|
+
return chunk.unstoredId !== void 0 || isAgentToolLifecycleChunk(chunk.body);
|
|
38
|
+
}
|
|
17
39
|
//#endregion
|
|
18
|
-
export { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART };
|
|
40
|
+
export { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART, isAgentToolLifecycleChunk, isPositionlessAgentToolChunk };
|
|
19
41
|
|
|
20
42
|
//# sourceMappingURL=agent-tool-types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tool-types.js","names":[],"sources":["../src/agent-tool-types.ts"],"sourcesContent":["import type { Agent, SubAgentClass } from \"./index\";\n\nexport type AgentToolRunStatus =\n | \"starting\"\n | \"running\"\n | \"completed\"\n | \"error\"\n | \"aborted\"\n | \"interrupted\";\n\nexport type AgentToolTerminalStatus = Extract<\n AgentToolRunStatus,\n \"completed\" | \"error\" | \"aborted\" | \"interrupted\"\n>;\n\n/**\n * Machine-readable cause of an `interrupted` seal (#1630 follow-up). Lets a\n * caller branch on WHY a run was abandoned without parsing the human-readable\n * `error` prose, which is not a stable contract.\n *\n * - `no-progress` — the child went silent for a full no-progress window while\n * the parent was tailing it (genuinely stalled / hung).\n * - `window-exceeded` — a finite `agentToolReattachMaxWindowMs` ceiling elapsed\n * while the child was still non-terminal. Only fires when an integrator opts\n * into a hard wall-clock cap (the default ceiling is `Infinity`).\n * - `not-tailable` — the child runtime cannot live-tail, so the parent could\n * not re-attach to its stream to follow it to terminal.\n * - `inspect-timeout` — inspecting the child timed out during parent recovery.\n * - `inspect-failed` — inspecting the child failed during parent recovery.\n * - `recovery-deadline` — the overall parent-recovery deadline elapsed before\n * this run could be reconciled.\n * - `budget-exceeded` — a detached run's absolute `maxBudgetMs` ceiling elapsed\n * before it reached a terminal. The parent gave up watching and tore the\n * child down. Like `window-exceeded` this is a soft seal: a child that\n * completes anyway can still repair the run and re-fire the completion hook.\n */\nexport type AgentToolInterruptedReason =\n | \"no-progress\"\n | \"window-exceeded\"\n | \"not-tailable\"\n | \"inspect-timeout\"\n | \"inspect-failed\"\n | \"recovery-deadline\"\n | \"budget-exceeded\";\n\n/**\n * Structured failure envelope an `agentTool()` returns when a sub-agent run\n * does not complete. Instead of an opaque error string the parent model would\n * parrot back to the user, the caller (or an orchestration harness) gets a\n * machine-readable signal:\n *\n * - `status` mirrors the underlying terminal status (`error` | `aborted` |\n * `interrupted`).\n * - `retryable` is `true` only for a transient interruption — the child was\n * reset or superseded by a deploy / parent recovery and never reached a\n * logical outcome, so re-dispatching the same run is the right move. A\n * genuine `error` or an intentional `aborted` is `false`.\n * - `error` stays human-readable for logs and UI.\n */\nexport type AgentToolFailure = {\n ok: false;\n status: Exclude<AgentToolTerminalStatus, \"completed\">;\n error: string;\n retryable: boolean;\n /** Present only when `status` is `interrupted` — machine-readable cause. */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. `true` when the child facet was\n * still non-terminal (running / advancing) at the moment the parent stopped\n * waiting; `false` once the parent has torn the child down so it is no longer\n * doing work. Lets a caller decide between re-dispatching vs. reconnecting.\n */\n childStillRunning?: boolean;\n};\n\nexport type AgentToolDisplayMetadata = {\n name?: string;\n icon?: string;\n} & Record<string, unknown>;\n\n/**\n * Reserved chunk type a sub-agent emits via `reportProgress` while it runs.\n * Rides the child's own UI-message stream as a **transient** data part, so it\n * re-broadcasts to the parent's clients (via the parent's tail) and surfaces in\n * `useAgentToolEvents` without persisting into the child's stored message parts.\n * See `design/rfc-detached-agent-tools.md` §\"Progress and milestone signaling\".\n */\nexport const AGENT_TOOL_PROGRESS_PART = \"data-agent-progress\";\n\n/**\n * Reserved chunk type a sub-agent emits via `reportProgress({ milestone })`.\n * Unlike the ephemeral progress part this rides the child's stream as a\n * **persisted** data part, so it survives eviction, replays on drill-in, and\n * re-resolves milestone waiters. See `design/rfc-detached-agent-tools.md`.\n */\nexport const AGENT_TOOL_MILESTONE_PART = \"data-agent-milestone\";\n\n/**\n * Ephemeral progress signal a running sub-agent emits with `reportProgress`. The\n * well-known fields drive generic UI (a bar + status line) with no per-app\n * convention; `data` is an app-specific escape hatch that is **live-only** by\n * default (not persisted) unless `reportProgress(p, { persist: true })`. Naming a\n * `milestone` promotes the signal to the **durable** tier: it persists as one row\n * per milestone, replays, and (with `data`) is retained.\n */\nexport type AgentToolProgress<T = unknown> = {\n /** 0..1 — drives a progress bar. */\n fraction?: number;\n /** Human-readable status line, e.g. \"Ingested 40k/80k rows\". */\n message?: string;\n /** Coarse stage label, e.g. \"scaffolding\" | \"deploying\". */\n phase?: string;\n /**\n * Present ⇒ a **durable** milestone: persisted, replayable, and surfaced as a\n * distinct row in `AgentToolRunState.milestones` / `inspectAgentToolRun`. Use\n * for named phase boundaries (\"schema-ready\", \"preview-ready\", \"deployed\").\n */\n milestone?: string;\n /** App-specific payload; live-only for progress, persisted for milestones. */\n data?: T;\n};\n\n/**\n * A durable milestone a sub-agent reached, projected onto `AgentToolRunState`\n * and `inspectAgentToolRun`. `sequence` is monotonic per run so replay/live\n * races dedupe on `(runId, sequence)`.\n */\nexport type AgentToolMilestone = {\n name: string;\n /** Monotonic per-run ordinal; dedupe key for replay vs live races. */\n sequence: number;\n /** Epoch ms the milestone was reached. */\n at: number;\n /** App-specific payload carried with the milestone (persisted). */\n data?: unknown;\n};\n\n/**\n * Latest progress snapshot persisted on the child run row and surfaced through\n * `inspectAgentToolRun` + `AgentToolRunState`. Only the safe-to-inspect fields\n * are retained by default; `at` is the emit timestamp (drives the resetting\n * no-progress budget).\n */\nexport type AgentToolProgressSnapshot = {\n fraction?: number;\n message?: string;\n phase?: string;\n /**\n * Set when this signal was a durable milestone (`reportProgress({ milestone })`).\n * Lets an `onProgress` consumer branch on milestone vs. ephemeral progress.\n */\n milestone?: string;\n /** Epoch ms of the latest signal. */\n at: number;\n /** Present only when the emitter opted into persisting `data`. */\n data?: unknown;\n};\n\nexport type AgentToolRunInfo = {\n runId: string;\n parentToolCallId?: string;\n agentType: string;\n inputPreview?: unknown;\n status: AgentToolRunStatus;\n display?: AgentToolDisplayMetadata;\n /**\n * Caller-controlled `metadata.source` for chat-agent `detached.notify`\n * completions. Present only for detached notify runs that supplied one.\n */\n notifySource?: string;\n displayOrder: number;\n startedAt: number;\n completedAt?: number;\n};\n\nexport type AgentToolLifecycleResult = {\n status: AgentToolTerminalStatus;\n summary?: string;\n error?: string;\n /** Present only when `status` is `interrupted` — machine-readable cause. */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. Whether the child facet was\n * still non-terminal when the parent stopped waiting (before any teardown).\n */\n childStillRunning?: boolean;\n};\n\n/**\n * Configuration for a detached (\"background\") agent-tool run. See\n * `design/rfc-detached-agent-tools.md`.\n *\n * Callbacks are referenced by **method name** on the dispatching agent (the same\n * durable, eviction-surviving pattern as `Agent.schedule`) — never closures,\n * which cannot be rehydrated after the Durable Object is evicted.\n *\n * `Self` is threaded from `runAgentTool(cls, options)` so the method names are\n * type-checked against the calling agent's own methods.\n */\nexport type DetachedAgentToolConfig<Self = Record<string, unknown>> = {\n /**\n * Method invoked once per terminal delivery. Branch on `result.status`:\n * `\"completed\" | \"error\" | \"aborted\" | \"interrupted\"`. A budget give-up\n * arrives as `status: \"interrupted\"` with `reason: \"budget-exceeded\"`; because\n * `interrupted` is soft, a child that later completes can fire the hook again\n * with `\"completed\"`, so a give-up never hides a late real result. Make the\n * handler idempotent.\n */\n onFinish?: Extract<keyof Self, string>;\n /**\n * Absolute safety ceiling — a backstop against a child that runs forever. On\n * expiry the parent gives up watching (delivers `onFinish` with\n * `interrupted` / `budget-exceeded`) and tears the child down. Defaults to the\n * parent-level `detachedMaxBudgetMs`.\n */\n maxBudgetMs?: number;\n /**\n * Per-run override of the resetting no-progress window (ms). Once the child\n * emits its first `reportProgress`, the parent gives up if it then goes silent\n * for this long (resets on each signal). Defaults to the parent-level\n * `detachedNoProgressBudgetMs` (1h). `0`/`Infinity` disables it.\n */\n noProgressBudgetMs?: number;\n /**\n * Chat-agent convenience (`@cloudflare/think` / `AIChatAgent`): when the run\n * finishes, inject a message into the chat so the model can react to the\n * result, instead of you wiring `onFinish` by hand. Sugar that auto-targets\n * the agent's `_cfDetachedNotifyFinish` hook; ignored on a base `Agent` that\n * does not implement it, and ignored when `onFinish` is also set (an explicit\n * `onFinish` wins). Pass `{ source }` to fit the injected message into your\n * app's existing metadata taxonomy. Override `formatDetachedCompletion()` to\n * customize the injected text.\n */\n notify?: boolean | { source?: string };\n /**\n * Chat-agent convenience: milestone names that, when the detached run reaches\n * them, surface an idempotent synthetic message in the chat BEFORE the run\n * finishes. Each `(runId, name)` fires at most once (idempotency-keyed),\n * whether observed live or reconciled after eviction. Override the wording via\n * `formatDetachedMilestone()`. Requires a chat host (`@cloudflare/think`); a\n * no-op on a base `Agent`.\n *\n * Two delivery modes (the string-array shorthand defaults to `\"narrate\"`):\n * - `\"narrate\"` (default) — inject a synthetic **assistant** message directly\n * (no inference): a cheap, honest status line (\"Found 2 sources…\") that does\n * not trigger a model turn. Best for pure progress narration.\n * - `\"react\"` — inject a **user-role** turn so the model responds to the\n * milestone (steer, start dependent work, narrate with context). Costs a\n * model turn. Opt in for milestones the agent should *act on*.\n */\n onMilestones?: string[] | { names: string[]; mode?: \"react\" | \"narrate\" };\n};\n\nexport type RunAgentToolOptions<\n Input = unknown,\n Self = Record<string, unknown>\n> = {\n input: Input;\n runId?: string;\n parentToolCallId?: string;\n displayOrder?: number;\n signal?: AbortSignal;\n inputPreview?: unknown;\n display?: AgentToolDisplayMetadata;\n /**\n * Run the sub-agent **detached**: dispatch it, let the current turn continue,\n * and (optionally) get a durable callback when it finishes. `true` is\n * fire-and-forget (observe via `agent-tool-event` frames + the global\n * `onAgentToolFinish` hook); an object adds the targeted, eviction-surviving\n * `onFinish` callback. A detached run does NOT inherit `options.signal` — it\n * must outlive the spawning turn; cancel it explicitly via `cancelAgentTool`.\n */\n detached?: boolean | DetachedAgentToolConfig<Self>;\n};\n\n/**\n * Result of dispatching a detached run. Returns immediately after dispatch\n * rather than after completion.\n */\nexport type DetachedRunAgentToolResult = {\n runId: string;\n agentType: string;\n /**\n * `\"running\"` on a successful dispatch; `\"error\"` if dispatch itself failed\n * (e.g. the `maxConcurrentAgentTools` cap was exceeded — rejected\n * synchronously, no child started, no callback wired).\n */\n status: \"running\" | \"error\";\n error?: string;\n};\n\nexport type RunAgentToolResult<Output = unknown> = {\n runId: string;\n agentType: string;\n status: AgentToolTerminalStatus;\n output?: Output;\n summary?: string;\n error?: string;\n /**\n * Present only when `status` is `interrupted` — a machine-readable cause so\n * callers don't pattern-match the `error` prose (#1630 follow-up).\n */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. `true` when the child facet was\n * still non-terminal (running / advancing) at the moment the parent stopped\n * waiting and before any teardown; `false` once the parent has torn the child\n * down so it is no longer doing work.\n */\n childStillRunning?: boolean;\n};\n\nexport type ChatCapableAgentClass<T extends Agent = Agent> = SubAgentClass<T>;\n\nexport type AgentToolRunInspection<Output = unknown> = {\n runId: string;\n status: Exclude<AgentToolRunStatus, \"interrupted\">;\n requestId?: string;\n streamId?: string;\n output?: Output;\n summary?: string;\n error?: string;\n startedAt: number;\n completedAt?: number;\n /**\n * Latest progress snapshot the child has persisted, so a rehydrated parent\n * (recovery / backbone reconcile) can reconstruct \"where is this run\" and\n * reset the resetting no-progress budget without having tailed the live\n * stream. Absent until the child emits its first `reportProgress`.\n */\n progress?: AgentToolProgressSnapshot;\n /**\n * Durable milestones the child has persisted, ordered by `sequence`. Lets a\n * rehydrated parent (recovery / backbone reconcile) replay milestone-gated\n * work and milestone notifications without having observed the live stream.\n */\n milestones?: AgentToolMilestone[];\n};\n\nexport type AgentToolStoredChunk = {\n sequence: number;\n body: string;\n};\n\nexport type AgentToolChildAdapter<Input = unknown, Output = unknown> = {\n startAgentToolRun(\n input: Input,\n options: { runId: string; signal?: AbortSignal }\n ): Promise<AgentToolRunInspection<Output>>;\n cancelAgentToolRun(runId: string, reason?: unknown): Promise<void>;\n inspectAgentToolRun(\n runId: string\n ): Promise<AgentToolRunInspection<Output> | null>;\n getAgentToolChunks(\n runId: string,\n options?: { afterSequence?: number }\n ): Promise<AgentToolStoredChunk[]>;\n tailAgentToolRun?(\n runId: string,\n options?: { afterSequence?: number; signal?: AbortSignal }\n ): Promise<ReadableStream<AgentToolStoredChunk>>;\n};\n\nexport type AgentToolEvent =\n | {\n kind: \"started\";\n runId: string;\n agentType: string;\n inputPreview?: unknown;\n order: number;\n display?: AgentToolDisplayMetadata;\n }\n | {\n kind: \"chunk\";\n runId: string;\n body: string;\n }\n | {\n kind: \"finished\";\n runId: string;\n summary: string;\n }\n | {\n kind: \"error\";\n runId: string;\n error: string;\n }\n | {\n kind: \"aborted\";\n runId: string;\n reason?: string;\n }\n | {\n kind: \"interrupted\";\n runId: string;\n error: string;\n /** Machine-readable cause of the interrupt (#1630 follow-up). */\n reason?: AgentToolInterruptedReason;\n /**\n * Whether the child facet was still non-terminal when the parent stopped\n * waiting (before any teardown). Lets a UI distinguish a still-running\n * child from one the parent has torn down.\n */\n childStillRunning?: boolean;\n };\n\nexport type AgentToolEventMessage = {\n type: \"agent-tool-event\";\n parentToolCallId?: string;\n sequence: number;\n replay?: true;\n event: AgentToolEvent;\n};\n\nexport type AgentToolRunPart = { type: string };\n\nexport type AgentToolRunState<\n Part extends AgentToolRunPart = AgentToolRunPart\n> = {\n runId: string;\n agentType: string;\n parentToolCallId?: string;\n inputPreview?: unknown;\n order: number;\n display?: AgentToolDisplayMetadata;\n status: \"running\" | \"completed\" | \"error\" | \"aborted\" | \"interrupted\";\n /**\n * Message parts reconstructed from the child agent's streamed chunks.\n *\n * The default stays framework-neutral so importing `agents` does not require\n * an AI SDK peer. AI SDK consumers can use\n * `AgentToolRunState<UIMessage[\"parts\"][number]>` when they need its exact\n * discriminated union.\n */\n parts: Part[];\n summary?: string;\n error?: string;\n /**\n * Present only when `status` is `interrupted` — machine-readable cause and\n * whether the child is still running, mirrored from the wire event so a UI\n * can render the reason without parsing `error` (#1630 follow-up).\n */\n reason?: AgentToolInterruptedReason;\n childStillRunning?: boolean;\n /**\n * Latest progress snapshot, projected from the child's transient\n * `data-agent-progress` signals so a UI can render a bar / ETA / phase label\n * for a running (especially detached / background) run without drilling in.\n */\n progress?: AgentToolProgressSnapshot;\n /**\n * Durable milestones the run has reached, ordered by `sequence` (deduped\n * across replay/live races). Drives milestone chips / a phase timeline.\n */\n milestones?: AgentToolMilestone[];\n subAgent: { agent: string; name: string };\n};\n\nexport type AgentToolEventState<\n Part extends AgentToolRunPart = AgentToolRunPart\n> = {\n runsById: Record<string, AgentToolRunState<Part>>;\n runsByToolCallId: Record<string, AgentToolRunState<Part>[]>;\n unboundRuns: AgentToolRunState<Part>[];\n};\n"],"mappings":";;;;;;;;AAuFA,MAAa,2BAA2B;;;;;;;AAQxC,MAAa,4BAA4B"}
|
|
1
|
+
{"version":3,"file":"agent-tool-types.js","names":[],"sources":["../src/agent-tool-types.ts"],"sourcesContent":["import type { Agent, SubAgentClass } from \"./index\";\n\nexport type AgentToolRunStatus =\n | \"starting\"\n | \"running\"\n | \"completed\"\n | \"error\"\n | \"aborted\"\n | \"interrupted\";\n\nexport type AgentToolTerminalStatus = Extract<\n AgentToolRunStatus,\n \"completed\" | \"error\" | \"aborted\" | \"interrupted\"\n>;\n\n/**\n * Machine-readable cause of an `interrupted` seal (#1630 follow-up). Lets a\n * caller branch on WHY a run was abandoned without parsing the human-readable\n * `error` prose, which is not a stable contract.\n *\n * - `no-progress` — the child went silent for a full no-progress window while\n * the parent was tailing it (genuinely stalled / hung).\n * - `window-exceeded` — a finite `agentToolReattachMaxWindowMs` ceiling elapsed\n * while the child was still non-terminal. Only fires when an integrator opts\n * into a hard wall-clock cap (the default ceiling is `Infinity`).\n * - `not-tailable` — the child runtime cannot live-tail, so the parent could\n * not re-attach to its stream to follow it to terminal.\n * - `inspect-timeout` — inspecting the child timed out during parent recovery.\n * - `inspect-failed` — inspecting the child failed during parent recovery.\n * - `recovery-deadline` — the overall parent-recovery deadline elapsed before\n * this run could be reconciled.\n * - `budget-exceeded` — a detached run's absolute `maxBudgetMs` ceiling elapsed\n * before it reached a terminal. The parent gave up watching and tore the\n * child down. Like `window-exceeded` this is a soft seal: a child that\n * completes anyway can still repair the run and re-fire the completion hook.\n */\nexport type AgentToolInterruptedReason =\n | \"no-progress\"\n | \"window-exceeded\"\n | \"not-tailable\"\n | \"inspect-timeout\"\n | \"inspect-failed\"\n | \"recovery-deadline\"\n | \"budget-exceeded\";\n\n/**\n * Structured failure envelope an `agentTool()` returns when a sub-agent run\n * does not complete. Instead of an opaque error string the parent model would\n * parrot back to the user, the caller (or an orchestration harness) gets a\n * machine-readable signal:\n *\n * - `status` mirrors the underlying terminal status (`error` | `aborted` |\n * `interrupted`).\n * - `retryable` is `true` only for a transient interruption — the child was\n * reset or superseded by a deploy / parent recovery and never reached a\n * logical outcome, so re-dispatching the same run is the right move. A\n * genuine `error` or an intentional `aborted` is `false`.\n * - `error` stays human-readable for logs and UI.\n */\nexport type AgentToolFailure = {\n ok: false;\n status: Exclude<AgentToolTerminalStatus, \"completed\">;\n error: string;\n retryable: boolean;\n /** Present only when `status` is `interrupted` — machine-readable cause. */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. `true` when the child facet was\n * still non-terminal (running / advancing) at the moment the parent stopped\n * waiting; `false` once the parent has torn the child down so it is no longer\n * doing work. Lets a caller decide between re-dispatching vs. reconnecting.\n */\n childStillRunning?: boolean;\n};\n\nexport type AgentToolDisplayMetadata = {\n name?: string;\n icon?: string;\n} & Record<string, unknown>;\n\n/**\n * Reserved chunk type a sub-agent emits via `reportProgress` while it runs.\n * Rides the child's own UI-message stream as a **transient** data part, so it\n * re-broadcasts to the parent's clients (via the parent's tail) and surfaces in\n * `useAgentToolEvents` without persisting into the child's stored message parts.\n * See `design/rfc-detached-agent-tools.md` §\"Progress and milestone signaling\".\n */\nexport const AGENT_TOOL_PROGRESS_PART = \"data-agent-progress\";\n\n/**\n * Reserved chunk type a sub-agent emits via `reportProgress({ milestone })`.\n * Unlike the ephemeral progress part this rides the child's stream as a\n * **persisted** data part, so it survives eviction, replays on drill-in, and\n * re-resolves milestone waiters. See `design/rfc-detached-agent-tools.md`.\n */\nexport const AGENT_TOOL_MILESTONE_PART = \"data-agent-milestone\";\n\n/**\n * Whether a chunk body is a progress or milestone frame. These are broadcast\n * but never written to the child's chunk store, so they have no stored-chunk\n * position and must not take part in stored-position numbering or dedupe.\n */\nexport function isAgentToolLifecycleChunk(body: string): boolean {\n if (\n !body.includes(AGENT_TOOL_PROGRESS_PART) &&\n !body.includes(AGENT_TOOL_MILESTONE_PART)\n ) {\n return false;\n }\n try {\n const type = (JSON.parse(body) as { type?: unknown } | null)?.type;\n return (\n type === AGENT_TOOL_PROGRESS_PART || type === AGENT_TOOL_MILESTONE_PART\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Whether a forwarded chunk has no stored-chunk position: a progress or\n * milestone frame, or a chunk too large to store. Such chunks carry the next\n * stored position without consuming it.\n */\nexport function isPositionlessAgentToolChunk(\n chunk: AgentToolStoredChunk\n): boolean {\n return (\n chunk.unstoredId !== undefined || isAgentToolLifecycleChunk(chunk.body)\n );\n}\n\n/**\n * Ephemeral progress signal a running sub-agent emits with `reportProgress`. The\n * well-known fields drive generic UI (a bar + status line) with no per-app\n * convention; `data` is an app-specific escape hatch that is **live-only** by\n * default (not persisted) unless `reportProgress(p, { persist: true })`. Naming a\n * `milestone` promotes the signal to the **durable** tier: it persists as one row\n * per milestone, replays, and (with `data`) is retained.\n */\nexport type AgentToolProgress<T = unknown> = {\n /** 0..1 — drives a progress bar. */\n fraction?: number;\n /** Human-readable status line, e.g. \"Ingested 40k/80k rows\". */\n message?: string;\n /** Coarse stage label, e.g. \"scaffolding\" | \"deploying\". */\n phase?: string;\n /**\n * Present ⇒ a **durable** milestone: persisted, replayable, and surfaced as a\n * distinct row in `AgentToolRunState.milestones` / `inspectAgentToolRun`. Use\n * for named phase boundaries (\"schema-ready\", \"preview-ready\", \"deployed\").\n */\n milestone?: string;\n /** App-specific payload; live-only for progress, persisted for milestones. */\n data?: T;\n};\n\n/**\n * A durable milestone a sub-agent reached, projected onto `AgentToolRunState`\n * and `inspectAgentToolRun`. `sequence` is monotonic per run so replay/live\n * races dedupe on `(runId, sequence)`.\n */\nexport type AgentToolMilestone = {\n name: string;\n /** Monotonic per-run ordinal; dedupe key for replay vs live races. */\n sequence: number;\n /** Epoch ms the milestone was reached. */\n at: number;\n /** App-specific payload carried with the milestone (persisted). */\n data?: unknown;\n};\n\n/**\n * Latest progress snapshot persisted on the child run row and surfaced through\n * `inspectAgentToolRun` + `AgentToolRunState`. Only the safe-to-inspect fields\n * are retained by default; `at` is the emit timestamp (drives the resetting\n * no-progress budget).\n */\nexport type AgentToolProgressSnapshot = {\n fraction?: number;\n message?: string;\n phase?: string;\n /**\n * Set when this signal was a durable milestone (`reportProgress({ milestone })`).\n * Lets an `onProgress` consumer branch on milestone vs. ephemeral progress.\n */\n milestone?: string;\n /** Epoch ms of the latest signal. */\n at: number;\n /** Present only when the emitter opted into persisting `data`. */\n data?: unknown;\n};\n\nexport type AgentToolRunInfo = {\n runId: string;\n parentToolCallId?: string;\n agentType: string;\n inputPreview?: unknown;\n status: AgentToolRunStatus;\n display?: AgentToolDisplayMetadata;\n /**\n * Caller-controlled `metadata.source` for chat-agent `detached.notify`\n * completions. Present only for detached notify runs that supplied one.\n */\n notifySource?: string;\n displayOrder: number;\n startedAt: number;\n completedAt?: number;\n};\n\nexport type AgentToolLifecycleResult = {\n status: AgentToolTerminalStatus;\n summary?: string;\n error?: string;\n /** Present only when `status` is `interrupted` — machine-readable cause. */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. Whether the child facet was\n * still non-terminal when the parent stopped waiting (before any teardown).\n */\n childStillRunning?: boolean;\n};\n\n/**\n * Configuration for a detached (\"background\") agent-tool run. See\n * `design/rfc-detached-agent-tools.md`.\n *\n * Callbacks are referenced by **method name** on the dispatching agent (the same\n * durable, eviction-surviving pattern as `Agent.schedule`) — never closures,\n * which cannot be rehydrated after the Durable Object is evicted.\n *\n * `Self` is threaded from `runAgentTool(cls, options)` so the method names are\n * type-checked against the calling agent's own methods.\n */\nexport type DetachedAgentToolConfig<Self = Record<string, unknown>> = {\n /**\n * Method invoked once per terminal delivery. Branch on `result.status`:\n * `\"completed\" | \"error\" | \"aborted\" | \"interrupted\"`. A budget give-up\n * arrives as `status: \"interrupted\"` with `reason: \"budget-exceeded\"`; because\n * `interrupted` is soft, a child that later completes can fire the hook again\n * with `\"completed\"`, so a give-up never hides a late real result. Make the\n * handler idempotent.\n */\n onFinish?: Extract<keyof Self, string>;\n /**\n * Absolute safety ceiling — a backstop against a child that runs forever. On\n * expiry the parent gives up watching (delivers `onFinish` with\n * `interrupted` / `budget-exceeded`) and tears the child down. Defaults to the\n * parent-level `detachedMaxBudgetMs`.\n */\n maxBudgetMs?: number;\n /**\n * Per-run override of the resetting no-progress window (ms). Once the child\n * emits its first `reportProgress`, the parent gives up if it then goes silent\n * for this long (resets on each signal). Defaults to the parent-level\n * `detachedNoProgressBudgetMs` (1h). `0`/`Infinity` disables it.\n */\n noProgressBudgetMs?: number;\n /**\n * Chat-agent convenience (`@cloudflare/think` / `AIChatAgent`): when the run\n * finishes, inject a message into the chat so the model can react to the\n * result, instead of you wiring `onFinish` by hand. Sugar that auto-targets\n * the agent's `_cfDetachedNotifyFinish` hook; ignored on a base `Agent` that\n * does not implement it, and ignored when `onFinish` is also set (an explicit\n * `onFinish` wins). Pass `{ source }` to fit the injected message into your\n * app's existing metadata taxonomy. Override `formatDetachedCompletion()` to\n * customize the injected text.\n */\n notify?: boolean | { source?: string };\n /**\n * Chat-agent convenience: milestone names that, when the detached run reaches\n * them, surface an idempotent synthetic message in the chat BEFORE the run\n * finishes. Each `(runId, name)` fires at most once (idempotency-keyed),\n * whether observed live or reconciled after eviction. Override the wording via\n * `formatDetachedMilestone()`. Requires a chat host (`@cloudflare/think`); a\n * no-op on a base `Agent`.\n *\n * Two delivery modes (the string-array shorthand defaults to `\"narrate\"`):\n * - `\"narrate\"` (default) — inject a synthetic **assistant** message directly\n * (no inference): a cheap, honest status line (\"Found 2 sources…\") that does\n * not trigger a model turn. Best for pure progress narration.\n * - `\"react\"` — inject a **user-role** turn so the model responds to the\n * milestone (steer, start dependent work, narrate with context). Costs a\n * model turn. Opt in for milestones the agent should *act on*.\n */\n onMilestones?: string[] | { names: string[]; mode?: \"react\" | \"narrate\" };\n};\n\nexport type RunAgentToolOptions<\n Input = unknown,\n Self = Record<string, unknown>\n> = {\n input: Input;\n runId?: string;\n parentToolCallId?: string;\n displayOrder?: number;\n signal?: AbortSignal;\n inputPreview?: unknown;\n display?: AgentToolDisplayMetadata;\n /**\n * Run the sub-agent **detached**: dispatch it, let the current turn continue,\n * and (optionally) get a durable callback when it finishes. `true` is\n * fire-and-forget (observe via `agent-tool-event` frames + the global\n * `onAgentToolFinish` hook); an object adds the targeted, eviction-surviving\n * `onFinish` callback. A detached run does NOT inherit `options.signal` — it\n * must outlive the spawning turn; cancel it explicitly via `cancelAgentTool`.\n */\n detached?: boolean | DetachedAgentToolConfig<Self>;\n /**\n * Which child events reach the parent's clients. `\"full\"` (default) forwards\n * every streamed chunk. `\"terminal\"` forwards only lifecycle events: started,\n * progress and milestone frames, and the terminal event. The child still\n * persists its whole stream, and the parent still tails it for completion,\n * cancellation, progress and recovery. Use it for a headless parent with no\n * client watching the child. Not supported with `detached`.\n */\n eventDelivery?: AgentToolEventDelivery;\n};\n\nexport type AgentToolEventDelivery = \"full\" | \"terminal\";\n\n/**\n * Result of dispatching a detached run. Returns immediately after dispatch\n * rather than after completion.\n */\nexport type DetachedRunAgentToolResult = {\n runId: string;\n agentType: string;\n /**\n * `\"running\"` on a successful dispatch; `\"error\"` if dispatch itself failed\n * (e.g. the `maxConcurrentAgentTools` cap was exceeded — rejected\n * synchronously, no child started, no callback wired).\n */\n status: \"running\" | \"error\";\n error?: string;\n};\n\nexport type RunAgentToolResult<Output = unknown> = {\n runId: string;\n agentType: string;\n status: AgentToolTerminalStatus;\n output?: Output;\n summary?: string;\n error?: string;\n /**\n * Present only when `status` is `interrupted` — a machine-readable cause so\n * callers don't pattern-match the `error` prose (#1630 follow-up).\n */\n reason?: AgentToolInterruptedReason;\n /**\n * Present only when `status` is `interrupted`. `true` when the child facet was\n * still non-terminal (running / advancing) at the moment the parent stopped\n * waiting and before any teardown; `false` once the parent has torn the child\n * down so it is no longer doing work.\n */\n childStillRunning?: boolean;\n};\n\nexport type ChatCapableAgentClass<T extends Agent = Agent> = SubAgentClass<T>;\n\nexport type AgentToolRunInspection<Output = unknown> = {\n runId: string;\n status: Exclude<AgentToolRunStatus, \"interrupted\">;\n requestId?: string;\n streamId?: string;\n output?: Output;\n summary?: string;\n error?: string;\n startedAt: number;\n completedAt?: number;\n /**\n * Latest progress snapshot the child has persisted, so a rehydrated parent\n * (recovery / backbone reconcile) can reconstruct \"where is this run\" and\n * reset the resetting no-progress budget without having tailed the live\n * stream. Absent until the child emits its first `reportProgress`.\n */\n progress?: AgentToolProgressSnapshot;\n /**\n * Durable milestones the child has persisted, ordered by `sequence`. Lets a\n * rehydrated parent (recovery / backbone reconcile) replay milestone-gated\n * work and milestone notifications without having observed the live stream.\n */\n milestones?: AgentToolMilestone[];\n};\n\nexport type AgentToolStoredChunk = {\n sequence: number;\n body: string;\n /**\n * Set when the child broadcast this chunk but could not store it (it exceeds\n * the stored-chunk size limit). The chunk is never replayed, so it carries\n * the next stored position without consuming it and dedupes on this id.\n */\n unstoredId?: string;\n};\n\nexport type AgentToolChildAdapter<Input = unknown, Output = unknown> = {\n startAgentToolRun(\n input: Input,\n options: {\n runId: string;\n signal?: AbortSignal;\n /**\n * `\"terminal\"` means no client is watching this run's chunks, so the\n * child can skip broadcasting them.\n */\n eventDelivery?: AgentToolEventDelivery;\n }\n ): Promise<AgentToolRunInspection<Output>>;\n cancelAgentToolRun(runId: string, reason?: unknown): Promise<void>;\n inspectAgentToolRun(\n runId: string,\n options?: {\n /**\n * `false` reports the stored row as-is instead of first reconciling\n * (and possibly sealing) a stale run. Defaults to `true`.\n */\n reconcile?: boolean;\n }\n ): Promise<AgentToolRunInspection<Output> | null>;\n getAgentToolChunks(\n runId: string,\n options?: { afterSequence?: number }\n ): Promise<AgentToolStoredChunk[]>;\n tailAgentToolRun?(\n runId: string,\n options?: { afterSequence?: number; signal?: AbortSignal }\n ): Promise<ReadableStream<AgentToolStoredChunk>>;\n};\n\nexport type AgentToolEvent =\n | {\n kind: \"started\";\n runId: string;\n agentType: string;\n inputPreview?: unknown;\n order: number;\n display?: AgentToolDisplayMetadata;\n }\n | {\n kind: \"chunk\";\n runId: string;\n body: string;\n /** See {@link AgentToolStoredChunk.unstoredId}. */\n unstoredId?: string;\n }\n | {\n kind: \"finished\";\n runId: string;\n summary: string;\n }\n | {\n kind: \"error\";\n runId: string;\n error: string;\n }\n | {\n kind: \"aborted\";\n runId: string;\n reason?: string;\n }\n | {\n kind: \"interrupted\";\n runId: string;\n error: string;\n /** Machine-readable cause of the interrupt (#1630 follow-up). */\n reason?: AgentToolInterruptedReason;\n /**\n * Whether the child facet was still non-terminal when the parent stopped\n * waiting (before any teardown). Lets a UI distinguish a still-running\n * child from one the parent has torn down.\n */\n childStillRunning?: boolean;\n };\n\nexport type AgentToolEventMessage = {\n type: \"agent-tool-event\";\n parentToolCallId?: string;\n sequence: number;\n replay?: true;\n event: AgentToolEvent;\n};\n\nexport type AgentToolRunPart = { type: string };\n\nexport type AgentToolRunState<\n Part extends AgentToolRunPart = AgentToolRunPart\n> = {\n runId: string;\n agentType: string;\n parentToolCallId?: string;\n inputPreview?: unknown;\n order: number;\n display?: AgentToolDisplayMetadata;\n status: \"running\" | \"completed\" | \"error\" | \"aborted\" | \"interrupted\";\n /**\n * Message parts reconstructed from the child agent's streamed chunks.\n *\n * The default stays framework-neutral so importing `agents` does not require\n * an AI SDK peer. AI SDK consumers can use\n * `AgentToolRunState<UIMessage[\"parts\"][number]>` when they need its exact\n * discriminated union.\n */\n parts: Part[];\n summary?: string;\n error?: string;\n /**\n * Present only when `status` is `interrupted` — machine-readable cause and\n * whether the child is still running, mirrored from the wire event so a UI\n * can render the reason without parsing `error` (#1630 follow-up).\n */\n reason?: AgentToolInterruptedReason;\n childStillRunning?: boolean;\n /**\n * Latest progress snapshot, projected from the child's transient\n * `data-agent-progress` signals so a UI can render a bar / ETA / phase label\n * for a running (especially detached / background) run without drilling in.\n */\n progress?: AgentToolProgressSnapshot;\n /**\n * Durable milestones the run has reached, ordered by `sequence` (deduped\n * across replay/live races). Drives milestone chips / a phase timeline.\n */\n milestones?: AgentToolMilestone[];\n subAgent: { agent: string; name: string };\n};\n\nexport type AgentToolEventState<\n Part extends AgentToolRunPart = AgentToolRunPart\n> = {\n runsById: Record<string, AgentToolRunState<Part>>;\n runsByToolCallId: Record<string, AgentToolRunState<Part>[]>;\n unboundRuns: AgentToolRunState<Part>[];\n};\n"],"mappings":";;;;;;;;AAuFA,MAAa,2BAA2B;;;;;;;AAQxC,MAAa,4BAA4B;;;;;;AAOzC,SAAgB,0BAA0B,MAAuB;CAC/D,IACE,CAAC,KAAK,SAAA,qBAAiC,KACvC,CAAC,KAAK,SAAA,sBAAkC,GAExC,OAAO;CAET,IAAI;EACF,MAAM,OAAQ,KAAK,MAAM,IAAI,CAAC,EAAgC;EAC9D,OACE,SAAA,yBAAqC,SAAA;CAEzC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;AAOA,SAAgB,6BACd,OACS;CACT,OACE,MAAM,eAAe,KAAA,KAAa,0BAA0B,MAAM,IAAI;AAE1E"}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART } from "./agent-tool-types.js";
|
|
2
|
-
import { t as applyChunkToParts } from "./message-builder-
|
|
1
|
+
import { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART, isAgentToolLifecycleChunk } from "./agent-tool-types.js";
|
|
2
|
+
import { t as applyChunkToParts } from "./message-builder-DAl9AhHH.js";
|
|
3
|
+
//#region src/chat/chunk-size.ts
|
|
4
|
+
const textEncoder = new TextEncoder();
|
|
5
|
+
/** Maximum serialized chunk body size before skipping storage (bytes). */
|
|
6
|
+
const CHUNK_MAX_BYTES = 18e5;
|
|
7
|
+
/** Byte size of a chunk body in its stored (JSON-escaped) encoding. */
|
|
8
|
+
function storedChunkBytes(body) {
|
|
9
|
+
return textEncoder.encode(JSON.stringify(body)).byteLength;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Whether `ResumableStream.storeChunk` skips storing this body: it is still
|
|
13
|
+
* broadcast live, but absent from replay.
|
|
14
|
+
*/
|
|
15
|
+
function isChunkTooLargeToStore(body) {
|
|
16
|
+
return storedChunkBytes(body) > CHUNK_MAX_BYTES;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
3
19
|
//#region src/chat/agent-tools.ts
|
|
4
20
|
/**
|
|
5
21
|
* Pull a reserved `data-agent-progress` chunk (emitted by a running sub-agent's
|
|
@@ -91,6 +107,7 @@ var AgentToolProgressEmitter = class {
|
|
|
91
107
|
};
|
|
92
108
|
this.hooks.broadcast(requestId, JSON.stringify({
|
|
93
109
|
type: AGENT_TOOL_PROGRESS_PART,
|
|
110
|
+
id: crypto.randomUUID(),
|
|
94
111
|
transient: true,
|
|
95
112
|
data: wire
|
|
96
113
|
}));
|
|
@@ -250,6 +267,42 @@ function createAgentToolEventState() {
|
|
|
250
267
|
unboundRuns: []
|
|
251
268
|
};
|
|
252
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Identity of an agent-tool event for replay-vs-live dedupe. Ordinary chunks
|
|
272
|
+
* key on the broadcast `sequence`, which is their stored-chunk position on
|
|
273
|
+
* both the live and replay paths. Lifecycle events key on their content: a
|
|
274
|
+
* reattached run can be interrupted again with a different reason, and the
|
|
275
|
+
* reducer overwrites on lifecycle events, so re-applying one is harmless.
|
|
276
|
+
* Milestones key on their own persisted sequence. Progress frames and chunks
|
|
277
|
+
* too large to store reuse the next stored chunk's sequence without consuming
|
|
278
|
+
* it and are never replayed, so they key on their own emitter-assigned id.
|
|
279
|
+
*/
|
|
280
|
+
function agentToolEventDedupeKey(message) {
|
|
281
|
+
const { event } = message;
|
|
282
|
+
let identity;
|
|
283
|
+
if (event.kind !== "chunk") identity = `event:${JSON.stringify(event)}`;
|
|
284
|
+
else if (event.unstoredId !== void 0) identity = `unstored:${event.unstoredId}`;
|
|
285
|
+
else {
|
|
286
|
+
let milestone;
|
|
287
|
+
let progressId;
|
|
288
|
+
let progress = false;
|
|
289
|
+
if (event.body.includes("data-agent-milestone") || event.body.includes("data-agent-progress")) try {
|
|
290
|
+
const parsed = JSON.parse(event.body);
|
|
291
|
+
milestone = readAgentToolMilestoneChunk(parsed);
|
|
292
|
+
progress = readAgentToolProgressChunk(parsed) !== void 0;
|
|
293
|
+
const id = parsed.id;
|
|
294
|
+
if (typeof id === "string") progressId = id;
|
|
295
|
+
} catch {
|
|
296
|
+
milestone = void 0;
|
|
297
|
+
}
|
|
298
|
+
identity = milestone ? `milestone:${milestone.sequence}` : progress ? progressId !== void 0 ? `progress:${progressId}` : `progress:${message.sequence}:${event.body}` : `seq:${message.sequence}`;
|
|
299
|
+
}
|
|
300
|
+
return [
|
|
301
|
+
message.parentToolCallId ?? "",
|
|
302
|
+
event.runId,
|
|
303
|
+
identity
|
|
304
|
+
].join("\0");
|
|
305
|
+
}
|
|
253
306
|
function applyAgentToolEvent(state, message) {
|
|
254
307
|
if (message.type !== "agent-tool-event") return state;
|
|
255
308
|
const runId = message.event.runId;
|
|
@@ -276,29 +329,39 @@ function applyAgentToolEvent(state, message) {
|
|
|
276
329
|
* error capture never depends on tailer timing. A frame belongs to a run iff it
|
|
277
330
|
* carries that run's turn request id, so concurrent runs can't cross-contaminate
|
|
278
331
|
* each other's progress or error state.
|
|
332
|
+
*
|
|
333
|
+
* Returns the run id when the frame is one of that run's content chunks, so a
|
|
334
|
+
* host can skip broadcasting chunks no client is watching.
|
|
279
335
|
*/
|
|
280
336
|
function interceptAgentToolBroadcast(msg, hooks) {
|
|
281
|
-
if ((hooks.forwarders.size > 0 || hooks.liveSequences.size > 0) && typeof msg === "string") try {
|
|
337
|
+
if ((hooks.forwarders.size > 0 || hooks.liveSequences.size > 0 || (hooks.terminalOnlyRuns?.size ?? 0) > 0) && typeof msg === "string") try {
|
|
282
338
|
const parsed = JSON.parse(msg);
|
|
283
339
|
if (parsed.type === hooks.responseType && typeof parsed.id === "string") {
|
|
284
340
|
const runId = hooks.runForRequest(parsed.id);
|
|
285
341
|
if (runId !== null) {
|
|
286
|
-
if (parsed.error === true && typeof parsed.body === "string")
|
|
287
|
-
|
|
342
|
+
if (parsed.error === true && typeof parsed.body === "string") {
|
|
343
|
+
hooks.lastErrors.set(runId, parsed.body);
|
|
344
|
+
hooks.onError?.(runId, parsed.body);
|
|
345
|
+
} else if (typeof parsed.body === "string" && parsed.body.length > 0) {
|
|
288
346
|
const sequence = hooks.liveSequences.get(runId) ?? 0;
|
|
289
|
-
|
|
347
|
+
const lifecycle = isAgentToolLifecycleChunk(parsed.body);
|
|
348
|
+
const unstored = !lifecycle && isChunkTooLargeToStore(parsed.body);
|
|
349
|
+
hooks.liveSequences.set(runId, lifecycle || unstored ? sequence : sequence + 1);
|
|
290
350
|
const chunk = {
|
|
291
351
|
sequence,
|
|
292
|
-
body: parsed.body
|
|
352
|
+
body: parsed.body,
|
|
353
|
+
...unstored ? { unstoredId: crypto.randomUUID() } : {}
|
|
293
354
|
};
|
|
294
355
|
const forwarders = hooks.forwarders.get(runId);
|
|
295
356
|
if (forwarders) for (const forward of forwarders) forward(chunk);
|
|
357
|
+
return runId;
|
|
296
358
|
}
|
|
297
359
|
}
|
|
298
360
|
}
|
|
299
361
|
} catch {}
|
|
362
|
+
return null;
|
|
300
363
|
}
|
|
301
364
|
//#endregion
|
|
302
|
-
export { interceptAgentToolBroadcast as i,
|
|
365
|
+
export { interceptAgentToolBroadcast as a, createAgentToolEventState as i, agentToolEventDedupeKey as n, CHUNK_MAX_BYTES as o, applyAgentToolEvent as r, storedChunkBytes as s, AgentToolProgressEmitter as t };
|
|
303
366
|
|
|
304
|
-
//# sourceMappingURL=agent-tools-
|
|
367
|
+
//# sourceMappingURL=agent-tools-CdJC-8Dc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-tools-CdJC-8Dc.js","names":[],"sources":["../src/chat/chunk-size.ts","../src/chat/agent-tools.ts"],"sourcesContent":["const textEncoder = new TextEncoder();\n\n/** Maximum serialized chunk body size before skipping storage (bytes). */\nexport const CHUNK_MAX_BYTES = 1_800_000;\n\n/** Byte size of a chunk body in its stored (JSON-escaped) encoding. */\nexport function storedChunkBytes(body: string): number {\n return textEncoder.encode(JSON.stringify(body)).byteLength;\n}\n\n/**\n * Whether `ResumableStream.storeChunk` skips storing this body: it is still\n * broadcast live, but absent from replay.\n */\nexport function isChunkTooLargeToStore(body: string): boolean {\n return storedChunkBytes(body) > CHUNK_MAX_BYTES;\n}\n","import { applyChunkToParts, type MessagePart } from \"./message-builder\";\nimport { isChunkTooLargeToStore } from \"./chunk-size\";\nimport {\n AGENT_TOOL_MILESTONE_PART,\n AGENT_TOOL_PROGRESS_PART,\n isAgentToolLifecycleChunk,\n isPositionlessAgentToolChunk\n} from \"../agent-tool-types\";\nimport type {\n AgentToolEventMessage,\n AgentToolEventState,\n AgentToolMilestone,\n AgentToolProgress,\n AgentToolProgressSnapshot,\n AgentToolRunPart,\n AgentToolRunState,\n AgentToolStoredChunk\n} from \"../agent-tool-types\";\n\n/**\n * Pull a reserved `data-agent-progress` chunk (emitted by a running sub-agent's\n * `reportProgress`) into a latest-wins snapshot. Returns `undefined` for any\n * other chunk so the caller keeps the prior snapshot.\n */\nfunction readAgentToolProgressChunk(\n chunk: unknown\n): AgentToolProgressSnapshot | undefined {\n if (\n typeof chunk !== \"object\" ||\n chunk === null ||\n (chunk as { type?: unknown }).type !== AGENT_TOOL_PROGRESS_PART\n ) {\n return undefined;\n }\n const data = (chunk as { data?: AgentToolProgress }).data ?? {};\n return {\n ...(typeof data.fraction === \"number\" ? { fraction: data.fraction } : {}),\n ...(typeof data.message === \"string\" ? { message: data.message } : {}),\n ...(typeof data.phase === \"string\" ? { phase: data.phase } : {}),\n ...(data.data !== undefined ? { data: data.data } : {}),\n at: Date.now()\n };\n}\n\n/**\n * Pull a reserved `data-agent-milestone` chunk into a durable milestone record,\n * or `undefined` for any other chunk. Milestones carry their own monotonic\n * `sequence` so the caller can dedupe replay-vs-live races.\n */\nfunction readAgentToolMilestoneChunk(\n chunk: unknown\n): AgentToolMilestone | undefined {\n if (\n typeof chunk !== \"object\" ||\n chunk === null ||\n (chunk as { type?: unknown }).type !== AGENT_TOOL_MILESTONE_PART\n ) {\n return undefined;\n }\n const data = (chunk as { data?: Partial<AgentToolMilestone> }).data ?? {};\n if (typeof data.name !== \"string\") return undefined;\n return {\n name: data.name,\n sequence: typeof data.sequence === \"number\" ? data.sequence : 0,\n at: typeof data.at === \"number\" ? data.at : Date.now(),\n ...(data.data !== undefined ? { data: data.data } : {})\n };\n}\n\n/**\n * Merge a milestone into a run's ordered milestone list, deduping on `sequence`\n * (idempotent across replay + live races) and keeping the list sorted.\n */\nfunction mergeMilestone(\n existing: AgentToolMilestone[] | undefined,\n milestone: AgentToolMilestone\n): AgentToolMilestone[] {\n // Returns `existing` unchanged (same reference) when the milestone is a dup,\n // so callers can identity-compare to detect a genuinely new milestone.\n if (existing?.some((m) => m.sequence === milestone.sequence)) return existing;\n const list = existing ? [...existing, milestone] : [milestone];\n list.sort((a, b) => a.sequence - b.sequence);\n return list;\n}\n\n/** Latest-wins coalescing window for `reportProgress` emits (per run). */\nconst AGENT_TOOL_PROGRESS_COALESCE_MS = 200;\n\nexport type AgentToolProgressEmitResult = \"emitted\" | \"coalesced\" | \"inactive\";\n\n/**\n * Host-injected seams the shared progress emitter needs. Keeps the per-host\n * `reportProgress` thin: Think / AIChatAgent supply how to resolve the active\n * agent-tool run, how to broadcast a chat-response frame, and how to persist the\n * latest snapshot on their own child-run table.\n */\nexport type AgentToolProgressEmitHooks = {\n /** The agent-tool run currently executing in this turn, or null. */\n resolveActiveRun: () => { runId: string; requestId: string } | null;\n /** Broadcast a chat-response frame (id = requestId) to clients/tailers. */\n broadcast: (requestId: string, chunkBody: string) => void;\n /** Persist the latest snapshot + signal timestamp on the child run row. */\n persistSnapshot: (\n runId: string,\n snapshot: {\n fraction?: number;\n message?: string;\n phase?: string;\n data?: unknown;\n },\n at: number\n ) => void;\n /**\n * Persist a durable milestone row, bump the run's signal timestamp, and return\n * the assigned monotonic per-run `sequence` (used to dedupe replay/live races).\n */\n persistMilestone: (\n runId: string,\n name: string,\n data: unknown,\n at: number\n ) => number;\n};\n\n/**\n * Shared implementation of `reportProgress` for chat hosts. Builds the reserved\n * transient `data-agent-progress` wire frame, coalesces bursts to a bounded\n * cadence (latest-wins; a `fraction >= 1` \"done\" frame always flushes), and\n * persists a latest snapshot. `data` rides the live frame but is only persisted\n * when the caller opts in via `{ persist: true }`.\n */\nexport class AgentToolProgressEmitter {\n private readonly _lastEmitAt = new Map<string, number>();\n\n constructor(private readonly hooks: AgentToolProgressEmitHooks) {}\n\n report(\n progress: AgentToolProgress,\n options?: { persist?: boolean }\n ): AgentToolProgressEmitResult {\n const active = this.hooks.resolveActiveRun();\n if (!active) return \"inactive\";\n const { runId, requestId } = active;\n const now = Date.now();\n\n // Durable milestone: never coalesced (each named boundary must land,\n // persist, and replay). Rides the stream as a PERSISTED data part.\n if (typeof progress.milestone === \"string\" && progress.milestone) {\n this._lastEmitAt.set(runId, now);\n const sequence = this.hooks.persistMilestone(\n runId,\n progress.milestone,\n progress.data,\n now\n );\n this.hooks.broadcast(\n requestId,\n JSON.stringify({\n type: AGENT_TOOL_MILESTONE_PART,\n data: {\n name: progress.milestone,\n sequence,\n at: now,\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\"\n ? { phase: progress.phase }\n : {}),\n ...(progress.data !== undefined ? { data: progress.data } : {})\n }\n })\n );\n return \"emitted\";\n }\n\n const last = this._lastEmitAt.get(runId) ?? 0;\n const isDone =\n typeof progress.fraction === \"number\" && progress.fraction >= 1;\n if (now - last < AGENT_TOOL_PROGRESS_COALESCE_MS && !isDone) {\n return \"coalesced\";\n }\n this._lastEmitAt.set(runId, now);\n\n const wire: AgentToolProgress = {\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\" ? { phase: progress.phase } : {}),\n ...(progress.data !== undefined ? { data: progress.data } : {})\n };\n // Identical payloads must not dedupe against each other on a client that\n // keeps seen keys for its connection's lifetime, including across a child\n // restart, so the id is unique rather than a per-instance counter.\n this.hooks.broadcast(\n requestId,\n JSON.stringify({\n type: AGENT_TOOL_PROGRESS_PART,\n id: crypto.randomUUID(),\n transient: true,\n data: wire\n })\n );\n this.hooks.persistSnapshot(\n runId,\n {\n ...(typeof progress.fraction === \"number\"\n ? { fraction: progress.fraction }\n : {}),\n ...(typeof progress.message === \"string\"\n ? { message: progress.message }\n : {}),\n ...(typeof progress.phase === \"string\"\n ? { phase: progress.phase }\n : {}),\n ...(options?.persist && progress.data !== undefined\n ? { data: progress.data }\n : {})\n },\n now\n );\n return \"emitted\";\n }\n\n /** Drop coalescing state for a settled run (called on terminal). */\n forget(runId: string): void {\n this._lastEmitAt.delete(runId);\n }\n}\n\nfunction sortRuns<Part extends AgentToolRunPart>(\n runs: AgentToolRunState<Part>[]\n): AgentToolRunState<Part>[] {\n return [...runs].sort((a, b) => {\n if (a.order !== b.order) return a.order - b.order;\n return a.runId.localeCompare(b.runId);\n });\n}\n\nfunction rebuildIndexes<Part extends AgentToolRunPart>(\n runsById: Record<string, AgentToolRunState<Part>>\n): Pick<AgentToolEventState<Part>, \"runsByToolCallId\" | \"unboundRuns\"> {\n const grouped: Record<string, AgentToolRunState<Part>[]> = {};\n const unboundRuns: AgentToolRunState<Part>[] = [];\n for (const run of Object.values(runsById)) {\n if (run.parentToolCallId) {\n grouped[run.parentToolCallId] = grouped[run.parentToolCallId] ?? [];\n grouped[run.parentToolCallId].push(run);\n } else {\n unboundRuns.push(run);\n }\n }\n for (const [toolCallId, runs] of Object.entries(grouped)) {\n grouped[toolCallId] = sortRuns(runs);\n }\n return { runsByToolCallId: grouped, unboundRuns: sortRuns(unboundRuns) };\n}\n\nfunction emptyRun<Part extends AgentToolRunPart>(\n message: AgentToolEventMessage\n): AgentToolRunState<Part> | undefined {\n const { event } = message;\n if (event.kind === \"started\") {\n return {\n runId: event.runId,\n agentType: event.agentType,\n parentToolCallId: message.parentToolCallId,\n inputPreview: event.inputPreview,\n order: event.order,\n display: event.display,\n status: \"running\",\n parts: [],\n subAgent: { agent: event.agentType, name: event.runId }\n };\n }\n return undefined;\n}\n\nfunction applyToRun<Part extends AgentToolRunPart>(\n prev: AgentToolRunState<Part> | undefined,\n message: AgentToolEventMessage\n): AgentToolRunState<Part> | undefined {\n const seeded = prev ?? emptyRun(message);\n const { event } = message;\n\n switch (event.kind) {\n case \"started\":\n if (\n seeded?.status === \"completed\" ||\n seeded?.status === \"error\" ||\n seeded?.status === \"aborted\" ||\n seeded?.status === \"interrupted\"\n ) {\n return seeded;\n }\n return {\n ...seeded,\n runId: event.runId,\n agentType: event.agentType,\n parentToolCallId: message.parentToolCallId,\n inputPreview: event.inputPreview,\n order: event.order,\n display: event.display,\n status: \"running\",\n parts: seeded?.parts ?? [],\n subAgent: { agent: event.agentType, name: event.runId }\n };\n case \"chunk\": {\n if (!seeded) return undefined;\n // `applyChunkToParts` mutates part objects in place (e.g.\n // `lastTextPart.text += delta`). A shallow array copy (`[...seeded.parts]`)\n // keeps the *element* references shared with the previous state, so those\n // in-place mutations leak back into `prev`. React double-invokes setState\n // updaters in StrictMode / dev hydration, replaying each chunk against the\n // same (already-mutated) `prev` and doubling the text (#1835). Clone each\n // part so the reducer stays pure — every mutation here is to a top-level\n // field, so a per-part shallow copy is sufficient.\n const parts = seeded.parts.map((part) => ({ ...part }) as Part);\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.body);\n applyChunkToParts(\n parts as MessagePart[],\n parsed as Parameters<typeof applyChunkToParts>[1]\n );\n } catch {\n return seeded;\n }\n // Project a reserved `data-agent-progress` part onto the run's latest\n // progress snapshot so a tray can render a bar/phase without drilling in.\n // The part is transient (not persisted into `parts`), so it is read here\n // off the raw chunk rather than from the reduced parts array.\n const progress = readAgentToolProgressChunk(parsed);\n if (progress) {\n return { ...seeded, parts, progress };\n }\n // Durable milestones land as a persisted `data-agent-milestone` part:\n // append (deduped by sequence) to the run's milestone list, and reflect\n // any progress fields the milestone carried onto the latest snapshot.\n const milestone = readAgentToolMilestoneChunk(parsed);\n if (milestone) {\n const milestones = mergeMilestone(seeded.milestones, milestone);\n // Only advance the snapshot for a genuinely new, not-older milestone, so\n // a late replay of an earlier milestone never rolls `progress` backward.\n const isNew = milestones !== seeded.milestones;\n const notOlder =\n seeded.progress === undefined || milestone.at >= seeded.progress.at;\n if (!isNew || !notOlder) {\n return { ...seeded, parts, milestones };\n }\n const data = (parsed as { data?: AgentToolProgress }).data ?? {};\n const snapshot: AgentToolProgressSnapshot = {\n ...(typeof data.fraction === \"number\"\n ? { fraction: data.fraction }\n : {}),\n ...(typeof data.message === \"string\"\n ? { message: data.message }\n : {}),\n ...(typeof data.phase === \"string\" ? { phase: data.phase } : {}),\n milestone: milestone.name,\n at: milestone.at\n };\n return { ...seeded, parts, progress: snapshot, milestones };\n }\n return { ...seeded, parts };\n }\n case \"finished\":\n if (!seeded) return undefined;\n return {\n ...seeded,\n status: \"completed\",\n summary: event.summary,\n error: undefined\n };\n case \"error\":\n if (!seeded) return undefined;\n return { ...seeded, status: \"error\", error: event.error };\n case \"aborted\":\n if (!seeded) return undefined;\n return { ...seeded, status: \"aborted\", error: event.reason };\n case \"interrupted\":\n if (!seeded) return undefined;\n return {\n ...seeded,\n status: \"interrupted\",\n error: event.error,\n reason: event.reason,\n childStillRunning: event.childStillRunning\n };\n }\n}\n\nexport function createAgentToolEventState<\n Part extends AgentToolRunPart = AgentToolRunPart\n>(): AgentToolEventState<Part> {\n return {\n runsById: {},\n runsByToolCallId: {},\n unboundRuns: []\n };\n}\n\n/**\n * Identity of an agent-tool event for replay-vs-live dedupe. Ordinary chunks\n * key on the broadcast `sequence`, which is their stored-chunk position on\n * both the live and replay paths. Lifecycle events key on their content: a\n * reattached run can be interrupted again with a different reason, and the\n * reducer overwrites on lifecycle events, so re-applying one is harmless.\n * Milestones key on their own persisted sequence. Progress frames and chunks\n * too large to store reuse the next stored chunk's sequence without consuming\n * it and are never replayed, so they key on their own emitter-assigned id.\n */\nexport function agentToolEventDedupeKey(\n message: AgentToolEventMessage\n): string {\n const { event } = message;\n let identity: string;\n if (event.kind !== \"chunk\") {\n identity = `event:${JSON.stringify(event)}`;\n } else if (event.unstoredId !== undefined) {\n identity = `unstored:${event.unstoredId}`;\n } else {\n let milestone: AgentToolMilestone | undefined;\n let progressId: string | undefined;\n let progress = false;\n if (\n event.body.includes(AGENT_TOOL_MILESTONE_PART) ||\n event.body.includes(AGENT_TOOL_PROGRESS_PART)\n ) {\n try {\n const parsed: unknown = JSON.parse(event.body);\n milestone = readAgentToolMilestoneChunk(parsed);\n progress = readAgentToolProgressChunk(parsed) !== undefined;\n const id = (parsed as { id?: unknown }).id;\n if (typeof id === \"string\") progressId = id;\n } catch {\n milestone = undefined;\n }\n }\n identity = milestone\n ? `milestone:${milestone.sequence}`\n : progress\n ? progressId !== undefined\n ? `progress:${progressId}`\n : `progress:${message.sequence}:${event.body}`\n : `seq:${message.sequence}`;\n }\n return [message.parentToolCallId ?? \"\", event.runId, identity].join(\"\\0\");\n}\n\nexport function applyAgentToolEvent<\n Part extends AgentToolRunPart = AgentToolRunPart\n>(\n state: AgentToolEventState<Part>,\n message: AgentToolEventMessage\n): AgentToolEventState<Part> {\n if (message.type !== \"agent-tool-event\") return state;\n const runId = message.event.runId;\n const nextRun = applyToRun(state.runsById[runId], message);\n if (!nextRun) return state;\n\n const runsById = { ...state.runsById, [runId]: nextRun };\n return { runsById, ...rebuildIndexes(runsById) };\n}\n\nexport { isPositionlessAgentToolChunk };\n\nexport type {\n AgentToolEvent,\n AgentToolEventMessage,\n AgentToolEventState,\n AgentToolRunPart,\n AgentToolRunState\n} from \"../agent-tool-types\";\n\n/**\n * @internal Host substrate the {@link interceptAgentToolBroadcast} snoop reads,\n * abstracting the divergent per-host run-lookup and response-frame constant.\n */\nexport interface AgentToolBroadcastHooks {\n /** Live tailers per run; iterated to forward each progress chunk. */\n forwarders: Map<string, Set<(chunk: AgentToolStoredChunk) => void>>;\n /**\n * Per-run live counter of stored chunks; advanced even with no tailer\n * attached, so a stored chunk's live sequence equals its stored chunk_index.\n *\n * Progress/milestone frames (`reportProgress`) ride the same\n * `USE_CHAT_RESPONSE` wire type and are forwarded here, but persist\n * out-of-band (progress snapshot / milestone rows) and have no store\n * position. Neither do chunks too large to store (they carry an\n * `unstoredId`). Both carry the next position WITHOUT consuming it, and\n * tails emit them outside the stored-position high-water dedupe; counting\n * them would push later stored chunks past their stored index, so a chunk\n * stored and broadcast during a tail's drain would be emitted twice. A tail\n * seeds a cold counter from the stored high-water before it attaches.\n */\n liveSequences: Map<string, number>;\n /** Per-run last error body, captured for replay to a late-attaching tailer. */\n lastErrors: Map<string, string>;\n /**\n * Called after a run's error body is captured, so the host can record it\n * durably on the still-open run row (the in-memory {@link lastErrors} entry\n * is lost if the DO is evicted before the run is finalized).\n */\n onError?: (runId: string, body: string) => void;\n /** The host's use-chat-response wire type (`CHAT_MESSAGE_TYPES.USE_CHAT_RESPONSE`). */\n responseType: string;\n /** Resolve the agent-tool run that owns a turn request id, or null. */\n runForRequest: (requestId: string) => string | null;\n /**\n * Runs whose chunks the host suppresses (`eventDelivery: \"terminal\"`). Keeps\n * inspection on after a restart empties the other maps, so a recovered\n * turn's chunks are still attributed and suppressed.\n */\n terminalOnlyRuns?: ReadonlySet<string>;\n}\n\n/**\n * Snoop a host's outgoing chat frames while any agent-tool run is in flight and\n * forward the owning run's streamed body to its live tailers (or capture its\n * error), without altering the frame — the caller still broadcasts it (#1575).\n *\n * Shared verbatim by `@cloudflare/ai-chat` and `@cloudflare/think`; the only\n * per-host variance (the response-frame type constant and the run-lookup, whose\n * SQL differs) is supplied via {@link AgentToolBroadcastHooks}. Inspection runs\n * for a run's whole lifecycle (live sequences exist even with no tailer), so\n * error capture never depends on tailer timing. A frame belongs to a run iff it\n * carries that run's turn request id, so concurrent runs can't cross-contaminate\n * each other's progress or error state.\n *\n * Returns the run id when the frame is one of that run's content chunks, so a\n * host can skip broadcasting chunks no client is watching.\n */\nexport function interceptAgentToolBroadcast(\n msg: string | ArrayBuffer | ArrayBufferView,\n hooks: AgentToolBroadcastHooks\n): string | null {\n if (\n (hooks.forwarders.size > 0 ||\n hooks.liveSequences.size > 0 ||\n (hooks.terminalOnlyRuns?.size ?? 0) > 0) &&\n typeof msg === \"string\"\n ) {\n try {\n const parsed = JSON.parse(msg) as {\n type?: unknown;\n body?: unknown;\n error?: unknown;\n id?: unknown;\n };\n if (parsed.type === hooks.responseType && typeof parsed.id === \"string\") {\n const runId = hooks.runForRequest(parsed.id);\n if (runId !== null) {\n if (parsed.error === true && typeof parsed.body === \"string\") {\n hooks.lastErrors.set(runId, parsed.body);\n hooks.onError?.(runId, parsed.body);\n } else if (\n typeof parsed.body === \"string\" &&\n parsed.body.length > 0\n ) {\n // Advance the live sequence even with no tailer attached so a tailer\n // registering mid-run resumes at the right offset. Progress,\n // milestone, and unstored frames carry the next position without\n // consuming it.\n const sequence = hooks.liveSequences.get(runId) ?? 0;\n const lifecycle = isAgentToolLifecycleChunk(parsed.body);\n const unstored = !lifecycle && isChunkTooLargeToStore(parsed.body);\n hooks.liveSequences.set(\n runId,\n lifecycle || unstored ? sequence : sequence + 1\n );\n const chunk: AgentToolStoredChunk = {\n sequence,\n body: parsed.body,\n ...(unstored ? { unstoredId: crypto.randomUUID() } : {})\n };\n const forwarders = hooks.forwarders.get(runId);\n if (forwarders) {\n for (const forward of forwarders) forward(chunk);\n }\n return runId;\n }\n }\n }\n } catch {\n // Non-chat frames pass through unchanged.\n }\n }\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
W as AgentToolProgress,
|
|
5
5
|
Z as AgentToolStoredChunk,
|
|
6
6
|
z as AgentToolEventState
|
|
7
|
-
} from "./agent-routing-
|
|
7
|
+
} from "./agent-routing-0DR0Tk2v.js";
|
|
8
8
|
|
|
9
9
|
//#region src/chat/agent-tools.d.ts
|
|
10
10
|
type AgentToolProgressEmitResult = "emitted" | "coalesced" | "inactive";
|
|
@@ -81,27 +81,38 @@ interface AgentToolBroadcastHooks {
|
|
|
81
81
|
/** Live tailers per run; iterated to forward each progress chunk. */
|
|
82
82
|
forwarders: Map<string, Set<(chunk: AgentToolStoredChunk) => void>>;
|
|
83
83
|
/**
|
|
84
|
-
* Per-run
|
|
84
|
+
* Per-run live counter of stored chunks; advanced even with no tailer
|
|
85
|
+
* attached, so a stored chunk's live sequence equals its stored chunk_index.
|
|
85
86
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* on one monotonic line; the tail realigns it to the stored high-water on each
|
|
96
|
-
* (re)attach so a replay→live handoff stays gap/duplicate-free.
|
|
87
|
+
* Progress/milestone frames (`reportProgress`) ride the same
|
|
88
|
+
* `USE_CHAT_RESPONSE` wire type and are forwarded here, but persist
|
|
89
|
+
* out-of-band (progress snapshot / milestone rows) and have no store
|
|
90
|
+
* position. Neither do chunks too large to store (they carry an
|
|
91
|
+
* `unstoredId`). Both carry the next position WITHOUT consuming it, and
|
|
92
|
+
* tails emit them outside the stored-position high-water dedupe; counting
|
|
93
|
+
* them would push later stored chunks past their stored index, so a chunk
|
|
94
|
+
* stored and broadcast during a tail's drain would be emitted twice. A tail
|
|
95
|
+
* seeds a cold counter from the stored high-water before it attaches.
|
|
97
96
|
*/
|
|
98
97
|
liveSequences: Map<string, number>;
|
|
99
98
|
/** Per-run last error body, captured for replay to a late-attaching tailer. */
|
|
100
99
|
lastErrors: Map<string, string>;
|
|
100
|
+
/**
|
|
101
|
+
* Called after a run's error body is captured, so the host can record it
|
|
102
|
+
* durably on the still-open run row (the in-memory {@link lastErrors} entry
|
|
103
|
+
* is lost if the DO is evicted before the run is finalized).
|
|
104
|
+
*/
|
|
105
|
+
onError?: (runId: string, body: string) => void;
|
|
101
106
|
/** The host's use-chat-response wire type (`CHAT_MESSAGE_TYPES.USE_CHAT_RESPONSE`). */
|
|
102
107
|
responseType: string;
|
|
103
108
|
/** Resolve the agent-tool run that owns a turn request id, or null. */
|
|
104
109
|
runForRequest: (requestId: string) => string | null;
|
|
110
|
+
/**
|
|
111
|
+
* Runs whose chunks the host suppresses (`eventDelivery: "terminal"`). Keeps
|
|
112
|
+
* inspection on after a restart empties the other maps, so a recovered
|
|
113
|
+
* turn's chunks are still attributed and suppressed.
|
|
114
|
+
*/
|
|
115
|
+
terminalOnlyRuns?: ReadonlySet<string>;
|
|
105
116
|
}
|
|
106
117
|
/**
|
|
107
118
|
* Snoop a host's outgoing chat frames while any agent-tool run is in flight and
|
|
@@ -115,11 +126,14 @@ interface AgentToolBroadcastHooks {
|
|
|
115
126
|
* error capture never depends on tailer timing. A frame belongs to a run iff it
|
|
116
127
|
* carries that run's turn request id, so concurrent runs can't cross-contaminate
|
|
117
128
|
* each other's progress or error state.
|
|
129
|
+
*
|
|
130
|
+
* Returns the run id when the frame is one of that run's content chunks, so a
|
|
131
|
+
* host can skip broadcasting chunks no client is watching.
|
|
118
132
|
*/
|
|
119
133
|
declare function interceptAgentToolBroadcast(
|
|
120
134
|
msg: string | ArrayBuffer | ArrayBufferView,
|
|
121
135
|
hooks: AgentToolBroadcastHooks
|
|
122
|
-
):
|
|
136
|
+
): string | null;
|
|
123
137
|
//#endregion
|
|
124
138
|
export {
|
|
125
139
|
applyAgentToolEvent as a,
|
|
@@ -130,4 +144,4 @@ export {
|
|
|
130
144
|
interceptAgentToolBroadcast as s,
|
|
131
145
|
AgentToolBroadcastHooks as t
|
|
132
146
|
};
|
|
133
|
-
//# sourceMappingURL=agent-tools-
|
|
147
|
+
//# sourceMappingURL=agent-tools-YrATZJu2.d.ts.map
|
package/dist/agent-tools.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
$ as ChatCapableAgentClass,
|
|
3
3
|
B as AgentToolFailure,
|
|
4
|
-
F as
|
|
4
|
+
F as AgentToolDisplayMetadata,
|
|
5
5
|
H as AgentToolLifecycleResult,
|
|
6
|
-
I as
|
|
6
|
+
I as AgentToolEvent,
|
|
7
7
|
J as AgentToolRunPart,
|
|
8
8
|
K as AgentToolRunInfo,
|
|
9
|
-
L as
|
|
9
|
+
L as AgentToolEventDelivery,
|
|
10
|
+
P as AgentToolChildAdapter,
|
|
10
11
|
Q as AgentToolTerminalStatus,
|
|
11
12
|
R as AgentToolEventMessage,
|
|
12
13
|
V as AgentToolInterruptedReason,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
rt as RunAgentToolResult,
|
|
20
21
|
tt as DetachedRunAgentToolResult,
|
|
21
22
|
z as AgentToolEventState
|
|
22
|
-
} from "./agent-routing-
|
|
23
|
+
} from "./agent-routing-0DR0Tk2v.js";
|
|
23
24
|
import { FlexibleSchema, InferSchema, Tool } from "ai";
|
|
24
25
|
|
|
25
26
|
//#region src/agent-tools.d.ts
|
|
@@ -63,6 +64,7 @@ export {
|
|
|
63
64
|
type AgentToolChildAdapter,
|
|
64
65
|
type AgentToolDisplayMetadata,
|
|
65
66
|
type AgentToolEvent,
|
|
67
|
+
type AgentToolEventDelivery,
|
|
66
68
|
type AgentToolEventMessage,
|
|
67
69
|
type AgentToolEventState,
|
|
68
70
|
type AgentToolFactoryOptions,
|