agents 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/{agent-routing-B2XLNMxq.d.ts → agent-routing-0DR0Tk2v.d.ts} +205 -132
  2. package/dist/agent-routing.d.ts +1 -1
  3. package/dist/agent-routing.js.map +1 -1
  4. package/dist/agent-tool-types.d.ts +28 -22
  5. package/dist/agent-tool-types.js +23 -1
  6. package/dist/agent-tool-types.js.map +1 -1
  7. package/dist/{agent-tools-y7zLfw4Q.js → agent-tools-CdJC-8Dc.js} +72 -9
  8. package/dist/agent-tools-CdJC-8Dc.js.map +1 -0
  9. package/dist/{agent-tools-Dj5Mzlw7.d.ts → agent-tools-YrATZJu2.d.ts} +34 -20
  10. package/dist/agent-tools.d.ts +20 -18
  11. package/dist/agent-tools.js.map +1 -1
  12. package/dist/ai-fm7xx1BK.js +312 -0
  13. package/dist/ai-fm7xx1BK.js.map +1 -0
  14. package/dist/base64-redaction-C1Uu29t5.js +59 -0
  15. package/dist/base64-redaction-C1Uu29t5.js.map +1 -0
  16. package/dist/browser/ai-sdk.d.ts +90 -0
  17. package/dist/browser/ai-sdk.js +51 -0
  18. package/dist/browser/ai-sdk.js.map +1 -0
  19. package/dist/browser/ai.d.ts +4 -4
  20. package/dist/browser/ai.js +1 -347
  21. package/dist/browser/index.d.ts +81 -79
  22. package/dist/browser/index.js +361 -2
  23. package/dist/browser/index.js.map +1 -0
  24. package/dist/browser/tanstack-ai.d.ts +96 -1
  25. package/dist/browser/tanstack-ai.js +62 -2
  26. package/dist/browser/tanstack-ai.js.map +1 -1
  27. package/dist/browser-DE3d-RLk.d.ts +275 -0
  28. package/dist/browser-tool-CQ10e6Kj.js +480 -0
  29. package/dist/browser-tool-CQ10e6Kj.js.map +1 -0
  30. package/dist/browser-tool-DuNdlwZ9.d.ts +73 -0
  31. package/dist/capability-B4WbF81e.js.map +1 -1
  32. package/dist/{capability-runner-BUBa6Ake.d.ts → capability-runner-DBAnGr6L.d.ts} +7 -2
  33. package/dist/chat/index.d.ts +340 -234
  34. package/dist/chat/index.js +592 -66
  35. package/dist/chat/index.js.map +1 -1
  36. package/dist/chat/react.d.ts +42 -2
  37. package/dist/chat/react.js +191 -35
  38. package/dist/chat/react.js.map +1 -1
  39. package/dist/chat/transport.d.ts +1 -1
  40. package/dist/chat/transport.js +1 -1
  41. package/dist/chat-sdk/index.d.ts +17 -3
  42. package/dist/chat-sdk/index.js +28 -2
  43. package/dist/chat-sdk/index.js.map +1 -1
  44. package/dist/{client-C9DAjZIY.js → client-4OlMIJx-.js} +102 -29
  45. package/dist/client-4OlMIJx-.js.map +1 -0
  46. package/dist/{client-BxdkCuVy.d.ts → client-je3koD9Z.d.ts} +45 -10
  47. package/dist/client.d.ts +7 -5
  48. package/dist/client.js +2 -2
  49. package/dist/{connector-CptFKzRh.js → connector-58XDGvc3.js} +251 -120
  50. package/dist/connector-58XDGvc3.js.map +1 -0
  51. package/dist/{connector-CkQD4MK3.d.ts → connector-Cl-VqPmA.d.ts} +244 -146
  52. package/dist/context/index.d.ts +29 -0
  53. package/dist/context/index.js +64 -17
  54. package/dist/context/index.js.map +1 -1
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{current-agent-C4w86kcN.d.ts → current-agent-vAk_5JMt.d.ts} +4 -4
  57. package/dist/{durable-object-lifecycle-ei7M7lqB.d.ts → durable-object-lifecycle-HhgOMWq9.d.ts} +15 -7
  58. package/dist/harnesses/pi/index.d.ts +348 -0
  59. package/dist/harnesses/pi/index.js +754 -0
  60. package/dist/harnesses/pi/index.js.map +1 -0
  61. package/dist/images-iiTDSyRu.js +1631 -0
  62. package/dist/images-iiTDSyRu.js.map +1 -0
  63. package/dist/{index-Dlgtd3Mj.d.ts → index-BreL0YrQ.d.ts} +2 -2
  64. package/dist/index-kbSUIer3.d.ts +343 -0
  65. package/dist/index.d.ts +46 -44
  66. package/dist/index.js +1 -1
  67. package/dist/internal_context.d.ts +1 -1
  68. package/dist/lifecycle/index.d.ts +3 -3
  69. package/dist/lifecycle/index.js +1 -1
  70. package/dist/{lifecycle-Mm_jQh7r.js → lifecycle-CFu6OV03.js} +39 -10
  71. package/dist/{lifecycle-Mm_jQh7r.js.map → lifecycle-CFu6OV03.js.map} +1 -1
  72. package/dist/mcp/client/index.d.ts +20 -20
  73. package/dist/mcp/client/x402.js +21 -19
  74. package/dist/mcp/client/x402.js.map +1 -1
  75. package/dist/mcp/index.d.ts +35 -35
  76. package/dist/mcp/index.js +1 -1
  77. package/dist/{message-builder-BymO4N_D.js → message-builder-DAl9AhHH.js} +89 -4
  78. package/dist/message-builder-DAl9AhHH.js.map +1 -0
  79. package/dist/models/ai-sdk/index.d.ts +353 -0
  80. package/dist/models/ai-sdk/index.js +2443 -0
  81. package/dist/models/ai-sdk/index.js.map +1 -0
  82. package/dist/models/pi-ai/index.d.ts +313 -0
  83. package/dist/models/pi-ai/index.js +1795 -0
  84. package/dist/models/pi-ai/index.js.map +1 -0
  85. package/dist/observability/ai/index.js +20 -4
  86. package/dist/observability/ai/index.js.map +1 -1
  87. package/dist/{protocol-B0nh6KNf.js → protocol-kHsr-f0X.js} +26 -12
  88. package/dist/{protocol-B0nh6KNf.js.map → protocol-kHsr-f0X.js.map} +1 -1
  89. package/dist/queue/index.d.ts +3 -3
  90. package/dist/queue/index.js +1 -1
  91. package/dist/{queue-BC9F5cUo.js → queue-BB-zfIYF.js} +2 -2
  92. package/dist/{queue-BC9F5cUo.js.map → queue-BB-zfIYF.js.map} +1 -1
  93. package/dist/react.d.ts +6 -6
  94. package/dist/react.js +160 -64
  95. package/dist/react.js.map +1 -1
  96. package/dist/{retries-D9B2UCq3.d.ts → retries-CV6AkXmQ.d.ts} +18 -9
  97. package/dist/retries.d.ts +11 -9
  98. package/dist/retries.js +11 -1
  99. package/dist/retries.js.map +1 -1
  100. package/dist/routing/index.d.ts +2 -2
  101. package/dist/routing/index.js +1 -1
  102. package/dist/{scheduler-D_KHqxBa.js → scheduler-DZ3xQfeK.js} +2 -2
  103. package/dist/{scheduler-D_KHqxBa.js.map → scheduler-DZ3xQfeK.js.map} +1 -1
  104. package/dist/{scheduler-BGq6M5Kd.d.ts → scheduler-RdACNXDP.d.ts} +3 -3
  105. package/dist/schedules/index.d.ts +1 -1
  106. package/dist/schedules/index.js +1 -1
  107. package/dist/serializable.d.ts +1 -1
  108. package/dist/sessions/index.d.ts +70 -3
  109. package/dist/sessions/index.js +276 -67
  110. package/dist/sessions/index.js.map +1 -1
  111. package/dist/skills/index.d.ts +29 -314
  112. package/dist/socket-address.d.ts +16 -0
  113. package/dist/socket-address.js +19 -0
  114. package/dist/socket-address.js.map +1 -0
  115. package/dist/{src-BNU3ZiJM.js → src-BZeu-SCD.js} +423 -115
  116. package/dist/src-BZeu-SCD.js.map +1 -0
  117. package/dist/state/index.d.ts +1 -1
  118. package/dist/state/index.js +1 -1
  119. package/dist/streams/index.d.ts +1 -1
  120. package/dist/streams/index.js +1 -1
  121. package/dist/{streams-BcE8JP2X.d.ts → streams-Cmkj9QfW.d.ts} +4 -2
  122. package/dist/{streams-CCPRV6dt.js → streams-DW-UCOUc.js} +9 -2
  123. package/dist/streams-DW-UCOUc.js.map +1 -0
  124. package/dist/sub-routing.d.ts +12 -12
  125. package/dist/tasks/index.d.ts +1 -1
  126. package/dist/tasks/index.js +1 -1
  127. package/dist/{tasks-D4nLqVSI.js → tasks-68DESxf0.js} +2 -2
  128. package/dist/{tasks-D4nLqVSI.js.map → tasks-68DESxf0.js.map} +1 -1
  129. package/dist/{tasks-V2lCT8ZV.d.ts → tasks-9YxYtByh.d.ts} +2 -2
  130. package/dist/transport-PfFnt-Ld.d.ts +525 -0
  131. package/dist/{types-DCD6BNZH.d.ts → types-BA4anrjI.d.ts} +2 -2
  132. package/dist/voice/index.d.ts +2 -2
  133. package/dist/websockets/index.d.ts +23 -6
  134. package/dist/websockets/index.js +1 -1
  135. package/dist/{websockets-D7IzWbZb.js → websockets-Ci-LZFHH.js} +45 -20
  136. package/dist/{websockets-D7IzWbZb.js.map → websockets-Ci-LZFHH.js.map} +1 -1
  137. package/dist/wire-types-CnMt6_HR.js.map +1 -1
  138. package/dist/wire-types-CrjKvDyi.d.ts +300 -0
  139. package/dist/workflow-types.d.ts +25 -25
  140. package/dist/workflows.d.ts +21 -21
  141. package/dist/workflows.js +1 -1
  142. package/dist/{ws-chat-transport-UNRIS2xl.d.ts → ws-chat-transport-BbT1A5Lc.d.ts} +51 -2
  143. package/dist/{ws-chat-transport-rWwta645.js → ws-chat-transport-cqMKq3IY.js} +143 -16
  144. package/dist/ws-chat-transport-cqMKq3IY.js.map +1 -0
  145. package/docs/agent-tools.md +29 -4
  146. package/docs/browse-the-web.md +87 -5
  147. package/docs/chat-agents.md +124 -16
  148. package/docs/context.md +27 -0
  149. package/docs/durable-execution.md +2 -0
  150. package/docs/harnesses/pi.md +91 -0
  151. package/docs/human-in-the-loop.md +4 -0
  152. package/docs/index.md +3 -0
  153. package/docs/lifecycle.md +20 -4
  154. package/docs/models-pi-ai.md +325 -0
  155. package/docs/models.md +504 -0
  156. package/docs/resumable-streaming.md +2 -0
  157. package/docs/routing.md +13 -13
  158. package/docs/sessions.md +36 -1
  159. package/docs/state.md +1 -0
  160. package/docs/sub-agents.md +9 -0
  161. package/package.json +40 -2
  162. package/dist/agent-tools-y7zLfw4Q.js.map +0 -1
  163. package/dist/browser/ai.js.map +0 -1
  164. package/dist/client-C9DAjZIY.js.map +0 -1
  165. package/dist/client-tools-aIBO0Fk7.d.ts +0 -53
  166. package/dist/connector-CptFKzRh.js.map +0 -1
  167. package/dist/message-builder-BymO4N_D.js.map +0 -1
  168. package/dist/src-BNU3ZiJM.js.map +0 -1
  169. package/dist/streams-CCPRV6dt.js.map +0 -1
  170. package/dist/ws-chat-transport-rWwta645.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"streams-CCPRV6dt.js","names":[],"sources":["../src/streams/errors.ts","../src/streams/streams.ts"],"sourcesContent":["/**\n * Error classes for the Streams capability. Each carries a stable `name` so\n * hosts and tests can classify failures without depending on message text.\n */\n\n/**\n * Thrown when `open()` targets a terminal stream, or an append reaches a\n * stream that settled (or was deleted) after the writer was created.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class StreamClosedError extends Error {\n /** The stream that no longer accepts writes. */\n readonly streamId: string;\n\n constructor(streamId: string, detail: string) {\n super(`Stream \"${streamId}\" is closed: ${detail}`);\n this.name = \"StreamClosedError\";\n this.streamId = streamId;\n }\n}\n\n/**\n * Thrown when `read()` targets a stream that was never opened (or was\n * deleted). `status()` returns `null` instead, for existence probes.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class StreamNotFoundError extends Error {\n readonly streamId: string;\n\n constructor(streamId: string) {\n super(\n `Stream \"${streamId}\" does not exist. Open it before reading, or use ` +\n `status() to probe for existence.`\n );\n this.name = \"StreamNotFoundError\";\n this.streamId = streamId;\n }\n}\n\n/**\n * Thrown when a chunk or metadata value is not JSON-serializable or exceeds\n * the configured size limit.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class StreamSerializationError extends Error {\n constructor(context: string, detail: string) {\n super(`Cannot serialize ${context}: ${detail}`);\n this.name = \"StreamSerializationError\";\n }\n}\n","/**\n * Durable incremental output for Lifecycle Objects. `Streams` owns the\n * `cf_agents_streams` and `cf_agents_stream_blocks` tables: an ordered,\n * durable chunk log per stream with a monotonic cursor, replay-then-tail\n * reads, and terminal status that doubles as recovery evidence for the\n * Tasks capability (which composes through checkpointed cursors, never\n * imports).\n *\n * Streams consumes only the standard capability services — storage and\n * events. It needs no alarm, so it also works on facets. Live fanout is\n * in-isolate: a Durable Object executes in one isolate at a time, so every\n * concurrent reader shares the producer's isolate; readers that outlive an\n * isolate replay from their cursor on reconnect.\n */\n\nimport { LifecycleCapability } from \"../lifecycle/capability\";\nimport { SqlError } from \"../sql-error\";\nimport {\n StreamClosedError,\n StreamNotFoundError,\n StreamSerializationError\n} from \"./errors\";\nimport type {\n StreamChunk,\n StreamChunkRow,\n StreamJson,\n StreamListOptions,\n StreamOpenOptions,\n StreamReadBatchesOptions,\n StreamReadOptions,\n StreamRow,\n StreamSettleOptions,\n StreamState,\n StreamStatus,\n StreamWriter\n} from \"./types\";\n\nconst STREAM_SCHEMA_VERSION_KEY = \"cf_agents:streams_schema_version\";\nconst CURRENT_STREAM_SCHEMA_VERSION = 2;\n\n/**\n * A block row grows by UPDATE until its body reaches this many characters,\n * then the next append opens a new block. Sized well under the 2 MiB row\n * limit so a 1 MiB chunk always fits in a fresh block, and small enough\n * that a replay page parses one block at a time.\n */\nconst BLOCK_MAX_CHARS = 256 * 1024;\n/** Rows read per page while folding one stream's v1 chunk rows into blocks. */\nconst LEGACY_FOLD_PAGE_ROWS = 500;\n\n/** Default ceiling for one serialized chunk (1 MiB). */\nexport const DEFAULT_MAX_CHUNK_BYTES = 1_048_576;\n\nconst MAX_STREAM_ID_LENGTH = 256;\nconst READ_BATCH_SIZE = 100;\nconst DEFAULT_LIST_LIMIT = 100;\n\nconst utf8 = new TextEncoder();\n\n/**\n * Policy for a Streams capability.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport interface StreamsOptions {\n /** Ceiling for one serialized chunk. Default: 1 MiB. */\n readonly maxChunkBytes?: number;\n}\n\n/**\n * @internal Synchronous operations returned by\n * {@link Streams.__DO_NOT_USE_WILL_BREAK__sync}. For same-isolate first-party\n * machinery only (the chat `ResumableStream` adapter); every method bypasses\n * `lifecycle.ready()`, so the caller owns startup ordering.\n */\nexport interface StreamsSyncInternal {\n /** Idempotent DDL — safe to call before the Lifecycle starts. */\n ensureTables(): void;\n getStream(streamId: string): StreamRow | undefined;\n /** Insert a live stream row (no idempotency — caller checks first). */\n insertStream(\n streamId: string,\n tag: string | null,\n metadata: Record<string, StreamJson> | undefined\n ): void;\n /** The read-fenced append: one chunk insert at the log tail, reader wakeup. */\n append(streamId: string, chunk: StreamJson): number;\n /**\n * The newest chunk's timestamp, or null for an empty log. One PK-served\n * read — the per-append liveness signal retention sweeps verify against\n * (a live row's `updated_at` is set at open and not bumped by appends).\n */\n lastChunkAt(streamId: string): number | null;\n /**\n * Segments durably appended so far: the chunk log's tail, read in the\n * calling synchronous block. Zero for an unknown stream.\n */\n cursor(streamId: string): number;\n /**\n * Observe every deletion of a stream's rows — the public `delete()`, the\n * aperture's own deletes, and a cutover's discard — with the row and its\n * cursor as they were just before removal, in the same synchronous block\n * (and, for a cutover, the same transaction). Hooks must be synchronous\n * and must not await: the cutover runs them inside `transactionSync`.\n * The chat adapter uses this to keep its recovery progress marker exact\n * however a chat row leaves the table. Returns the unsubscribe: an owner\n * constructed again (a host whose startup retried) must drop its earlier\n * hook, or a deletion is observed once per construction.\n */\n onDelete(hook: (row: StreamRow, cursor: number) => void): () => void;\n /**\n * Idempotent settlement with events and reader wakeup. With `options`,\n * the settle, the caller's `commit` writes and the log discard run in\n * one SQLite transaction (see {@link StreamSettleOptions}). Returns\n * whether the stream transitioned; on a repeat or a deleted stream the\n * `commit` callback does not run.\n */\n settle(\n streamId: string,\n state: \"completed\" | \"errored\",\n reason: string | null,\n options?: StreamSettleOptions\n ): boolean;\n /** Delete a stream and its chunks regardless of state. */\n deleteUnchecked(streamId: string): void;\n /** Delete many streams and their chunks regardless of state, silently. */\n deleteMany(streamIds: string[]): void;\n /**\n * One page of a stream's chunk log from `fromSeq` (inclusive), ordered by\n * seq. Paged rather than read-it-all so replaying a large stream holds\n * one page of segment bodies in memory, not the whole turn.\n */\n readChunks(\n streamId: string,\n fromSeq: number,\n limit: number\n ): StreamChunkRow[];\n /** Every stream row, newest first (created_at, then insertion order). */\n listRows(): StreamRow[];\n /**\n * Every row carrying a tag, newest first, optionally narrowed to one\n * state. Tags are non-unique and the table is shared across producers,\n * so callers apply their own ownership filter (e.g. chat's metadata\n * marker) rather than trusting the newest row.\n */\n rowsByTag(tag: string, state?: StreamState): StreamRow[];\n /**\n * Import one historical stream row verbatim (migrations, test seeding):\n * explicit timestamps and count, no events, no wakeups.\n */\n importStream(row: {\n streamId: string;\n state: StreamState;\n tag: string | null;\n metadata: Record<string, StreamJson> | undefined;\n chunkCount: number;\n createdAt: number;\n updatedAt: number;\n closedAt: number | null;\n }): void;\n /**\n * Import one historical chunk at the log's tail: one INSERT, nothing else.\n * The stream row is not touched — importers pass the final `chunkCount`\n * and `updatedAt` to {@link importStream}, so the row is exact at rest\n * without a per-chunk row write.\n */\n importChunk(streamId: string, chunk: StreamJson, createdAt: number): void;\n}\n\n/**\n * Durable incremental output for a Lifecycle Object.\n *\n * `open()` a stream, `append()` chunks (synchronous durable writes that wake\n * live readers), and settle it with `close()` or `error()`. `read()` replays\n * persisted chunks from a cursor and then tails live appends; `status()`\n * reports the state and cursor — the recovery evidence a Task's `recover`\n * callback consults after its producer was interrupted.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class Streams extends LifecycleCapability {\n readonly #maxChunkBytes: number;\n /** Wakeup callbacks for readers tailing a live stream, per stream. */\n readonly #wakeups = new Map<string, Set<() => void>>();\n /**\n * Whether the schema v1 `cf_agents_stream_chunks` table still exists.\n * Its rows are folded into blocks one stream at a time, on first touch\n * (see {@link #foldLegacyChunks}); the table is dropped once empty.\n */\n #legacyChunkTable = false;\n\n constructor(options: StreamsOptions = {}) {\n super(\"streams\");\n this.#maxChunkBytes = options.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;\n }\n\n // ── Lifecycle capability hooks ───────────────────────────────────────────\n\n /** Migrate stream storage during Lifecycle startup. */\n async onStart(): Promise<void> {\n const storage = this.lifecycle.storage;\n const version = (await storage.get<number>(STREAM_SCHEMA_VERSION_KEY)) ?? 0;\n if (version < CURRENT_STREAM_SCHEMA_VERSION) {\n this.#ensureTables();\n await storage.put(\n STREAM_SCHEMA_VERSION_KEY,\n CURRENT_STREAM_SCHEMA_VERSION\n );\n }\n if (version >= 1) this.#legacyChunkTable = this.#hasLegacyChunkTable();\n }\n\n // ── Producer surface ─────────────────────────────────────────────────────\n\n /**\n * Open a stream for writing. Idempotent on the id: reopening a live stream\n * returns a writer positioned at its current cursor; reopening a terminal\n * stream throws {@link StreamClosedError}.\n */\n async open(\n streamId: string,\n options: StreamOpenOptions = {}\n ): Promise<StreamWriter> {\n await this.lifecycle.ready();\n this.#validateStreamId(streamId);\n\n const existing = this.#getStream(streamId);\n if (existing) {\n if (existing.state !== \"streaming\") {\n throw new StreamClosedError(\n streamId,\n `already settled as ${existing.state}`\n );\n }\n // The tag is part of the stream's identity, fixed at creation: a\n // reopen naming a different tag is a config conflict, not a resume.\n if (\n options.tag !== undefined &&\n options.tag !== (existing.tag ?? undefined)\n ) {\n throw new Error(\n `Stream \"${streamId}\" is already open with tag ${JSON.stringify(existing.tag)}; refusing reopen with tag ${JSON.stringify(options.tag)}`\n );\n }\n return this.#writer(streamId);\n }\n\n const metadataJson = this.#serialize(\n options.metadata,\n `metadata for stream \"${streamId}\"`\n );\n const now = Date.now();\n this.#sql`\n INSERT INTO cf_agents_streams\n (stream_id, state, tag, metadata, chunk_count, created_at, updated_at)\n VALUES\n (${streamId}, 'streaming', ${options.tag ?? null}, ${metadataJson}, 0, ${now}, ${now})\n `;\n this.#emit(\"stream:opened\", { streamId });\n return this.#writer(streamId);\n }\n\n // ── Consumer surface ─────────────────────────────────────────────────────\n\n /**\n * Replay persisted chunks from `from` (inclusive), then tail live appends\n * until the stream settles. Ends when the stream reaches a terminal state\n * and every durable chunk has been yielded; a read of an `errored` stream\n * still yields its chunks and then simply ends — consult {@link status}\n * for the terminal outcome. Aborting `options.signal` throws its reason.\n */\n async *read(\n streamId: string,\n options: StreamReadOptions = {}\n ): AsyncGenerator<StreamChunk, void, undefined> {\n const signal = options.signal;\n for await (const batch of this.readBatches(streamId, options)) {\n for (const item of batch) {\n if (signal?.aborted) throw signal.reason ?? new Error(\"Read aborted\");\n yield item;\n }\n }\n }\n\n /**\n * Batched form of {@link read}: yields non-empty arrays of consecutive\n * chunks instead of one chunk at a time. Replay yields up to\n * `options.batchSize` chunks per array; a live tail yields everything\n * that accumulated since the last wakeup as one array — so a consumer\n * paying per write (an SSE flush, an RPC hop, a history append) pays\n * once per backlog, not once per chunk. Same lifecycle as {@link read}:\n * ends when the stream settles and every durable chunk has been\n * yielded; aborting `options.signal` throws its reason.\n */\n async *readBatches(\n streamId: string,\n options: StreamReadBatchesOptions = {}\n ): AsyncGenerator<StreamChunk[], void, undefined> {\n await this.lifecycle.ready();\n const signal = options.signal;\n const batchSize = Math.max(\n 1,\n Math.floor(options.batchSize ?? READ_BATCH_SIZE)\n );\n let next = Math.max(0, options.from ?? 0);\n let signaledUpToDate = false;\n\n if (this.#state(streamId) === undefined) {\n throw new StreamNotFoundError(streamId);\n }\n\n for (;;) {\n if (signal?.aborted) throw signal.reason ?? new Error(\"Read aborted\");\n\n const rows = this.#readChunks(streamId, next, batchSize);\n if (rows.length > 0) {\n next = rows[rows.length - 1].seq + 1;\n yield rows.map((row) => ({\n seq: row.seq,\n chunk: JSON.parse(row.chunk) as StreamJson\n }));\n }\n if (rows.length === batchSize) continue;\n\n // A short batch means every durable chunk up to this instant has been\n // yielded — the reader has reached the tail (caught up ≠ ended: a live\n // stream keeps tailing from here).\n if (!signaledUpToDate) {\n signaledUpToDate = true;\n options.onUpToDate?.();\n // The callback is application code and can synchronously append to\n // this same stream — a wake that would fire before any waiter is\n // registered. Re-poll instead of sleeping so that append is never a\n // lost wakeup; everything from the next query to waiter\n // registration is synchronous, so no other append can slip past.\n continue;\n }\n\n const state = this.#state(streamId);\n if (state === undefined) return; // deleted mid-read: nothing further\n if (state !== \"streaming\") {\n // Terminal. Appends happen-before settlement (the append fence\n // rejects a settled stream), so a poll that returned zero rows in\n // this same synchronous block proves every durable chunk has been\n // yielded; a non-empty short batch yielded (a suspension point),\n // so re-poll to drain the remainder first.\n if (rows.length === 0) return;\n continue;\n }\n\n // Live tail: wait for the next append or settlement, then re-poll.\n // Wakeups carry no data, so there is nothing to buffer or dedupe.\n await this.#waitForWakeup(streamId, signal);\n }\n }\n\n /** Read one stream's state and cursor, or null when it does not exist. */\n async status(streamId: string): Promise<StreamStatus | null> {\n await this.lifecycle.ready();\n const row = this.#getStream(streamId);\n return row ? this.#rowToStatus(row) : null;\n }\n\n /** List streams, newest first. */\n async list(options: StreamListOptions = {}): Promise<StreamStatus[]> {\n await this.lifecycle.ready();\n const states = Array.isArray(options.state)\n ? options.state\n : options.state !== undefined\n ? [options.state]\n : [];\n let query = \"SELECT * FROM cf_agents_streams WHERE 1 = 1\";\n const params: (string | number)[] = [];\n if (states.length > 0) {\n query += ` AND state IN (${states.map(() => \"?\").join(\", \")})`;\n params.push(...states);\n }\n if (options.tag !== undefined) {\n query += \" AND tag = ?\";\n params.push(options.tag);\n }\n query += \" ORDER BY created_at DESC, stream_id DESC LIMIT ?\";\n params.push(options.limit ?? DEFAULT_LIST_LIMIT);\n let rows: unknown[];\n try {\n rows = this.lifecycle.storage.sql.exec(query, ...params).toArray();\n } catch (cause) {\n throw new SqlError(query, cause);\n }\n // SAFETY: the query selects * from Streams' own schema.\n return (rows as StreamRow[]).map((row) => this.#rowToStatus(row));\n }\n\n /**\n * Delete one terminal stream and its chunk log.\n *\n * @returns True when a terminal stream was deleted; false when none\n * exists. Throws on a live stream — settle it first.\n */\n async delete(streamId: string): Promise<boolean> {\n await this.lifecycle.ready();\n const row = this.#getStream(streamId);\n if (!row) return false;\n if (row.state === \"streaming\") {\n throw new Error(\n `Cannot delete live stream \"${streamId}\"; close() or error() it first`\n );\n }\n this.#deleteRows(streamId);\n this.#emit(\"stream:deleted\", { streamId });\n return true;\n }\n\n // ── Internal sync aperture ───────────────────────────────────────────────\n\n /**\n * @internal Synchronous storage operations for same-isolate first-party\n * machinery — today the chat `ResumableStream` adapter, whose whole public\n * surface is synchronous and constructed before the Lifecycle starts.\n * Bypasses `lifecycle.ready()`: the caller owns startup ordering. The\n * invariant-bearing writes (append fence, settlement, wakeups, events) go\n * through the same private methods as the public API, so live readers and\n * diagnostics observe aperture writes exactly like capability writes. Will\n * break without notice; never use from application code.\n */\n __DO_NOT_USE_WILL_BREAK__sync(): StreamsSyncInternal {\n return {\n ensureTables: () => this.#ensureTables(),\n getStream: (streamId) => this.#getStream(streamId),\n insertStream: (streamId, tag, metadata) => {\n this.#validateStreamId(streamId);\n const metadataJson = this.#serialize(\n metadata,\n `metadata for stream \"${streamId}\"`\n );\n const now = Date.now();\n this.#sql`\n INSERT INTO cf_agents_streams\n (stream_id, state, tag, metadata, chunk_count, created_at, updated_at)\n VALUES\n (${streamId}, 'streaming', ${tag}, ${metadataJson}, 0, ${now}, ${now})\n `;\n this.#emit(\"stream:opened\", { streamId });\n },\n append: (streamId, chunk) => this.#append(streamId, chunk),\n lastChunkAt: (streamId) => this.#tail(streamId).lastChunkAt,\n cursor: (streamId) => this.#tail(streamId).nextSeq,\n onDelete: (hook) => {\n this.#deleteHooks.push(hook);\n return () => {\n const index = this.#deleteHooks.indexOf(hook);\n if (index !== -1) this.#deleteHooks.splice(index, 1);\n };\n },\n settle: (streamId, state, reason, options) =>\n this.#settle(streamId, state, reason, options),\n deleteUnchecked: (streamId) => {\n const removed = this.#deleteRows(streamId);\n if (removed > 0) this.#emit(\"stream:deleted\", { streamId });\n // Unchecked deletes can remove a live stream: wake tailing readers\n // so they observe the deletion instead of pending forever.\n this.#wake(streamId);\n },\n deleteMany: (streamIds) => {\n for (const streamId of streamIds) {\n this.#deleteRows(streamId);\n this.#wake(streamId);\n }\n },\n readChunks: (streamId, fromSeq, limit) =>\n this.#readChunks(streamId, fromSeq, limit),\n listRows: () => this.#sql<StreamRow>`\n SELECT * FROM cf_agents_streams ORDER BY created_at DESC, rowid DESC\n `,\n rowsByTag: (tag, state) =>\n state\n ? this.#sql<StreamRow>`\n SELECT * FROM cf_agents_streams\n WHERE tag = ${tag} AND state = ${state}\n ORDER BY created_at DESC, rowid DESC\n `\n : this.#sql<StreamRow>`\n SELECT * FROM cf_agents_streams\n WHERE tag = ${tag}\n ORDER BY created_at DESC, rowid DESC\n `,\n importStream: (row) => {\n this.#validateStreamId(row.streamId);\n const metadataJson = this.#serialize(\n row.metadata,\n `metadata for stream \"${row.streamId}\"`\n );\n this.#sql`\n INSERT INTO cf_agents_streams\n (stream_id, state, tag, metadata, chunk_count,\n created_at, updated_at, closed_at)\n VALUES\n (${row.streamId}, ${row.state}, ${row.tag}, ${metadataJson},\n ${row.chunkCount}, ${row.createdAt}, ${row.updatedAt},\n ${row.closedAt})\n `;\n },\n importChunk: (streamId, chunk, createdAt) => {\n const chunkJson = this.#serialize(\n chunk,\n `chunk for stream \"${streamId}\"`\n );\n if (chunkJson === null) return;\n this.#writeChunk(streamId, chunkJson, createdAt);\n }\n };\n }\n\n // ── Writer ───────────────────────────────────────────────────────────────\n\n #writer(streamId: string): StreamWriter {\n const capability = this;\n return {\n streamId,\n get cursor(): number {\n return capability.#tail(streamId).nextSeq;\n },\n append: (chunk) => this.#append(streamId, chunk),\n close: (options) => this.#settle(streamId, \"completed\", null, options),\n error: (reason, options) =>\n this.#settle(streamId, \"errored\", reason ?? null, options)\n };\n }\n\n #append(streamId: string, chunk: StreamJson): number {\n // Serialization runs BEFORE the fence read: JSON.stringify can execute\n // user toJSON() methods, which may synchronously re-enter this stream.\n const chunkJson = this.#serialize(chunk, `chunk for stream \"${streamId}\"`);\n if (chunkJson === null) {\n throw new StreamSerializationError(\n `chunk for stream \"${streamId}\"`,\n \"chunks must not be undefined\"\n );\n }\n // The fence is a read, and its atomicity lives in the isolate's\n // threading model: a Durable Object executes one synchronous block at\n // a time, so the state check, tail read, and block write below cannot\n // interleave with a settle, delete, or another append. Nothing between\n // here and the write may await or call user code — either would\n // reintroduce the lost-update races the old guarded-UPDATE fence\n // prevented, at the cost of one stream-row write per append.\n const state = this.#state(streamId);\n if (state !== \"streaming\") {\n throw new StreamClosedError(\n streamId,\n state !== undefined ? `already settled as ${state}` : \"it was deleted\"\n );\n }\n const seq = this.#writeChunk(streamId, chunkJson, Date.now());\n this.#wake(streamId);\n return seq;\n }\n\n /**\n * Append one serialized chunk to the stream's open block, or open a new\n * block when the current one is full. Either way it is one billed row:\n * an UPDATE that grows the block body, or the INSERT of the next block.\n * Blocks are what make cleanup cheap — a stream of thousands of chunks\n * is a handful of rows to delete at cutover, not thousands.\n */\n #writeChunk(streamId: string, chunkJson: string, at: number): number {\n const tail = this.#blockTail(streamId);\n const seq = tail?.seq_to ?? 0;\n if (tail && tail.len + chunkJson.length + 1 <= BLOCK_MAX_CHARS) {\n this.#sql`\n UPDATE cf_agents_stream_blocks\n SET body = body || ',' || ${chunkJson}, seq_to = ${seq + 1}, updated_at = ${at}\n WHERE stream_id = ${streamId} AND block = ${tail.block}\n `;\n } else {\n this.#sql`\n INSERT INTO cf_agents_stream_blocks\n (stream_id, block, seq_from, seq_to, body, created_at, updated_at)\n VALUES\n (${streamId}, ${(tail?.block ?? -1) + 1}, ${seq}, ${seq + 1}, ${chunkJson}, ${at}, ${at})\n `;\n }\n return seq;\n }\n\n /**\n * One page of chunks from `fromSeq`, in seq order, parsing one block at\n * a time. A block body is the chunks' JSON texts joined by commas, so\n * `[${body}]` parses straight back into the chunk values.\n */\n #readChunks(\n streamId: string,\n fromSeq: number,\n limit: number\n ): StreamChunkRow[] {\n this.#foldLegacyChunks(streamId);\n const rows: StreamChunkRow[] = [];\n let block = -1;\n while (rows.length < limit) {\n const next = this.#sql<{\n block: number;\n seq_from: number;\n seq_to: number;\n body: string;\n updated_at: number;\n }>`\n SELECT block, seq_from, seq_to, body, updated_at\n FROM cf_agents_stream_blocks\n WHERE stream_id = ${streamId} AND block > ${block} AND seq_to > ${fromSeq}\n ORDER BY block ASC\n LIMIT 1\n `[0];\n if (!next) break;\n block = next.block;\n const chunks = JSON.parse(`[${next.body}]`) as StreamJson[];\n for (\n let seq = Math.max(fromSeq, next.seq_from);\n seq < next.seq_to && rows.length < limit;\n seq++\n ) {\n rows.push({\n stream_id: streamId,\n seq,\n chunk: JSON.stringify(chunks[seq - next.seq_from]),\n created_at: next.updated_at\n });\n }\n }\n return rows;\n }\n\n /** Delete a stream's blocks and row. Returns rows removed from the row table. */\n readonly #deleteHooks: Array<(row: StreamRow, cursor: number) => void> = [];\n\n /**\n * Remove a stream's row and log. Deletion hooks see the row and its\n * cursor first, so an owner can account for the segments before they are\n * gone; this is the single point every delete path passes through.\n */\n #deleteRows(streamId: string): number {\n if (this.#deleteHooks.length > 0) {\n const row = this.#getStream(streamId);\n if (row) {\n const cursor = this.#tail(streamId).nextSeq;\n for (const hook of this.#deleteHooks) hook(row, cursor);\n }\n }\n if (this.#legacyChunkTable) {\n // Unfolded v1 rows die with the stream; no point folding them first.\n this.#sql`DELETE FROM cf_agents_stream_chunks WHERE stream_id = ${streamId}`;\n this.#dropLegacyChunkTableIfEmpty();\n }\n this.#sql`DELETE FROM cf_agents_stream_blocks WHERE stream_id = ${streamId}`;\n return this.#sqlWrite(\"DELETE FROM cf_agents_streams WHERE stream_id = ?\", [\n streamId\n ]);\n }\n\n /**\n * @returns Whether this call transitioned the stream (a repeat, or a\n * deleted stream, is a no-op and returns false: the caller's `commit`\n * does not run and nothing is discarded).\n */\n #settle(\n streamId: string,\n state: Extract<StreamState, \"completed\" | \"errored\">,\n reason: string | null,\n options?: StreamSettleOptions\n ): boolean {\n if (!options?.commit && !options?.discard) {\n const settled = this.#settleRow(streamId, state, reason);\n if (settled) this.#emitSettled(streamId, state, reason);\n // Idempotent for recovery callers; readers re-poll and observe the\n // terminal state either way.\n this.#wake(streamId);\n return settled;\n }\n // The cutover: settle, the caller's writes (a session message), and\n // the discard of this stream's rows commit together or not at all. A\n // throwing `commit` rolls everything back and leaves the stream live.\n // Events and wakeups are side effects outside SQLite, so they fire only\n // once the transaction has returned.\n let settled = false;\n let deleted = false;\n const hadLegacy = this.#legacyChunkTable;\n try {\n this.lifecycle.storage.transactionSync(() => {\n settled = this.#settleRow(streamId, state, reason);\n if (!settled) return;\n options.commit?.();\n if (options.discard) deleted = this.#deleteRows(streamId) > 0;\n });\n } finally {\n // The settle's tail read may have folded this stream's v1 rows and,\n // if they were the last, dropped the legacy table and cleared the\n // flag — inside the transaction. A rollback restores the table but\n // not the flag, so re-derive it from the schema rather than trust a\n // bit written by a transaction that may not have committed.\n if (hadLegacy && !this.#legacyChunkTable) {\n this.#legacyChunkTable = this.#hasLegacyChunkTable();\n }\n }\n if (settled) this.#emitSettled(streamId, state, reason);\n if (deleted) this.#emit(\"stream:deleted\", { streamId });\n this.#wake(streamId);\n return settled;\n }\n\n /**\n * The one guarded UPDATE that ends a stream. Settlement is the moment\n * the stream row becomes exact at rest: the same write stamps the final\n * cursor, read from the chunk log's tail in the same synchronous block.\n * While the stream was live, appends wrote only the chunk log — the\n * row's chunk_count and updated_at were not maintained per append.\n * @returns Whether the row transitioned from `streaming`.\n */\n #settleRow(\n streamId: string,\n state: Extract<StreamState, \"completed\" | \"errored\">,\n reason: string | null\n ): boolean {\n const finalCursor = this.#tail(streamId).nextSeq;\n const settled = this.#sqlWrite(\n `UPDATE cf_agents_streams\n SET state = ?, error_message = ?, closed_at = ?, updated_at = ?,\n chunk_count = ?\n WHERE stream_id = ? AND state = 'streaming'`,\n [state, reason, Date.now(), Date.now(), finalCursor, streamId]\n );\n return settled > 0;\n }\n\n #emitSettled(\n streamId: string,\n state: Extract<StreamState, \"completed\" | \"errored\">,\n reason: string | null\n ): void {\n this.#emit(state === \"completed\" ? \"stream:closed\" : \"stream:errored\", {\n streamId,\n ...(reason !== null ? { reason } : {})\n });\n }\n\n // ── Live fanout ──────────────────────────────────────────────────────────\n\n #wake(streamId: string): void {\n const waiters = this.#wakeups.get(streamId);\n if (!waiters) return;\n this.#wakeups.delete(streamId);\n for (const wake of waiters) wake();\n }\n\n #waitForWakeup(streamId: string, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const waiters = this.#wakeups.get(streamId) ?? new Set();\n this.#wakeups.set(streamId, waiters);\n const wake = () => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n };\n const onAbort = () => {\n waiters.delete(wake);\n // The last aborted waiter removes the map entry too, so abandoned\n // streams do not accumulate empty sets for the isolate's lifetime.\n if (waiters.size === 0 && this.#wakeups.get(streamId) === waiters) {\n this.#wakeups.delete(streamId);\n }\n // Resolve rather than reject: the read loop re-checks the signal\n // first and throws its reason from generator context.\n resolve();\n };\n waiters.add(wake);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n\n // ── Storage ──────────────────────────────────────────────────────────────\n\n #validateStreamId(streamId: string): void {\n if (typeof streamId !== \"string\" || streamId.length === 0) {\n throw new Error(\"Stream ids must be non-empty strings\");\n }\n if (streamId.length > MAX_STREAM_ID_LENGTH) {\n throw new Error(`Stream id exceeds ${MAX_STREAM_ID_LENGTH} characters`);\n }\n }\n\n #serialize(value: unknown, context: string): string | null {\n if (value === undefined) return null;\n let json: string | undefined;\n try {\n json = JSON.stringify(value);\n } catch (error) {\n throw new StreamSerializationError(\n context,\n error instanceof Error ? error.message : String(error)\n );\n }\n if (json === undefined) {\n throw new StreamSerializationError(\n context,\n `value of type ${typeof value} has no JSON representation`\n );\n }\n const bytes = utf8.encode(json).byteLength;\n if (bytes > this.#maxChunkBytes) {\n throw new StreamSerializationError(\n context,\n `serialized size ${bytes} bytes exceeds the ${this.#maxChunkBytes}-byte limit`\n );\n }\n return json;\n }\n\n #sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[] {\n const query = strings.reduce(\n (result, part, index) =>\n result + part + (index < values.length ? \"?\" : \"\"),\n \"\"\n );\n try {\n // SAFETY: Streams queries select from its own schema; T describes the\n // projected columns of the accompanying query text.\n return [...this.lifecycle.storage.sql.exec(query, ...values)] as T[];\n } catch (cause) {\n throw new SqlError(query, cause);\n }\n }\n\n #sqlWrite(query: string, params: (string | number | null)[]): number {\n try {\n return this.lifecycle.storage.sql.exec(query, ...params).rowsWritten;\n } catch (cause) {\n throw new SqlError(query, cause);\n }\n }\n\n #getStream(streamId: string): StreamRow | undefined {\n const rows = this.#sql<StreamRow>`\n SELECT * FROM cf_agents_streams WHERE stream_id = ${streamId}\n `;\n return rows[0];\n }\n\n /**\n * One stream's state alone — the narrow read for the append fence and the\n * reader loop's liveness checks, which need neither the metadata column\n * nor the (live-stale) counters of the full row.\n */\n #state(streamId: string): StreamState | undefined {\n const rows = this.#sql<{ state: StreamState }>`\n SELECT state FROM cf_agents_streams WHERE stream_id = ${streamId}\n `;\n return rows[0]?.state;\n }\n\n /**\n * The chunk log's tail: the next append sequence and the newest chunk's\n * timestamp. One PK-served read (`ORDER BY seq DESC LIMIT 1`), and the\n * single derivation point for every cursor and per-append-liveness\n * consumer — while a stream is live, the chunk log is authoritative and\n * the stream row's `chunk_count`/`updated_at` are not maintained.\n */\n #tail(streamId: string): { nextSeq: number; lastChunkAt: number | null } {\n const tail = this.#blockTail(streamId);\n return tail\n ? { nextSeq: tail.seq_to, lastChunkAt: tail.updated_at }\n : { nextSeq: 0, lastChunkAt: null };\n }\n\n /** The open block: one PK-served read (`ORDER BY block DESC LIMIT 1`). */\n #blockTail(streamId: string) {\n this.#foldLegacyChunks(streamId);\n return this.#sql<{\n block: number;\n seq_to: number;\n updated_at: number;\n len: number;\n }>`\n SELECT block, seq_to, updated_at, length(body) AS len\n FROM cf_agents_stream_blocks\n WHERE stream_id = ${streamId}\n ORDER BY block DESC\n LIMIT 1\n `[0];\n }\n\n /**\n * Schema v1 → v2 is lazy: the per-chunk `cf_agents_stream_chunks` rows of\n * ONE stream are folded into blocks the first time that stream is\n * touched (a tail read before an append or settle, a replay, a delete).\n * Startup never pays for the whole legacy log, so an object that let a\n * large log accumulate still boots within its memory budget; each fold\n * pages through its stream's rows and writes whole blocks, not one row\n * per chunk. The table is dropped once the last stream's rows are gone.\n */\n #foldLegacyChunks(streamId: string): void {\n if (!this.#legacyChunkTable) return;\n this.lifecycle.storage.transactionSync(() => {\n const tail = this.#sql<{ block: number; seq_to: number }>`\n SELECT block, seq_to FROM cf_agents_stream_blocks\n WHERE stream_id = ${streamId}\n ORDER BY block DESC\n LIMIT 1\n `[0];\n let block = (tail?.block ?? -1) + 1;\n let seq = tail?.seq_to ?? 0;\n let body = \"\";\n let seqFrom = seq;\n let createdAt = 0;\n let updatedAt = 0;\n const flush = () => {\n if (body === \"\") return;\n this.#sql`\n INSERT INTO cf_agents_stream_blocks\n (stream_id, block, seq_from, seq_to, body, created_at, updated_at)\n VALUES\n (${streamId}, ${block}, ${seqFrom}, ${seq}, ${body}, ${createdAt}, ${updatedAt})\n `;\n block += 1;\n body = \"\";\n seqFrom = seq;\n };\n let after = -1;\n for (;;) {\n const rows = this.#sql<{\n seq: number;\n chunk: string;\n created_at: number;\n }>`\n SELECT seq, chunk, created_at FROM cf_agents_stream_chunks\n WHERE stream_id = ${streamId} AND seq > ${after}\n ORDER BY seq ASC\n LIMIT ${LEGACY_FOLD_PAGE_ROWS}\n `;\n for (const row of rows) {\n if (\n body !== \"\" &&\n body.length + row.chunk.length + 1 > BLOCK_MAX_CHARS\n ) {\n flush();\n }\n if (body === \"\") createdAt = row.created_at;\n body = body === \"\" ? row.chunk : `${body},${row.chunk}`;\n updatedAt = row.created_at;\n seq += 1;\n after = row.seq;\n }\n if (rows.length < LEGACY_FOLD_PAGE_ROWS) break;\n }\n flush();\n if (after >= 0) {\n this.#sql`DELETE FROM cf_agents_stream_chunks WHERE stream_id = ${streamId}`;\n }\n this.#dropLegacyChunkTableIfEmpty();\n });\n }\n\n #hasLegacyChunkTable(): boolean {\n return (\n this.#sql<{ name: string }>`\n SELECT name FROM sqlite_master\n WHERE type = 'table' AND name = 'cf_agents_stream_chunks'\n `.length > 0\n );\n }\n\n #dropLegacyChunkTableIfEmpty(): void {\n const remaining = this.#sql<{ n: number }>`\n SELECT COUNT(*) AS n FROM (SELECT 1 FROM cf_agents_stream_chunks LIMIT 1)\n `[0].n;\n if (remaining > 0) return;\n this.#sqlWrite(\"DROP TABLE cf_agents_stream_chunks\", []);\n this.#legacyChunkTable = false;\n }\n\n #rowToStatus(row: StreamRow): StreamStatus {\n // A live row's stored counters are stale by design (appends write only\n // the chunk log), so cursor and updatedAt are derived from the tail;\n // terminal rows were stamped exact at settle and read straight through.\n let cursor = row.chunk_count;\n let updatedAt = row.updated_at;\n if (row.state === \"streaming\") {\n const tail = this.#tail(row.stream_id);\n cursor = tail.nextSeq;\n if (tail.lastChunkAt !== null && tail.lastChunkAt > updatedAt) {\n updatedAt = tail.lastChunkAt;\n }\n }\n return {\n streamId: row.stream_id,\n state: row.state,\n cursor,\n ...(row.tag !== null ? { tag: row.tag } : {}),\n ...(row.metadata !== null\n ? {\n metadata: JSON.parse(row.metadata) as Record<string, StreamJson>\n }\n : {}),\n ...(row.error_message !== null ? { error: row.error_message } : {}),\n createdAt: row.created_at,\n updatedAt,\n ...(row.closed_at !== null ? { closedAt: row.closed_at } : {})\n };\n }\n\n #ensureTables(): void {\n const rawSql = (query: string) => {\n try {\n this.lifecycle.storage.sql.exec(query);\n } catch (cause) {\n throw new SqlError(query, cause);\n }\n };\n // The chunk table is WITHOUT ROWID: Cloudflare bills index maintenance\n // as rows written, and an ordinary rowid table maintains a hidden\n // UNIQUE index for its PRIMARY KEY — one extra billed row on every\n // INSERT and DELETE. WITHOUT ROWID makes the PK the table itself, so a\n // chunk append bills exactly one row (see the write-accounting test).\n // The stream metadata table deliberately stays a rowid table: rowid is\n // the insertion-order tiebreak that keeps \"newest first\" deterministic\n // when rows share a created_at millisecond (stream ids are random),\n // and it costs one billed row per stream open — per turn, never per\n // chunk.\n rawSql(`\n CREATE TABLE IF NOT EXISTS cf_agents_streams (\n stream_id TEXT PRIMARY KEY,\n state TEXT NOT NULL CHECK (state IN (\n 'streaming', 'completed', 'errored'\n )),\n tag TEXT,\n metadata TEXT,\n error_message TEXT,\n chunk_count INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n closed_at INTEGER\n )`);\n rawSql(`\n CREATE INDEX IF NOT EXISTS idx_cf_agents_streams_tag\n ON cf_agents_streams(tag, created_at)\n `);\n rawSql(`\n CREATE TABLE IF NOT EXISTS cf_agents_stream_blocks (\n stream_id TEXT NOT NULL,\n block INTEGER NOT NULL,\n seq_from INTEGER NOT NULL,\n seq_to INTEGER NOT NULL,\n body TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (stream_id, block)\n ) WITHOUT ROWID`);\n }\n\n #emit(type: string, payload: Record<string, unknown>): void {\n this.lifecycle.events.emit(type, payload);\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
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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"}