agents 0.22.0 → 0.23.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 (186) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-DE5zmCQ8.d.ts} +1038 -394
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +26 -26
  5. package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-DtXMTDGM.d.ts} +7 -7
  6. package/dist/agent-tools.d.ts +21 -21
  7. package/dist/browser/ai.js +4 -1
  8. package/dist/browser/ai.js.map +1 -1
  9. package/dist/browser/tanstack-ai.js.map +1 -1
  10. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  11. package/dist/callable-decorator.d.ts +18 -0
  12. package/dist/callable-decorator.js +71 -0
  13. package/dist/callable-decorator.js.map +1 -0
  14. package/dist/capability-BjSKYpzg.js.map +1 -1
  15. package/dist/capability-runner-Be_-PLR1.d.ts +459 -0
  16. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  17. package/dist/channels/ai-sdk.d.ts +46 -0
  18. package/dist/channels/ai-sdk.js +120 -0
  19. package/dist/channels/ai-sdk.js.map +1 -0
  20. package/dist/channels/email.d.ts +95 -0
  21. package/dist/channels/email.js +323 -0
  22. package/dist/channels/email.js.map +1 -0
  23. package/dist/channels/index.d.ts +233 -0
  24. package/dist/channels/index.js +608 -0
  25. package/dist/channels/index.js.map +1 -0
  26. package/dist/channels/slack.d.ts +140 -0
  27. package/dist/channels/slack.js +614 -0
  28. package/dist/channels/slack.js.map +1 -0
  29. package/dist/channels/tanstack-ai.d.ts +39 -0
  30. package/dist/channels/tanstack-ai.js +17 -0
  31. package/dist/channels/tanstack-ai.js.map +1 -0
  32. package/dist/channels/telegram.d.ts +106 -0
  33. package/dist/channels/telegram.js +427 -0
  34. package/dist/channels/telegram.js.map +1 -0
  35. package/dist/channels/voice.d.ts +45 -0
  36. package/dist/channels/voice.js +122 -0
  37. package/dist/channels/voice.js.map +1 -0
  38. package/dist/chat/index.d.ts +2325 -2019
  39. package/dist/chat/index.js +888 -518
  40. package/dist/chat/index.js.map +1 -1
  41. package/dist/chat-sdk/index.d.ts +7 -7
  42. package/dist/chat-sdk/index.js +1 -1
  43. package/dist/client.d.ts +1 -1
  44. package/dist/context/index.d.ts +216 -0
  45. package/dist/context/index.js +454 -0
  46. package/dist/context/index.js.map +1 -0
  47. package/dist/{current-agent-CuMErtly.d.ts → current-agent-Da_C9a3b.d.ts} +90 -107
  48. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  49. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  50. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  51. package/dist/diagnostics-C4jcz3VK.js +360 -0
  52. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  53. package/dist/index-BB0kqhIz.d.ts +101 -0
  54. package/dist/index-BVVgDSdq.d.ts +1 -0
  55. package/dist/index-XDkuQ7zm.d.ts +89 -0
  56. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  57. package/dist/index.d.ts +91 -82
  58. package/dist/index.js +3 -2
  59. package/dist/ingress-BfetZbMO.js +83 -0
  60. package/dist/ingress-BfetZbMO.js.map +1 -0
  61. package/dist/internal-CYlgHl1l.js +59 -0
  62. package/dist/internal-CYlgHl1l.js.map +1 -0
  63. package/dist/internal_context.d.ts +1 -1
  64. package/dist/lifecycle/index.d.ts +35 -17
  65. package/dist/lifecycle/index.js +1 -1
  66. package/dist/lifecycle-CMRGjZdw.js +1299 -0
  67. package/dist/lifecycle-CMRGjZdw.js.map +1 -0
  68. package/dist/mcp/client/index.d.ts +20 -20
  69. package/dist/mcp/index.d.ts +35 -35
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/observability/index.d.ts +1 -1
  72. package/dist/observability/index.js +1 -1
  73. package/dist/react.d.ts +4 -4
  74. package/dist/{retries-CAvxtG9d.d.ts → retries-D9Ds-1lz.d.ts} +17 -6
  75. package/dist/retries.d.ts +8 -6
  76. package/dist/retries.js +13 -1
  77. package/dist/retries.js.map +1 -1
  78. package/dist/routing/index.d.ts +137 -0
  79. package/dist/routing/index.js +244 -0
  80. package/dist/routing/index.js.map +1 -0
  81. package/dist/sanitize-D9TujEK8.js +79 -0
  82. package/dist/sanitize-D9TujEK8.js.map +1 -0
  83. package/dist/scheduler-DD9NdYbF.js +665 -0
  84. package/dist/scheduler-DD9NdYbF.js.map +1 -0
  85. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-Dwh85ZGl.d.ts} +21 -22
  86. package/dist/schedules/index.d.ts +1 -1
  87. package/dist/schedules/index.js +1 -1
  88. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  89. package/dist/serializable.d.ts +1 -1
  90. package/dist/sessions/index.d.ts +441 -0
  91. package/dist/sessions/index.js +2063 -0
  92. package/dist/sessions/index.js.map +1 -0
  93. package/dist/skills/index.d.ts +99 -0
  94. package/dist/skills/index.js +254 -5
  95. package/dist/skills/index.js.map +1 -1
  96. package/dist/{src-5W6JNKVb.js → src-DlSHshb2.js} +1460 -1110
  97. package/dist/src-DlSHshb2.js.map +1 -0
  98. package/dist/streams/index.d.ts +120 -0
  99. package/dist/streams/index.js +107 -0
  100. package/dist/streams/index.js.map +1 -0
  101. package/dist/streams-D6tJ0NN9.d.ts +370 -0
  102. package/dist/streams-DZKgAj9b.js +709 -0
  103. package/dist/streams-DZKgAj9b.js.map +1 -0
  104. package/dist/sub-routing.d.ts +12 -12
  105. package/dist/surface-bZZJqBka.js +17 -0
  106. package/dist/surface-bZZJqBka.js.map +1 -0
  107. package/dist/tasks/index.d.ts +64 -0
  108. package/dist/tasks/index.js +2 -0
  109. package/dist/tasks-BRJ5zgya.d.ts +517 -0
  110. package/dist/tasks-ylZgBjhj.js +1656 -0
  111. package/dist/tasks-ylZgBjhj.js.map +1 -0
  112. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  113. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  114. package/dist/text-stream-CpdiKrJB.js +272 -0
  115. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  116. package/dist/tokens-nHAKcN6M.js +52 -0
  117. package/dist/tokens-nHAKcN6M.js.map +1 -0
  118. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  119. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  120. package/dist/types-B7LojTe4.d.ts +202 -0
  121. package/dist/types-_Faxb570.d.ts +439 -0
  122. package/dist/voice/client.d.ts +226 -0
  123. package/dist/voice/client.js +932 -0
  124. package/dist/voice/client.js.map +1 -0
  125. package/dist/voice/errors.d.ts +43 -0
  126. package/dist/voice/errors.js +41 -0
  127. package/dist/voice/errors.js.map +1 -0
  128. package/dist/voice/index.d.ts +271 -0
  129. package/dist/voice/index.js +1812 -0
  130. package/dist/voice/index.js.map +1 -0
  131. package/dist/voice/react.d.ts +167 -0
  132. package/dist/voice/react.js +234 -0
  133. package/dist/voice/react.js.map +1 -0
  134. package/dist/voice/sfu.d.ts +71 -0
  135. package/dist/voice/sfu.js +157 -0
  136. package/dist/voice/sfu.js.map +1 -0
  137. package/dist/voice/text.d.ts +6 -0
  138. package/dist/voice/text.js +2 -0
  139. package/dist/voice/types.d.ts +58 -0
  140. package/dist/voice/types.js +18 -0
  141. package/dist/voice/types.js.map +1 -0
  142. package/dist/voice/workers-ai.d.ts +136 -0
  143. package/dist/voice/workers-ai.js +568 -0
  144. package/dist/voice/workers-ai.js.map +1 -0
  145. package/dist/websockets/index.d.ts +192 -0
  146. package/dist/websockets/index.js +2 -0
  147. package/dist/websockets-DUfRHPRq.js +502 -0
  148. package/dist/websockets-DUfRHPRq.js.map +1 -0
  149. package/dist/workflow-types.d.ts +25 -25
  150. package/dist/workflows.d.ts +21 -21
  151. package/dist/workflows.js +1 -1
  152. package/docs/agent-class.md +2 -2
  153. package/docs/agent-tools.md +2 -1
  154. package/docs/channels.md +323 -0
  155. package/docs/chat-agents.md +6 -13
  156. package/docs/context.md +131 -0
  157. package/docs/index.md +15 -12
  158. package/docs/lifecycle.md +102 -55
  159. package/docs/long-running-agents.md +2 -2
  160. package/docs/mcp-servers.md +5 -1
  161. package/docs/resumable-streaming.md +1 -1
  162. package/docs/routing.md +105 -0
  163. package/docs/sessions.md +237 -871
  164. package/docs/streams.md +213 -0
  165. package/docs/sub-agents.md +184 -124
  166. package/docs/tasks.md +246 -0
  167. package/docs/voice.md +745 -0
  168. package/package.json +115 -13
  169. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  170. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  171. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  172. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  173. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  174. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  175. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  176. package/dist/experimental/memory/session/index.d.ts +0 -671
  177. package/dist/experimental/memory/session/index.js +0 -2379
  178. package/dist/experimental/memory/session/index.js.map +0 -1
  179. package/dist/experimental/memory/utils/index.d.ts +0 -96
  180. package/dist/experimental/memory/utils/index.js +0 -79
  181. package/dist/experimental/memory/utils/index.js.map +0 -1
  182. package/dist/scheduler-CR9RHGos.js +0 -857
  183. package/dist/scheduler-CR9RHGos.js.map +0 -1
  184. package/dist/src-5W6JNKVb.js.map +0 -1
  185. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  186. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams-DZKgAj9b.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,16 +1,16 @@
1
1
  import {
2
- An as buildSubAgentPathUnchecked,
3
- Cn as AgentPathStep,
4
- Dn as buildAgentPath,
5
- En as SubAgentPathMatch,
6
- Mn as parseSubAgentPath,
7
- Nn as routeSubAgentRequest,
8
- On as buildAgentUrl,
9
- Tn as SUB_PREFIX,
10
- jn as getSubAgentByName,
11
- kn as buildSubAgentPath,
12
- wn as BuildAgentPathOptions
13
- } from "./agent-routing-CnkaHb-v.js";
2
+ An as routeSubAgentRequest,
3
+ Cn as SubAgentPathMatch,
4
+ Dn as buildSubAgentPathUnchecked,
5
+ En as buildSubAgentPath,
6
+ On as getSubAgentByName,
7
+ Sn as SUB_PREFIX,
8
+ Tn as buildAgentUrl,
9
+ bn as AgentPathStep,
10
+ kn as parseSubAgentPath,
11
+ wn as buildAgentPath,
12
+ xn as BuildAgentPathOptions
13
+ } from "./agent-routing-DE5zmCQ8.js";
14
14
  export {
15
15
  AgentPathStep,
16
16
  BuildAgentPathOptions,
@@ -0,0 +1,17 @@
1
+ //#region src/channels/surface.ts
2
+ function isSurfaceValue(value) {
3
+ if (value === null || typeof value === "boolean" || typeof value === "string") return true;
4
+ if (typeof value === "number") return Number.isFinite(value);
5
+ if (Array.isArray(value)) return value.every(isSurfaceValue);
6
+ return typeof value === "object" && Object.values(value).every(isSurfaceValue);
7
+ }
8
+ /** Validate the common envelope before provider-specific address parsing. */
9
+ function isChannelMessageSurface(value) {
10
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
11
+ const surface = value;
12
+ return typeof surface.channelKey === "string" && surface.channelKey.length > 0 && surface.version === 1 && isSurfaceValue(surface.address) && typeof surface.label === "string" && surface.label.trim().length > 0;
13
+ }
14
+ //#endregion
15
+ export { isChannelMessageSurface as t };
16
+
17
+ //# sourceMappingURL=surface-bZZJqBka.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-bZZJqBka.js","names":[],"sources":["../src/channels/surface.ts"],"sourcesContent":["/**\n * A JSON value safe to persist across Worker and Durable Object boundaries.\n *\n * The recursive arms are interfaces rather than inline type literals so that\n * TypeScript defers resolving them. Workers RPC checks a return type with\n * `R extends Rpc.Serializable<R>`, which eagerly expands a self-referential\n * type alias and fails with \"Type instantiation is excessively deep\". Deferred\n * arms let a surface be returned from a Durable Object method.\n */\nexport type ChannelSurfaceValue =\n | null\n | boolean\n | number\n | string\n | ChannelSurfaceArray\n | ChannelSurfaceObject;\n\nexport interface ChannelSurfaceArray extends ReadonlyArray<ChannelSurfaceValue> {}\n\nexport interface ChannelSurfaceObject {\n readonly [key: string]: ChannelSurfaceValue;\n}\n\nfunction isSurfaceValue(value: unknown): value is ChannelSurfaceValue {\n if (\n value === null ||\n typeof value === \"boolean\" ||\n typeof value === \"string\"\n ) {\n return true;\n }\n if (typeof value === \"number\") return Number.isFinite(value);\n if (Array.isArray(value)) return value.every(isSurfaceValue);\n return (\n typeof value === \"object\" && Object.values(value).every(isSurfaceValue)\n );\n}\n\n/** A durable configured destination for one outbound message attempt. */\nexport type ChannelMessageSurface<\n TChannelKey extends string = string,\n TAddress extends ChannelSurfaceValue = ChannelSurfaceValue\n> = Readonly<{\n channelKey: TChannelKey;\n version: 1;\n address: TAddress;\n /** Human-readable destination text captured when the surface is created. */\n label: string;\n}>;\n\n/** A Channel-produced destination before its Host stamps the configured key. */\nexport type ChannelMessageSurfaceInput<\n TAddress extends ChannelSurfaceValue = ChannelSurfaceValue\n> = Readonly<{\n version: 1;\n address: TAddress;\n label: string;\n}>;\n\n/** Validate the common envelope before provider-specific address parsing. */\nexport function isChannelMessageSurface(\n value: unknown\n): value is ChannelMessageSurface {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n const surface = value as Record<string, unknown>;\n return (\n typeof surface.channelKey === \"string\" &&\n surface.channelKey.length > 0 &&\n surface.version === 1 &&\n isSurfaceValue(surface.address) &&\n typeof surface.label === \"string\" &&\n surface.label.trim().length > 0\n );\n}\n"],"mappings":";AAuBA,SAAS,eAAe,OAA8C;CACpE,IACE,UAAU,QACV,OAAO,UAAU,aACjB,OAAO,UAAU,UAEjB,OAAO;CAET,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK;CAC3D,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,MAAM,cAAc;CAC3D,OACE,OAAO,UAAU,YAAY,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,cAAc;AAE1E;;AAwBA,SAAgB,wBACd,OACgC;CAChC,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GACpE,OAAO;CAET,MAAM,UAAU;CAChB,OACE,OAAO,QAAQ,eAAe,YAC9B,QAAQ,WAAW,SAAS,KAC5B,QAAQ,YAAY,KACpB,eAAe,QAAQ,OAAO,KAC9B,OAAO,QAAQ,UAAU,YACzB,QAAQ,MAAM,KAAK,CAAC,CAAC,SAAS;AAElC"}
@@ -0,0 +1,64 @@
1
+ import {
2
+ C as TaskDurationUnit,
3
+ S as TaskDurationString,
4
+ _ as TaskStep,
5
+ a as TasksOptions,
6
+ b as TaskValue,
7
+ c as TaskError,
8
+ d as TaskJson,
9
+ f as TaskOutput,
10
+ g as TaskRunState,
11
+ h as TaskRunSnapshot,
12
+ i as TaskEventType,
13
+ l as TaskHandlers,
14
+ m as TaskRunOptions,
15
+ n as TaskListOptions,
16
+ o as Task,
17
+ p as TaskReceipt,
18
+ r as Tasks,
19
+ s as TaskCallbacks,
20
+ t as TaskDeleteOptions,
21
+ u as TaskInput,
22
+ v as TaskStepAttempt,
23
+ x as TaskWaitReason,
24
+ y as TaskStepConfig
25
+ } from "../tasks-BRJ5zgya.js";
26
+ import {
27
+ a as TaskReplayDivergedError,
28
+ i as NonRetryableError,
29
+ n as DuplicateTaskStepError,
30
+ o as TaskSerializationError,
31
+ r as MissingTaskDefinitionError,
32
+ t as MAX_SERIALIZED_BYTES
33
+ } from "../index-XDkuQ7zm.js";
34
+ export {
35
+ DuplicateTaskStepError,
36
+ MAX_SERIALIZED_BYTES,
37
+ MissingTaskDefinitionError,
38
+ NonRetryableError,
39
+ type Task,
40
+ type TaskCallbacks,
41
+ type TaskDeleteOptions,
42
+ type TaskDurationString,
43
+ type TaskDurationUnit,
44
+ type TaskError,
45
+ type TaskEventType,
46
+ type TaskHandlers,
47
+ type TaskInput,
48
+ type TaskJson,
49
+ type TaskListOptions,
50
+ type TaskOutput,
51
+ type TaskReceipt,
52
+ TaskReplayDivergedError,
53
+ type TaskRunOptions,
54
+ type TaskRunSnapshot,
55
+ type TaskRunState,
56
+ TaskSerializationError,
57
+ type TaskStep,
58
+ type TaskStepAttempt,
59
+ type TaskStepConfig,
60
+ type TaskValue,
61
+ type TaskWaitReason,
62
+ Tasks,
63
+ type TasksOptions
64
+ };
@@ -0,0 +1,2 @@
1
+ import { a as DuplicateTaskStepError, c as TaskReplayDivergedError, i as MAX_SERIALIZED_BYTES, l as TaskSerializationError, o as MissingTaskDefinitionError, s as NonRetryableError, t as Tasks } from "../tasks-ylZgBjhj.js";
2
+ export { DuplicateTaskStepError, MAX_SERIALIZED_BYTES, MissingTaskDefinitionError, NonRetryableError, TaskReplayDivergedError, TaskSerializationError, Tasks };