agents 0.20.1 → 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.
Files changed (169) hide show
  1. package/README.md +51 -12
  2. package/dist/{agent-tool-types-BC-WFlsz.d.ts → agent-routing-CnkaHb-v.d.ts} +3305 -3138
  3. package/dist/agent-routing.d.ts +14 -0
  4. package/dist/agent-routing.js +187 -0
  5. package/dist/agent-routing.js.map +1 -0
  6. package/dist/agent-tool-types.d.ts +26 -26
  7. package/dist/{agent-tools-DeHe9Xov.d.ts → agent-tools-C0XJqWzB.d.ts} +7 -7
  8. package/dist/agent-tools.d.ts +44 -28
  9. package/dist/agent-tools.js +16 -7
  10. package/dist/agent-tools.js.map +1 -1
  11. package/dist/browser/ai.d.ts +5 -3
  12. package/dist/browser/ai.js +88 -8
  13. package/dist/browser/ai.js.map +1 -1
  14. package/dist/browser/index.d.ts +1 -1
  15. package/dist/browser/index.js +1 -1
  16. package/dist/browser/tanstack-ai.js +13 -1
  17. package/dist/browser/tanstack-ai.js.map +1 -1
  18. package/dist/capability-BjSKYpzg.js +42 -0
  19. package/dist/capability-BjSKYpzg.js.map +1 -0
  20. package/dist/capability-runner-CvHGZqUu.d.ts +150 -0
  21. package/dist/chat/index.d.ts +51 -15
  22. package/dist/chat/index.js +59 -4
  23. package/dist/chat/index.js.map +1 -1
  24. package/dist/chat/react.d.ts +19 -180
  25. package/dist/chat/react.js +93 -600
  26. package/dist/chat/react.js.map +1 -1
  27. package/dist/chat/transport.d.ts +10 -0
  28. package/dist/chat/transport.js +2 -0
  29. package/dist/chat-sdk/index.d.ts +4 -4
  30. package/dist/chat-sdk/index.js +1 -1
  31. package/dist/{client-zqKcsyFa.js → client-jagG8a9_.js} +129 -37
  32. package/dist/client-jagG8a9_.js.map +1 -0
  33. package/dist/client.d.ts +1 -1
  34. package/dist/client.js +1 -1
  35. package/dist/{cloudflare-BduZwmYK.js → cloudflare-Dzvc7V2N.js} +10 -3
  36. package/dist/{cloudflare-BduZwmYK.js.map → cloudflare-Dzvc7V2N.js.map} +1 -1
  37. package/dist/{connector-v2M1zlZp.d.ts → connector-CkQD4MK3.d.ts} +20 -3
  38. package/dist/{connector-KEJnl6e5.js → connector-CptFKzRh.js} +158 -40
  39. package/dist/connector-CptFKzRh.js.map +1 -0
  40. package/dist/current-agent-CuMErtly.d.ts +283 -0
  41. package/dist/current-agent-DhoDkSnH.js +51 -0
  42. package/dist/current-agent-DhoDkSnH.js.map +1 -0
  43. package/dist/diagnostics-CaBjfz4J.js +41 -0
  44. package/dist/diagnostics-CaBjfz4J.js.map +1 -0
  45. package/dist/{do-oauth-client-provider-VTZj2VtM.d.ts → do-oauth-client-provider-Tmf1vgKz.d.ts} +2 -2
  46. package/dist/durable-object-lifecycle-D6nNQJJd.js +862 -0
  47. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +1 -0
  48. package/dist/{email-CL27preh.d.ts → email-7TatiTnl.d.ts} +38 -9
  49. package/dist/email-send.d.ts +15 -0
  50. package/dist/email-send.js +32 -0
  51. package/dist/email-send.js.map +1 -0
  52. package/dist/email.d.ts +14 -10
  53. package/dist/email.js.map +1 -1
  54. package/dist/experimental/memory/session/index.d.ts +3 -2
  55. package/dist/experimental/memory/session/index.js +15 -10
  56. package/dist/experimental/memory/session/index.js.map +1 -1
  57. package/dist/{handler-stateless-C_bo-Ytq.d.ts → handler-stateless-DxYpJ_XF.d.ts} +3 -3
  58. package/dist/{handler-stateless-CIkKPETH.js → handler-stateless-VvrWSAVA.js} +5 -5
  59. package/dist/handler-stateless-VvrWSAVA.js.map +1 -0
  60. package/dist/{index-BRnybD6X.d.ts → index-DcSAZKsB.d.ts} +19 -31
  61. package/dist/index.d.ts +102 -91
  62. package/dist/index.js +12 -7235
  63. package/dist/internal_context-BlxFEWfn.d.ts +19 -0
  64. package/dist/internal_context.d.ts +10 -4
  65. package/dist/internal_context.js +1 -10
  66. package/dist/{client-invoker-BNSZxAkv.d.ts → invoker-CG0_p_Wq.d.ts} +2 -2
  67. package/dist/{client-invoker-VNZ7X0nn.js → invoker-CHMnoxIA.js} +2 -2
  68. package/dist/invoker-CHMnoxIA.js.map +1 -0
  69. package/dist/lifecycle/index.d.ts +48 -0
  70. package/dist/lifecycle/index.js +4 -0
  71. package/dist/mcp/{do-oauth-client-provider.d.ts → client/do-oauth-client-provider.d.ts} +1 -1
  72. package/dist/mcp/{do-oauth-client-provider.js → client/do-oauth-client-provider.js} +1 -1
  73. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -0
  74. package/dist/mcp/client/index.d.ts +42 -0
  75. package/dist/mcp/{client.js → client/index.js} +1 -1
  76. package/dist/mcp/{x402.d.ts → client/x402.d.ts} +2 -2
  77. package/dist/mcp/{x402.js → client/x402.js} +2 -2
  78. package/dist/mcp/client/x402.js.map +1 -0
  79. package/dist/mcp/index.d.ts +36 -36
  80. package/dist/mcp/index.js +14 -16
  81. package/dist/mcp/index.js.map +1 -1
  82. package/dist/mcp/{server.d.ts → server/index.d.ts} +1 -1
  83. package/dist/mcp/{server.js → server/index.js} +1 -1
  84. package/dist/observability/ai/index.d.ts +1 -130
  85. package/dist/observability/ai/index.js +88 -433
  86. package/dist/observability/ai/index.js.map +1 -1
  87. package/dist/observability/index.d.ts +4 -4
  88. package/dist/observability/index.js +3 -50
  89. package/dist/observability/index.js.map +1 -1
  90. package/dist/{wire-types-CU9rLoeS.js → protocol-B0nh6KNf.js} +20 -66
  91. package/dist/protocol-B0nh6KNf.js.map +1 -0
  92. package/dist/react.d.ts +4 -4
  93. package/dist/react.js +6 -9
  94. package/dist/react.js.map +1 -1
  95. package/dist/schedule.d.ts +25 -94
  96. package/dist/schedule.js +1 -98
  97. package/dist/schedule.js.map +1 -1
  98. package/dist/scheduler-CR9RHGos.js +857 -0
  99. package/dist/scheduler-CR9RHGos.js.map +1 -0
  100. package/dist/scheduler-DQoTGoAW.d.ts +224 -0
  101. package/dist/schedules/index.d.ts +22 -0
  102. package/dist/schedules/index.js +2 -0
  103. package/dist/schedules/parser.d.ts +79 -0
  104. package/dist/schedules/parser.js +103 -0
  105. package/dist/schedules/parser.js.map +1 -0
  106. package/dist/serializable.d.ts +1 -1
  107. package/dist/sql-error-CPY-GXyI.d.ts +12 -0
  108. package/dist/sql-error.d.ts +2 -0
  109. package/dist/sql-error.js +16 -0
  110. package/dist/sql-error.js.map +1 -0
  111. package/dist/src-5W6JNKVb.js +6613 -0
  112. package/dist/src-5W6JNKVb.js.map +1 -0
  113. package/dist/sub-routing.d.ts +18 -6
  114. package/dist/sub-routing.js +92 -2
  115. package/dist/sub-routing.js.map +1 -1
  116. package/dist/wire-types-CnMt6_HR.js +47 -0
  117. package/dist/wire-types-CnMt6_HR.js.map +1 -0
  118. package/dist/workflow-types.d.ts +25 -25
  119. package/dist/workflow-types.js.map +1 -1
  120. package/dist/workflows.d.ts +22 -22
  121. package/dist/workflows.js +2 -1
  122. package/dist/workflows.js.map +1 -1
  123. package/dist/ws-chat-transport-UNRIS2xl.d.ts +184 -0
  124. package/dist/ws-chat-transport-rWwta645.js +698 -0
  125. package/dist/ws-chat-transport-rWwta645.js.map +1 -0
  126. package/docs/adding-to-existing-project.md +4 -2
  127. package/docs/agent-class.md +29 -87
  128. package/docs/agent-tools.md +29 -0
  129. package/docs/browse-the-web.md +16 -1
  130. package/docs/chat-agents.md +16 -13
  131. package/docs/client-sdk.md +12 -8
  132. package/docs/configuration.md +7 -1
  133. package/docs/cross-domain-authentication.md +7 -35
  134. package/docs/durable-execution.md +1 -1
  135. package/docs/email.md +2 -13
  136. package/docs/http-websockets.md +1 -11
  137. package/docs/human-in-the-loop.md +16 -13
  138. package/docs/index.md +1 -0
  139. package/docs/lifecycle.md +323 -0
  140. package/docs/long-running-agents.md +13 -15
  141. package/docs/mcp-client.md +55 -0
  142. package/docs/mcp-servers.md +6 -0
  143. package/docs/mcp-transports.md +18 -12
  144. package/docs/migration-to-ai-sdk-v5.md +2 -2
  145. package/docs/migration-to-ai-sdk-v6.md +5 -1
  146. package/docs/observability.md +33 -77
  147. package/docs/resumable-streaming.md +1 -1
  148. package/docs/routing.md +27 -0
  149. package/docs/scheduling.md +175 -15
  150. package/docs/server-driven-messages.md +1 -1
  151. package/docs/sub-agents.md +47 -2
  152. package/docs/webhooks.md +109 -136
  153. package/docs/workflows.md +9 -1
  154. package/package.json +41 -23
  155. package/dist/cli/index.d.ts +0 -1
  156. package/dist/cli/index.js +0 -26
  157. package/dist/cli/index.js.map +0 -1
  158. package/dist/client-invoker-VNZ7X0nn.js.map +0 -1
  159. package/dist/client-zqKcsyFa.js.map +0 -1
  160. package/dist/connector-KEJnl6e5.js.map +0 -1
  161. package/dist/handler-stateless-CIkKPETH.js.map +0 -1
  162. package/dist/index.js.map +0 -1
  163. package/dist/internal_context-Dg4Cgjcu.d.ts +0 -37
  164. package/dist/internal_context.js.map +0 -1
  165. package/dist/mcp/client.d.ts +0 -42
  166. package/dist/mcp/do-oauth-client-provider.js.map +0 -1
  167. package/dist/mcp/x402.js.map +0 -1
  168. package/dist/wire-types-CU9rLoeS.js.map +0 -1
  169. package/dist/workflow-types-Baz_PO5v.d.ts +0 -280
@@ -0,0 +1,698 @@
1
+ import "./wire-types-CnMt6_HR.js";
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
128
+ //#region src/chat/ws-chat-transport.ts
129
+ /**
130
+ * Short safety-net timeout for a resume probe when the server has said nothing.
131
+ * Under normal operation the server answers a `STREAM_RESUME_REQUEST` with
132
+ * `STREAM_RESUMING`, `STREAM_RESUME_NONE`, or `STREAM_PENDING` well before this.
133
+ */
134
+ const RESUME_PROBE_TIMEOUT_MS = 5e3;
135
+ /**
136
+ * Extended backstop applied once the server says a turn is pending
137
+ * (`STREAM_PENDING`, #1784). The pre-stream window (queueing, MCP setup,
138
+ * debounce, model latency) can exceed the short probe timeout, and the server
139
+ * guarantees a follow-up `STREAM_RESUMING` or `STREAM_RESUME_NONE` — so we wait
140
+ * much longer (refreshed on every keep-waiting frame) but still cap it so a
141
+ * dropped follow-up degrades to a null resolve instead of hanging forever.
142
+ */
143
+ const RESUME_PENDING_TIMEOUT_MS = 6e4;
144
+ /**
145
+ * ChatTransport that sends messages over WebSocket and returns a
146
+ * ReadableStream<UIMessageChunk> that the AI SDK's useChat consumes directly.
147
+ *
148
+ * This low-level transport handles new and regenerated request streams plus
149
+ * cancellation. Higher-level protocol coordination such as automatic reconnect
150
+ * resume, cross-tab transcript synchronization, and client-tool continuations
151
+ * is provided by integrations such as `useAgentChat`.
152
+ */
153
+ var WebSocketChatTransport = class {
154
+ constructor(options) {
155
+ this._resumeResolver = null;
156
+ this._resumeNoneResolver = null;
157
+ this._onStreamPending = null;
158
+ this._retryResumeProbe = null;
159
+ this._expectToolContinuation = false;
160
+ this._abortToolContinuation = null;
161
+ this._activeServerTurnId = null;
162
+ this._cancelAttachedStream = null;
163
+ this._detachResumeStream = null;
164
+ this.agent = options.agent;
165
+ this.prepareBody = options.prepareBody;
166
+ this.activeRequestIds = options.activeRequestIds;
167
+ this.cancelOnClientAbort = options.cancelOnClientAbort ?? false;
168
+ }
169
+ /**
170
+ * Point the singleton transport at a new Agent connection. A pending resolver
171
+ * belongs to the old Chat/socket generation and must settle before messages
172
+ * from the replacement connection can be consumed (#1914 review).
173
+ */
174
+ setAgent(agent) {
175
+ if (this.agent === agent) return;
176
+ this.resetResumeState();
177
+ this.agent = agent;
178
+ }
179
+ setCancelOnClientAbort(cancelOnClientAbort) {
180
+ this.cancelOnClientAbort = cancelOnClientAbort;
181
+ }
182
+ /**
183
+ * Explicitly cancel the active server turn, if any.
184
+ * This is separate from generic client-side abort/cancel lifecycle so
185
+ * clients can detach locally without stopping server work.
186
+ */
187
+ cancelActiveServerTurn() {
188
+ const requestId = this._activeServerTurnId;
189
+ let cancelledRequest = false;
190
+ if (requestId) {
191
+ this.sendCancelFrame(requestId);
192
+ this._cancelAttachedStream?.();
193
+ this.clearActiveServerTurn(requestId);
194
+ cancelledRequest = true;
195
+ }
196
+ const cancelledToolContinuation = this.abortActiveToolContinuation();
197
+ return cancelledRequest || cancelledToolContinuation;
198
+ }
199
+ sendCancelFrame(requestId) {
200
+ try {
201
+ this.agent.send(JSON.stringify({
202
+ id: requestId,
203
+ type: "cf_agent_chat_request_cancel"
204
+ }));
205
+ } catch {}
206
+ }
207
+ setActiveServerTurn(requestId, cancelAttachedStream) {
208
+ this._activeServerTurnId = requestId;
209
+ this._cancelAttachedStream = cancelAttachedStream;
210
+ }
211
+ clearActiveServerTurn(requestId) {
212
+ if (this._activeServerTurnId === requestId) {
213
+ this._activeServerTurnId = null;
214
+ this._cancelAttachedStream = null;
215
+ }
216
+ }
217
+ /**
218
+ * Mark that the next reconnectToStream() call should attach to a
219
+ * server-initiated tool continuation rather than a page-load resume.
220
+ */
221
+ expectToolContinuation() {
222
+ this._expectToolContinuation = true;
223
+ }
224
+ /**
225
+ * Abort the active client-side tool continuation stream, if one is attached
226
+ * to a server request id.
227
+ */
228
+ abortActiveToolContinuation() {
229
+ return this._abortToolContinuation?.() ?? false;
230
+ }
231
+ /**
232
+ * True when the transport is waiting for a resume handshake.
233
+ */
234
+ isAwaitingResume() {
235
+ return this._resumeResolver !== null || this._resumeNoneResolver !== null;
236
+ }
237
+ /**
238
+ * Settle and detach the current handshake without interpreting it as a
239
+ * server-idle response. Used when the owning hook/agent generation changes.
240
+ */
241
+ cancelPendingResume() {
242
+ const resolveNone = this._resumeNoneResolver;
243
+ if (!resolveNone) return false;
244
+ return resolveNone({});
245
+ }
246
+ /**
247
+ * Invalidate all client-side resume state for an obsolete hook/agent
248
+ * generation without cancelling its durable server turn.
249
+ */
250
+ resetResumeState() {
251
+ this._expectToolContinuation = false;
252
+ this.cancelPendingResume();
253
+ this._detachResumeStream?.();
254
+ }
255
+ /**
256
+ * Re-send the active handshake request on the latest socket generation. This
257
+ * preserves one AI SDK resume operation while recovering a request/reply lost
258
+ * with the previous WebSocket.
259
+ */
260
+ retryPendingResume() {
261
+ const retry = this._retryResumeProbe;
262
+ if (!retry) return false;
263
+ retry();
264
+ return true;
265
+ }
266
+ /**
267
+ * Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUMING.
268
+ * If reconnectToStream is waiting, this handles the resume handshake
269
+ * (ACK + stream creation) and returns true. Otherwise returns false
270
+ * so the caller can use its own fallback path.
271
+ */
272
+ handleStreamResuming(data) {
273
+ if (!this._resumeResolver) return false;
274
+ this._resumeResolver(data);
275
+ return true;
276
+ }
277
+ /**
278
+ * Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUME_NONE.
279
+ * If reconnectToStream is waiting, resolves the promise with null
280
+ * immediately (no 5-second timeout). Returns true if handled.
281
+ */
282
+ handleStreamResumeNone(data = {}) {
283
+ if (!this._resumeNoneResolver) return false;
284
+ return this._resumeNoneResolver(data);
285
+ }
286
+ /**
287
+ * Called by onAgentMessage when it receives CF_AGENT_STREAM_PENDING (#1784):
288
+ * the server accepted a turn but its stream has not started yet. If a resume
289
+ * path is awaiting, extend its probe timeout (so it keeps waiting for the
290
+ * eventual STREAM_RESUMING / STREAM_RESUME_NONE instead of resolving null
291
+ * after the short window). Returns true if a waiting path consumed it.
292
+ */
293
+ handleStreamPending() {
294
+ if (!this._onStreamPending) return false;
295
+ this._onStreamPending();
296
+ return true;
297
+ }
298
+ /**
299
+ * Called by the hook's shared message handler when a server turn finishes
300
+ * outside the currently attached transport stream, such as after local-only
301
+ * client cleanup.
302
+ */
303
+ handleServerTurnCompleted(requestId) {
304
+ this.clearActiveServerTurn(requestId);
305
+ }
306
+ /**
307
+ * Register a server turn that is being rendered outside a transport-owned
308
+ * stream, such as the hook's fallback cross-tab/resume observer path.
309
+ */
310
+ observeServerTurn(requestId) {
311
+ this.setActiveServerTurn(requestId, null);
312
+ }
313
+ async sendMessages(options) {
314
+ const requestId = nanoid(8);
315
+ const abortController = new AbortController();
316
+ let completed = false;
317
+ let requestSent = false;
318
+ let extraBody = {};
319
+ if (this.prepareBody) extraBody = await this.prepareBody({
320
+ messages: options.messages,
321
+ trigger: options.trigger,
322
+ messageId: options.messageId
323
+ });
324
+ if (options.body) extraBody = {
325
+ ...extraBody,
326
+ ...options.body
327
+ };
328
+ const bodyPayload = JSON.stringify({
329
+ messages: options.messages,
330
+ trigger: options.trigger,
331
+ ...extraBody
332
+ });
333
+ this.activeRequestIds?.add(requestId);
334
+ const agent = this.agent;
335
+ const activeIds = this.activeRequestIds;
336
+ const finish = (action, keepId = false, clearServerTurn = true) => {
337
+ if (completed) return;
338
+ completed = true;
339
+ if (clearServerTurn) this.clearActiveServerTurn(requestId);
340
+ try {
341
+ action();
342
+ } catch {}
343
+ if (!keepId) activeIds?.delete(requestId);
344
+ abortController.abort();
345
+ };
346
+ const abortError = /* @__PURE__ */ new Error("Aborted");
347
+ abortError.name = "AbortError";
348
+ const cancelActiveRequest = () => {
349
+ if (completed) return false;
350
+ finish(() => streamController.error(abortError), true);
351
+ return true;
352
+ };
353
+ this.setActiveServerTurn(requestId, cancelActiveRequest);
354
+ const onAbort = () => {
355
+ if (completed) return;
356
+ if (this.cancelOnClientAbort) {
357
+ if (requestSent) this.sendCancelFrame(requestId);
358
+ finish(() => streamController.error(abortError), requestSent);
359
+ } else finish(() => streamController.error(abortError), false, !requestSent);
360
+ };
361
+ let streamController;
362
+ const stream = new ReadableStream({
363
+ start(controller) {
364
+ streamController = controller;
365
+ const onMessage = (event) => {
366
+ try {
367
+ const data = JSON.parse(event.data);
368
+ if (data.type !== "cf_agent_use_chat_response") return;
369
+ if (data.id !== requestId) return;
370
+ if (data.error) {
371
+ finish(() => controller.error(new Error(data.body || "Stream error")));
372
+ return;
373
+ }
374
+ if (data.body?.trim()) try {
375
+ const chunk = JSON.parse(data.body);
376
+ controller.enqueue(chunk);
377
+ } catch {}
378
+ if (data.done) finish(() => controller.close());
379
+ } catch {}
380
+ };
381
+ const onClose = () => {
382
+ finish(() => controller.close(), false, false);
383
+ };
384
+ agent.addEventListener("message", onMessage, { signal: abortController.signal });
385
+ agent.addEventListener("close", onClose, { signal: abortController.signal });
386
+ },
387
+ cancel() {
388
+ onAbort();
389
+ }
390
+ });
391
+ if (options.abortSignal) {
392
+ options.abortSignal.addEventListener("abort", onAbort, { once: true });
393
+ if (options.abortSignal.aborted) onAbort();
394
+ }
395
+ if (completed) return stream;
396
+ requestSent = true;
397
+ agent.send(JSON.stringify({
398
+ id: requestId,
399
+ init: {
400
+ method: "POST",
401
+ body: bodyPayload
402
+ },
403
+ type: "cf_agent_use_chat_request"
404
+ }));
405
+ return stream;
406
+ }
407
+ async reconnectToStream(_options) {
408
+ if (this.isAwaitingResume()) return null;
409
+ if (this._expectToolContinuation) {
410
+ this._expectToolContinuation = false;
411
+ return this._createToolContinuationStream();
412
+ }
413
+ const activeIds = this.activeRequestIds;
414
+ const probeId = nanoid(8);
415
+ return new Promise((resolve) => {
416
+ let resolved = false;
417
+ let timeout;
418
+ let resumeResolver = null;
419
+ let resumeNoneResolver = null;
420
+ let onStreamPending = null;
421
+ let retryResumeProbe = null;
422
+ const clearOwnedCallbacks = () => {
423
+ if (resumeResolver && this._resumeResolver === resumeResolver) this._resumeResolver = null;
424
+ if (resumeNoneResolver && this._resumeNoneResolver === resumeNoneResolver) this._resumeNoneResolver = null;
425
+ if (onStreamPending && this._onStreamPending === onStreamPending) this._onStreamPending = null;
426
+ if (retryResumeProbe && this._retryResumeProbe === retryResumeProbe) this._retryResumeProbe = null;
427
+ };
428
+ const done = (value) => {
429
+ if (resolved) return;
430
+ resolved = true;
431
+ clearOwnedCallbacks();
432
+ if (timeout) clearTimeout(timeout);
433
+ resolve(value);
434
+ };
435
+ const armTimeout = (delay) => {
436
+ if (timeout) clearTimeout(timeout);
437
+ timeout = setTimeout(() => done(null), delay);
438
+ };
439
+ onStreamPending = () => {
440
+ if (resolved) return;
441
+ armTimeout(RESUME_PENDING_TIMEOUT_MS);
442
+ };
443
+ resumeNoneResolver = (data) => {
444
+ if (data.probeId && data.probeId !== probeId) return false;
445
+ done(null);
446
+ return true;
447
+ };
448
+ resumeResolver = (data) => {
449
+ const requestId = data.id;
450
+ activeIds?.add(requestId);
451
+ const stream = this._createResumeStream(requestId);
452
+ this.agent.send(JSON.stringify({
453
+ type: "cf_agent_stream_resume_ack",
454
+ id: requestId
455
+ }));
456
+ done(stream);
457
+ };
458
+ retryResumeProbe = () => {
459
+ if (resolved) return;
460
+ armTimeout(RESUME_PROBE_TIMEOUT_MS);
461
+ try {
462
+ this.agent.send(JSON.stringify({
463
+ type: "cf_agent_stream_resume_request",
464
+ probeId
465
+ }));
466
+ } catch {}
467
+ };
468
+ this._onStreamPending = onStreamPending;
469
+ this._resumeNoneResolver = resumeNoneResolver;
470
+ this._resumeResolver = resumeResolver;
471
+ this._retryResumeProbe = retryResumeProbe;
472
+ retryResumeProbe();
473
+ });
474
+ }
475
+ /**
476
+ * Creates a deferred ReadableStream for client-side tool continuations.
477
+ * The stream is returned immediately so AI SDK status becomes "submitted"
478
+ * right after addToolOutput()/addToolApprovalResponse(), then it waits for
479
+ * the server to announce the continuation via STREAM_RESUMING.
480
+ */
481
+ _createToolContinuationStream() {
482
+ const agent = this.agent;
483
+ const activeIds = this.activeRequestIds;
484
+ const streamController = new AbortController();
485
+ const abortError = /* @__PURE__ */ new Error("Aborted");
486
+ abortError.name = "AbortError";
487
+ let completed = false;
488
+ let requestId = null;
489
+ let readerController = null;
490
+ let replayBatch = null;
491
+ const probeId = nanoid(8);
492
+ let onResumeRef = null;
493
+ let onResumeNoneRef = null;
494
+ let onStreamPendingRef = null;
495
+ let retryResumeProbeRef = null;
496
+ let abortToolContinuationRef = null;
497
+ let detachResumeStreamRef = null;
498
+ const clearOwnedHandshake = () => {
499
+ if (onResumeRef && this._resumeResolver === onResumeRef) this._resumeResolver = null;
500
+ if (onResumeNoneRef && this._resumeNoneResolver === onResumeNoneRef) this._resumeNoneResolver = null;
501
+ if (onStreamPendingRef && this._onStreamPending === onStreamPendingRef) this._onStreamPending = null;
502
+ if (retryResumeProbeRef && this._retryResumeProbe === retryResumeProbeRef) this._retryResumeProbe = null;
503
+ };
504
+ const finish = (action, keepRequestId = false) => {
505
+ if (completed) return;
506
+ completed = true;
507
+ if (this._abortToolContinuation === abortToolContinuationRef) this._abortToolContinuation = null;
508
+ if (this._detachResumeStream === detachResumeStreamRef) this._detachResumeStream = null;
509
+ clearOwnedHandshake();
510
+ try {
511
+ action();
512
+ } catch {}
513
+ if (requestId && !keepRequestId) activeIds?.delete(requestId);
514
+ streamController.abort();
515
+ };
516
+ const transport = this;
517
+ abortToolContinuationRef = () => {
518
+ if (completed) return false;
519
+ if (requestId === null) {
520
+ finish(() => readerController?.error(abortError));
521
+ return true;
522
+ }
523
+ try {
524
+ agent.send(JSON.stringify({
525
+ type: "cf_agent_chat_request_cancel",
526
+ id: requestId
527
+ }));
528
+ } catch {}
529
+ finish(() => readerController?.error(abortError), true);
530
+ return true;
531
+ };
532
+ this._abortToolContinuation = abortToolContinuationRef;
533
+ detachResumeStreamRef = () => {
534
+ if (completed) return false;
535
+ finish(() => {
536
+ replayBatch?.flush();
537
+ readerController?.close();
538
+ });
539
+ return true;
540
+ };
541
+ this._detachResumeStream = detachResumeStreamRef;
542
+ return new ReadableStream({
543
+ start(controller) {
544
+ readerController = controller;
545
+ const batch = new ReplayChunkBatch(controller);
546
+ replayBatch = batch;
547
+ let timeout;
548
+ const armTimeout = (delay) => {
549
+ if (timeout) clearTimeout(timeout);
550
+ timeout = setTimeout(() => finish(() => controller.close()), delay);
551
+ };
552
+ const onResumeNone = (data) => {
553
+ if (data.probeId && data.probeId !== probeId) return false;
554
+ finish(() => controller.close());
555
+ return true;
556
+ };
557
+ const onResume = (data) => {
558
+ if (requestId) return;
559
+ requestId = data.id;
560
+ activeIds?.add(requestId);
561
+ clearOwnedHandshake();
562
+ if (timeout) clearTimeout(timeout);
563
+ agent.send(JSON.stringify({
564
+ type: "cf_agent_stream_resume_ack",
565
+ id: requestId
566
+ }));
567
+ };
568
+ const onStreamPending = () => {
569
+ if (completed) return;
570
+ armTimeout(RESUME_PENDING_TIMEOUT_MS);
571
+ };
572
+ const retryResumeProbe = () => {
573
+ if (completed || requestId !== null) return;
574
+ armTimeout(RESUME_PROBE_TIMEOUT_MS);
575
+ try {
576
+ transport.agent.send(JSON.stringify({
577
+ type: "cf_agent_stream_resume_request",
578
+ probeId
579
+ }));
580
+ } catch {}
581
+ };
582
+ onResumeRef = onResume;
583
+ onResumeNoneRef = onResumeNone;
584
+ onStreamPendingRef = onStreamPending;
585
+ retryResumeProbeRef = retryResumeProbe;
586
+ transport._resumeResolver = onResume;
587
+ transport._resumeNoneResolver = onResumeNone;
588
+ transport._onStreamPending = onStreamPending;
589
+ transport._retryResumeProbe = retryResumeProbe;
590
+ const onMessage = (event) => {
591
+ try {
592
+ const data = JSON.parse(event.data);
593
+ if (data.type !== "cf_agent_use_chat_response" || requestId == null || data.id !== requestId) return;
594
+ if (data.error) {
595
+ finish(() => failChatStream(batch, data.body || "Stream error"));
596
+ return;
597
+ }
598
+ applyChatResponseFrame(batch, data);
599
+ if (data.done) finish(() => controller.close());
600
+ } catch {}
601
+ };
602
+ const onClose = () => finish(() => {
603
+ batch.flush();
604
+ controller.close();
605
+ });
606
+ agent.addEventListener("message", onMessage, { signal: streamController.signal });
607
+ agent.addEventListener("close", onClose, { signal: streamController.signal });
608
+ retryResumeProbe();
609
+ },
610
+ cancel() {
611
+ if (requestId && transport.cancelOnClientAbort) {
612
+ transport.sendCancelFrame(requestId);
613
+ finish(() => {}, true);
614
+ } else finish(() => {});
615
+ }
616
+ });
617
+ }
618
+ /**
619
+ * Creates a ReadableStream that receives resumed stream chunks
620
+ * and forwards them to useChat as UIMessageChunk objects.
621
+ */
622
+ _createResumeStream(requestId) {
623
+ const agent = this.agent;
624
+ const activeIds = this.activeRequestIds;
625
+ const chunkController = new AbortController();
626
+ const abortError = /* @__PURE__ */ new Error("Aborted");
627
+ abortError.name = "AbortError";
628
+ let completed = false;
629
+ let detachResumeStream = null;
630
+ const finish = (action, keepId = false, clearServerTurn = true) => {
631
+ if (completed) return;
632
+ completed = true;
633
+ if (clearServerTurn) this.clearActiveServerTurn(requestId);
634
+ if (this._detachResumeStream === detachResumeStream) this._detachResumeStream = null;
635
+ try {
636
+ action();
637
+ } catch {}
638
+ if (!keepId) activeIds?.delete(requestId);
639
+ chunkController.abort();
640
+ };
641
+ let streamController = null;
642
+ let replayBatch = null;
643
+ const cancelActiveRequest = () => {
644
+ if (completed) return false;
645
+ finish(() => streamController?.error(abortError), true);
646
+ return true;
647
+ };
648
+ this.setActiveServerTurn(requestId, cancelActiveRequest);
649
+ const transport = this;
650
+ detachResumeStream = () => {
651
+ if (completed) return false;
652
+ finish(() => {
653
+ replayBatch?.flush();
654
+ streamController?.close();
655
+ });
656
+ return true;
657
+ };
658
+ this._detachResumeStream = detachResumeStream;
659
+ return new ReadableStream({
660
+ start(controller) {
661
+ streamController = controller;
662
+ const batch = new ReplayChunkBatch(controller);
663
+ replayBatch = batch;
664
+ const onMessage = (event) => {
665
+ try {
666
+ const data = JSON.parse(event.data);
667
+ if (data.type !== "cf_agent_use_chat_response") return;
668
+ if (data.id !== requestId) return;
669
+ if (data.error) {
670
+ finish(() => failChatStream(batch, data.body || "Stream error"));
671
+ return;
672
+ }
673
+ applyChatResponseFrame(batch, data);
674
+ if (data.done) finish(() => controller.close());
675
+ } catch {}
676
+ };
677
+ const onClose = () => {
678
+ finish(() => {
679
+ batch.flush();
680
+ controller.close();
681
+ }, false, false);
682
+ };
683
+ agent.addEventListener("message", onMessage, { signal: chunkController.signal });
684
+ agent.addEventListener("close", onClose, { signal: chunkController.signal });
685
+ },
686
+ cancel() {
687
+ if (transport.cancelOnClientAbort) {
688
+ transport.sendCancelFrame(requestId);
689
+ finish(() => {}, true);
690
+ } else finish(() => {}, false, false);
691
+ }
692
+ });
693
+ }
694
+ };
695
+ //#endregion
696
+ export { WebSocketChatTransport as t };
697
+
698
+ //# sourceMappingURL=ws-chat-transport-rWwta645.js.map