agents 0.21.0 → 0.22.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/README.md +1 -0
- package/dist/{agent-tool-types-CzGGB-20.d.ts → agent-routing-CnkaHb-v.d.ts} +2921 -3057
- package/dist/agent-routing.d.ts +14 -0
- package/dist/agent-routing.js +187 -0
- package/dist/agent-routing.js.map +1 -0
- package/dist/agent-tool-types.d.ts +26 -26
- package/dist/{agent-tools-zR2d5uij.d.ts → agent-tools-C0XJqWzB.d.ts} +7 -7
- package/dist/agent-tools.d.ts +21 -21
- package/dist/agent-tools.js +2 -1
- package/dist/agent-tools.js.map +1 -1
- package/dist/browser/ai.js +2 -1
- package/dist/browser/ai.js.map +1 -1
- package/dist/capability-BjSKYpzg.js +42 -0
- package/dist/capability-BjSKYpzg.js.map +1 -0
- package/dist/capability-runner-CvHGZqUu.d.ts +150 -0
- package/dist/chat/index.d.ts +22 -15
- package/dist/chat/index.js +4 -4
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +14 -1
- package/dist/chat/react.js +82 -52
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/transport.js +1 -1
- package/dist/chat-sdk/index.d.ts +4 -4
- package/dist/chat-sdk/index.js +1 -1
- package/dist/{client-zqKcsyFa.js → client-jagG8a9_.js} +129 -37
- package/dist/client-jagG8a9_.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/{cloudflare-BduZwmYK.js → cloudflare-Dzvc7V2N.js} +10 -3
- package/dist/{cloudflare-BduZwmYK.js.map → cloudflare-Dzvc7V2N.js.map} +1 -1
- package/dist/current-agent-CuMErtly.d.ts +283 -0
- package/dist/current-agent-DhoDkSnH.js +51 -0
- package/dist/current-agent-DhoDkSnH.js.map +1 -0
- package/dist/diagnostics-CaBjfz4J.js +41 -0
- package/dist/diagnostics-CaBjfz4J.js.map +1 -0
- package/dist/{do-oauth-client-provider-VTZj2VtM.d.ts → do-oauth-client-provider-Tmf1vgKz.d.ts} +2 -2
- package/dist/durable-object-lifecycle-D6nNQJJd.js +862 -0
- package/dist/durable-object-lifecycle-D6nNQJJd.js.map +1 -0
- package/dist/{email-CL27preh.d.ts → email-7TatiTnl.d.ts} +38 -9
- package/dist/email-send.d.ts +15 -0
- package/dist/email-send.js +32 -0
- package/dist/email-send.js.map +1 -0
- package/dist/email.d.ts +14 -10
- package/dist/email.js.map +1 -1
- package/dist/experimental/memory/session/index.d.ts +3 -2
- package/dist/experimental/memory/session/index.js +15 -10
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/{handler-stateless-C_bo-Ytq.d.ts → handler-stateless-DxYpJ_XF.d.ts} +3 -3
- package/dist/{handler-stateless-CIkKPETH.js → handler-stateless-VvrWSAVA.js} +5 -5
- package/dist/handler-stateless-VvrWSAVA.js.map +1 -0
- package/dist/{index-BRnybD6X.d.ts → index-DcSAZKsB.d.ts} +19 -31
- package/dist/index.d.ts +98 -95
- package/dist/index.js +10 -7234
- package/dist/internal_context-BlxFEWfn.d.ts +19 -0
- package/dist/internal_context.d.ts +10 -4
- package/dist/internal_context.js +1 -10
- package/dist/{client-invoker-BNSZxAkv.d.ts → invoker-CG0_p_Wq.d.ts} +2 -2
- package/dist/{client-invoker-VNZ7X0nn.js → invoker-CHMnoxIA.js} +2 -2
- package/dist/invoker-CHMnoxIA.js.map +1 -0
- package/dist/lifecycle/index.d.ts +48 -0
- package/dist/lifecycle/index.js +4 -0
- package/dist/mcp/{do-oauth-client-provider.d.ts → client/do-oauth-client-provider.d.ts} +1 -1
- package/dist/mcp/{do-oauth-client-provider.js → client/do-oauth-client-provider.js} +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -0
- package/dist/mcp/client/index.d.ts +42 -0
- package/dist/mcp/{client.js → client/index.js} +1 -1
- package/dist/mcp/{x402.d.ts → client/x402.d.ts} +2 -2
- package/dist/mcp/{x402.js → client/x402.js} +2 -2
- package/dist/mcp/client/x402.js.map +1 -0
- package/dist/mcp/index.d.ts +36 -36
- package/dist/mcp/index.js +14 -16
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/{server.d.ts → server/index.d.ts} +1 -1
- package/dist/mcp/{server.js → server/index.js} +1 -1
- package/dist/observability/ai/index.js +50 -35
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/observability/index.d.ts +4 -4
- package/dist/observability/index.js +3 -50
- package/dist/observability/index.js.map +1 -1
- package/dist/{protocol-Dqc2MQxo.js → protocol-B0nh6KNf.js} +19 -21
- package/dist/protocol-B0nh6KNf.js.map +1 -0
- package/dist/react.d.ts +4 -4
- package/dist/react.js +1 -1
- package/dist/schedule.d.ts +25 -94
- package/dist/schedule.js +1 -98
- package/dist/schedule.js.map +1 -1
- package/dist/scheduler-CR9RHGos.js +857 -0
- package/dist/scheduler-CR9RHGos.js.map +1 -0
- package/dist/scheduler-DQoTGoAW.d.ts +224 -0
- package/dist/schedules/index.d.ts +22 -0
- package/dist/schedules/index.js +2 -0
- package/dist/schedules/parser.d.ts +79 -0
- package/dist/schedules/parser.js +103 -0
- package/dist/schedules/parser.js.map +1 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/sql-error-CPY-GXyI.d.ts +12 -0
- package/dist/sql-error.d.ts +2 -0
- package/dist/sql-error.js +16 -0
- package/dist/sql-error.js.map +1 -0
- package/dist/src-5W6JNKVb.js +6613 -0
- package/dist/src-5W6JNKVb.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflows.d.ts +22 -22
- package/dist/workflows.js +2 -1
- package/dist/workflows.js.map +1 -1
- package/dist/{ws-chat-transport-CIoOBbO7.js → ws-chat-transport-rWwta645.js} +152 -15
- package/dist/ws-chat-transport-rWwta645.js.map +1 -0
- package/docs/agent-class.md +28 -86
- package/docs/chat-agents.md +13 -12
- package/docs/durable-execution.md +1 -1
- package/docs/http-websockets.md +1 -11
- package/docs/human-in-the-loop.md +1 -1
- package/docs/index.md +1 -0
- package/docs/lifecycle.md +323 -0
- package/docs/long-running-agents.md +2 -4
- package/docs/mcp-client.md +55 -0
- package/docs/observability.md +11 -11
- package/docs/resumable-streaming.md +1 -1
- package/docs/scheduling.md +175 -15
- package/docs/server-driven-messages.md +1 -1
- package/docs/sub-agents.md +1 -1
- package/package.json +30 -21
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -26
- package/dist/cli/index.js.map +0 -1
- package/dist/client-invoker-VNZ7X0nn.js.map +0 -1
- package/dist/client-zqKcsyFa.js.map +0 -1
- package/dist/handler-stateless-CIkKPETH.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal_context-Dg4Cgjcu.d.ts +0 -37
- package/dist/internal_context.js.map +0 -1
- package/dist/mcp/client.d.ts +0 -42
- package/dist/mcp/do-oauth-client-provider.js.map +0 -1
- package/dist/mcp/x402.js.map +0 -1
- package/dist/protocol-Dqc2MQxo.js.map +0 -1
- package/dist/ws-chat-transport-CIoOBbO7.js.map +0 -1
package/dist/sub-routing.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Mn as
|
|
7
|
-
Nn as
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "./agent-
|
|
2
|
+
An as buildSubAgentPathUnchecked,
|
|
3
|
+
Cn as AgentPathStep,
|
|
4
|
+
Dn as buildAgentPath,
|
|
5
|
+
En as SubAgentPathMatch,
|
|
6
|
+
Mn as parseSubAgentPath,
|
|
7
|
+
Nn as routeSubAgentRequest,
|
|
8
|
+
On as buildAgentUrl,
|
|
9
|
+
Tn as SUB_PREFIX,
|
|
10
|
+
jn as getSubAgentByName,
|
|
11
|
+
kn as buildSubAgentPath,
|
|
12
|
+
wn as BuildAgentPathOptions
|
|
13
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
14
14
|
export {
|
|
15
15
|
AgentPathStep,
|
|
16
16
|
BuildAgentPathOptions,
|
package/dist/workflow-types.d.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
|
-
At as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "./agent-
|
|
2
|
+
At as WorkflowRejectedError,
|
|
3
|
+
Ct as WorkflowErrorCallback,
|
|
4
|
+
Dt as WorkflowPage,
|
|
5
|
+
Et as WorkflowInfo,
|
|
6
|
+
Mt as WorkflowTrackingRow,
|
|
7
|
+
Ot as WorkflowProgressCallback,
|
|
8
|
+
St as WorkflowCompleteCallback,
|
|
9
|
+
Tt as WorkflowEventPayload,
|
|
10
|
+
_t as RunWorkflowOptions,
|
|
11
|
+
bt as WorkflowCallbackBase,
|
|
12
|
+
dt as AgentWorkflowOrigin,
|
|
13
|
+
ft as AgentWorkflowParams,
|
|
14
|
+
gt as DefaultProgress,
|
|
15
|
+
ht as ApprovalEventPayload,
|
|
16
|
+
jt as WorkflowStatus,
|
|
17
|
+
kt as WorkflowQueryCriteria,
|
|
18
|
+
lt as AgentWorkflowEvent,
|
|
19
|
+
mt as AgentWorkflowStep,
|
|
20
|
+
pt as AgentWorkflowPathStep,
|
|
21
|
+
ut as AgentWorkflowInternalParams,
|
|
22
|
+
vt as WaitForApprovalOptions,
|
|
23
|
+
wt as WorkflowEventCallback,
|
|
24
|
+
xt as WorkflowCallbackType,
|
|
25
|
+
yt as WorkflowCallback
|
|
26
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
27
27
|
export {
|
|
28
28
|
AgentWorkflowEvent,
|
|
29
29
|
AgentWorkflowInternalParams,
|
package/dist/workflows.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
|
-
At as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from "./agent-
|
|
2
|
+
At as WorkflowRejectedError,
|
|
3
|
+
Ct as WorkflowErrorCallback,
|
|
4
|
+
Dt as WorkflowPage,
|
|
5
|
+
Et as WorkflowInfo,
|
|
6
|
+
Mt as WorkflowTrackingRow,
|
|
7
|
+
Ot as WorkflowProgressCallback,
|
|
8
|
+
St as WorkflowCompleteCallback,
|
|
9
|
+
Tt as WorkflowEventPayload,
|
|
10
|
+
_t as RunWorkflowOptions,
|
|
11
|
+
c as Agent,
|
|
12
|
+
ft as AgentWorkflowParams,
|
|
13
|
+
gt as DefaultProgress,
|
|
14
|
+
ht as ApprovalEventPayload,
|
|
15
|
+
jt as WorkflowStatus,
|
|
16
|
+
kt as WorkflowQueryCriteria,
|
|
17
|
+
lt as AgentWorkflowEvent,
|
|
18
|
+
mt as AgentWorkflowStep,
|
|
19
|
+
vt as WaitForApprovalOptions,
|
|
20
|
+
wt as WorkflowEventCallback,
|
|
21
|
+
xt as WorkflowCallbackType,
|
|
22
|
+
yt as WorkflowCallback
|
|
23
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
24
24
|
import { WorkflowEntrypoint, WorkflowEvent } from "cloudflare:workers";
|
|
25
25
|
|
|
26
26
|
//#region src/workflows.d.ts
|
package/dist/workflows.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isInternalJsStubProp } from "./utils.js";
|
|
2
|
-
import { getAgentByName } from "./
|
|
2
|
+
import { getAgentByName } from "./agent-routing.js";
|
|
3
|
+
import "./src-5W6JNKVb.js";
|
|
3
4
|
import { WorkflowRejectedError } from "./workflow-types.js";
|
|
4
5
|
import { WorkflowEntrypoint } from "cloudflare:workers";
|
|
5
6
|
//#region src/workflows.ts
|
package/dist/workflows.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows.js","names":[],"sources":["../src/workflows.ts"],"sourcesContent":["/**\n * AgentWorkflow - Base class for Workflows that integrate with Agents\n *\n * Extends Cloudflare's WorkflowEntrypoint to provide seamless access to\n * the Agent that started the workflow, enabling bidirectional communication.\n *\n * @example\n * ```typescript\n * import { AgentWorkflow } from 'agents/workflows';\n * import type { MyAgent } from './agent';\n *\n * type TaskParams = { taskId: string; data: string };\n *\n * export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {\n * async run(event: AgentWorkflowEvent<TaskParams>, step: WorkflowStep) {\n * // Access the originating Agent via typed RPC\n * await this.agent.updateTaskStatus(event.payload.taskId, 'processing');\n *\n * const result = await step.do('process', async () => {\n * // ... processing logic\n * return { processed: true };\n * });\n *\n * // Report progress to Agent (typed)\n * await this.reportProgress({ step: 'process', status: 'complete', percent: 0.5 });\n *\n * // Broadcast to connected clients\n * await this.broadcastToClients({ type: 'progress', data: result });\n *\n * return result;\n * }\n * }\n * ```\n */\n\nimport { WorkflowEntrypoint } from \"cloudflare:workers\";\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowStepEvent\n} from \"cloudflare:workers\";\nimport { getAgentByName, type Agent } from \"./index\";\nimport type {\n AgentWorkflowParams,\n AgentWorkflowStep,\n WorkflowCallback,\n DefaultProgress,\n WaitForApprovalOptions\n} from \"./workflow-types\";\nimport { WorkflowRejectedError } from \"./workflow-types\";\nimport type {\n AgentWorkflowOrigin,\n AgentWorkflowPathStep\n} from \"./workflow-types\";\nimport { isInternalJsStubProp } from \"./utils\";\n\ntype AgentPathInvoker = {\n _cf_invokeAgentPath(\n path: ReadonlyArray<AgentWorkflowPathStep>,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n};\n\n/**\n * WeakSet to track which prototypes have been wrapped.\n * This prevents re-wrapping on subsequent instantiations of the same class.\n */\nconst wrappedPrototypes = new WeakSet<object>();\n\n/**\n * Base class for Workflows that need access to their originating Agent.\n *\n * @template AgentType - The Agent class type (for typed RPC access)\n * @template Params - User-defined params passed to the workflow (optional)\n * @template ProgressType - Type for progress reporting (defaults to DefaultProgress)\n * @template Env - Environment type (defaults to Cloudflare.Env)\n */\nexport class AgentWorkflow<\n AgentType extends Agent = Agent,\n Params = unknown,\n ProgressType = DefaultProgress,\n Env extends Cloudflare.Env = Cloudflare.Env\n> extends WorkflowEntrypoint<Env, AgentWorkflowParams<Params>> {\n /**\n * The Agent stub - initialized before run() is called.\n * Use this.agent to access the Agent's RPC methods.\n */\n private _agent?: DurableObjectStub<AgentType>;\n\n /**\n * Workflow instance ID\n */\n private _workflowId!: string;\n\n /**\n * Workflow binding name (for callbacks)\n */\n private _workflowName!: string;\n\n /**\n * Instance-level guard to prevent double initialization.\n * Used when a subclass calls super.run() after its own run() was wrapped.\n */\n private __agentInitCalled = false;\n\n /**\n * Guard to prevent double error notification.\n * Set to true when reportError() is called explicitly, so the automatic\n * error catch in the run() wrapper doesn't send a duplicate notification.\n */\n private _errorReported = false;\n\n constructor(ctx: ExecutionContext, env: Env) {\n super(ctx, env);\n\n const proto = Object.getPrototypeOf(this);\n\n // Only wrap if:\n // 1. This prototype defines its own run method (hasOwnProperty)\n // 2. It hasn't been wrapped yet (WeakSet check)\n // This prevents double-wrapping inherited methods and ensures each subclass\n // that defines run() gets wrapped exactly once.\n if (Object.hasOwn(proto, \"run\") && !wrappedPrototypes.has(proto)) {\n const originalRun = proto.run as (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>;\n\n // Replace the prototype's run method with a wrapper that initializes\n // the agent before calling the user's implementation\n proto.run = async function (\n this: AgentWorkflow<AgentType, Params, ProgressType, Env>,\n event: WorkflowEvent<AgentWorkflowParams<Params>>,\n step: WorkflowStep\n ) {\n // Instance-level guard: only init once per instance\n // (prevents double init if super.run() is called from a subclass)\n if (!this.__agentInitCalled) {\n const {\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n ...userParams\n } = event.payload;\n\n // Initialize agent connection\n await this._initAgent(\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n event.instanceId\n );\n this.__agentInitCalled = true;\n\n try {\n // Pass cleaned event and wrapped step to user's implementation\n const cleanedEvent = {\n ...event,\n payload: userParams as Params\n } as WorkflowEvent<Params>;\n\n const wrappedStep = this.extendStep(\n this._wrapStep(step),\n cleanedEvent\n );\n\n return await this._runWithErrorReporting(\n originalRun,\n cleanedEvent,\n wrappedStep\n );\n } finally {\n this._disposeAgent();\n }\n }\n\n // If already initialized (e.g., called via super.run()),\n // just call the original with the event as-is.\n return await this._runWithErrorReporting(\n originalRun,\n event as WorkflowEvent<Params>,\n step as AgentWorkflowStep\n );\n };\n\n wrappedPrototypes.add(proto);\n }\n }\n\n /**\n * Initialize the Agent stub from workflow params.\n * Called automatically before run() executes.\n */\n private async _initAgent(\n agentName: string | undefined,\n agentBinding: string | undefined,\n workflowName: string | undefined,\n agentOrigin: AgentWorkflowOrigin | undefined,\n instanceId: string\n ): Promise<void> {\n if (!workflowName || (!agentOrigin && (!agentName || !agentBinding))) {\n throw new Error(\n \"AgentWorkflow requires __agentName, __agentBinding, and __workflowName in params. \" +\n \"Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n this._workflowId = instanceId;\n this._workflowName = workflowName;\n this._errorReported = false;\n\n // The origin payload is durably persisted in workflow params, so a workflow\n // started by an older SDK can resume against newer code (and vice versa).\n // Reject origin versions this build does not understand rather than\n // silently misreading a future shape.\n if (agentOrigin && agentOrigin.version !== 1) {\n throw new Error(\n `AgentWorkflow received an unsupported origin version (${\n (agentOrigin as { version?: unknown }).version\n }). Upgrade the \"agents\" package running this Workflow to match the Agent that started it.`\n );\n }\n\n if (agentOrigin?.kind === \"facet\") {\n this._agent = await this._initFacetAgent(agentOrigin);\n return;\n }\n\n const resolvedAgentName =\n agentOrigin?.kind === \"agent\" ? agentOrigin.name : agentName;\n const resolvedAgentBinding =\n agentOrigin?.kind === \"agent\" ? agentOrigin.binding : agentBinding;\n\n if (!resolvedAgentName || !resolvedAgentBinding) {\n throw new Error(\n \"AgentWorkflow requires a valid Agent origin. Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n // Get the Agent namespace from env\n const namespace = (this.env as Record<string, unknown>)[\n resolvedAgentBinding\n ] as DurableObjectNamespace<AgentType>;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${resolvedAgentBinding}' not found in environment`\n );\n }\n\n // Get the Agent stub by name\n this._agent = await getAgentByName<Cloudflare.Env, AgentType>(\n namespace,\n resolvedAgentName\n );\n }\n\n private async _initFacetAgent(\n origin: Extract<AgentWorkflowOrigin, { kind: \"facet\" }>\n ): Promise<DurableObjectStub<AgentType>> {\n const root = origin.path[0];\n if (!root) {\n throw new Error(\"AgentWorkflow facet origin requires a non-empty path\");\n }\n\n const namespace = (this.env as Record<string, unknown>)[\n origin.rootBinding\n ] as DurableObjectNamespace<Agent> | undefined;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${origin.rootBinding}' not found in environment`\n );\n }\n\n const rootAgent = (await getAgentByName<Cloudflare.Env, Agent>(\n namespace,\n root.name\n )) as unknown as AgentPathInvoker;\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n \"AgentWorkflow.agent for sub-agent origins is an RPC-only stub — .fetch() is not supported. Use routeSubAgentRequest() or the /agents/{parent}/{name}/sub/{child}/{name} URL for external HTTP/WS routing.\"\n );\n };\n }\n return async (...args: unknown[]) =>\n rootAgent._cf_invokeAgentPath(origin.path, prop, args);\n }\n }\n ) as DurableObjectStub<AgentType>;\n }\n\n /**\n * Call user workflow code and report unhandled errors to the Agent.\n */\n private async _runWithErrorReporting(\n originalRun: (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>,\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ): Promise<unknown> {\n try {\n return await originalRun.call(this, event, step);\n } catch (err) {\n await this._autoReportError(err);\n throw err;\n }\n }\n\n /**\n * Dispose the Agent stub owned by this workflow run.\n */\n private _disposeAgent(): void {\n const agent = this._agent;\n this._agent = undefined;\n this.__agentInitCalled = false;\n disposeIfPresent(agent);\n }\n\n /**\n * Wrap WorkflowStep with durable Agent communication methods.\n * Methods added to the wrapped step are idempotent and won't repeat on retry.\n *\n * Note: We add methods directly to the step object to preserve instanceof checks\n * that Cloudflare's runtime may perform on the WorkflowStep class.\n */\n private _wrapStep(step: WorkflowStep): AgentWorkflowStep {\n let stepCounter = 0;\n\n // Cast step to our extended type and add methods directly\n // This preserves the original object identity and instanceof relationship\n const wrappedStep = step as AgentWorkflowStep;\n\n // Add durable Agent methods directly to the step object\n wrappedStep.reportComplete = async <T>(result?: T): Promise<void> => {\n await step.do(`__agent_reportComplete_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"complete\",\n result,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.reportError = async (error: Error | string): Promise<void> => {\n const errorMessage = error instanceof Error ? error.message : error;\n this._errorReported = true;\n await step.do(`__agent_reportError_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.sendEvent = async <T>(event: T): Promise<void> => {\n await step.do(`__agent_sendEvent_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"event\",\n event,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.updateAgentState = async (state: unknown): Promise<void> => {\n await step.do(`__agent_updateState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"set\", state);\n });\n };\n\n wrappedStep.mergeAgentState = async (\n partialState: Record<string, unknown>\n ): Promise<void> => {\n await step.do(`__agent_mergeState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"merge\", partialState);\n });\n };\n\n wrappedStep.resetAgentState = async (): Promise<void> => {\n await step.do(`__agent_resetState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"reset\");\n });\n };\n\n return wrappedStep;\n }\n\n /**\n * Extend the Agent-aware workflow step before user code receives it.\n *\n * Subclasses can override this to add framework-specific step helpers while\n * preserving the underlying WorkflowStep object identity.\n */\n protected extendStep(\n step: AgentWorkflowStep,\n _event: WorkflowEvent<Params>\n ): AgentWorkflowStep {\n return step;\n }\n\n /**\n * Get the Agent stub for RPC calls.\n * Provides typed access to the Agent's methods.\n *\n * @example\n * ```typescript\n * // Call any public method on the Agent\n * await this.agent.updateStatus('processing');\n * const data = await this.agent.getData();\n * ```\n */\n get agent(): DurableObjectStub<AgentType> {\n if (!this._agent) {\n throw new Error(\n \"Agent not initialized. Ensure you're accessing this.agent inside run().\"\n );\n }\n return this._agent;\n }\n\n /**\n * Get the workflow instance ID\n */\n get workflowId(): string {\n return this._workflowId;\n }\n\n /**\n * Get the workflow binding name\n */\n get workflowName(): string {\n return this._workflowName;\n }\n\n /**\n * Automatically report an unhandled error to the Agent.\n * Skipped if reportError() was already called (prevents double notification).\n * Best-effort: notification failures are swallowed so the original error propagates.\n *\n * @param err - The caught error\n */\n private async _autoReportError(err: unknown): Promise<void> {\n if (this._errorReported) {\n return;\n }\n this._errorReported = true;\n const errorMessage = err instanceof Error ? err.message : String(err);\n try {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n } catch (_notifyErr) {\n // Best-effort: don't mask the original error\n }\n }\n\n /**\n * Send a notification to the Agent via RPC.\n *\n * @param callback - Callback payload to send\n */\n protected async notifyAgent(callback: WorkflowCallback): Promise<void> {\n await this.agent._workflow_handleCallback(callback);\n }\n\n /**\n * Report progress to the Agent with typed progress data.\n * Triggers onWorkflowProgress() on the Agent.\n *\n * @param progress - Typed progress data\n *\n * @example\n * ```typescript\n * // Using default progress type\n * await this.reportProgress({ step: 'fetch', status: 'running' });\n * await this.reportProgress({ step: 'fetch', status: 'complete', percent: 0.5 });\n *\n * // With custom progress type\n * await this.reportProgress({ stage: 'extract', recordsProcessed: 100 });\n * ```\n */\n protected async reportProgress(progress: ProgressType): Promise<void> {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"progress\",\n progress: progress as DefaultProgress,\n timestamp: Date.now()\n });\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients via the Agent.\n * This is non-durable and may repeat on workflow retry.\n *\n * @param message - Message to broadcast (will be JSON-stringified)\n */\n protected broadcastToClients(message: unknown): void {\n this.agent._workflow_broadcast(message);\n }\n\n /**\n * Wait for approval from the Agent.\n * Handles rejection by reporting error (durably) and throwing WorkflowRejectedError.\n *\n * @param step - AgentWorkflowStep object\n * @param options - Wait options (timeout, eventType, stepName)\n * @returns Approval payload (throws WorkflowRejectedError if rejected)\n *\n * @example\n * ```typescript\n * const approval = await this.waitForApproval(step, { timeout: '7 days' });\n * // approval contains the payload from approveWorkflow()\n * ```\n */\n protected async waitForApproval<T = unknown>(\n step: AgentWorkflowStep,\n options?: WaitForApprovalOptions\n ): Promise<T> {\n const stepName = options?.stepName ?? \"wait-for-approval\";\n const eventType = options?.eventType ?? \"approval\";\n const timeout = options?.timeout;\n\n // Wait for the approval event\n // Note: Call reportProgress() before this method if you want to update progress\n const event = (await step.waitForEvent(stepName, {\n type: eventType,\n timeout\n })) as WorkflowStepEvent<{\n approved: boolean;\n reason?: string;\n metadata?: T;\n }>;\n\n try {\n const payload = event.payload;\n\n // Check if rejected\n if (!payload.approved) {\n const reason = payload.reason;\n await step.reportError(reason ?? \"Workflow rejected\");\n throw new WorkflowRejectedError(reason, this._workflowId);\n }\n\n // Return the approval metadata as the result\n return payload.metadata as T;\n } finally {\n disposeIfPresent(event);\n }\n }\n}\n\ntype DisposableResource = {\n [Symbol.dispose](): void;\n};\n\nfunction isDisposableResource(value: unknown): value is DisposableResource {\n return (\n !!value &&\n typeof value === \"object\" &&\n Symbol.dispose in value &&\n typeof value[Symbol.dispose] === \"function\"\n );\n}\n\nfunction disposeIfPresent(value: unknown): void {\n if (isDisposableResource(value)) {\n value[Symbol.dispose]();\n }\n}\n\n// Re-export types for convenience\nexport type {\n AgentWorkflowEvent,\n AgentWorkflowStep,\n WorkflowCallback,\n WorkflowCallbackType,\n WorkflowProgressCallback,\n WorkflowCompleteCallback,\n WorkflowErrorCallback,\n WorkflowEventCallback,\n DefaultProgress,\n WaitForApprovalOptions,\n ApprovalEventPayload,\n WorkflowStatus,\n WorkflowTrackingRow,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\n\nexport { WorkflowRejectedError } from \"./workflow-types\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflows.js","names":[],"sources":["../src/workflows.ts"],"sourcesContent":["/**\n * AgentWorkflow - Base class for Workflows that integrate with Agents\n *\n * Extends Cloudflare's WorkflowEntrypoint to provide seamless access to\n * the Agent that started the workflow, enabling bidirectional communication.\n *\n * @example\n * ```typescript\n * import { AgentWorkflow } from 'agents/workflows';\n * import type { MyAgent } from './agent';\n *\n * type TaskParams = { taskId: string; data: string };\n *\n * export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {\n * async run(event: AgentWorkflowEvent<TaskParams>, step: WorkflowStep) {\n * // Access the originating Agent via typed RPC\n * await this.agent.updateTaskStatus(event.payload.taskId, 'processing');\n *\n * const result = await step.do('process', async () => {\n * // ... processing logic\n * return { processed: true };\n * });\n *\n * // Report progress to Agent (typed)\n * await this.reportProgress({ step: 'process', status: 'complete', percent: 0.5 });\n *\n * // Broadcast to connected clients\n * await this.broadcastToClients({ type: 'progress', data: result });\n *\n * return result;\n * }\n * }\n * ```\n */\n\nimport { WorkflowEntrypoint } from \"cloudflare:workers\";\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowStepEvent\n} from \"cloudflare:workers\";\nimport { getAgentByName, type Agent } from \"./index\";\nimport type {\n AgentWorkflowParams,\n AgentWorkflowStep,\n WorkflowCallback,\n DefaultProgress,\n WaitForApprovalOptions\n} from \"./workflow-types\";\nimport { WorkflowRejectedError } from \"./workflow-types\";\nimport type {\n AgentWorkflowOrigin,\n AgentWorkflowPathStep\n} from \"./workflow-types\";\nimport { isInternalJsStubProp } from \"./utils\";\n\ntype AgentPathInvoker = {\n _cf_invokeAgentPath(\n path: ReadonlyArray<AgentWorkflowPathStep>,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n};\n\n/**\n * WeakSet to track which prototypes have been wrapped.\n * This prevents re-wrapping on subsequent instantiations of the same class.\n */\nconst wrappedPrototypes = new WeakSet<object>();\n\n/**\n * Base class for Workflows that need access to their originating Agent.\n *\n * @template AgentType - The Agent class type (for typed RPC access)\n * @template Params - User-defined params passed to the workflow (optional)\n * @template ProgressType - Type for progress reporting (defaults to DefaultProgress)\n * @template Env - Environment type (defaults to Cloudflare.Env)\n */\nexport class AgentWorkflow<\n AgentType extends Agent = Agent,\n Params = unknown,\n ProgressType = DefaultProgress,\n Env extends Cloudflare.Env = Cloudflare.Env\n> extends WorkflowEntrypoint<Env, AgentWorkflowParams<Params>> {\n /**\n * The Agent stub - initialized before run() is called.\n * Use this.agent to access the Agent's RPC methods.\n */\n private _agent?: DurableObjectStub<AgentType>;\n\n /**\n * Workflow instance ID\n */\n private _workflowId!: string;\n\n /**\n * Workflow binding name (for callbacks)\n */\n private _workflowName!: string;\n\n /**\n * Instance-level guard to prevent double initialization.\n * Used when a subclass calls super.run() after its own run() was wrapped.\n */\n private __agentInitCalled = false;\n\n /**\n * Guard to prevent double error notification.\n * Set to true when reportError() is called explicitly, so the automatic\n * error catch in the run() wrapper doesn't send a duplicate notification.\n */\n private _errorReported = false;\n\n constructor(ctx: ExecutionContext, env: Env) {\n super(ctx, env);\n\n const proto = Object.getPrototypeOf(this);\n\n // Only wrap if:\n // 1. This prototype defines its own run method (hasOwnProperty)\n // 2. It hasn't been wrapped yet (WeakSet check)\n // This prevents double-wrapping inherited methods and ensures each subclass\n // that defines run() gets wrapped exactly once.\n if (Object.hasOwn(proto, \"run\") && !wrappedPrototypes.has(proto)) {\n const originalRun = proto.run as (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>;\n\n // Replace the prototype's run method with a wrapper that initializes\n // the agent before calling the user's implementation\n proto.run = async function (\n this: AgentWorkflow<AgentType, Params, ProgressType, Env>,\n event: WorkflowEvent<AgentWorkflowParams<Params>>,\n step: WorkflowStep\n ) {\n // Instance-level guard: only init once per instance\n // (prevents double init if super.run() is called from a subclass)\n if (!this.__agentInitCalled) {\n const {\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n ...userParams\n } = event.payload;\n\n // Initialize agent connection\n await this._initAgent(\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n event.instanceId\n );\n this.__agentInitCalled = true;\n\n try {\n // Pass cleaned event and wrapped step to user's implementation\n const cleanedEvent = {\n ...event,\n payload: userParams as Params\n } as WorkflowEvent<Params>;\n\n const wrappedStep = this.extendStep(\n this._wrapStep(step),\n cleanedEvent\n );\n\n return await this._runWithErrorReporting(\n originalRun,\n cleanedEvent,\n wrappedStep\n );\n } finally {\n this._disposeAgent();\n }\n }\n\n // If already initialized (e.g., called via super.run()),\n // just call the original with the event as-is.\n return await this._runWithErrorReporting(\n originalRun,\n event as WorkflowEvent<Params>,\n step as AgentWorkflowStep\n );\n };\n\n wrappedPrototypes.add(proto);\n }\n }\n\n /**\n * Initialize the Agent stub from workflow params.\n * Called automatically before run() executes.\n */\n private async _initAgent(\n agentName: string | undefined,\n agentBinding: string | undefined,\n workflowName: string | undefined,\n agentOrigin: AgentWorkflowOrigin | undefined,\n instanceId: string\n ): Promise<void> {\n if (!workflowName || (!agentOrigin && (!agentName || !agentBinding))) {\n throw new Error(\n \"AgentWorkflow requires __agentName, __agentBinding, and __workflowName in params. \" +\n \"Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n this._workflowId = instanceId;\n this._workflowName = workflowName;\n this._errorReported = false;\n\n // The origin payload is durably persisted in workflow params, so a workflow\n // started by an older SDK can resume against newer code (and vice versa).\n // Reject origin versions this build does not understand rather than\n // silently misreading a future shape.\n if (agentOrigin && agentOrigin.version !== 1) {\n throw new Error(\n `AgentWorkflow received an unsupported origin version (${\n (agentOrigin as { version?: unknown }).version\n }). Upgrade the \"agents\" package running this Workflow to match the Agent that started it.`\n );\n }\n\n if (agentOrigin?.kind === \"facet\") {\n this._agent = await this._initFacetAgent(agentOrigin);\n return;\n }\n\n const resolvedAgentName =\n agentOrigin?.kind === \"agent\" ? agentOrigin.name : agentName;\n const resolvedAgentBinding =\n agentOrigin?.kind === \"agent\" ? agentOrigin.binding : agentBinding;\n\n if (!resolvedAgentName || !resolvedAgentBinding) {\n throw new Error(\n \"AgentWorkflow requires a valid Agent origin. Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n // Get the Agent namespace from env\n const namespace = (this.env as Record<string, unknown>)[\n resolvedAgentBinding\n ] as DurableObjectNamespace<AgentType>;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${resolvedAgentBinding}' not found in environment`\n );\n }\n\n // Get the Agent stub by name\n this._agent = await getAgentByName<Cloudflare.Env, AgentType>(\n namespace,\n resolvedAgentName\n );\n }\n\n private async _initFacetAgent(\n origin: Extract<AgentWorkflowOrigin, { kind: \"facet\" }>\n ): Promise<DurableObjectStub<AgentType>> {\n const root = origin.path[0];\n if (!root) {\n throw new Error(\"AgentWorkflow facet origin requires a non-empty path\");\n }\n\n const namespace = (this.env as Record<string, unknown>)[\n origin.rootBinding\n ] as DurableObjectNamespace<Agent> | undefined;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${origin.rootBinding}' not found in environment`\n );\n }\n\n const rootAgent = (await getAgentByName<Cloudflare.Env, Agent>(\n namespace,\n root.name\n )) as unknown as AgentPathInvoker;\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n \"AgentWorkflow.agent for sub-agent origins is an RPC-only stub — .fetch() is not supported. Use routeSubAgentRequest() or the /agents/{parent}/{name}/sub/{child}/{name} URL for external HTTP/WS routing.\"\n );\n };\n }\n return async (...args: unknown[]) =>\n rootAgent._cf_invokeAgentPath(origin.path, prop, args);\n }\n }\n ) as DurableObjectStub<AgentType>;\n }\n\n /**\n * Call user workflow code and report unhandled errors to the Agent.\n */\n private async _runWithErrorReporting(\n originalRun: (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>,\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ): Promise<unknown> {\n try {\n return await originalRun.call(this, event, step);\n } catch (err) {\n await this._autoReportError(err);\n throw err;\n }\n }\n\n /**\n * Dispose the Agent stub owned by this workflow run.\n */\n private _disposeAgent(): void {\n const agent = this._agent;\n this._agent = undefined;\n this.__agentInitCalled = false;\n disposeIfPresent(agent);\n }\n\n /**\n * Wrap WorkflowStep with durable Agent communication methods.\n * Methods added to the wrapped step are idempotent and won't repeat on retry.\n *\n * Note: We add methods directly to the step object to preserve instanceof checks\n * that Cloudflare's runtime may perform on the WorkflowStep class.\n */\n private _wrapStep(step: WorkflowStep): AgentWorkflowStep {\n let stepCounter = 0;\n\n // Cast step to our extended type and add methods directly\n // This preserves the original object identity and instanceof relationship\n const wrappedStep = step as AgentWorkflowStep;\n\n // Add durable Agent methods directly to the step object\n wrappedStep.reportComplete = async <T>(result?: T): Promise<void> => {\n await step.do(`__agent_reportComplete_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"complete\",\n result,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.reportError = async (error: Error | string): Promise<void> => {\n const errorMessage = error instanceof Error ? error.message : error;\n this._errorReported = true;\n await step.do(`__agent_reportError_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.sendEvent = async <T>(event: T): Promise<void> => {\n await step.do(`__agent_sendEvent_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"event\",\n event,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.updateAgentState = async (state: unknown): Promise<void> => {\n await step.do(`__agent_updateState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"set\", state);\n });\n };\n\n wrappedStep.mergeAgentState = async (\n partialState: Record<string, unknown>\n ): Promise<void> => {\n await step.do(`__agent_mergeState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"merge\", partialState);\n });\n };\n\n wrappedStep.resetAgentState = async (): Promise<void> => {\n await step.do(`__agent_resetState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"reset\");\n });\n };\n\n return wrappedStep;\n }\n\n /**\n * Extend the Agent-aware workflow step before user code receives it.\n *\n * Subclasses can override this to add framework-specific step helpers while\n * preserving the underlying WorkflowStep object identity.\n */\n protected extendStep(\n step: AgentWorkflowStep,\n _event: WorkflowEvent<Params>\n ): AgentWorkflowStep {\n return step;\n }\n\n /**\n * Get the Agent stub for RPC calls.\n * Provides typed access to the Agent's methods.\n *\n * @example\n * ```typescript\n * // Call any public method on the Agent\n * await this.agent.updateStatus('processing');\n * const data = await this.agent.getData();\n * ```\n */\n get agent(): DurableObjectStub<AgentType> {\n if (!this._agent) {\n throw new Error(\n \"Agent not initialized. Ensure you're accessing this.agent inside run().\"\n );\n }\n return this._agent;\n }\n\n /**\n * Get the workflow instance ID\n */\n get workflowId(): string {\n return this._workflowId;\n }\n\n /**\n * Get the workflow binding name\n */\n get workflowName(): string {\n return this._workflowName;\n }\n\n /**\n * Automatically report an unhandled error to the Agent.\n * Skipped if reportError() was already called (prevents double notification).\n * Best-effort: notification failures are swallowed so the original error propagates.\n *\n * @param err - The caught error\n */\n private async _autoReportError(err: unknown): Promise<void> {\n if (this._errorReported) {\n return;\n }\n this._errorReported = true;\n const errorMessage = err instanceof Error ? err.message : String(err);\n try {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n } catch (_notifyErr) {\n // Best-effort: don't mask the original error\n }\n }\n\n /**\n * Send a notification to the Agent via RPC.\n *\n * @param callback - Callback payload to send\n */\n protected async notifyAgent(callback: WorkflowCallback): Promise<void> {\n await this.agent._workflow_handleCallback(callback);\n }\n\n /**\n * Report progress to the Agent with typed progress data.\n * Triggers onWorkflowProgress() on the Agent.\n *\n * @param progress - Typed progress data\n *\n * @example\n * ```typescript\n * // Using default progress type\n * await this.reportProgress({ step: 'fetch', status: 'running' });\n * await this.reportProgress({ step: 'fetch', status: 'complete', percent: 0.5 });\n *\n * // With custom progress type\n * await this.reportProgress({ stage: 'extract', recordsProcessed: 100 });\n * ```\n */\n protected async reportProgress(progress: ProgressType): Promise<void> {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"progress\",\n progress: progress as DefaultProgress,\n timestamp: Date.now()\n });\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients via the Agent.\n * This is non-durable and may repeat on workflow retry.\n *\n * @param message - Message to broadcast (will be JSON-stringified)\n */\n protected broadcastToClients(message: unknown): void {\n this.agent._workflow_broadcast(message);\n }\n\n /**\n * Wait for approval from the Agent.\n * Handles rejection by reporting error (durably) and throwing WorkflowRejectedError.\n *\n * @param step - AgentWorkflowStep object\n * @param options - Wait options (timeout, eventType, stepName)\n * @returns Approval payload (throws WorkflowRejectedError if rejected)\n *\n * @example\n * ```typescript\n * const approval = await this.waitForApproval(step, { timeout: '7 days' });\n * // approval contains the payload from approveWorkflow()\n * ```\n */\n protected async waitForApproval<T = unknown>(\n step: AgentWorkflowStep,\n options?: WaitForApprovalOptions\n ): Promise<T> {\n const stepName = options?.stepName ?? \"wait-for-approval\";\n const eventType = options?.eventType ?? \"approval\";\n const timeout = options?.timeout;\n\n // Wait for the approval event\n // Note: Call reportProgress() before this method if you want to update progress\n const event = (await step.waitForEvent(stepName, {\n type: eventType,\n timeout\n })) as WorkflowStepEvent<{\n approved: boolean;\n reason?: string;\n metadata?: T;\n }>;\n\n try {\n const payload = event.payload;\n\n // Check if rejected\n if (!payload.approved) {\n const reason = payload.reason;\n await step.reportError(reason ?? \"Workflow rejected\");\n throw new WorkflowRejectedError(reason, this._workflowId);\n }\n\n // Return the approval metadata as the result\n return payload.metadata as T;\n } finally {\n disposeIfPresent(event);\n }\n }\n}\n\ntype DisposableResource = {\n [Symbol.dispose](): void;\n};\n\nfunction isDisposableResource(value: unknown): value is DisposableResource {\n return (\n !!value &&\n typeof value === \"object\" &&\n Symbol.dispose in value &&\n typeof value[Symbol.dispose] === \"function\"\n );\n}\n\nfunction disposeIfPresent(value: unknown): void {\n if (isDisposableResource(value)) {\n value[Symbol.dispose]();\n }\n}\n\n// Re-export types for convenience\nexport type {\n AgentWorkflowEvent,\n AgentWorkflowStep,\n WorkflowCallback,\n WorkflowCallbackType,\n WorkflowProgressCallback,\n WorkflowCompleteCallback,\n WorkflowErrorCallback,\n WorkflowEventCallback,\n DefaultProgress,\n WaitForApprovalOptions,\n ApprovalEventPayload,\n WorkflowStatus,\n WorkflowTrackingRow,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\n\nexport { WorkflowRejectedError } from \"./workflow-types\";\n"],"mappings":"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"}
|
|
@@ -1,5 +1,130 @@
|
|
|
1
1
|
import "./wire-types-CnMt6_HR.js";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
|
+
//#region src/chat/replay-batch.ts
|
|
4
|
+
/**
|
|
5
|
+
* Batches chunks replayed during stream resume.
|
|
6
|
+
*
|
|
7
|
+
* Replaying every chunk separately can exceed React's update limit. Adjacent
|
|
8
|
+
* deltas for the same message part are merged until the replay pauses or ends.
|
|
9
|
+
*/
|
|
10
|
+
var ReplayChunkBatch = class {
|
|
11
|
+
constructor(controller, closeWindow = (flush) => {
|
|
12
|
+
const timer = setTimeout(flush, 0);
|
|
13
|
+
return () => clearTimeout(timer);
|
|
14
|
+
}) {
|
|
15
|
+
this.controller = controller;
|
|
16
|
+
this.closeWindow = closeWindow;
|
|
17
|
+
this.chunks = [];
|
|
18
|
+
this.tailMergeKey = null;
|
|
19
|
+
}
|
|
20
|
+
get bufferedStartMessageId() {
|
|
21
|
+
return this.startMessageId;
|
|
22
|
+
}
|
|
23
|
+
get isEmpty() {
|
|
24
|
+
return this.chunks.length === 0;
|
|
25
|
+
}
|
|
26
|
+
push(chunk) {
|
|
27
|
+
const key = mergeKeyOf(chunk);
|
|
28
|
+
const tail = this.chunks[this.chunks.length - 1];
|
|
29
|
+
if (tail !== void 0 && key !== null && key === this.tailMergeKey) {
|
|
30
|
+
appendDeltaText(tail, chunk);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (this.chunks.length === 0) this.cancelWindow = this.closeWindow(() => {
|
|
34
|
+
this.cancelWindow = void 0;
|
|
35
|
+
this.flush();
|
|
36
|
+
});
|
|
37
|
+
if (chunk.type === "start") this.startMessageId = chunk.messageId;
|
|
38
|
+
this.chunks.push(chunk);
|
|
39
|
+
this.tailMergeKey = key;
|
|
40
|
+
}
|
|
41
|
+
discard() {
|
|
42
|
+
this.cancelWindow?.();
|
|
43
|
+
this.cancelWindow = void 0;
|
|
44
|
+
this.chunks = [];
|
|
45
|
+
this.tailMergeKey = null;
|
|
46
|
+
this.startMessageId = void 0;
|
|
47
|
+
}
|
|
48
|
+
flush() {
|
|
49
|
+
this.cancelWindow?.();
|
|
50
|
+
this.cancelWindow = void 0;
|
|
51
|
+
if (this.chunks.length === 0) return;
|
|
52
|
+
const batch = this.chunks;
|
|
53
|
+
this.chunks = [];
|
|
54
|
+
this.tailMergeKey = null;
|
|
55
|
+
this.startMessageId = void 0;
|
|
56
|
+
try {
|
|
57
|
+
for (const chunk of batch) this.controller.enqueue(chunk);
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
enqueueNow(chunk) {
|
|
61
|
+
this.controller.enqueue(chunk);
|
|
62
|
+
}
|
|
63
|
+
closeNow() {
|
|
64
|
+
this.controller.close();
|
|
65
|
+
}
|
|
66
|
+
errorNow(error) {
|
|
67
|
+
this.controller.error(error);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/** Buffers replay chunks and flushes them before live or boundary frames. */
|
|
71
|
+
function applyChatResponseFrame(batch, frame) {
|
|
72
|
+
const endsReplayBurst = frame.replay !== true || frame.done === true || frame.replayComplete === true;
|
|
73
|
+
const body = frame.body?.trim();
|
|
74
|
+
if (!body) {
|
|
75
|
+
if (endsReplayBurst) batch.flush();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
let chunk;
|
|
79
|
+
try {
|
|
80
|
+
chunk = JSON.parse(body);
|
|
81
|
+
} catch {
|
|
82
|
+
if (endsReplayBurst) batch.flush();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (endsReplayBurst) {
|
|
86
|
+
batch.flush();
|
|
87
|
+
batch.enqueueNow(chunk);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (supersedesBufferedPass(batch, chunk, frame)) batch.discard();
|
|
91
|
+
batch.push(chunk);
|
|
92
|
+
}
|
|
93
|
+
function supersedesBufferedPass(batch, chunk, frame) {
|
|
94
|
+
return chunk.type === "start" && frame.continuation !== true && chunk.messageId !== void 0 && chunk.messageId === batch.bufferedStartMessageId;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reports an error after buffered content. `controller.error()` would discard
|
|
98
|
+
* chunks that have not reached the consumer.
|
|
99
|
+
*/
|
|
100
|
+
function failChatStream(batch, message) {
|
|
101
|
+
if (batch.isEmpty) {
|
|
102
|
+
batch.errorNow(new Error(message));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
batch.flush();
|
|
106
|
+
batch.enqueueNow({
|
|
107
|
+
errorText: message,
|
|
108
|
+
type: "error"
|
|
109
|
+
});
|
|
110
|
+
batch.closeNow();
|
|
111
|
+
}
|
|
112
|
+
function mergeKeyOf(chunk) {
|
|
113
|
+
switch (chunk.type) {
|
|
114
|
+
case "text-delta":
|
|
115
|
+
case "reasoning-delta": return chunk.providerMetadata === void 0 ? `${chunk.type}\u0000${chunk.id}` : null;
|
|
116
|
+
case "tool-input-delta": return `tool-input-delta\u0000${chunk.toolCallId}`;
|
|
117
|
+
default: return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function appendDeltaText(target, source) {
|
|
121
|
+
if (target.type === "tool-input-delta" && source.type === "tool-input-delta") {
|
|
122
|
+
target.inputTextDelta += source.inputTextDelta;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if ((target.type === "text-delta" || target.type === "reasoning-delta") && (source.type === "text-delta" || source.type === "reasoning-delta")) target.delta += source.delta;
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
3
128
|
//#region src/chat/ws-chat-transport.ts
|
|
4
129
|
/**
|
|
5
130
|
* Short safety-net timeout for a resume probe when the server has said nothing.
|
|
@@ -362,6 +487,7 @@ var WebSocketChatTransport = class {
|
|
|
362
487
|
let completed = false;
|
|
363
488
|
let requestId = null;
|
|
364
489
|
let readerController = null;
|
|
490
|
+
let replayBatch = null;
|
|
365
491
|
const probeId = nanoid(8);
|
|
366
492
|
let onResumeRef = null;
|
|
367
493
|
let onResumeNoneRef = null;
|
|
@@ -406,13 +532,18 @@ var WebSocketChatTransport = class {
|
|
|
406
532
|
this._abortToolContinuation = abortToolContinuationRef;
|
|
407
533
|
detachResumeStreamRef = () => {
|
|
408
534
|
if (completed) return false;
|
|
409
|
-
finish(() =>
|
|
535
|
+
finish(() => {
|
|
536
|
+
replayBatch?.flush();
|
|
537
|
+
readerController?.close();
|
|
538
|
+
});
|
|
410
539
|
return true;
|
|
411
540
|
};
|
|
412
541
|
this._detachResumeStream = detachResumeStreamRef;
|
|
413
542
|
return new ReadableStream({
|
|
414
543
|
start(controller) {
|
|
415
544
|
readerController = controller;
|
|
545
|
+
const batch = new ReplayChunkBatch(controller);
|
|
546
|
+
replayBatch = batch;
|
|
416
547
|
let timeout;
|
|
417
548
|
const armTimeout = (delay) => {
|
|
418
549
|
if (timeout) clearTimeout(timeout);
|
|
@@ -461,17 +592,17 @@ var WebSocketChatTransport = class {
|
|
|
461
592
|
const data = JSON.parse(event.data);
|
|
462
593
|
if (data.type !== "cf_agent_use_chat_response" || requestId == null || data.id !== requestId) return;
|
|
463
594
|
if (data.error) {
|
|
464
|
-
finish(() =>
|
|
595
|
+
finish(() => failChatStream(batch, data.body || "Stream error"));
|
|
465
596
|
return;
|
|
466
597
|
}
|
|
467
|
-
|
|
468
|
-
const chunk = JSON.parse(data.body);
|
|
469
|
-
controller.enqueue(chunk);
|
|
470
|
-
} catch {}
|
|
598
|
+
applyChatResponseFrame(batch, data);
|
|
471
599
|
if (data.done) finish(() => controller.close());
|
|
472
600
|
} catch {}
|
|
473
601
|
};
|
|
474
|
-
const onClose = () => finish(() =>
|
|
602
|
+
const onClose = () => finish(() => {
|
|
603
|
+
batch.flush();
|
|
604
|
+
controller.close();
|
|
605
|
+
});
|
|
475
606
|
agent.addEventListener("message", onMessage, { signal: streamController.signal });
|
|
476
607
|
agent.addEventListener("close", onClose, { signal: streamController.signal });
|
|
477
608
|
retryResumeProbe();
|
|
@@ -508,6 +639,7 @@ var WebSocketChatTransport = class {
|
|
|
508
639
|
chunkController.abort();
|
|
509
640
|
};
|
|
510
641
|
let streamController = null;
|
|
642
|
+
let replayBatch = null;
|
|
511
643
|
const cancelActiveRequest = () => {
|
|
512
644
|
if (completed) return false;
|
|
513
645
|
finish(() => streamController?.error(abortError), true);
|
|
@@ -517,31 +649,36 @@ var WebSocketChatTransport = class {
|
|
|
517
649
|
const transport = this;
|
|
518
650
|
detachResumeStream = () => {
|
|
519
651
|
if (completed) return false;
|
|
520
|
-
finish(() =>
|
|
652
|
+
finish(() => {
|
|
653
|
+
replayBatch?.flush();
|
|
654
|
+
streamController?.close();
|
|
655
|
+
});
|
|
521
656
|
return true;
|
|
522
657
|
};
|
|
523
658
|
this._detachResumeStream = detachResumeStream;
|
|
524
659
|
return new ReadableStream({
|
|
525
660
|
start(controller) {
|
|
526
661
|
streamController = controller;
|
|
662
|
+
const batch = new ReplayChunkBatch(controller);
|
|
663
|
+
replayBatch = batch;
|
|
527
664
|
const onMessage = (event) => {
|
|
528
665
|
try {
|
|
529
666
|
const data = JSON.parse(event.data);
|
|
530
667
|
if (data.type !== "cf_agent_use_chat_response") return;
|
|
531
668
|
if (data.id !== requestId) return;
|
|
532
669
|
if (data.error) {
|
|
533
|
-
finish(() =>
|
|
670
|
+
finish(() => failChatStream(batch, data.body || "Stream error"));
|
|
534
671
|
return;
|
|
535
672
|
}
|
|
536
|
-
|
|
537
|
-
const chunk = JSON.parse(data.body);
|
|
538
|
-
controller.enqueue(chunk);
|
|
539
|
-
} catch {}
|
|
673
|
+
applyChatResponseFrame(batch, data);
|
|
540
674
|
if (data.done) finish(() => controller.close());
|
|
541
675
|
} catch {}
|
|
542
676
|
};
|
|
543
677
|
const onClose = () => {
|
|
544
|
-
finish(() =>
|
|
678
|
+
finish(() => {
|
|
679
|
+
batch.flush();
|
|
680
|
+
controller.close();
|
|
681
|
+
}, false, false);
|
|
545
682
|
};
|
|
546
683
|
agent.addEventListener("message", onMessage, { signal: chunkController.signal });
|
|
547
684
|
agent.addEventListener("close", onClose, { signal: chunkController.signal });
|
|
@@ -558,4 +695,4 @@ var WebSocketChatTransport = class {
|
|
|
558
695
|
//#endregion
|
|
559
696
|
export { WebSocketChatTransport as t };
|
|
560
697
|
|
|
561
|
-
//# sourceMappingURL=ws-chat-transport-
|
|
698
|
+
//# sourceMappingURL=ws-chat-transport-rWwta645.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-chat-transport-rWwta645.js","names":[],"sources":["../src/chat/replay-batch.ts","../src/chat/ws-chat-transport.ts"],"sourcesContent":["import type { UIMessageChunk } from \"ai\";\n\n/**\n * Batches chunks replayed during stream resume.\n *\n * Replaying every chunk separately can exceed React's update limit. Adjacent\n * deltas for the same message part are merged until the replay pauses or ends.\n */\nexport class ReplayChunkBatch {\n private chunks: UIMessageChunk[] = [];\n private tailMergeKey: string | null = null;\n private cancelWindow: (() => void) | undefined;\n private startMessageId: string | undefined;\n\n constructor(\n private readonly controller: ReadableStreamDefaultController<UIMessageChunk>,\n private readonly closeWindow: (flush: () => void) => () => void = (\n flush\n ) => {\n const timer = setTimeout(flush, 0);\n return () => clearTimeout(timer);\n }\n ) {}\n\n get bufferedStartMessageId(): string | undefined {\n return this.startMessageId;\n }\n\n get isEmpty(): boolean {\n return this.chunks.length === 0;\n }\n\n push(chunk: UIMessageChunk): void {\n const key = mergeKeyOf(chunk);\n const tail = this.chunks[this.chunks.length - 1];\n\n if (tail !== undefined && key !== null && key === this.tailMergeKey) {\n appendDeltaText(tail, chunk);\n return;\n }\n\n if (this.chunks.length === 0) {\n this.cancelWindow = this.closeWindow(() => {\n this.cancelWindow = undefined;\n this.flush();\n });\n }\n\n if (chunk.type === \"start\") {\n this.startMessageId = chunk.messageId;\n }\n this.chunks.push(chunk);\n this.tailMergeKey = key;\n }\n\n discard(): void {\n this.cancelWindow?.();\n this.cancelWindow = undefined;\n this.chunks = [];\n this.tailMergeKey = null;\n this.startMessageId = undefined;\n }\n\n flush(): void {\n this.cancelWindow?.();\n this.cancelWindow = undefined;\n\n if (this.chunks.length === 0) return;\n const batch = this.chunks;\n this.chunks = [];\n this.tailMergeKey = null;\n this.startMessageId = undefined;\n try {\n for (const chunk of batch) {\n this.controller.enqueue(chunk);\n }\n } catch {\n // The stream is already closed; callers still need to finish cleanup.\n }\n }\n\n enqueueNow(chunk: UIMessageChunk): void {\n this.controller.enqueue(chunk);\n }\n\n closeNow(): void {\n this.controller.close();\n }\n\n errorNow(error: Error): void {\n this.controller.error(error);\n }\n}\n\ntype ChatResponseFrame = {\n body?: string;\n continuation?: boolean;\n done?: boolean;\n replay?: boolean;\n replayComplete?: boolean;\n};\n\n/** Buffers replay chunks and flushes them before live or boundary frames. */\nexport function applyChatResponseFrame(\n batch: ReplayChunkBatch,\n frame: ChatResponseFrame\n): void {\n const endsReplayBurst =\n frame.replay !== true ||\n frame.done === true ||\n frame.replayComplete === true;\n\n const body = frame.body?.trim();\n if (!body) {\n if (endsReplayBurst) batch.flush();\n return;\n }\n\n let chunk: UIMessageChunk;\n try {\n chunk = JSON.parse(body) as UIMessageChunk;\n } catch {\n // Do not leave buffered chunks behind a malformed boundary frame.\n if (endsReplayBurst) batch.flush();\n return;\n }\n\n if (endsReplayBurst) {\n batch.flush();\n batch.enqueueNow(chunk);\n return;\n }\n\n if (supersedesBufferedPass(batch, chunk, frame)) {\n batch.discard();\n }\n\n batch.push(chunk);\n}\n\nfunction supersedesBufferedPass(\n batch: ReplayChunkBatch,\n chunk: UIMessageChunk,\n frame: ChatResponseFrame\n): boolean {\n return (\n chunk.type === \"start\" &&\n frame.continuation !== true &&\n chunk.messageId !== undefined &&\n chunk.messageId === batch.bufferedStartMessageId\n );\n}\n\n/**\n * Reports an error after buffered content. `controller.error()` would discard\n * chunks that have not reached the consumer.\n */\nexport function failChatStream(batch: ReplayChunkBatch, message: string): void {\n if (batch.isEmpty) {\n batch.errorNow(new Error(message));\n return;\n }\n\n batch.flush();\n batch.enqueueNow({ errorText: message, type: \"error\" });\n batch.closeNow();\n}\n\nfunction mergeKeyOf(chunk: UIMessageChunk): string | null {\n switch (chunk.type) {\n case \"text-delta\":\n case \"reasoning-delta\":\n return chunk.providerMetadata === undefined\n ? `${chunk.type}\\u0000${chunk.id}`\n : null;\n case \"tool-input-delta\":\n return `tool-input-delta\\u0000${chunk.toolCallId}`;\n default:\n return null;\n }\n}\n\nfunction appendDeltaText(target: UIMessageChunk, source: UIMessageChunk): void {\n if (\n target.type === \"tool-input-delta\" &&\n source.type === \"tool-input-delta\"\n ) {\n target.inputTextDelta += source.inputTextDelta;\n return;\n }\n if (\n (target.type === \"text-delta\" || target.type === \"reasoning-delta\") &&\n (source.type === \"text-delta\" || source.type === \"reasoning-delta\")\n ) {\n target.delta += source.delta;\n }\n}\n","/**\n * Framework-neutral WebSocket transport for AI SDK chat clients.\n *\n * Speaks the CF_AGENT protocol directly and returns AI SDK UI message chunks\n * without reconstructing an HTTP response or parsing an SSE stream.\n */\n\nimport type { ChatTransport, UIMessage, UIMessageChunk } from \"ai\";\nimport { nanoid } from \"nanoid\";\nimport {\n applyChatResponseFrame,\n failChatStream,\n ReplayChunkBatch\n} from \"./replay-batch\";\nimport { MessageType, type OutgoingMessage } from \"./wire-types\";\n\n/**\n * Short safety-net timeout for a resume probe when the server has said nothing.\n * Under normal operation the server answers a `STREAM_RESUME_REQUEST` with\n * `STREAM_RESUMING`, `STREAM_RESUME_NONE`, or `STREAM_PENDING` well before this.\n */\nconst RESUME_PROBE_TIMEOUT_MS = 5000;\n\n/**\n * Extended backstop applied once the server says a turn is pending\n * (`STREAM_PENDING`, #1784). The pre-stream window (queueing, MCP setup,\n * debounce, model latency) can exceed the short probe timeout, and the server\n * guarantees a follow-up `STREAM_RESUMING` or `STREAM_RESUME_NONE` — so we wait\n * much longer (refreshed on every keep-waiting frame) but still cap it so a\n * dropped follow-up degrades to a null resolve instead of hanging forever.\n */\nconst RESUME_PENDING_TIMEOUT_MS = 60000;\n\n/**\n * Agent-like interface for sending/receiving WebSocket messages.\n * Matches `AgentClient` from `agents/client` and the connection returned by\n * `useAgent` from `agents/react`.\n */\nexport interface AgentConnection {\n send: (data: string) => void;\n addEventListener: (\n type: string,\n listener: (event: MessageEvent) => void,\n options?: { signal?: AbortSignal }\n ) => void;\n removeEventListener: (\n type: string,\n listener: (event: MessageEvent) => void\n ) => void;\n}\n\nexport type WebSocketChatTransportOptions<\n ChatMessage extends UIMessage = UIMessage\n> = {\n /** The framework-neutral AgentClient or useAgent connection. */\n agent: AgentConnection;\n /**\n * Callback to add custom fields to the request body before sending.\n */\n prepareBody?: (options: {\n messages: ChatMessage[];\n trigger: \"submit-message\" | \"regenerate-message\";\n messageId?: string;\n }) => Promise<Record<string, unknown>> | Record<string, unknown>;\n /**\n * Optional set to track active request IDs.\n * IDs are added when a request starts and removed when it completes.\n * Used by the onAgentMessage handler to skip messages already handled by the transport.\n */\n activeRequestIds?: Set<string>;\n /**\n * Whether generic client-side abort/cancel lifecycle should cancel the\n * server turn. Explicit cancellation via cancelActiveServerTurn() always\n * sends CF_AGENT_CHAT_REQUEST_CANCEL.\n * @default false\n */\n cancelOnClientAbort?: boolean;\n};\n\n/**\n * ChatTransport that sends messages over WebSocket and returns a\n * ReadableStream<UIMessageChunk> that the AI SDK's useChat consumes directly.\n *\n * This low-level transport handles new and regenerated request streams plus\n * cancellation. Higher-level protocol coordination such as automatic reconnect\n * resume, cross-tab transcript synchronization, and client-tool continuations\n * is provided by integrations such as `useAgentChat`.\n */\nexport class WebSocketChatTransport<\n ChatMessage extends UIMessage = UIMessage\n> implements ChatTransport<ChatMessage> {\n agent: AgentConnection;\n private prepareBody?: WebSocketChatTransportOptions<ChatMessage>[\"prepareBody\"];\n private activeRequestIds?: Set<string>;\n private cancelOnClientAbort: boolean;\n\n // Pending resume resolver — set by reconnectToStream, called by\n // handleStreamResuming when onAgentMessage sees CF_AGENT_STREAM_RESUMING.\n private _resumeResolver: ((data: { id: string }) => void) | null = null;\n // Pending \"no stream\" resolver — called by handleStreamResumeNone\n // when onAgentMessage sees CF_AGENT_STREAM_RESUME_NONE.\n private _resumeNoneResolver:\n | ((data: { probeId?: string }) => boolean)\n | null = null;\n // Keep-waiting hook (#1784) — set by whichever resume path is currently\n // awaiting, called by handleStreamPending when onAgentMessage sees\n // CF_AGENT_STREAM_PENDING. Extends the path's probe timeout so a slow\n // pre-stream window (queue / MCP / model latency) does not resolve early.\n private _onStreamPending: (() => void) | null = null;\n // Retransmits the current handshake on a replacement socket without starting\n // a second AI SDK resume request. Set only while a resolver is active.\n private _retryResumeProbe: (() => void) | null = null;\n // Set when a client-side tool result/approval is expected to trigger\n // a new continuation stream. In this mode reconnectToStream() returns\n // a deferred ReadableStream immediately so AI SDK status can transition\n // to \"submitted\" before the server starts streaming.\n private _expectToolContinuation = false;\n private _abortToolContinuation: (() => boolean) | null = null;\n private _activeServerTurnId: string | null = null;\n private _cancelAttachedStream: (() => boolean) | null = null;\n // Local-only detach for a resume stream owned by an obsolete Chat/agent\n // generation. Unlike explicit cancellation, this never cancels server work.\n private _detachResumeStream: (() => boolean) | null = null;\n\n constructor(options: WebSocketChatTransportOptions<ChatMessage>) {\n this.agent = options.agent;\n this.prepareBody = options.prepareBody;\n this.activeRequestIds = options.activeRequestIds;\n this.cancelOnClientAbort = options.cancelOnClientAbort ?? false;\n }\n\n /**\n * Point the singleton transport at a new Agent connection. A pending resolver\n * belongs to the old Chat/socket generation and must settle before messages\n * from the replacement connection can be consumed (#1914 review).\n */\n setAgent(agent: AgentConnection) {\n if (this.agent === agent) return;\n this.resetResumeState();\n this.agent = agent;\n }\n\n setCancelOnClientAbort(cancelOnClientAbort: boolean) {\n this.cancelOnClientAbort = cancelOnClientAbort;\n }\n\n /**\n * Explicitly cancel the active server turn, if any.\n * This is separate from generic client-side abort/cancel lifecycle so\n * clients can detach locally without stopping server work.\n */\n cancelActiveServerTurn(): boolean {\n const requestId = this._activeServerTurnId;\n let cancelledRequest = false;\n\n if (requestId) {\n this.sendCancelFrame(requestId);\n this._cancelAttachedStream?.();\n this.clearActiveServerTurn(requestId);\n cancelledRequest = true;\n }\n\n const cancelledToolContinuation = this.abortActiveToolContinuation();\n return cancelledRequest || cancelledToolContinuation;\n }\n\n private sendCancelFrame(requestId: string) {\n try {\n this.agent.send(\n JSON.stringify({\n id: requestId,\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL\n })\n );\n } catch {\n // Ignore failures (e.g. agent already disconnected)\n }\n }\n\n private setActiveServerTurn(\n requestId: string,\n cancelAttachedStream: (() => boolean) | null\n ) {\n this._activeServerTurnId = requestId;\n this._cancelAttachedStream = cancelAttachedStream;\n }\n\n private clearActiveServerTurn(requestId: string) {\n if (this._activeServerTurnId === requestId) {\n this._activeServerTurnId = null;\n this._cancelAttachedStream = null;\n }\n }\n\n /**\n * Mark that the next reconnectToStream() call should attach to a\n * server-initiated tool continuation rather than a page-load resume.\n */\n expectToolContinuation() {\n this._expectToolContinuation = true;\n }\n\n /**\n * Abort the active client-side tool continuation stream, if one is attached\n * to a server request id.\n */\n abortActiveToolContinuation(): boolean {\n return this._abortToolContinuation?.() ?? false;\n }\n\n /**\n * True when the transport is waiting for a resume handshake.\n */\n isAwaitingResume(): boolean {\n return this._resumeResolver !== null || this._resumeNoneResolver !== null;\n }\n\n /**\n * Settle and detach the current handshake without interpreting it as a\n * server-idle response. Used when the owning hook/agent generation changes.\n */\n cancelPendingResume(): boolean {\n const resolveNone = this._resumeNoneResolver;\n if (!resolveNone) return false;\n return resolveNone({});\n }\n\n /**\n * Invalidate all client-side resume state for an obsolete hook/agent\n * generation without cancelling its durable server turn.\n */\n resetResumeState(): void {\n this._expectToolContinuation = false;\n this.cancelPendingResume();\n this._detachResumeStream?.();\n }\n\n /**\n * Re-send the active handshake request on the latest socket generation. This\n * preserves one AI SDK resume operation while recovering a request/reply lost\n * with the previous WebSocket.\n */\n retryPendingResume(): boolean {\n const retry = this._retryResumeProbe;\n if (!retry) return false;\n retry();\n return true;\n }\n\n /**\n * Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUMING.\n * If reconnectToStream is waiting, this handles the resume handshake\n * (ACK + stream creation) and returns true. Otherwise returns false\n * so the caller can use its own fallback path.\n */\n handleStreamResuming(data: { id: string }): boolean {\n if (!this._resumeResolver) return false;\n this._resumeResolver(data);\n return true;\n }\n\n /**\n * Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUME_NONE.\n * If reconnectToStream is waiting, resolves the promise with null\n * immediately (no 5-second timeout). Returns true if handled.\n */\n handleStreamResumeNone(data: { probeId?: string } = {}): boolean {\n if (!this._resumeNoneResolver) return false;\n return this._resumeNoneResolver(data);\n }\n\n /**\n * Called by onAgentMessage when it receives CF_AGENT_STREAM_PENDING (#1784):\n * the server accepted a turn but its stream has not started yet. If a resume\n * path is awaiting, extend its probe timeout (so it keeps waiting for the\n * eventual STREAM_RESUMING / STREAM_RESUME_NONE instead of resolving null\n * after the short window). Returns true if a waiting path consumed it.\n */\n handleStreamPending(): boolean {\n if (!this._onStreamPending) return false;\n this._onStreamPending();\n return true;\n }\n\n /**\n * Called by the hook's shared message handler when a server turn finishes\n * outside the currently attached transport stream, such as after local-only\n * client cleanup.\n */\n handleServerTurnCompleted(requestId: string) {\n this.clearActiveServerTurn(requestId);\n }\n\n /**\n * Register a server turn that is being rendered outside a transport-owned\n * stream, such as the hook's fallback cross-tab/resume observer path.\n */\n observeServerTurn(requestId: string) {\n this.setActiveServerTurn(requestId, null);\n }\n\n async sendMessages(options: {\n chatId: string;\n messages: ChatMessage[];\n abortSignal: AbortSignal | undefined;\n trigger: \"submit-message\" | \"regenerate-message\";\n messageId?: string;\n body?: object;\n headers?: Record<string, string> | Headers;\n metadata?: unknown;\n }): Promise<ReadableStream<UIMessageChunk>> {\n const requestId = nanoid(8);\n const abortController = new AbortController();\n let completed = false;\n let requestSent = false;\n\n // Build the request body\n let extraBody: Record<string, unknown> = {};\n if (this.prepareBody) {\n extraBody = await this.prepareBody({\n messages: options.messages,\n trigger: options.trigger,\n messageId: options.messageId\n });\n }\n if (options.body) {\n extraBody = {\n ...extraBody,\n ...(options.body as Record<string, unknown>)\n };\n }\n\n const bodyPayload = JSON.stringify({\n messages: options.messages,\n trigger: options.trigger,\n ...extraBody\n });\n\n // Track this request so the onAgentMessage handler skips it\n this.activeRequestIds?.add(requestId);\n\n // Create a ReadableStream<UIMessageChunk> that emits parsed chunks\n // as they arrive over the WebSocket\n const agent = this.agent;\n const activeIds = this.activeRequestIds;\n\n // Single cleanup helper — every terminal path (done, error, abort)\n // goes through here exactly once.\n // keepId: when true, do NOT remove requestId from activeIds. Used by\n // explicit cancellation so onAgentMessage skips in-flight chunks\n // and the server's final done:true signal until cleanup happens there.\n const finish = (\n action: () => void,\n keepId = false,\n clearServerTurn = true\n ) => {\n if (completed) return;\n completed = true;\n if (clearServerTurn) {\n this.clearActiveServerTurn(requestId);\n }\n try {\n action();\n } catch {\n // Stream may already be closed\n }\n if (!keepId) {\n activeIds?.delete(requestId);\n }\n abortController.abort();\n };\n\n const abortError = new Error(\"Aborted\");\n abortError.name = \"AbortError\";\n\n const cancelActiveRequest = () => {\n if (completed) return false;\n finish(() => streamController.error(abortError), true);\n return true;\n };\n this.setActiveServerTurn(requestId, cancelActiveRequest);\n\n // Abort handler: terminate the local stream. By default, generic AI SDK\n // abort/cancel lifecycle is local-only so durable server turns can continue\n // and be resumed. Use cancelActiveServerTurn() for explicit user/app\n // cancellation, or cancelOnClientAbort for request-lifetime semantics.\n const onAbort = () => {\n if (completed) return;\n if (this.cancelOnClientAbort) {\n if (requestSent) {\n this.sendCancelFrame(requestId);\n }\n finish(() => streamController.error(abortError), requestSent);\n } else {\n finish(() => streamController.error(abortError), false, !requestSent);\n }\n };\n\n // streamController is assigned synchronously by start(), so it is\n // always available by the time onAbort or onMessage can fire.\n let streamController!: ReadableStreamDefaultController<UIMessageChunk>;\n\n const stream = new ReadableStream<UIMessageChunk>({\n start(controller) {\n streamController = controller;\n\n const onMessage = (event: MessageEvent) => {\n try {\n const data = JSON.parse(\n event.data as string\n ) as OutgoingMessage<ChatMessage>;\n\n if (data.type !== MessageType.CF_AGENT_USE_CHAT_RESPONSE) return;\n if (data.id !== requestId) return;\n\n if (data.error) {\n finish(() =>\n controller.error(new Error(data.body || \"Stream error\"))\n );\n return;\n }\n\n // Parse the body as UIMessageChunk and enqueue\n if (data.body?.trim()) {\n try {\n const chunk = JSON.parse(data.body) as UIMessageChunk;\n controller.enqueue(chunk);\n } catch {\n // Skip malformed chunk bodies\n }\n }\n\n if (data.done) {\n finish(() => controller.close());\n }\n } catch {\n // Ignore non-JSON messages\n }\n };\n\n const onClose = () => {\n finish(() => controller.close(), false, false);\n };\n\n agent.addEventListener(\"message\", onMessage, {\n signal: abortController.signal\n });\n agent.addEventListener(\"close\", onClose, {\n signal: abortController.signal\n });\n },\n cancel() {\n onAbort();\n }\n });\n\n // Handle abort from the caller\n if (options.abortSignal) {\n options.abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n if (options.abortSignal.aborted) onAbort();\n }\n\n if (completed) {\n return stream;\n }\n\n // Send the request over WebSocket\n requestSent = true;\n agent.send(\n JSON.stringify({\n id: requestId,\n init: {\n method: \"POST\",\n body: bodyPayload\n },\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST\n })\n );\n\n return stream;\n }\n\n async reconnectToStream(_options: {\n chatId: string;\n }): Promise<ReadableStream<UIMessageChunk> | null> {\n // A transport has one handshake slot. Returning null for an unexpected\n // concurrent caller is safer than overwriting callbacks owned by the first\n // AI SDK request (StrictMode/manual overlap); the hook serializes its normal\n // mount, tool, public, and reconnect entry points.\n if (this.isAwaitingResume()) return null;\n\n if (this._expectToolContinuation) {\n this._expectToolContinuation = false;\n return this._createToolContinuationStream();\n }\n\n // Detect whether the server has an active stream for this chat.\n // Instead of registering another message listener (which races with the\n // hook), expose identity-owned callbacks consumed synchronously by the\n // shared handler.\n const activeIds = this.activeRequestIds;\n const probeId = nanoid(8);\n\n return new Promise<ReadableStream<UIMessageChunk> | null>((resolve) => {\n let resolved = false;\n let timeout: ReturnType<typeof setTimeout> | undefined;\n let resumeResolver: ((data: { id: string }) => void) | null = null;\n let resumeNoneResolver: ((data: { probeId?: string }) => boolean) | null =\n null;\n let onStreamPending: (() => void) | null = null;\n let retryResumeProbe: (() => void) | null = null;\n\n const clearOwnedCallbacks = () => {\n if (resumeResolver && this._resumeResolver === resumeResolver) {\n this._resumeResolver = null;\n }\n if (\n resumeNoneResolver &&\n this._resumeNoneResolver === resumeNoneResolver\n ) {\n this._resumeNoneResolver = null;\n }\n if (onStreamPending && this._onStreamPending === onStreamPending) {\n this._onStreamPending = null;\n }\n if (retryResumeProbe && this._retryResumeProbe === retryResumeProbe) {\n this._retryResumeProbe = null;\n }\n };\n\n const done = (value: ReadableStream<UIMessageChunk> | null) => {\n if (resolved) return;\n resolved = true;\n clearOwnedCallbacks();\n if (timeout) clearTimeout(timeout);\n resolve(value);\n };\n\n const armTimeout = (delay: number) => {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => done(null), delay);\n };\n\n // Keep-waiting (#1784): the server says a turn is accepted but its stream\n // has not started. Extend this operation's own timeout only.\n onStreamPending = () => {\n if (resolved) return;\n armTimeout(RESUME_PENDING_TIMEOUT_MS);\n };\n\n resumeNoneResolver = (data) => {\n if (data.probeId && data.probeId !== probeId) return false;\n done(null);\n return true;\n };\n\n resumeResolver = (data: { id: string }) => {\n const requestId = data.id;\n activeIds?.add(requestId);\n const stream = this._createResumeStream(requestId);\n\n this.agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STREAM_RESUME_ACK,\n id: requestId\n })\n );\n\n done(stream);\n };\n\n // Re-arm both the request and timeout on each replacement socket. This is\n // a retransmission of this resolver's handshake, not a second Chat resume.\n retryResumeProbe = () => {\n if (resolved) return;\n armTimeout(RESUME_PROBE_TIMEOUT_MS);\n try {\n this.agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STREAM_RESUME_REQUEST,\n probeId\n })\n );\n } catch {\n // The next socket open retries again; the timeout remains a backstop.\n }\n };\n\n this._onStreamPending = onStreamPending;\n this._resumeNoneResolver = resumeNoneResolver;\n this._resumeResolver = resumeResolver;\n this._retryResumeProbe = retryResumeProbe;\n retryResumeProbe();\n });\n }\n\n /**\n * Creates a deferred ReadableStream for client-side tool continuations.\n * The stream is returned immediately so AI SDK status becomes \"submitted\"\n * right after addToolOutput()/addToolApprovalResponse(), then it waits for\n * the server to announce the continuation via STREAM_RESUMING.\n */\n private _createToolContinuationStream(): ReadableStream<UIMessageChunk> {\n const agent = this.agent;\n const activeIds = this.activeRequestIds;\n const streamController = new AbortController();\n const abortError = new Error(\"Aborted\");\n abortError.name = \"AbortError\";\n let completed = false;\n let requestId: string | null = null;\n let readerController: ReadableStreamDefaultController<UIMessageChunk> | null =\n null;\n // Held outside start() so the close and detach paths can flush replayed\n // content before they close the stream.\n let replayBatch: ReplayChunkBatch | null = null;\n const probeId = nanoid(8);\n let onResumeRef: ((data: { id: string }) => void) | null = null;\n let onResumeNoneRef: ((data: { probeId?: string }) => boolean) | null =\n null;\n let onStreamPendingRef: (() => void) | null = null;\n let retryResumeProbeRef: (() => void) | null = null;\n let abortToolContinuationRef: (() => boolean) | null = null;\n let detachResumeStreamRef: (() => boolean) | null = null;\n\n const clearOwnedHandshake = () => {\n if (onResumeRef && this._resumeResolver === onResumeRef) {\n this._resumeResolver = null;\n }\n if (onResumeNoneRef && this._resumeNoneResolver === onResumeNoneRef) {\n this._resumeNoneResolver = null;\n }\n if (onStreamPendingRef && this._onStreamPending === onStreamPendingRef) {\n this._onStreamPending = null;\n }\n if (\n retryResumeProbeRef &&\n this._retryResumeProbe === retryResumeProbeRef\n ) {\n this._retryResumeProbe = null;\n }\n };\n\n const finish = (action: () => void, keepRequestId = false) => {\n if (completed) return;\n completed = true;\n if (this._abortToolContinuation === abortToolContinuationRef) {\n this._abortToolContinuation = null;\n }\n if (this._detachResumeStream === detachResumeStreamRef) {\n this._detachResumeStream = null;\n }\n clearOwnedHandshake();\n try {\n action();\n } catch {\n // Stream may already be closed\n }\n if (requestId && !keepRequestId) {\n activeIds?.delete(requestId);\n }\n streamController.abort();\n };\n\n const transport = this;\n\n abortToolContinuationRef = () => {\n if (completed) return false;\n\n if (requestId === null) {\n finish(() => readerController?.error(abortError));\n return true;\n }\n\n try {\n agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL,\n id: requestId\n })\n );\n } catch {\n // Ignore failures (e.g. agent already disconnected)\n }\n\n // Keep the ID so the shared message handler ignores in-flight chunks\n // until the server's terminal frame performs its normal cleanup.\n finish(() => readerController?.error(abortError), true);\n return true;\n };\n this._abortToolContinuation = abortToolContinuationRef;\n detachResumeStreamRef = () => {\n if (completed) return false;\n finish(() => {\n replayBatch?.flush();\n readerController?.close();\n });\n return true;\n };\n this._detachResumeStream = detachResumeStreamRef;\n\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n readerController = controller;\n const batch = new ReplayChunkBatch(controller);\n replayBatch = batch;\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n const armTimeout = (delay: number) => {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => finish(() => controller.close()), delay);\n };\n\n const onResumeNone = (data: { probeId?: string }) => {\n if (data.probeId && data.probeId !== probeId) return false;\n finish(() => controller.close());\n return true;\n };\n\n const onResume = (data: { id: string }) => {\n if (requestId) return;\n\n requestId = data.id;\n activeIds?.add(requestId);\n clearOwnedHandshake();\n if (timeout) clearTimeout(timeout);\n\n agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STREAM_RESUME_ACK,\n id: requestId\n })\n );\n };\n\n const onStreamPending = () => {\n if (completed) return;\n armTimeout(RESUME_PENDING_TIMEOUT_MS);\n };\n\n const retryResumeProbe = () => {\n if (completed || requestId !== null) return;\n armTimeout(RESUME_PROBE_TIMEOUT_MS);\n try {\n transport.agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STREAM_RESUME_REQUEST,\n probeId\n })\n );\n } catch {\n // A later socket open can retry this same deferred handshake.\n }\n };\n\n onResumeRef = onResume;\n onResumeNoneRef = onResumeNone;\n onStreamPendingRef = onStreamPending;\n retryResumeProbeRef = retryResumeProbe;\n transport._resumeResolver = onResume;\n transport._resumeNoneResolver = onResumeNone;\n transport._onStreamPending = onStreamPending;\n transport._retryResumeProbe = retryResumeProbe;\n\n const onMessage = (event: MessageEvent) => {\n try {\n const data = JSON.parse(\n event.data as string\n ) as OutgoingMessage<UIMessage>;\n\n if (\n data.type !== MessageType.CF_AGENT_USE_CHAT_RESPONSE ||\n requestId == null ||\n data.id !== requestId\n ) {\n return;\n }\n\n if (data.error) {\n finish(() => failChatStream(batch, data.body || \"Stream error\"));\n return;\n }\n\n applyChatResponseFrame(batch, data);\n\n if (data.done) {\n finish(() => controller.close());\n }\n } catch {\n // Ignore non-JSON messages\n }\n };\n\n const onClose = () =>\n finish(() => {\n batch.flush();\n controller.close();\n });\n\n agent.addEventListener(\"message\", onMessage, {\n signal: streamController.signal\n });\n agent.addEventListener(\"close\", onClose, {\n signal: streamController.signal\n });\n\n retryResumeProbe();\n },\n cancel() {\n if (requestId && transport.cancelOnClientAbort) {\n transport.sendCancelFrame(requestId);\n finish(() => {}, true);\n } else {\n finish(() => {});\n }\n }\n });\n }\n\n /**\n * Creates a ReadableStream that receives resumed stream chunks\n * and forwards them to useChat as UIMessageChunk objects.\n */\n private _createResumeStream(\n requestId: string\n ): ReadableStream<UIMessageChunk> {\n // Read agent at resolve time (not when reconnectToStream was called)\n // so chunk listener attaches to the latest socket after _pk changes.\n const agent = this.agent;\n const activeIds = this.activeRequestIds;\n const chunkController = new AbortController();\n const abortError = new Error(\"Aborted\");\n abortError.name = \"AbortError\";\n let completed = false;\n let detachResumeStream: (() => boolean) | null = null;\n\n const finish = (\n action: () => void,\n keepId = false,\n clearServerTurn = true\n ) => {\n if (completed) return;\n completed = true;\n if (clearServerTurn) {\n this.clearActiveServerTurn(requestId);\n }\n if (this._detachResumeStream === detachResumeStream) {\n this._detachResumeStream = null;\n }\n try {\n action();\n } catch {\n // Stream may already be closed\n }\n if (!keepId) {\n activeIds?.delete(requestId);\n }\n chunkController.abort();\n };\n\n let streamController: ReadableStreamDefaultController<UIMessageChunk> | null =\n null;\n // Held outside start() so the close and detach paths can flush replayed\n // content before they close the stream.\n let replayBatch: ReplayChunkBatch | null = null;\n const cancelActiveRequest = () => {\n if (completed) return false;\n finish(() => streamController?.error(abortError), true);\n return true;\n };\n this.setActiveServerTurn(requestId, cancelActiveRequest);\n\n const transport = this;\n detachResumeStream = () => {\n if (completed) return false;\n finish(() => {\n replayBatch?.flush();\n streamController?.close();\n });\n return true;\n };\n this._detachResumeStream = detachResumeStream;\n\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n streamController = controller;\n const batch = new ReplayChunkBatch(controller);\n replayBatch = batch;\n\n const onMessage = (event: MessageEvent) => {\n try {\n const data = JSON.parse(\n event.data as string\n ) as OutgoingMessage<UIMessage>;\n\n if (data.type !== MessageType.CF_AGENT_USE_CHAT_RESPONSE) return;\n if (data.id !== requestId) return;\n\n if (data.error) {\n finish(() => failChatStream(batch, data.body || \"Stream error\"));\n return;\n }\n\n applyChatResponseFrame(batch, data);\n\n if (data.done) {\n finish(() => controller.close());\n }\n } catch {\n // Ignore non-JSON messages\n }\n };\n\n const onClose = () => {\n finish(\n () => {\n batch.flush();\n controller.close();\n },\n false,\n false\n );\n };\n\n agent.addEventListener(\"message\", onMessage, {\n signal: chunkController.signal\n });\n agent.addEventListener(\"close\", onClose, {\n signal: chunkController.signal\n });\n },\n cancel() {\n if (transport.cancelOnClientAbort) {\n transport.sendCancelFrame(requestId);\n finish(() => {}, true);\n } else {\n finish(() => {}, false, false);\n }\n }\n });\n }\n}\n"],"mappings":"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"}
|