agents 0.27.0 → 0.28.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 (193) hide show
  1. package/dist/abortable-C1SpfVoi.js +21 -0
  2. package/dist/abortable-C1SpfVoi.js.map +1 -0
  3. package/dist/{agent-routing-Bhdbvf7s.d.ts → agent-routing-QDcchcQP.d.ts} +10 -15
  4. package/dist/agent-routing.d.ts +1 -1
  5. package/dist/agent-tool-types.d.ts +1 -1
  6. package/dist/{agent-tools-bJZwBMfq.d.ts → agent-tools-DHL2XI7u.d.ts} +2 -2
  7. package/dist/agent-tools.d.ts +1 -1
  8. package/dist/ai-ahruGw7e.d.ts +239 -0
  9. package/dist/{ai-sdk-OoGkFy3s.js → ai-sdk-Bdsf6mSA.js} +2 -2
  10. package/dist/{ai-sdk-OoGkFy3s.js.map → ai-sdk-Bdsf6mSA.js.map} +1 -1
  11. package/dist/browser/ai.d.ts +8 -227
  12. package/dist/browser/ai.js +259 -1
  13. package/dist/browser/ai.js.map +1 -0
  14. package/dist/browser/index.d.ts +56 -46
  15. package/dist/browser/index.js +4 -361
  16. package/dist/browser/{ai-sdk.d.ts → tools/ai-sdk.d.ts} +7 -7
  17. package/dist/browser/{ai-sdk.js → tools/ai-sdk.js} +5 -4
  18. package/dist/browser/tools/ai-sdk.js.map +1 -0
  19. package/dist/browser/tools/pi.d.ts +111 -0
  20. package/dist/browser/tools/pi.js +119 -0
  21. package/dist/browser/tools/pi.js.map +1 -0
  22. package/dist/browser/{tanstack-ai.d.ts → tools/tanstack-ai.d.ts} +39 -37
  23. package/dist/browser/{tanstack-ai.js → tools/tanstack-ai.js} +73 -59
  24. package/dist/browser/tools/tanstack-ai.js.map +1 -0
  25. package/dist/browser-CEdNlsaD.js +481 -0
  26. package/dist/browser-CEdNlsaD.js.map +1 -0
  27. package/dist/{browser-tmkcAAI3.d.ts → browser-D30VlpcA.d.ts} +63 -37
  28. package/dist/{browser-tool-CBqs6hqa.js → browser-tool-4iomavs_.js} +145 -49
  29. package/dist/browser-tool-4iomavs_.js.map +1 -0
  30. package/dist/{browser-tool-Bn-nzJQI.d.ts → browser-tool-vtrPOV8e.d.ts} +24 -5
  31. package/dist/{capability-B4WbF81e.js → capability-DBAKc6UZ.js} +1 -3
  32. package/dist/capability-DBAKc6UZ.js.map +1 -0
  33. package/dist/{capability-runner-O5VbQzqg.d.ts → capability-runner-BiVUtjqC.d.ts} +1 -7
  34. package/dist/chat/index.d.ts +4 -4
  35. package/dist/chat/index.js +1 -1
  36. package/dist/chat-sdk/index.d.ts +1 -1
  37. package/dist/chat-sdk/index.js +1 -1
  38. package/dist/{client-DS3Dz9l0.d.ts → client-BGIQKJhX.d.ts} +2 -2
  39. package/dist/{client-1tEQ1Oqz.js → client-BnYbNT3z.js} +3 -4
  40. package/dist/client-BnYbNT3z.js.map +1 -0
  41. package/dist/client.d.ts +1 -1
  42. package/dist/{connector-58XDGvc3.js → connector-CtZylXdk.js} +3 -603
  43. package/dist/connector-CtZylXdk.js.map +1 -0
  44. package/dist/{connector-Cl-VqPmA.d.ts → connector-DEXzVoaY.d.ts} +9 -374
  45. package/dist/{conversations-DH0ut_8n.d.ts → conversations-FjHDRZyD.d.ts} +4 -4
  46. package/dist/{current-agent-C07C5o5Y.d.ts → current-agent-CKgT5d1O.d.ts} +3 -5
  47. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  48. package/dist/{durable-object-lifecycle-DRqp475_.d.ts → durable-object-lifecycle-DOI_bzCH.d.ts} +2 -2
  49. package/dist/experimental/channels/index.d.ts +2 -2
  50. package/dist/experimental/channels/index.js +2 -2
  51. package/dist/experimental/channels/web/index.d.ts +2 -2
  52. package/dist/experimental/channels/web/index.js +1 -1
  53. package/dist/{gateway-BDC07gYO.d.ts → gateway-BFO6vRDn.d.ts} +2 -2
  54. package/dist/harness/ai-sdk/index.d.ts +2 -2
  55. package/dist/harness/ai-sdk/index.js +1 -1
  56. package/dist/harness/container/index.d.ts +2 -2
  57. package/dist/harness/container/index.js +3 -3
  58. package/dist/harness/opencode/index.d.ts +1 -1
  59. package/dist/harness/opencode/index.js +2 -2
  60. package/dist/harness/pi/index.d.ts +2 -2
  61. package/dist/harness/pi/index.js +3 -3
  62. package/dist/harness/store/index.d.ts +1 -1
  63. package/dist/harness/store/index.js +1 -1
  64. package/dist/harness/think/index.d.ts +2 -2
  65. package/dist/harness/think/index.js +363 -171
  66. package/dist/harness/think/index.js.map +1 -1
  67. package/dist/{index-D0A5tbWu.d.ts → index-BEL3ZV-s.d.ts} +2 -6
  68. package/dist/{index-Ib_4dwOo.d.ts → index-CBt8oRJt.d.ts} +3 -5
  69. package/dist/index.d.ts +4 -4
  70. package/dist/index.js +2 -2
  71. package/dist/input-schema-BQykTEp_.js +20 -0
  72. package/dist/input-schema-BQykTEp_.js.map +1 -0
  73. package/dist/{input-schema-DNrpTu49.js → input-schema-D2QAtHZH.js} +3 -3
  74. package/dist/input-schema-D2QAtHZH.js.map +1 -0
  75. package/dist/internal_context.d.ts +1 -1
  76. package/dist/lifecycle/index.d.ts +3 -3
  77. package/dist/lifecycle/index.js +2 -2
  78. package/dist/{lifecycle-CFu6OV03.js → lifecycle-DGorpAmA.js} +2 -4
  79. package/dist/lifecycle-DGorpAmA.js.map +1 -0
  80. package/dist/mcp/client/index.d.ts +1 -1
  81. package/dist/mcp/client/index.js +1 -1
  82. package/dist/mcp/index.d.ts +1 -1
  83. package/dist/mcp/index.js +2 -2
  84. package/dist/models/ai-sdk/index.js +1 -1
  85. package/dist/models/opencode/index.js +1 -1
  86. package/dist/models/pi-ai/index.js +1 -1
  87. package/dist/{options-pwTNq9z6.d.ts → options-CiIsJHXR.d.ts} +2 -6
  88. package/dist/queue/index.d.ts +1 -1
  89. package/dist/queue/index.js +1 -1
  90. package/dist/{queue-BB-zfIYF.js → queue-CcIjVYTE.js} +2 -2
  91. package/dist/{queue-BB-zfIYF.js.map → queue-CcIjVYTE.js.map} +1 -1
  92. package/dist/react.d.ts +2 -2
  93. package/dist/routing/index.d.ts +2 -2
  94. package/dist/routing/index.js +1 -1
  95. package/dist/{scheduler-CrFCnv_J.d.ts → scheduler-BCLESHSC.d.ts} +2 -12
  96. package/dist/{scheduler-DZ3xQfeK.js → scheduler-FIHv2-kJ.js} +2 -4
  97. package/dist/scheduler-FIHv2-kJ.js.map +1 -0
  98. package/dist/schedules/index.d.ts +1 -1
  99. package/dist/schedules/index.js +1 -1
  100. package/dist/serializable.d.ts +1 -1
  101. package/dist/session-store-Do4xkDcf.js +606 -0
  102. package/dist/session-store-Do4xkDcf.js.map +1 -0
  103. package/dist/session-store-DoPY12xM.d.ts +383 -0
  104. package/dist/sessions/index.d.ts +1 -1
  105. package/dist/sessions/index.js +1 -1
  106. package/dist/{sessions-B9pNuxdT.js → sessions-_vN5BEZX.js} +2 -2
  107. package/dist/{sessions-B9pNuxdT.js.map → sessions-_vN5BEZX.js.map} +1 -1
  108. package/dist/{src-DgCbZtIR.js → src-CQxJFv4l.js} +8 -8
  109. package/dist/src-CQxJFv4l.js.map +1 -0
  110. package/dist/state/index.d.ts +1 -1
  111. package/dist/state/index.js +1 -3
  112. package/dist/state/index.js.map +1 -1
  113. package/dist/{store-DLeqKuj3.d.ts → store-BKM4Xm9M.d.ts} +23 -1
  114. package/dist/{store-vgcPYo8K.js → store-CslVzfN7.js} +28 -2
  115. package/dist/store-CslVzfN7.js.map +1 -0
  116. package/dist/streams/index.d.ts +1 -1
  117. package/dist/streams/index.js +1 -1
  118. package/dist/{streams-CITClVer.js → streams-lsHMJhRW.js} +2 -2
  119. package/dist/{streams-CITClVer.js.map → streams-lsHMJhRW.js.map} +1 -1
  120. package/dist/{streams-fbG61qM8.d.ts → streams-vrCtbUIn.d.ts} +2 -2
  121. package/dist/sub-routing.d.ts +1 -1
  122. package/dist/tasks/index.d.ts +1 -1
  123. package/dist/tasks/index.js +1 -1
  124. package/dist/{tasks-CkTZNaV1.js → tasks-BN_5AWqI.js} +2 -2
  125. package/dist/{tasks-CkTZNaV1.js.map → tasks-BN_5AWqI.js.map} +1 -1
  126. package/dist/{tasks-PtlB4Uyn.d.ts → tasks-E89KdwkS.d.ts} +2 -2
  127. package/dist/{tool-BPJEbwaX.d.ts → tool-CTp72Jb_.d.ts} +4 -4
  128. package/dist/tool-CxKsvxjm.js +1126 -0
  129. package/dist/tool-CxKsvxjm.js.map +1 -0
  130. package/dist/tool-DoVberpN.d.ts +301 -0
  131. package/dist/{tool-3PA8xjB_.js → tool-cQRkwSZZ.js} +6 -17
  132. package/dist/tool-cQRkwSZZ.js.map +1 -0
  133. package/dist/tool-helpers-O5BDVEAY.js +58 -0
  134. package/dist/tool-helpers-O5BDVEAY.js.map +1 -0
  135. package/dist/voice/index.d.ts +2 -2
  136. package/dist/web/fetch/index.d.ts +89 -0
  137. package/dist/web/fetch/index.js +20 -0
  138. package/dist/web/fetch/index.js.map +1 -0
  139. package/dist/web/fetch/tools/ai-sdk.d.ts +80 -0
  140. package/dist/web/fetch/tools/ai-sdk.js +47 -0
  141. package/dist/web/fetch/tools/ai-sdk.js.map +1 -0
  142. package/dist/web/fetch/tools/pi.d.ts +84 -0
  143. package/dist/web/fetch/tools/pi.js +88 -0
  144. package/dist/web/fetch/tools/pi.js.map +1 -0
  145. package/dist/web/fetch/tools/tanstack-ai.d.ts +78 -0
  146. package/dist/web/fetch/tools/tanstack-ai.js +45 -0
  147. package/dist/web/fetch/tools/tanstack-ai.js.map +1 -0
  148. package/dist/{websearch → web/search}/index.d.ts +1 -1
  149. package/dist/{websearch → web/search}/index.js +1 -1
  150. package/dist/{websearch → web/search}/tools/ai-sdk.d.ts +2 -2
  151. package/dist/{websearch → web/search}/tools/ai-sdk.js +3 -3
  152. package/dist/web/search/tools/ai-sdk.js.map +1 -0
  153. package/dist/{websearch → web/search}/tools/pi.d.ts +3 -3
  154. package/dist/{websearch → web/search}/tools/pi.js +2 -2
  155. package/dist/web/search/tools/pi.js.map +1 -0
  156. package/dist/{websearch → web/search}/tools/tanstack-ai.d.ts +2 -2
  157. package/dist/{websearch → web/search}/tools/tanstack-ai.js +3 -3
  158. package/dist/web/search/tools/tanstack-ai.js.map +1 -0
  159. package/dist/websockets/index.d.ts +2 -2
  160. package/dist/websockets/index.js +1 -1
  161. package/dist/{websockets-CmENGb-Z.js → websockets-C3zy8YR0.js} +3 -5
  162. package/dist/websockets-C3zy8YR0.js.map +1 -0
  163. package/dist/workflow-types.d.ts +1 -1
  164. package/dist/workflows.d.ts +1 -1
  165. package/dist/workflows.js +1 -1
  166. package/docs/browse-the-web.md +26 -1
  167. package/docs/fetch-the-web.md +276 -0
  168. package/docs/harnesses/pi.md +25 -0
  169. package/docs/index.md +99 -76
  170. package/docs/lifecycle.md +2 -3
  171. package/docs/queue.md +2 -3
  172. package/docs/scheduling.md +2 -6
  173. package/docs/search-the-web.md +2 -0
  174. package/package.json +44 -19
  175. package/dist/ai-fm7xx1BK.js +0 -312
  176. package/dist/ai-fm7xx1BK.js.map +0 -1
  177. package/dist/browser/ai-sdk.js.map +0 -1
  178. package/dist/browser/index.js.map +0 -1
  179. package/dist/browser/tanstack-ai.js.map +0 -1
  180. package/dist/browser-tool-CBqs6hqa.js.map +0 -1
  181. package/dist/capability-B4WbF81e.js.map +0 -1
  182. package/dist/client-1tEQ1Oqz.js.map +0 -1
  183. package/dist/connector-58XDGvc3.js.map +0 -1
  184. package/dist/input-schema-DNrpTu49.js.map +0 -1
  185. package/dist/lifecycle-CFu6OV03.js.map +0 -1
  186. package/dist/scheduler-DZ3xQfeK.js.map +0 -1
  187. package/dist/src-DgCbZtIR.js.map +0 -1
  188. package/dist/store-vgcPYo8K.js.map +0 -1
  189. package/dist/tool-3PA8xjB_.js.map +0 -1
  190. package/dist/websearch/tools/ai-sdk.js.map +0 -1
  191. package/dist/websearch/tools/pi.js.map +0 -1
  192. package/dist/websearch/tools/tanstack-ai.js.map +0 -1
  193. package/dist/websockets-CmENGb-Z.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-vgcPYo8K.js","names":[],"sources":["../src/harness/store/store.ts"],"sourcesContent":["/**\n * A session store for harnesses, on a Durable Object's SQLite database.\n *\n * Any harness that runs its agent somewhere other than the object (a\n * container, a sandbox, a remote process) needs the same few things kept\n * durably next to it: which sessions exist, which operations were submitted\n * and how each one ended, and the session's history in whatever format the\n * harness speaks. This store keeps those and nothing more. It knows no\n * message format, no event vocabulary and no runtime: inputs, results,\n * session state and log entries are opaque JSON that the harness parses.\n *\n * Three record kinds:\n *\n * - **Sessions**: an id, an optional parent (a fork), and one JSON state\n * value the harness owns (model, cursors, resume handles).\n * - **Operations**: one row per submitted operation, keyed by an\n * idempotency id within its session, moving `queued` → `running` →\n * `done` | `unanswered`. Transitions are guarded in SQL, so a duplicate or\n * late transition is a no-op rather than a regression.\n * - **Logs**: named, append-ordered streams of JSON entries per session\n * (`\"messages\"`, `\"engine\"`, …). An entry may carry an id, and an entry\n * written again under the same id replaces the old one in place. Entries\n * larger than one SQLite row are split across continuation rows.\n *\n * The store is synchronous, like the SQL API under it, so a harness can\n * group several writes in `transaction()` without awaiting.\n *\n * @experimental The API may change before it stabilizes.\n */\n\n/** A JSON value, as the store keeps it. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | readonly JsonValue[]\n | { readonly [key: string]: JsonValue };\n\n/** Where an operation is in its life. */\nexport type OperationStatus = \"queued\" | \"running\" | \"done\" | \"unanswered\";\n\n/** A session, as stored. */\nexport type SessionRecord = {\n readonly id: string;\n /** The session this one was forked from. */\n readonly parent: string | undefined;\n /** Harness-owned state. `null` until the harness writes some. */\n readonly state: JsonValue;\n readonly createdAt: number;\n readonly updatedAt: number;\n};\n\n/** One operation, as stored. */\nexport type OperationRecord = {\n readonly session: string;\n /** The idempotency key, unique within the session. */\n readonly id: string;\n /** Submission order within the whole store. */\n readonly seq: number;\n readonly status: OperationStatus;\n /** What was submitted, in the harness's format. */\n readonly input: JsonValue;\n /** Harness-owned submission options and bookkeeping. */\n readonly meta: JsonValue;\n /** The harness's result for a `done` operation, else `null`. */\n readonly result: JsonValue;\n /** Why an `unanswered` operation ended. */\n readonly reason: string | undefined;\n readonly createdAt: number;\n readonly settledAt: number | undefined;\n};\n\n/** One log entry, as stored. */\nexport type LogEntry = {\n /** Position in the log. Stable when the entry is replaced by id. */\n readonly seq: number;\n readonly id: string | undefined;\n readonly data: JsonValue;\n readonly createdAt: number;\n};\n\n/** One entry to append. */\nexport type LogAppend = {\n /** Replace an existing entry with this id in place, instead of appending. */\n readonly id?: string;\n readonly data: JsonValue;\n};\n\n/** How an operation ended. */\nexport type OperationOutcome =\n | { readonly status: \"done\"; readonly result: JsonValue }\n | { readonly status: \"unanswered\"; readonly reason: string };\n\n/** `openHarnessStore`'s options. */\nexport type HarnessStoreOptions = {\n /**\n * Prefix for the store's tables. Two harnesses in one object use two\n * prefixes. Must not start with `_cf_`, which Durable Objects reserve.\n * Default `harness_`.\n */\n readonly prefix?: string;\n};\n\nconst DEFAULT_PREFIX = \"harness_\";\n\n/**\n * Characters per stored chunk of a JSON value. A Durable Object row holds\n * at most 2 MB and a character is at most 4 bytes of UTF-8, so a quarter of\n * a megabyte of characters always fits with room for the other columns.\n */\nconst CHUNK_CHARS = 256 * 1024;\n\n/**\n * Open the store over this object's SQLite database, creating its tables on\n * first use. Cheap: call it once per isolate and keep the result.\n *\n * @param storage - The Durable Object's storage.\n * @param options - Table prefix.\n * @returns The store.\n */\nexport function openHarnessStore(\n storage: DurableObjectStorage,\n options: HarnessStoreOptions = {}\n): HarnessStore {\n return new HarnessStore(storage, options);\n}\n\ntype SessionRow = {\n id: string;\n parent: string | null;\n state: string;\n created_at: number;\n updated_at: number;\n};\n\ntype OperationRow = {\n session: string;\n id: string;\n seq: number;\n status: string;\n input: string;\n meta: string;\n result: string;\n reason: string | null;\n created_at: number;\n settled_at: number | null;\n};\n\ntype LogRow = {\n seq: number;\n part: number;\n id: string | null;\n data: string;\n created_at: number;\n};\n\nfunction parseJson(text: string): JsonValue {\n // SAFETY: every stored value was produced by JSON.stringify of a JsonValue\n // in this module; parsing it back yields the same shape.\n return JSON.parse(text) as JsonValue;\n}\n\nfunction isStatus(value: string): value is OperationStatus {\n return (\n value === \"queued\" ||\n value === \"running\" ||\n value === \"done\" ||\n value === \"unanswered\"\n );\n}\n\nfunction chunks(text: string): string[] {\n if (text.length <= CHUNK_CHARS) return [text];\n const parts: string[] = [];\n for (let at = 0; at < text.length; at += CHUNK_CHARS) {\n parts.push(text.slice(at, at + CHUNK_CHARS));\n }\n return parts;\n}\n\n/**\n * The store. Construct it with `openHarnessStore`.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport class HarnessStore {\n readonly #storage: DurableObjectStorage;\n readonly #sessions: string;\n readonly #operations: string;\n readonly #log: string;\n\n /**\n * @param storage - The Durable Object's storage.\n * @param options - Table prefix.\n */\n constructor(storage: DurableObjectStorage, options: HarnessStoreOptions) {\n const prefix = options.prefix ?? DEFAULT_PREFIX;\n if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(prefix)) {\n throw new Error(`Invalid harness store prefix ${JSON.stringify(prefix)}`);\n }\n if (prefix.startsWith(\"_cf_\")) {\n throw new Error(\"The harness store prefix must not start with _cf_\");\n }\n this.#storage = storage;\n this.#sessions = `${prefix}sessions`;\n this.#operations = `${prefix}operations`;\n this.#log = `${prefix}log`;\n this.#migrate();\n }\n\n #migrate(): void {\n const sql = this.#storage.sql;\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#sessions} (\n id TEXT PRIMARY KEY,\n parent TEXT,\n state TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )`);\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#operations} (\n session TEXT NOT NULL,\n id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n status TEXT NOT NULL,\n input TEXT NOT NULL,\n meta TEXT NOT NULL,\n result TEXT NOT NULL,\n reason TEXT,\n created_at INTEGER NOT NULL,\n settled_at INTEGER,\n PRIMARY KEY (session, id)\n )`);\n sql.exec(\n `CREATE INDEX IF NOT EXISTS ${this.#operations}_open ON ${this.#operations} (status, seq)`\n );\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#log} (\n session TEXT NOT NULL,\n log TEXT NOT NULL,\n seq INTEGER NOT NULL,\n part INTEGER NOT NULL,\n id TEXT,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n PRIMARY KEY (session, log, seq, part)\n )`);\n sql.exec(\n `CREATE INDEX IF NOT EXISTS ${this.#log}_id ON ${this.#log} (session, log, id) WHERE id IS NOT NULL`\n );\n }\n\n /**\n * Run `fn` in one storage transaction. Writes inside it commit together or\n * not at all.\n *\n * @template T - What `fn` returns.\n * @param fn - Synchronous work against this store.\n * @returns What `fn` returned.\n */\n transaction<T>(fn: () => T): T {\n return this.#storage.transactionSync(fn);\n }\n\n // ── Sessions ─────────────────────────────────────────────────────────────\n\n /**\n * Create a session, or return the existing one with this id unchanged.\n *\n * @param input - The id, an optional parent, and the initial state.\n * @returns The stored session.\n */\n createSession(input: {\n readonly id: string;\n readonly parent?: string;\n readonly state?: JsonValue;\n }): SessionRecord {\n const now = Date.now();\n this.#storage.sql.exec(\n `INSERT INTO ${this.#sessions} (id, parent, state, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?) ON CONFLICT (id) DO NOTHING`,\n input.id,\n input.parent ?? null,\n JSON.stringify(input.state ?? null),\n now,\n now\n );\n const created = this.session(input.id);\n if (!created) throw new Error(`Session ${input.id} was not stored`);\n return created;\n }\n\n /**\n * Read one session.\n *\n * @param id - The session id.\n * @returns The session, or `undefined` when there is none.\n */\n session(id: string): SessionRecord | undefined {\n const row = this.#storage.sql\n .exec<SessionRow>(`SELECT * FROM ${this.#sessions} WHERE id = ?`, id)\n .toArray()[0];\n return row ? this.#sessionOf(row) : undefined;\n }\n\n /**\n * Every session, oldest first.\n *\n * @returns The sessions.\n */\n sessions(): SessionRecord[] {\n return this.#storage.sql\n .exec<SessionRow>(\n `SELECT * FROM ${this.#sessions} ORDER BY created_at, id`\n )\n .toArray()\n .map((row) => this.#sessionOf(row));\n }\n\n /**\n * Replace a session's harness-owned state.\n *\n * @param id - The session id.\n * @param state - The new state.\n * @returns False when there is no such session.\n */\n setSessionState(id: string, state: JsonValue): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#sessions} SET state = ?, updated_at = ? WHERE id = ?`,\n JSON.stringify(state),\n Date.now(),\n id\n ).rowsWritten > 0\n );\n }\n\n /**\n * Delete a session with its operations and logs.\n *\n * @param id - The session id.\n * @returns False when there was no such session.\n */\n deleteSession(id: string): boolean {\n return this.transaction(() => {\n const sql = this.#storage.sql;\n sql.exec(`DELETE FROM ${this.#operations} WHERE session = ?`, id);\n sql.exec(`DELETE FROM ${this.#log} WHERE session = ?`, id);\n return (\n sql.exec(`DELETE FROM ${this.#sessions} WHERE id = ?`, id).rowsWritten >\n 0\n );\n });\n }\n\n #sessionOf(row: SessionRow): SessionRecord {\n return {\n id: row.id,\n parent: row.parent ?? undefined,\n state: parseJson(row.state),\n createdAt: row.created_at,\n updatedAt: row.updated_at\n };\n }\n\n // ── Operations ───────────────────────────────────────────────────────────\n\n /**\n * Durably queue an operation. Idempotent on `(session, id)`: a second\n * enqueue with the same id stores nothing and returns the first record.\n *\n * @param input - The session, the idempotency id, the input and options.\n * @returns The stored record, and whether this call created it.\n */\n enqueue(input: {\n readonly session: string;\n readonly id: string;\n readonly input: JsonValue;\n readonly meta?: JsonValue;\n }): { readonly record: OperationRecord; readonly accepted: boolean } {\n return this.transaction(() => {\n const existing = this.operation(input.session, input.id);\n if (existing) return { record: existing, accepted: false };\n const sql = this.#storage.sql;\n const next =\n sql\n .exec<{\n seq: number | null;\n }>(`SELECT MAX(seq) AS seq FROM ${this.#operations}`)\n .toArray()[0]?.seq ?? 0;\n sql.exec(\n `INSERT INTO ${this.#operations}\n (session, id, seq, status, input, meta, result, reason, created_at, settled_at)\n VALUES (?, ?, ?, 'queued', ?, ?, 'null', NULL, ?, NULL)`,\n input.session,\n input.id,\n next + 1,\n JSON.stringify(input.input),\n JSON.stringify(input.meta ?? null),\n Date.now()\n );\n const record = this.operation(input.session, input.id);\n if (!record) throw new Error(`Operation ${input.id} was not stored`);\n return { record, accepted: true };\n });\n }\n\n /**\n * Read one operation.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns The operation, or `undefined` when there is none.\n */\n operation(session: string, id: string): OperationRecord | undefined {\n const row = this.#storage.sql\n .exec<OperationRow>(\n `SELECT * FROM ${this.#operations} WHERE session = ? AND id = ?`,\n session,\n id\n )\n .toArray()[0];\n return row ? this.#operationOf(row) : undefined;\n }\n\n /**\n * Operations in submission order, optionally narrowed to one session and\n * to some statuses.\n *\n * @param filter - The session and statuses to keep. Default: all.\n * @returns The matching operations, oldest first.\n */\n operations(\n filter: {\n readonly session?: string;\n readonly status?: readonly OperationStatus[];\n } = {}\n ): OperationRecord[] {\n const where: string[] = [];\n const params: string[] = [];\n if (filter.session !== undefined) {\n where.push(\"session = ?\");\n params.push(filter.session);\n }\n if (filter.status !== undefined) {\n if (filter.status.length === 0) return [];\n where.push(`status IN (${filter.status.map(() => \"?\").join(\", \")})`);\n params.push(...filter.status);\n }\n return this.#storage.sql\n .exec<OperationRow>(\n `SELECT * FROM ${this.#operations}\n ${where.length > 0 ? `WHERE ${where.join(\" AND \")}` : \"\"}\n ORDER BY seq`,\n ...params\n )\n .toArray()\n .map((row) => this.#operationOf(row));\n }\n\n /**\n * Move a queued operation to `running`.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns False when it was not queued.\n */\n start(session: string, id: string): boolean {\n return this.#transition(session, id, [\"queued\"], \"running\");\n }\n\n /**\n * Move a running operation back to `queued`, to run it again.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns False when it was not running.\n */\n requeue(session: string, id: string): boolean {\n return this.#transition(session, id, [\"running\"], \"queued\");\n }\n\n /**\n * Settle a queued or running operation.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @param outcome - How it ended.\n * @returns False when it had already settled or does not exist.\n */\n settle(session: string, id: string, outcome: OperationOutcome): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations}\n SET status = ?, result = ?, reason = ?, settled_at = ?\n WHERE session = ? AND id = ? AND status IN ('queued', 'running')`,\n outcome.status,\n JSON.stringify(outcome.status === \"done\" ? outcome.result : null),\n outcome.status === \"unanswered\" ? outcome.reason : null,\n Date.now(),\n session,\n id\n ).rowsWritten > 0\n );\n }\n\n /**\n * Replace an operation's harness-owned bookkeeping.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @param meta - The new value.\n * @returns False when there is no such operation.\n */\n setOperationMeta(session: string, id: string, meta: JsonValue): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations} SET meta = ? WHERE session = ? AND id = ?`,\n JSON.stringify(meta),\n session,\n id\n ).rowsWritten > 0\n );\n }\n\n #transition(\n session: string,\n id: string,\n from: readonly OperationStatus[],\n to: OperationStatus\n ): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations} SET status = ?\n WHERE session = ? AND id = ? AND status IN (${from.map(() => \"?\").join(\", \")})`,\n to,\n session,\n id,\n ...from\n ).rowsWritten > 0\n );\n }\n\n #operationOf(row: OperationRow): OperationRecord {\n if (!isStatus(row.status)) {\n throw new Error(`Unknown operation status ${row.status}`);\n }\n return {\n session: row.session,\n id: row.id,\n seq: row.seq,\n status: row.status,\n input: parseJson(row.input),\n meta: parseJson(row.meta),\n result: parseJson(row.result),\n reason: row.reason ?? undefined,\n createdAt: row.created_at,\n settledAt: row.settled_at ?? undefined\n };\n }\n\n // ── Logs ─────────────────────────────────────────────────────────────────\n\n /**\n * Append entries to a session's log. An entry with an id that is already\n * in the log replaces that entry in place, keeping its position.\n *\n * @param session - The session id.\n * @param log - The log's name, such as `\"messages\"`.\n * @param entries - The entries, in order.\n * @returns The position of the last entry written, or of the log's end.\n */\n append(session: string, log: string, entries: readonly LogAppend[]): number {\n return this.transaction(() => {\n let end = this.end(session, log);\n for (const entry of entries) {\n const existing =\n entry.id === undefined\n ? undefined\n : this.#seqOf(session, log, entry.id);\n if (existing !== undefined) {\n this.#write(session, log, existing, entry);\n continue;\n }\n end += 1;\n this.#write(session, log, end, entry);\n }\n return end;\n });\n }\n\n /**\n * Read a session's log in order.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @param range - Entries after position `after` (exclusive), at most `limit`.\n * @returns The entries.\n */\n read(\n session: string,\n log: string,\n range: { readonly after?: number; readonly limit?: number } = {}\n ): LogEntry[] {\n const after = range.after ?? 0;\n const limit = range.limit ?? -1;\n const rows = this.#storage.sql\n .exec<LogRow>(\n `SELECT seq, part, id, data, created_at FROM ${this.#log}\n WHERE session = ? AND log = ? AND seq IN (\n SELECT DISTINCT seq FROM ${this.#log}\n WHERE session = ? AND log = ? AND seq > ?\n ORDER BY seq LIMIT ?\n )\n ORDER BY seq, part`,\n session,\n log,\n session,\n log,\n after,\n limit\n )\n .toArray();\n const entries: LogEntry[] = [];\n let current: { row: LogRow; text: string } | undefined;\n const flush = () => {\n if (!current) return;\n entries.push({\n seq: current.row.seq,\n id: current.row.id ?? undefined,\n data: parseJson(current.text),\n createdAt: current.row.created_at\n });\n };\n for (const row of rows) {\n if (current && current.row.seq === row.seq) {\n current.text += row.data;\n continue;\n }\n flush();\n current = { row, text: row.data };\n }\n flush();\n return entries;\n }\n\n /**\n * One entry by id.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @param id - The entry id.\n * @returns The entry, or `undefined`.\n */\n entry(session: string, log: string, id: string): LogEntry | undefined {\n const seq = this.#seqOf(session, log, id);\n if (seq === undefined) return undefined;\n return this.read(session, log, { after: seq - 1, limit: 1 })[0];\n }\n\n /**\n * The position of a log's last entry.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @returns The position, or 0 for an empty log.\n */\n end(session: string, log: string): number {\n return (\n this.#storage.sql\n .exec<{ seq: number | null }>(\n `SELECT MAX(seq) AS seq FROM ${this.#log} WHERE session = ? AND log = ?`,\n session,\n log\n )\n .toArray()[0]?.seq ?? 0\n );\n }\n\n /**\n * Empty a session's log.\n *\n * @param session - The session id.\n * @param log - The log's name.\n */\n clear(session: string, log: string): void {\n this.#storage.sql.exec(\n `DELETE FROM ${this.#log} WHERE session = ? AND log = ?`,\n session,\n log\n );\n }\n\n /**\n * Copy one session's log onto the end of another's, keeping entry ids.\n *\n * @param from - The source session.\n * @param to - The target session.\n * @param log - The log's name.\n */\n copy(from: string, to: string, log: string): void {\n this.transaction(() => {\n const offset = this.end(to, log);\n this.#storage.sql.exec(\n `INSERT INTO ${this.#log} (session, log, seq, part, id, data, created_at)\n SELECT ?, log, seq + ?, part, id, data, created_at FROM ${this.#log}\n WHERE session = ? AND log = ?`,\n to,\n offset,\n from,\n log\n );\n });\n }\n\n #seqOf(session: string, log: string, id: string): number | undefined {\n return this.#storage.sql\n .exec<{ seq: number }>(\n `SELECT seq FROM ${this.#log} WHERE session = ? AND log = ? AND id = ? LIMIT 1`,\n session,\n log,\n id\n )\n .toArray()[0]?.seq;\n }\n\n #write(session: string, log: string, seq: number, entry: LogAppend): void {\n const sql = this.#storage.sql;\n const createdAt =\n sql\n .exec<{ created_at: number }>(\n `SELECT created_at FROM ${this.#log} WHERE session = ? AND log = ? AND seq = ? LIMIT 1`,\n session,\n log,\n seq\n )\n .toArray()[0]?.created_at ?? Date.now();\n sql.exec(\n `DELETE FROM ${this.#log} WHERE session = ? AND log = ? AND seq = ?`,\n session,\n log,\n seq\n );\n chunks(JSON.stringify(entry.data)).forEach((part, index) => {\n sql.exec(\n `INSERT INTO ${this.#log} (session, log, seq, part, id, data, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n session,\n log,\n seq,\n index,\n entry.id ?? null,\n part,\n createdAt\n );\n });\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-3PA8xjB_.js","names":[],"sources":["../src/websearch/contract.ts","../src/websearch/source.ts","../src/websearch/tool.ts"],"sourcesContent":["/**\n * The `web_search` tool contract: its name, what it tells the model, what the\n * model passes in, what comes back, and how results are rendered for the\n * model. Shared by every executor of the tool — the harness-executed\n * adapters in `agents/websearch/*` today, and a gateway-executed variant in\n * `agents/models/*` once AI Gateway server tools ship — so a `web_search` call\n * looks the same in a transcript whoever ran it.\n */\n\n/**\n * The tool's name, as the model calls it and as it appears in transcripts.\n * `web_search` is the name models know from Anthropic's and OpenAI's built-in\n * search tools.\n */\nexport const WEB_SEARCH_TOOL_NAME = \"web_search\";\n\n/** The default number of results when the model doesn't ask for a count. */\nexport const DEFAULT_WEB_SEARCH_LIMIT = 5;\n\n/** The most results one search can return; the API rejects more. */\nexport const MAX_WEB_SEARCH_LIMIT = 10;\n\n/** The longest query the API accepts, in characters. */\nexport const MAX_WEB_SEARCH_QUERY_LENGTH = 1024;\n\n/**\n * Per-result description length in the model's view, in characters. Provider\n * descriptions run to ~8,000 characters (Ceramic returns page text), which at\n * ten results is 80 KB of context per search. The full text stays in the\n * host-side output.\n */\nexport const DEFAULT_WEB_SEARCH_DESCRIPTION_CHARS = 600;\n\n/*\n * These are type aliases, not interfaces: pi stores tool details as strict\n * JSON, and only aliases satisfy its `JsonValue` index signature.\n */\n\n/** What the model says when it wants a search. */\nexport type WebSearchToolInput = {\n /** The search query. */\n query: string;\n /** How many results to return, 1–10. Defaults to the host's `limit`. */\n limit?: number;\n};\n\n/**\n * One search result. `url` and `title` are always present; the rest only\n * when the provider returns them (Exa adds `imageUrl` and\n * `lastModifiedDate`, Linkup adds `faviconUrl`, Ceramic adds neither).\n */\nexport type WebSearchResult = {\n url: string;\n title: string;\n /** A snippet or extract of the page. Length and style vary by provider. */\n description?: string;\n /** ISO 8601 timestamp of the page's last modification. */\n lastModifiedDate?: string;\n imageUrl?: string;\n faviconUrl?: string;\n};\n\n/** The Web Search API's response: results plus request metadata. */\nexport type WebSearchResponse = {\n items: WebSearchResult[];\n metadata: {\n /** The query as the provider saw it. */\n query: string;\n /** AI Gateway request id, for the gateway log. */\n requestId: string;\n /** Provider latency in milliseconds. */\n latencyMs: number;\n };\n};\n\n/**\n * What one `web_search` run produces for the host: the full API response and\n * which provider served it. The model sees {@link renderWebSearchResults}\n * of this.\n */\nexport type WebSearchToolOutput = WebSearchResponse & {\n /** The provider that ran the search, when the source knows. */\n provider?: string;\n};\n\nexport const WEB_SEARCH_TOOL_DESCRIPTION = [\n \"Search the public web. Returns up to `limit` results, each with a URL, a title, and a short description of the page.\",\n \"Use it for current events, facts you're unsure of, documentation, and anything that may have changed since your training.\",\n \"There is no next page: for more or different results, search again with a rephrased query.\",\n \"Results are discovery only: to read a page, fetch its URL if you have a tool that reads pages.\"\n].join(\" \");\n\nexport interface RenderWebSearchResultsOptions {\n /**\n * Trim each description to this many characters in the model's view.\n * Defaults to {@link DEFAULT_WEB_SEARCH_DESCRIPTION_CHARS}; `Infinity`\n * disables trimming.\n */\n maxDescriptionChars?: number;\n}\n\n/**\n * Render search results as the text the model reads: one numbered block per\n * result, descriptions trimmed and whitespace collapsed.\n */\nexport function renderWebSearchResults(\n response: WebSearchResponse,\n options: RenderWebSearchResultsOptions = {}\n): string {\n const maxChars =\n options.maxDescriptionChars ?? DEFAULT_WEB_SEARCH_DESCRIPTION_CHARS;\n if (response.items.length === 0) {\n return `No results for \"${response.metadata.query}\". Try a broader or rephrased query.`;\n }\n const blocks = response.items.map((item, index) => {\n const lines = [`${index + 1}. ${item.title.trim() || item.url}`, item.url];\n const description = compactDescription(item.description, maxChars);\n if (description) lines.push(description);\n if (item.lastModifiedDate) lines.push(`Modified: ${item.lastModifiedDate}`);\n return lines.join(\"\\n\");\n });\n return [\n `${response.items.length} result${response.items.length === 1 ? \"\" : \"s\"} for \"${response.metadata.query}\":`,\n \"\",\n blocks.join(\"\\n\\n\")\n ].join(\"\\n\");\n}\n\nfunction compactDescription(\n description: string | undefined,\n maxChars: number\n): string | undefined {\n if (!description) return undefined;\n const compact = description.replace(/\\s+/g, \" \").trim();\n if (!compact) return undefined;\n if (compact.length <= maxChars) return compact;\n const cut = compact.slice(0, Math.max(0, maxChars - 1));\n // Back off to the last word boundary, unless that loses too much.\n const space = cut.lastIndexOf(\" \");\n const end = space >= cut.length - WORD_BOUNDARY_BACKOFF ? space : cut.length;\n return `${cut.slice(0, end).trimEnd()}…`;\n}\n\n/** How far truncation backs off to end on a whole word. */\nconst WORD_BOUNDARY_BACKOFF = 20;\n","/**\n * Where searches run. A {@link WebSearchSource} turns a query into a\n * {@link WebSearchResponse}; the tool core is written against it, so the\n * same tool works over the Workers AI binding, the HTTP API, or a fake in\n * tests.\n */\nimport { DEFAULT_GATEWAY_ID } from \"../models/core/settings\";\nimport {\n DEFAULT_WEB_SEARCH_LIMIT,\n MAX_WEB_SEARCH_LIMIT,\n MAX_WEB_SEARCH_QUERY_LENGTH,\n type WebSearchResponse,\n type WebSearchResult\n} from \"./contract\";\n\n/**\n * Search providers behind the Cloudflare Web Search API. `ceramic` is the\n * platform default and the cheapest; `exa` and `linkup` cost more and, in our\n * testing, ranked announcement-style queries noticeably better. Pricing and\n * data-retention terms are in the Web Search docs.\n */\nexport type WebSearchProvider = \"ceramic\" | \"exa\" | \"linkup\";\n\n/** One search request as a source receives it. */\nexport interface WebSearchRequest {\n /** 1–1024 characters. */\n query: string;\n /** 1–10. Defaults to 5. */\n limit?: number;\n}\n\n/** Per-call options a source receives alongside the request. */\nexport interface WebSearchCallOptions {\n /** Abort the search. A source should reject with the signal's reason. */\n signal?: AbortSignal;\n}\n\n/**\n * Runs searches. The tool core calls `search` and renders what comes back.\n * An object rather than a bare function so a wrapper (caching, logging)\n * keeps `provider` by spreading the source it wraps.\n */\nexport interface WebSearchSource {\n search(\n request: WebSearchRequest,\n options?: WebSearchCallOptions\n ): Promise<WebSearchResponse>;\n /**\n * The provider this source searches with, when known. Informational:\n * recorded on the tool's host output.\n */\n readonly provider?: WebSearchProvider;\n}\n\n/** Options shared by the AI-binding and HTTP sources. */\nexport interface WebSearchGatewayOptions {\n /** AI Gateway id. Defaults to `\"default\"`, which Cloudflare creates on first use. */\n gateway?: string;\n /**\n * Which provider runs the search. Host-chosen; the model never picks.\n * Defaults to the platform default (`ceramic`).\n */\n provider?: WebSearchProvider;\n /**\n * The BYOK key alias on the gateway to bill the provider with. When set\n * and no such key exists the request fails rather than falling back to\n * AI Gateway credits. When omitted, a key under the `default` alias is\n * used if one exists, otherwise credits.\n */\n byokAlias?: string;\n}\n\n/** A search over the Workers AI binding (`env.AI.websearch`). */\nexport interface AIWebSearchOptions extends WebSearchGatewayOptions {\n /** The Workers AI binding. Requires `\"ai\": { \"binding\": \"AI\" }` in wrangler.jsonc. */\n binding: Ai;\n}\n\n/**\n * `Ai.websearch` as `@cloudflare/workers-types` ≥ 5.20260812.1 declares it.\n * This repo can't take that version yet — it breaks `@types/node`'s\n * `Buffer` (cloudflare/workerd#7026) — so the method is spelled out here\n * and the binding is viewed through it. Drop once the repo bumps.\n */\ninterface AiWebSearchBinding {\n websearch(request: {\n gatewayId: string;\n query: string;\n limit?: number;\n provider?: string;\n byokAlias?: string;\n }): Promise<Response>;\n}\n\n/**\n * Search through the Workers AI binding. The Worker's own account and the\n * named gateway are billed.\n */\nexport function createAIWebSearch(\n options: AIWebSearchOptions\n): WebSearchSource {\n validateGatewayOptions(options);\n const binding = options.binding as unknown as AiWebSearchBinding;\n const search: WebSearchSource[\"search\"] = async (input, call = {}) => {\n const request = validateRequest(input);\n if (typeof binding.websearch !== \"function\") {\n throw new WebSearchError(\n \"This Workers runtime has no env.AI.websearch(). Web search needs workerd 1.20260924.1 or later; see https://github.com/cloudflare/agents/blob/main/docs/agents/search-the-web.md.\",\n {\n status: 501,\n code: \"web_search_unsupported_runtime\",\n retryable: false\n }\n );\n }\n // Do not start a billed search for a call that is already cancelled.\n call.signal?.throwIfAborted();\n // The binding takes no signal, so an abort stops waiting for it.\n const response = await abortable(\n binding.websearch({\n gatewayId: options.gateway ?? DEFAULT_GATEWAY_ID,\n query: request.query,\n limit: request.limit,\n provider: options.provider,\n byokAlias: options.byokAlias\n }),\n call.signal\n );\n return readResponse(response, request.query);\n };\n return { search, provider: options.provider };\n}\n\n/** A search over the HTTP API, from any runtime with `fetch`. */\nexport interface HTTPWebSearchOptions extends WebSearchGatewayOptions {\n /** The Cloudflare account the gateway belongs to. */\n accountId: string;\n /** An API token with `Workers AI: Read` and `AI Gateway: Read` on that account. */\n apiToken: string;\n /** Override for tests. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** API origin. Defaults to `https://api.cloudflare.com`. */\n baseUrl?: string;\n}\n\n/**\n * Search through `POST /accounts/{account_id}/ai/websearch`. Use this\n * outside Workers, or to search through a gateway in another account.\n */\nexport function createHTTPWebSearch(\n options: HTTPWebSearchOptions\n): WebSearchSource {\n validateGatewayOptions(options);\n const doFetch = options.fetch ?? fetch;\n const baseUrl = (options.baseUrl ?? \"https://api.cloudflare.com\").replace(\n /\\/+$/,\n \"\"\n );\n const url = `${baseUrl}/client/v4/accounts/${encodeURIComponent(options.accountId)}/ai/websearch/`;\n const search: WebSearchSource[\"search\"] = async (input, call = {}) => {\n const request = validateRequest(input);\n const response = await doFetch(url, {\n method: \"POST\",\n signal: call.signal,\n headers: {\n Authorization: `Bearer ${options.apiToken}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n query: request.query,\n limit: request.limit,\n provider: options.provider,\n byokAlias: options.byokAlias,\n options: { gateway: { id: options.gateway ?? DEFAULT_GATEWAY_ID } }\n })\n });\n return readResponse(response, request.query);\n };\n return { search, provider: options.provider };\n}\n\n/** The API's pattern for `byokAlias`. */\nconst BYOK_ALIAS_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;\n\n/** Host configuration errors are programming errors: throw when building. */\nfunction validateGatewayOptions(options: WebSearchGatewayOptions): void {\n if (\n options.byokAlias !== undefined &&\n !BYOK_ALIAS_PATTERN.test(options.byokAlias)\n ) {\n throw new RangeError(\n `byokAlias must be 1–64 letters, digits, \"_\" or \"-\"; got ${JSON.stringify(options.byokAlias)}.`\n );\n }\n}\n\n/**\n * Error codes a {@link WebSearchError} carries. The `web_search_*` codes the\n * API returns pass through as-is; failures without one get a code from the\n * HTTP status, so every error has a code to branch on.\n */\nexport type WebSearchErrorCode =\n /** No AI Gateway credits and no provider key for the search. */\n | \"web_search_payment_required\"\n /** `byokAlias` names a key the gateway does not have. */\n | \"web_search_byok_not_configured\"\n /** The query, limit, or provider was rejected. */\n | \"invalid_web_search_input\"\n /** The gateway does not exist or is not set up. */\n | \"web_search_gateway_not_configured\"\n /** The API token or binding is not allowed to search. */\n | \"web_search_unauthorized\"\n /** Too many searches; retry later. */\n | \"web_search_rate_limited\"\n /** The search took longer than the tool's `timeoutMs`. */\n | \"web_search_timeout\"\n /** The API or the provider failed. */\n | \"web_search_unavailable\"\n /** The Workers runtime has no `env.AI.websearch()`. */\n | \"web_search_unsupported_runtime\"\n /** A code the API added after this release. */\n | (string & {});\n\n/** Why a search failed, with what the API said. */\nexport class WebSearchError extends Error {\n override readonly name = \"WebSearchError\";\n readonly status: number;\n readonly code: WebSearchErrorCode;\n /** Whether retrying the same search might succeed. */\n readonly retryable: boolean;\n /** AI Gateway's id for the failed request, for the gateway log. */\n readonly requestId?: string;\n /** The Cloudflare API's numeric error code, when it gave one. */\n readonly apiCode?: number;\n\n constructor(\n message: string,\n details: {\n status: number;\n code: WebSearchErrorCode;\n retryable?: boolean;\n requestId?: string;\n apiCode?: number;\n cause?: unknown;\n }\n ) {\n super(message, { cause: details.cause });\n this.status = details.status;\n this.code = details.code;\n this.retryable = details.retryable ?? isRetryableStatus(details.status);\n this.requestId = details.requestId;\n this.apiCode = details.apiCode;\n }\n}\n\n/** Check a request against the API's limits and fill in the default limit. */\nfunction validateRequest(\n request: WebSearchRequest\n): Required<WebSearchRequest> {\n const query = request.query.trim();\n const limit = request.limit ?? DEFAULT_WEB_SEARCH_LIMIT;\n if (query.length === 0) {\n throw new WebSearchError(\"Query must not be empty.\", {\n status: 400,\n code: \"invalid_web_search_input\"\n });\n }\n if (query.length > MAX_WEB_SEARCH_QUERY_LENGTH) {\n throw new WebSearchError(\n `Query must be at most ${MAX_WEB_SEARCH_QUERY_LENGTH} characters.`,\n { status: 400, code: \"invalid_web_search_input\" }\n );\n }\n if (!Number.isInteger(limit) || limit < 1 || limit > MAX_WEB_SEARCH_LIMIT) {\n throw new WebSearchError(\n `Limit must be an integer from 1 to ${MAX_WEB_SEARCH_LIMIT}.`,\n { status: 400, code: \"invalid_web_search_input\" }\n );\n }\n return { query, limit };\n}\n\n/** Settle with `promise`, or reject with the signal's reason once it aborts. */\nexport function abortable<T>(\n promise: Promise<T>,\n signal?: AbortSignal\n): Promise<T> {\n if (!signal) return promise;\n signal.throwIfAborted();\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(resolve, reject).finally(() => {\n signal.removeEventListener(\"abort\", onAbort);\n });\n });\n}\n\nasync function readResponse(\n response: Response,\n query: string\n): Promise<WebSearchResponse> {\n const text = await response.text();\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n body = undefined;\n }\n if (!response.ok) throw toWebSearchError(response.status, body, text);\n const result = toWebSearchResponse(body, query);\n if (!result) {\n // A success status with a body that is not a search response is an\n // upstream fault, likely transient, not a reason to stop searching.\n throw new WebSearchError(\n `Web search returned HTTP ${response.status} without search results${text ? `: ${text.slice(0, 200)}` : \"\"}.`,\n {\n status: response.status,\n code: \"web_search_unavailable\",\n retryable: true\n }\n );\n }\n return result;\n}\n\n/**\n * Read a 200 body into a {@link WebSearchResponse}, tolerating what a beta\n * API and three providers might send: items without a URL are dropped, a\n * missing title falls back to the URL, unknown or mistyped fields are left\n * out, and missing metadata gets defaults. Only a body with no `items`\n * array is rejected.\n */\nfunction toWebSearchResponse(\n body: unknown,\n query: string\n): WebSearchResponse | undefined {\n if (!isRecord(body) || !Array.isArray(body.items)) return undefined;\n const items: WebSearchResult[] = [];\n for (const item of body.items as unknown[]) {\n if (!isRecord(item)) continue;\n const url = asString(item.url)?.trim();\n if (!url) continue;\n const result: WebSearchResult = {\n url,\n title: asString(item.title)?.trim() || url\n };\n for (const key of OPTIONAL_RESULT_FIELDS) {\n const value = asString(item[key]);\n if (value !== undefined) result[key] = value;\n }\n items.push(result);\n }\n const metadata = isRecord(body.metadata) ? body.metadata : {};\n return {\n items,\n metadata: {\n query: asString(metadata.query) ?? query,\n requestId: asString(metadata.requestId) ?? \"\",\n latencyMs: typeof metadata.latencyMs === \"number\" ? metadata.latencyMs : 0\n }\n };\n}\n\nconst OPTIONAL_RESULT_FIELDS = [\n \"description\",\n \"lastModifiedDate\",\n \"imageUrl\",\n \"faviconUrl\"\n] as const satisfies readonly (keyof WebSearchResult)[];\n\n/**\n * The API fails in three shapes. Gateway-native:\n * `{ ok: false, error: { category, code, status, retryable, gatewayRequestId } }`.\n * Request validation, the Cloudflare envelope with issue details:\n * `{ success: false, errors: [{ code: 7000, message }], messages: [{ message, path }] }`.\n * Gateway configuration (`AiGatewayError`):\n * `{ success: false, error: [{ code: 2001, message }], message, description }`.\n */\nfunction toWebSearchError(\n status: number,\n body: unknown,\n text: string\n): WebSearchError {\n if (isRecord(body)) {\n const error = body.error;\n if (isRecord(error) && typeof error.code === \"string\") {\n const errorStatus =\n typeof error.status === \"number\" ? error.status : status;\n return new WebSearchError(describeCode(error.code, errorStatus), {\n status: errorStatus,\n code: error.code,\n retryable:\n typeof error.retryable === \"boolean\" ? error.retryable : undefined,\n requestId: asString(error.gatewayRequestId)\n });\n }\n const envelope: unknown[] = Array.isArray(body.errors)\n ? body.errors\n : Array.isArray(error)\n ? error\n : [];\n const entries = envelope.filter(isRecord);\n const issues: unknown[] = Array.isArray(body.messages) ? body.messages : [];\n const message =\n [\n ...entries.map((entry) => asString(entry.message)),\n ...issues.map(describeIssue)\n ]\n .filter((m): m is string => Boolean(m))\n .join(\"; \") || asString(body.message);\n if (message) {\n const apiCode = entries\n .map((entry) => entry.code)\n .find((code): code is number => typeof code === \"number\");\n return new WebSearchError(message, {\n status,\n code: codeForApiError(apiCode, status),\n apiCode\n });\n }\n }\n return new WebSearchError(\n `Web search failed with HTTP ${status}${text ? `: ${text.slice(0, 200)}` : \"\"}.`,\n { status, code: codeForStatus(status) }\n );\n}\n\nfunction codeForApiError(\n apiCode: number | undefined,\n status: number\n): WebSearchErrorCode {\n switch (apiCode) {\n case 7000:\n return \"invalid_web_search_input\";\n case 2001:\n return \"web_search_gateway_not_configured\";\n default:\n return codeForStatus(status);\n }\n}\n\nfunction codeForStatus(status: number): WebSearchErrorCode {\n if (status === 400) return \"invalid_web_search_input\";\n if (status === 401 || status === 403) return \"web_search_unauthorized\";\n if (status === 402) return \"web_search_payment_required\";\n if (status === 429) return \"web_search_rate_limited\";\n return \"web_search_unavailable\";\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction describeCode(code: string, status: number): string {\n switch (code) {\n case \"web_search_payment_required\":\n return \"Web search is unavailable: the AI Gateway has no credits and no provider key for this search. Top up AI Gateway credits or store a BYOK key for the provider.\";\n case \"web_search_byok_not_configured\":\n return \"Web search is unavailable: the requested BYOK key alias is not configured on the gateway.\";\n case \"invalid_web_search_input\":\n return \"The API rejected the request: check the query (1–1024 characters), limit (1–10), and provider (ceramic, exa, or linkup).\";\n default:\n return `Web search failed (${code}, HTTP ${status}).`;\n }\n}\n\nfunction describeIssue(issue: unknown): string | undefined {\n if (!isRecord(issue)) return undefined;\n const message = asString(issue.message);\n if (!message) return undefined;\n const path = Array.isArray(issue.path) ? issue.path.join(\".\") : \"\";\n return path ? `${path}: ${message}` : message;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n","/**\n * The harness-neutral core of the `web_search` tool, shared by the pi\n * (`agents/websearch/pi`), AI SDK (`agents/websearch/ai-sdk`), and TanStack\n * AI (`agents/websearch/tanstack-ai`) adapters. Internal — not an entry point.\n */\nimport {\n DEFAULT_WEB_SEARCH_LIMIT,\n MAX_WEB_SEARCH_LIMIT,\n WEB_SEARCH_TOOL_DESCRIPTION,\n WEB_SEARCH_TOOL_NAME,\n renderWebSearchResults,\n type WebSearchResponse,\n type WebSearchToolInput,\n type WebSearchToolOutput\n} from \"./contract\";\nimport {\n WebSearchError,\n abortable,\n createAIWebSearch,\n type AIWebSearchOptions,\n type WebSearchSource\n} from \"./source\";\n\n/** Search through the Workers AI binding; the tool builds the source. */\nexport type WebSearchToolBindingOptions = AIWebSearchOptions & {\n source?: never;\n};\n\n/**\n * Search through a source you built. Gateway, provider, and billing belong\n * to the source, so the binding options are not accepted here.\n */\nexport type WebSearchToolSourceOptions = {\n /** Where searches run, instead of the Workers AI binding. */\n source: WebSearchSource;\n binding?: never;\n gateway?: never;\n provider?: never;\n byokAlias?: never;\n};\n\n/**\n * Options every `web_search` tool adapter accepts. Invalid values throw a\n * `RangeError` when the tool is created.\n */\nexport type WebSearchToolOptions = (\n | WebSearchToolBindingOptions\n | WebSearchToolSourceOptions\n) & {\n /**\n * Results per search when the model doesn't ask for a count, and the most\n * it gets when it asks for more. An integer from 1 to 10; defaults to 5.\n */\n limit?: number;\n /** Replaces the default tool description. */\n description?: string;\n /**\n * Per-result description length in the model's view. A positive integer;\n * defaults to 600 characters. `Infinity` passes descriptions through whole.\n */\n maxDescriptionChars?: number;\n /**\n * Give up on a search after this many milliseconds, as a retryable\n * `web_search_timeout` failure. A positive integer; defaults to 30 seconds.\n */\n timeoutMs?: number;\n};\n\n/** The default for {@link WebSearchToolOptions.timeoutMs}. */\nexport const DEFAULT_WEB_SEARCH_TIMEOUT_MS = 30_000;\n\n/**\n * What one run returns to the adapter: the host output, and the model's\n * text. On failure, `error` is the source's error, with the API's detail for\n * the host, and `text` is what the model should read instead.\n */\nexport type WebSearchToolRun =\n | { ok: true; output: WebSearchToolOutput; text: string }\n | { ok: false; error: WebSearchError; text: string };\n\nexport interface WebSearchToolCore {\n name: typeof WEB_SEARCH_TOOL_NAME;\n description: string;\n /** The host's `limit`: the default and the cap for the model's `limit`. */\n limit: number;\n /** Render a search's output as the text the model reads. */\n render(output: WebSearchResponse): string;\n /**\n * Run one search. Aborting `signal` rejects with its reason rather than\n * producing a failed run, so the harness sees a cancelled call.\n */\n run(\n input: WebSearchToolInput,\n options?: { signal?: AbortSignal }\n ): Promise<WebSearchToolRun>;\n}\n\nexport function createWebSearchToolCore(\n options: WebSearchToolOptions\n): WebSearchToolCore {\n const limit = options.limit ?? DEFAULT_WEB_SEARCH_LIMIT;\n const timeoutMs = options.timeoutMs ?? DEFAULT_WEB_SEARCH_TIMEOUT_MS;\n const { maxDescriptionChars } = options;\n if (!Number.isInteger(limit) || limit < 1 || limit > MAX_WEB_SEARCH_LIMIT) {\n throw new RangeError(\n `limit must be an integer from 1 to ${MAX_WEB_SEARCH_LIMIT}; got ${limit}.`\n );\n }\n if (\n maxDescriptionChars !== undefined &&\n maxDescriptionChars !== Infinity &&\n !(Number.isInteger(maxDescriptionChars) && maxDescriptionChars > 0)\n ) {\n throw new RangeError(\n `maxDescriptionChars must be a positive integer or Infinity; got ${maxDescriptionChars}.`\n );\n }\n if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {\n throw new RangeError(\n `timeoutMs must be a positive integer; got ${timeoutMs}.`\n );\n }\n const source =\n options.source === undefined ? createAIWebSearch(options) : options.source;\n const provider = source.provider;\n const render = (output: WebSearchResponse) =>\n renderWebSearchResults(output, { maxDescriptionChars });\n\n return {\n name: WEB_SEARCH_TOOL_NAME,\n description: options.description ?? WEB_SEARCH_TOOL_DESCRIPTION,\n limit,\n render,\n async run(input, { signal } = {}) {\n signal?.throwIfAborted();\n const request = {\n query: input.query,\n limit: Math.min(clampLimit(input.limit ?? limit), limit)\n };\n const timeout = AbortSignal.timeout(timeoutMs);\n const searchSignal = signal\n ? AbortSignal.any([signal, timeout])\n : timeout;\n try {\n // Race the source too: a custom source may ignore the signal, and\n // the deadline must still end the call.\n const response = await abortable(\n source.search(request, { signal: searchSignal }),\n searchSignal\n );\n const output: WebSearchToolOutput = provider\n ? { ...response, provider }\n : response;\n return {\n ok: true,\n output,\n text: render(response)\n };\n } catch (cause) {\n if (signal?.aborted) throw signal.reason;\n const error = toToolError(cause, timeout.aborted, timeoutMs);\n return { ok: false, error, text: describeFailureForModel(error) };\n }\n }\n };\n}\n\n/**\n * The error a throwing adapter (AI SDK, TanStack AI) raises for a failed\n * run. Those frameworks show the model the error's `message`, so it carries\n * the model's text; the source's error, with the API's detail, is `cause`.\n */\nexport function toolFailure(\n run: Extract<WebSearchToolRun, { ok: false }>\n): WebSearchError {\n const { error } = run;\n return new WebSearchError(run.text, {\n status: error.status,\n code: error.code,\n retryable: error.retryable,\n requestId: error.requestId,\n apiCode: error.apiCode,\n cause: error\n });\n}\n\nfunction toToolError(\n cause: unknown,\n timedOut: boolean,\n timeoutMs: number\n): WebSearchError {\n if (timedOut) {\n return new WebSearchError(`Web search timed out after ${timeoutMs} ms.`, {\n status: 504,\n code: \"web_search_timeout\",\n retryable: true,\n cause\n });\n }\n if (cause instanceof WebSearchError) return cause;\n return new WebSearchError(\n cause instanceof Error ? cause.message : String(cause),\n { status: 500, code: \"web_search_unavailable\", retryable: true, cause }\n );\n}\n\n/**\n * What the model reads when a search fails: whether to retry, change the\n * query, or carry on without search. The operator's detail (credits, keys,\n * gateway setup) stays on the error for the host.\n */\nfunction describeFailureForModel(error: WebSearchError): string {\n if (error.code === \"invalid_web_search_input\") {\n return `Web search rejected the query (${error.message.replace(/\\.$/, \"\")}). Fix the query and try again.`;\n }\n if (error.retryable) {\n return `Web search failed temporarily (${error.code}). You may retry once.`;\n }\n return `Web search is unavailable here (${error.code}). Do not retry; answer without it and say that web search was unavailable.`;\n}\n\n/** The model's `limit`, made an integer from 1 to 10. */\nfunction clampLimit(value: number): number {\n if (!Number.isFinite(value)) return DEFAULT_WEB_SEARCH_LIMIT;\n return Math.min(MAX_WEB_SEARCH_LIMIT, Math.max(1, Math.trunc(value)));\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,uBAAuB;;AAGpC,MAAa,2BAA2B;;AAGxC,MAAa,uBAAuB;;AAGpC,MAAa,8BAA8B;;;;;;;AAQ3C,MAAa,uCAAuC;AAsDpD,MAAa,8BAA8B;CACzC;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;;;;;AAeV,SAAgB,uBACd,UACA,UAAyC,CAAC,GAClC;CACR,MAAM,WACJ,QAAQ,uBAAA;CACV,IAAI,SAAS,MAAM,WAAW,GAC5B,OAAO,mBAAmB,SAAS,SAAS,MAAM;CAEpD,MAAM,SAAS,SAAS,MAAM,KAAK,MAAM,UAAU;EACjD,MAAM,QAAQ,CAAC,GAAG,QAAQ,EAAE,IAAI,KAAK,MAAM,KAAK,KAAK,KAAK,OAAO,KAAK,GAAG;EACzE,MAAM,cAAc,mBAAmB,KAAK,aAAa,QAAQ;EACjE,IAAI,aAAa,MAAM,KAAK,WAAW;EACvC,IAAI,KAAK,kBAAkB,MAAM,KAAK,aAAa,KAAK,kBAAkB;EAC1E,OAAO,MAAM,KAAK,IAAI;CACxB,CAAC;CACD,OAAO;EACL,GAAG,SAAS,MAAM,OAAO,SAAS,SAAS,MAAM,WAAW,IAAI,KAAK,IAAI,QAAQ,SAAS,SAAS,MAAM;EACzG;EACA,OAAO,KAAK,MAAM;CACpB,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,mBACP,aACA,UACoB;CACpB,IAAI,CAAC,aAAa,OAAO,KAAA;CACzB,MAAM,UAAU,YAAY,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;CACtD,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,QAAQ,UAAU,UAAU,OAAO;CACvC,MAAM,MAAM,QAAQ,MAAM,GAAG,KAAK,IAAI,GAAG,WAAW,CAAC,CAAC;CAEtD,MAAM,QAAQ,IAAI,YAAY,GAAG;CACjC,MAAM,MAAM,SAAS,IAAI,SAAS,wBAAwB,QAAQ,IAAI;CACtE,OAAO,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE;AACxC;;AAGA,MAAM,wBAAwB;;;;;;;;;;;;;AC9C9B,SAAgB,kBACd,SACiB;CACjB,uBAAuB,OAAO;CAC9B,MAAM,UAAU,QAAQ;CACxB,MAAM,SAAoC,OAAO,OAAO,OAAO,CAAC,MAAM;EACpE,MAAM,UAAU,gBAAgB,KAAK;EACrC,IAAI,OAAO,QAAQ,cAAc,YAC/B,MAAM,IAAI,eACR,qLACA;GACE,QAAQ;GACR,MAAM;GACN,WAAW;EACb,CACF;EAGF,KAAK,QAAQ,eAAe;EAY5B,OAAO,aAAa,MAVG,UACrB,QAAQ,UAAU;GAChB,WAAW,QAAQ,WAAA;GACnB,OAAO,QAAQ;GACf,OAAO,QAAQ;GACf,UAAU,QAAQ;GAClB,WAAW,QAAQ;EACrB,CAAC,GACD,KAAK,MACP,GAC8B,QAAQ,KAAK;CAC7C;CACA,OAAO;EAAE;EAAQ,UAAU,QAAQ;CAAS;AAC9C;;;;;AAkBA,SAAgB,oBACd,SACiB;CACjB,uBAAuB,OAAO;CAC9B,MAAM,UAAU,QAAQ,SAAS;CAKjC,MAAM,MAAM,IAJK,QAAQ,WAAW,6BAAA,CAA8B,QAChE,QACA,EAEmB,EAAE,sBAAsB,mBAAmB,QAAQ,SAAS,EAAE;CACnF,MAAM,SAAoC,OAAO,OAAO,OAAO,CAAC,MAAM;EACpE,MAAM,UAAU,gBAAgB,KAAK;EAgBrC,OAAO,aAAa,MAfG,QAAQ,KAAK;GAClC,QAAQ;GACR,QAAQ,KAAK;GACb,SAAS;IACP,eAAe,UAAU,QAAQ;IACjC,gBAAgB;GAClB;GACA,MAAM,KAAK,UAAU;IACnB,OAAO,QAAQ;IACf,OAAO,QAAQ;IACf,UAAU,QAAQ;IAClB,WAAW,QAAQ;IACnB,SAAS,EAAE,SAAS,EAAE,IAAI,QAAQ,WAAA,UAA8B,EAAE;GACpE,CAAC;EACH,CAAC,GAC6B,QAAQ,KAAK;CAC7C;CACA,OAAO;EAAE;EAAQ,UAAU,QAAQ;CAAS;AAC9C;;AAGA,MAAM,qBAAqB;;AAG3B,SAAS,uBAAuB,SAAwC;CACtE,IACE,QAAQ,cAAc,KAAA,KACtB,CAAC,mBAAmB,KAAK,QAAQ,SAAS,GAE1C,MAAM,IAAI,WACR,2DAA2D,KAAK,UAAU,QAAQ,SAAS,EAAE,EAC/F;AAEJ;;AA8BA,IAAa,iBAAb,cAAoC,MAAM;CAWxC,YACE,SACA,SAQA;EACA,MAAM,SAAS,EAAE,OAAO,QAAQ,MAAM,CAAC;EArBzC,KAAkB,OAAO;EAsBvB,KAAK,SAAS,QAAQ;EACtB,KAAK,OAAO,QAAQ;EACpB,KAAK,YAAY,QAAQ,aAAa,kBAAkB,QAAQ,MAAM;EACtE,KAAK,YAAY,QAAQ;EACzB,KAAK,UAAU,QAAQ;CACzB;AACF;;AAGA,SAAS,gBACP,SAC4B;CAC5B,MAAM,QAAQ,QAAQ,MAAM,KAAK;CACjC,MAAM,QAAQ,QAAQ,SAAA;CACtB,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,eAAe,4BAA4B;EACnD,QAAQ;EACR,MAAM;CACR,CAAC;CAEH,IAAI,MAAM,SAAA,MACR,MAAM,IAAI,eACR,yBAAyB,4BAA4B,eACrD;EAAE,QAAQ;EAAK,MAAM;CAA2B,CAClD;CAEF,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAA,IAC3C,MAAM,IAAI,eACR,0CACA;EAAE,QAAQ;EAAK,MAAM;CAA2B,CAClD;CAEF,OAAO;EAAE;EAAO;CAAM;AACxB;;AAGA,SAAgB,UACd,SACA,QACY;CACZ,IAAI,CAAC,QAAQ,OAAO;CACpB,OAAO,eAAe;CACtB,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,MAAM,gBAAgB,OAAO,OAAO,MAAM;EAC1C,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACxD,QAAQ,KAAK,SAAS,MAAM,CAAC,CAAC,cAAc;GAC1C,OAAO,oBAAoB,SAAS,OAAO;EAC7C,CAAC;CACH,CAAC;AACH;AAEA,eAAe,aACb,UACA,OAC4B;CAC5B,MAAM,OAAO,MAAM,SAAS,KAAK;CACjC,IAAI;CACJ,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO,KAAA;CACT;CACA,IAAI,CAAC,SAAS,IAAI,MAAM,iBAAiB,SAAS,QAAQ,MAAM,IAAI;CACpE,MAAM,SAAS,oBAAoB,MAAM,KAAK;CAC9C,IAAI,CAAC,QAGH,MAAM,IAAI,eACR,4BAA4B,SAAS,OAAO,yBAAyB,OAAO,KAAK,KAAK,MAAM,GAAG,GAAG,MAAM,GAAG,IAC3G;EACE,QAAQ,SAAS;EACjB,MAAM;EACN,WAAW;CACb,CACF;CAEF,OAAO;AACT;;;;;;;;AASA,SAAS,oBACP,MACA,OAC+B;CAC/B,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,KAAK,KAAK,GAAG,OAAO,KAAA;CAC1D,MAAM,QAA2B,CAAC;CAClC,KAAK,MAAM,QAAQ,KAAK,OAAoB;EAC1C,IAAI,CAAC,SAAS,IAAI,GAAG;EACrB,MAAM,MAAM,SAAS,KAAK,GAAG,CAAC,EAAE,KAAK;EACrC,IAAI,CAAC,KAAK;EACV,MAAM,SAA0B;GAC9B;GACA,OAAO,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,KAAK;EACzC;EACA,KAAK,MAAM,OAAO,wBAAwB;GACxC,MAAM,QAAQ,SAAS,KAAK,IAAI;GAChC,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;EACzC;EACA,MAAM,KAAK,MAAM;CACnB;CACA,MAAM,WAAW,SAAS,KAAK,QAAQ,IAAI,KAAK,WAAW,CAAC;CAC5D,OAAO;EACL;EACA,UAAU;GACR,OAAO,SAAS,SAAS,KAAK,KAAK;GACnC,WAAW,SAAS,SAAS,SAAS,KAAK;GAC3C,WAAW,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY;EAC3E;CACF;AACF;AAEA,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;AACF;;;;;;;;;AAUA,SAAS,iBACP,QACA,MACA,MACgB;CAChB,IAAI,SAAS,IAAI,GAAG;EAClB,MAAM,QAAQ,KAAK;EACnB,IAAI,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAAU;GACrD,MAAM,cACJ,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;GACpD,OAAO,IAAI,eAAe,aAAa,MAAM,MAAM,WAAW,GAAG;IAC/D,QAAQ;IACR,MAAM,MAAM;IACZ,WACE,OAAO,MAAM,cAAc,YAAY,MAAM,YAAY,KAAA;IAC3D,WAAW,SAAS,MAAM,gBAAgB;GAC5C,CAAC;EACH;EAMA,MAAM,WALsB,MAAM,QAAQ,KAAK,MAAM,IACjD,KAAK,SACL,MAAM,QAAQ,KAAK,IACjB,QACA,CAAC,EAAA,CACkB,OAAO,QAAQ;EACxC,MAAM,SAAoB,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,WAAW,CAAC;EAC1E,MAAM,UACJ,CACE,GAAG,QAAQ,KAAK,UAAU,SAAS,MAAM,OAAO,CAAC,GACjD,GAAG,OAAO,IAAI,aAAa,CAC7B,CAAC,CACE,QAAQ,MAAmB,QAAQ,CAAC,CAAC,CAAC,CACtC,KAAK,IAAI,KAAK,SAAS,KAAK,OAAO;EACxC,IAAI,SAAS;GACX,MAAM,UAAU,QACb,KAAK,UAAU,MAAM,IAAI,CAAC,CAC1B,MAAM,SAAyB,OAAO,SAAS,QAAQ;GAC1D,OAAO,IAAI,eAAe,SAAS;IACjC;IACA,MAAM,gBAAgB,SAAS,MAAM;IACrC;GACF,CAAC;EACH;CACF;CACA,OAAO,IAAI,eACT,+BAA+B,SAAS,OAAO,KAAK,KAAK,MAAM,GAAG,GAAG,MAAM,GAAG,IAC9E;EAAE;EAAQ,MAAM,cAAc,MAAM;CAAE,CACxC;AACF;AAEA,SAAS,gBACP,SACA,QACoB;CACpB,QAAQ,SAAR;EACE,KAAK,KACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,SACE,OAAO,cAAc,MAAM;CAC/B;AACF;AAEA,SAAS,cAAc,QAAoC;CACzD,IAAI,WAAW,KAAK,OAAO;CAC3B,IAAI,WAAW,OAAO,WAAW,KAAK,OAAO;CAC7C,IAAI,WAAW,KAAK,OAAO;CAC3B,IAAI,WAAW,KAAK,OAAO;CAC3B,OAAO;AACT;AAEA,SAAS,kBAAkB,QAAyB;CAClD,OAAO,WAAW,OAAO,UAAU;AACrC;AAEA,SAAS,aAAa,MAAc,QAAwB;CAC1D,QAAQ,MAAR;EACE,KAAK,+BACH,OAAO;EACT,KAAK,kCACH,OAAO;EACT,KAAK,4BACH,OAAO;EACT,SACE,OAAO,sBAAsB,KAAK,SAAS,OAAO;CACtD;AACF;AAEA,SAAS,cAAc,OAAoC;CACzD,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO,KAAA;CAC7B,MAAM,UAAU,SAAS,MAAM,OAAO;CACtC,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,KAAK,KAAK,GAAG,IAAI;CAChE,OAAO,OAAO,GAAG,KAAK,IAAI,YAAY;AACxC;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,SAAS,OAAoC;CACpD,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;;;;;;;;;AC5ZA,MAAa,gCAAgC;AA4B7C,SAAgB,wBACd,SACmB;CACnB,MAAM,QAAQ,QAAQ,SAAA;CACtB,MAAM,YAAY,QAAQ,aAAA;CAC1B,MAAM,EAAE,wBAAwB;CAChC,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAA,IAC3C,MAAM,IAAI,WACR,8CAAmE,MAAM,EAC3E;CAEF,IACE,wBAAwB,KAAA,KACxB,wBAAwB,YACxB,EAAE,OAAO,UAAU,mBAAmB,KAAK,sBAAsB,IAEjE,MAAM,IAAI,WACR,mEAAmE,oBAAoB,EACzF;CAEF,IAAI,CAAC,OAAO,UAAU,SAAS,KAAK,aAAa,GAC/C,MAAM,IAAI,WACR,6CAA6C,UAAU,EACzD;CAEF,MAAM,SACJ,QAAQ,WAAW,KAAA,IAAY,kBAAkB,OAAO,IAAI,QAAQ;CACtE,MAAM,WAAW,OAAO;CACxB,MAAM,UAAU,WACd,uBAAuB,QAAQ,EAAE,oBAAoB,CAAC;CAExD,OAAO;EACL,MAAM;EACN,aAAa,QAAQ,eAAe;EACpC;EACA;EACA,MAAM,IAAI,OAAO,EAAE,WAAW,CAAC,GAAG;GAChC,QAAQ,eAAe;GACvB,MAAM,UAAU;IACd,OAAO,MAAM;IACb,OAAO,KAAK,IAAI,WAAW,MAAM,SAAS,KAAK,GAAG,KAAK;GACzD;GACA,MAAM,UAAU,YAAY,QAAQ,SAAS;GAC7C,MAAM,eAAe,SACjB,YAAY,IAAI,CAAC,QAAQ,OAAO,CAAC,IACjC;GACJ,IAAI;IAGF,MAAM,WAAW,MAAM,UACrB,OAAO,OAAO,SAAS,EAAE,QAAQ,aAAa,CAAC,GAC/C,YACF;IAIA,OAAO;KACL,IAAI;KACJ,QALkC,WAChC;MAAE,GAAG;MAAU;KAAS,IACxB;KAIF,MAAM,OAAO,QAAQ;IACvB;GACF,SAAS,OAAO;IACd,IAAI,QAAQ,SAAS,MAAM,OAAO;IAClC,MAAM,QAAQ,YAAY,OAAO,QAAQ,SAAS,SAAS;IAC3D,OAAO;KAAE,IAAI;KAAO;KAAO,MAAM,wBAAwB,KAAK;IAAE;GAClE;EACF;CACF;AACF;;;;;;AAOA,SAAgB,YACd,KACgB;CAChB,MAAM,EAAE,UAAU;CAClB,OAAO,IAAI,eAAe,IAAI,MAAM;EAClC,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,OAAO;CACT,CAAC;AACH;AAEA,SAAS,YACP,OACA,UACA,WACgB;CAChB,IAAI,UACF,OAAO,IAAI,eAAe,8BAA8B,UAAU,OAAO;EACvE,QAAQ;EACR,MAAM;EACN,WAAW;EACX;CACF,CAAC;CAEH,IAAI,iBAAiB,gBAAgB,OAAO;CAC5C,OAAO,IAAI,eACT,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GACrD;EAAE,QAAQ;EAAK,MAAM;EAA0B,WAAW;EAAM;CAAM,CACxE;AACF;;;;;;AAOA,SAAS,wBAAwB,OAA+B;CAC9D,IAAI,MAAM,SAAS,4BACjB,OAAO,kCAAkC,MAAM,QAAQ,QAAQ,OAAO,EAAE,EAAE;CAE5E,IAAI,MAAM,WACR,OAAO,kCAAkC,MAAM,KAAK;CAEtD,OAAO,mCAAmC,MAAM,KAAK;AACvD;;AAGA,SAAS,WAAW,OAAuB;CACzC,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAA;CAC7B,OAAO,KAAK,IAAA,IAA0B,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AACtE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ai-sdk.js","names":[],"sources":["../../../src/websearch/tools/ai-sdk.ts"],"sourcesContent":["/**\n * `agents/websearch/ai-sdk` — the `web_search` tool for the AI SDK.\n *\n * @beta\n */\nimport type { FlexibleSchema } from \"ai\";\nimport type { WebSearchToolInput, WebSearchToolOutput } from \"../contract\";\nimport {\n createWebSearchToolCore,\n toolFailure,\n type WebSearchToolOptions\n} from \"../tool\";\nimport { webSearchInputSchema } from \"./input-schema\";\n\nexport type {\n WebSearchResponse,\n WebSearchResult,\n WebSearchToolInput,\n WebSearchToolOutput\n} from \"../contract\";\nexport {\n WebSearchError,\n type WebSearchErrorCode,\n type WebSearchProvider,\n type WebSearchSource\n} from \"../source\";\nexport type { WebSearchToolOptions } from \"../tool\";\n\n/**\n * The part of the AI SDK's tool execution options the tool reads. Spelled\n * out rather than imported so it fits every supported `ai` major.\n */\nexport interface WebSearchToolExecuteOptions {\n abortSignal?: AbortSignal;\n}\n\n/**\n * The AI SDK tool {@link webSearchTool} returns. Assignable to the AI SDK's\n * `Tool`; `execute` and `toModelOutput` are always present.\n */\nexport interface WebSearchTool {\n description: string;\n inputSchema: FlexibleSchema<WebSearchToolInput>;\n execute(\n input: WebSearchToolInput,\n options: WebSearchToolExecuteOptions\n ): Promise<WebSearchToolOutput>;\n toModelOutput(options: { output: WebSearchToolOutput }): {\n type: \"text\";\n value: string;\n };\n}\n\n/**\n * Create an AI SDK tool that searches the web through Cloudflare's Web\n * Search API. The host gets the full response as the tool's output (whole\n * descriptions, provider metadata); the model gets a trimmed text rendering\n * via `toModelOutput`. A failed search throws a `WebSearchError`, which the\n * AI SDK reports to the model as a tool error: its `message` is written for\n * the model, and its `cause` is the source's error with the API's detail.\n *\n * `toModelOutput` only applies to earlier turns when the tools are passed to\n * `convertToModelMessages(messages, { tools })`; otherwise the AI SDK sends\n * the full response back to the model as JSON. `AiSdkHarness` passes them.\n *\n * @example\n * ```ts\n * import { webSearchTool } from \"agents/websearch/ai-sdk\";\n *\n * const result = streamText({\n * model,\n * tools: { web_search: webSearchTool({ binding: env.AI }) },\n * messages\n * });\n * ```\n */\nexport function webSearchTool(options: WebSearchToolOptions): WebSearchTool {\n const core = createWebSearchToolCore(options);\n return {\n description: core.description,\n inputSchema: webSearchInputSchema(core.limit),\n async execute(input, { abortSignal }) {\n const run = await core.run(input, { signal: abortSignal });\n if (!run.ok) throw toolFailure(run);\n return run.output;\n },\n toModelOutput: ({ output }) => ({\n type: \"text\",\n value: core.render(output)\n })\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,SAAgB,cAAc,SAA8C;CAC1E,MAAM,OAAO,wBAAwB,OAAO;CAC5C,OAAO;EACL,aAAa,KAAK;EAClB,aAAa,qBAAqB,KAAK,KAAK;EAC5C,MAAM,QAAQ,OAAO,EAAE,eAAe;GACpC,MAAM,MAAM,MAAM,KAAK,IAAI,OAAO,EAAE,QAAQ,YAAY,CAAC;GACzD,IAAI,CAAC,IAAI,IAAI,MAAM,YAAY,GAAG;GAClC,OAAO,IAAI;EACb;EACA,gBAAgB,EAAE,cAAc;GAC9B,MAAM;GACN,OAAO,KAAK,OAAO,MAAM;EAC3B;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"pi.js","names":[],"sources":["../../../src/websearch/tools/pi.ts"],"sourcesContent":["/**\n * `agents/websearch/pi` — the `web_search` tool for the pi harness.\n *\n * @beta\n */\nimport { Type } from \"@earendil-works/pi-ai\";\nimport type { ToolRegistration } from \"@earendil-works/pi-durable\";\nimport {\n MAX_WEB_SEARCH_QUERY_LENGTH,\n type WebSearchToolOutput\n} from \"../contract\";\nimport type { WebSearchErrorCode } from \"../source\";\nimport { createWebSearchToolCore, type WebSearchToolOptions } from \"../tool\";\n\nexport type {\n WebSearchResponse,\n WebSearchResult,\n WebSearchToolInput,\n WebSearchToolOutput\n} from \"../contract\";\nexport {\n WebSearchError,\n type WebSearchErrorCode,\n type WebSearchProvider,\n type WebSearchSource\n} from \"../source\";\nexport type { WebSearchToolOptions } from \"../tool\";\n\n/**\n * The model's input schema. The description tells the model the host's\n * `limit`; a larger value is not rejected (which would cost a validation\n * round trip) but capped by the core. pi already coerces `\"5\"` to `5`.\n */\nfunction webSearchParameters(maxLimit: number) {\n return Type.Object({\n query: Type.String({\n minLength: 1,\n maxLength: MAX_WEB_SEARCH_QUERY_LENGTH,\n description: \"What to search for.\"\n }),\n limit: Type.Optional(\n Type.Integer({\n minimum: 1,\n description: `How many results to return (at most ${maxLimit}).`\n })\n )\n });\n}\n\ntype WebSearchParameters = ReturnType<typeof webSearchParameters>;\n\n/**\n * Host-side details pi stores with each `web_search` result: the full API\n * response (untrimmed descriptions, provider metadata) or the failure.\n */\nexport type WebSearchToolDetails =\n | { ok: true; output: WebSearchToolOutput }\n | {\n ok: false;\n /** The source's error message, with the API's detail. */\n message: string;\n status: number;\n code: WebSearchErrorCode;\n retryable: boolean;\n requestId?: string;\n };\n\n/**\n * Create a pi tool that searches the web through Cloudflare's Web Search\n * API. Install it on a registry like any other pi tool.\n *\n * The model chooses the query and (within the host's `limit`) how many\n * results; the host chooses the gateway, provider, and billing. The tool is\n * `replay: \"safe\"`: a search interrupted mid-call (say, by an eviction) runs\n * again when the session recovers, which is a second billed search.\n * Completed results are stored and not searched again.\n *\n * @example\n * ```ts\n * import { createRegistry } from \"@earendil-works/pi-durable\";\n * import { webSearchTool } from \"agents/websearch/pi\";\n *\n * const registry = createRegistry();\n * registry.install({\n * name: \"tools\",\n * tools: [webSearchTool({ binding: env.AI, provider: \"exa\" })]\n * });\n * ```\n */\nexport function webSearchTool(\n options: WebSearchToolOptions\n): ToolRegistration<WebSearchParameters, WebSearchToolDetails> {\n const core = createWebSearchToolCore(options);\n return {\n name: core.name,\n description: core.description,\n parameters: webSearchParameters(core.limit),\n replay: \"safe\",\n async execute(input, _api, context) {\n const run = await core.run(input, { signal: context.abortSignal });\n if (run.ok) {\n return {\n content: [{ type: \"text\", text: run.text }],\n details: { ok: true, output: run.output }\n };\n }\n return {\n content: [{ type: \"text\", text: run.text }],\n isError: true,\n details: {\n ok: false,\n message: run.error.message,\n status: run.error.status,\n code: run.error.code,\n retryable: run.error.retryable,\n requestId: run.error.requestId\n }\n };\n }\n };\n}\n"],"mappings":";;;;;;;;;;;;;AAiCA,SAAS,oBAAoB,UAAkB;CAC7C,OAAO,KAAK,OAAO;EACjB,OAAO,KAAK,OAAO;GACjB,WAAW;GACX,WAAW;GACX,aAAa;EACf,CAAC;EACD,OAAO,KAAK,SACV,KAAK,QAAQ;GACX,SAAS;GACT,aAAa,uCAAuC,SAAS;EAC/D,CAAC,CACH;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,cACd,SAC6D;CAC7D,MAAM,OAAO,wBAAwB,OAAO;CAC5C,OAAO;EACL,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,YAAY,oBAAoB,KAAK,KAAK;EAC1C,QAAQ;EACR,MAAM,QAAQ,OAAO,MAAM,SAAS;GAClC,MAAM,MAAM,MAAM,KAAK,IAAI,OAAO,EAAE,QAAQ,QAAQ,YAAY,CAAC;GACjE,IAAI,IAAI,IACN,OAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,IAAI;IAAK,CAAC;IAC1C,SAAS;KAAE,IAAI;KAAM,QAAQ,IAAI;IAAO;GAC1C;GAEF,OAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,IAAI;IAAK,CAAC;IAC1C,SAAS;IACT,SAAS;KACP,IAAI;KACJ,SAAS,IAAI,MAAM;KACnB,QAAQ,IAAI,MAAM;KAClB,MAAM,IAAI,MAAM;KAChB,WAAW,IAAI,MAAM;KACrB,WAAW,IAAI,MAAM;IACvB;GACF;EACF;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tanstack-ai.js","names":[],"sources":["../../../src/websearch/tools/tanstack-ai.ts"],"sourcesContent":["/**\n * `agents/websearch/tanstack-ai` — the `web_search` tool for TanStack AI.\n *\n * @beta\n */\nimport { toolDefinition } from \"@tanstack/ai\";\nimport type { WEB_SEARCH_TOOL_NAME } from \"../contract\";\nimport {\n createWebSearchToolCore,\n toolFailure,\n type WebSearchToolOptions\n} from \"../tool\";\nimport { webSearchInputSchema } from \"./input-schema\";\n\nexport type {\n WebSearchResponse,\n WebSearchResult,\n WebSearchToolInput,\n WebSearchToolOutput\n} from \"../contract\";\nexport {\n WebSearchError,\n type WebSearchErrorCode,\n type WebSearchProvider,\n type WebSearchSource\n} from \"../source\";\nexport type { WebSearchToolOptions } from \"../tool\";\n\nexport type TanStackWebSearchToolOptions<\n TName extends string = typeof WEB_SEARCH_TOOL_NAME\n> = WebSearchToolOptions & {\n /** The tool's name. TanStack AI tools carry it in the definition. */\n name?: TName;\n};\n\n/**\n * Create a TanStack AI tool that searches the web through Cloudflare's Web\n * Search API. TanStack AI has one return channel, so the model and the host\n * both get the trimmed text rendering. A failed search throws a\n * `WebSearchError`, which TanStack AI reports as an error result: its\n * `message` is written for the model, and its `cause` is the source's error\n * with the API's detail. The tool is named `web_search` unless you pass\n * `name`.\n *\n * @example\n * ```ts\n * import { webSearchTool } from \"agents/websearch/tanstack-ai\";\n * import { chat } from \"@tanstack/ai\";\n *\n * const stream = chat({\n * adapter,\n * tools: [webSearchTool({ binding: env.AI })],\n * messages\n * });\n * ```\n */\nexport function webSearchTool<\n TName extends string = typeof WEB_SEARCH_TOOL_NAME\n>(options: TanStackWebSearchToolOptions<TName>) {\n const core = createWebSearchToolCore(options);\n return toolDefinition({\n name: options.name ?? (core.name as TName),\n description: core.description,\n inputSchema: webSearchInputSchema(core.limit)\n }).server(async (input, context) => {\n const run = await core.run(input, { signal: context?.abortSignal });\n if (!run.ok) throw toolFailure(run);\n return run.text;\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,SAAgB,cAEd,SAA8C;CAC9C,MAAM,OAAO,wBAAwB,OAAO;CAC5C,OAAO,eAAe;EACpB,MAAM,QAAQ,QAAS,KAAK;EAC5B,aAAa,KAAK;EAClB,aAAa,qBAAqB,KAAK,KAAK;CAC9C,CAAC,CAAC,CAAC,OAAO,OAAO,OAAO,YAAY;EAClC,MAAM,MAAM,MAAM,KAAK,IAAI,OAAO,EAAE,QAAQ,SAAS,YAAY,CAAC;EAClE,IAAI,CAAC,IAAI,IAAI,MAAM,YAAY,GAAG;EAClC,OAAO,IAAI;CACb,CAAC;AACH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"websockets-CmENGb-Z.js","names":["RpcTarget","RpcTarget"],"sources":["../src/websockets/connection-flags.ts","../src/websockets/connection.ts","../src/websockets/callables-target.ts","../src/websockets/transport.ts","../src/websockets/websockets.ts"],"sourcesContent":["import type { Connection } from \"../lifecycle\";\n\n/**\n * Internal per-connection flags, stored inside the connection's own state\n * under `_cf_`-prefixed keys so they ride the hibernation attachment (or a\n * bridged connection's synced state) and survive a wake. The state wrapper\n * installed by {@link ensureConnectionWrapped} hides them from\n * `connection.state` and preserves them across user `setState` calls.\n *\n * Owned by the WebSockets capability; `Agent` and framework mixins reach it\n * through the capability or, for their own keys, through\n * {@link registerInternalConnectionKeys}.\n */\n\n/** A readonly connection may not update host state. */\nexport const CF_READONLY_KEY = \"_cf_readonly\";\n\n/**\n * A no-protocol connection receives no protocol text frames (identity,\n * state sync, MCP servers) — neither on connect nor via broadcasts.\n */\nexport const CF_NO_PROTOCOL_KEY = \"_cf_no_protocol\";\n\nconst internalKeys = new Set<string>([CF_READONLY_KEY, CF_NO_PROTOCOL_KEY]);\n\n/**\n * Register additional `_cf_`-prefixed keys a host or mixin stores in\n * connection state, so they are hidden from `connection.state` and kept\n * across user `setState` calls like the capability's own flags.\n */\nexport function registerInternalConnectionKeys(...keys: string[]): void {\n for (const key of keys) internalKeys.add(key);\n}\n\nfunction rawHasInternalKeys(raw: Record<string, unknown>): boolean {\n for (const key of Object.keys(raw)) {\n if (internalKeys.has(key)) return true;\n }\n return false;\n}\n\n/** A copy of `raw` without internal keys, or null when no user keys remain. */\nfunction stripInternalKeys(\n raw: Record<string, unknown>\n): Record<string, unknown> | null {\n const result: Record<string, unknown> = {};\n let hasUserKeys = false;\n for (const key of Object.keys(raw)) {\n if (!internalKeys.has(key)) {\n result[key] = raw[key];\n hasUserKeys = true;\n }\n }\n return hasUserKeys ? result : null;\n}\n\n/** A copy containing only the internal keys present in `raw`. */\nfunction extractInternalFlags(\n raw: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(raw)) {\n if (internalKeys.has(key)) result[key] = raw[key];\n }\n return result;\n}\n\ntype RawAccessors = {\n getRaw: () => Record<string, unknown> | null;\n setRaw: (state: unknown) => unknown;\n};\n\n/**\n * Per-connection raw accessors, keyed by the live connection object. The\n * map is in-memory: after hibernation it is empty, and every entry point\n * re-wraps the connection on first use.\n */\nconst rawStateAccessors = new WeakMap<Connection, RawAccessors>();\n\n/**\n * Wrap `connection.state` / `connection.setState` so internal flags are\n * hidden from user code and preserved when user code sets state.\n * Idempotent, and safe to call after hibernation.\n */\nexport function ensureConnectionWrapped(connection: Connection): void {\n if (rawStateAccessors.has(connection)) return;\n\n // Hibernating connections expose attachment-backed state as a\n // configurable accessor. Virtual (bridged) connections use a data\n // property, so both projections are retained below.\n const descriptor = Object.getOwnPropertyDescriptor(connection, \"state\");\n\n let getRaw: RawAccessors[\"getRaw\"];\n let setRaw: RawAccessors[\"setRaw\"];\n\n if (descriptor?.get) {\n // Accessor property: bind the original getter. It reads the serialized\n // attachment, so it always returns the latest value after setState.\n getRaw = descriptor.get.bind(connection) as RawAccessors[\"getRaw\"];\n setRaw = connection.setState.bind(connection);\n } else {\n // Data property: track the raw value in a closure. Reading\n // `connection.state` after the override would hit the filtered getter.\n let rawState = (connection.state ?? null) as Record<string, unknown> | null;\n getRaw = () => rawState;\n setRaw = (state: unknown) => {\n rawState = state as Record<string, unknown> | null;\n return rawState;\n };\n }\n\n rawStateAccessors.set(connection, { getRaw, setRaw });\n\n Object.defineProperty(connection, \"state\", {\n configurable: true,\n enumerable: true,\n get() {\n const raw = getRaw();\n if (raw != null && typeof raw === \"object\" && rawHasInternalKeys(raw)) {\n return stripInternalKeys(raw);\n }\n return raw;\n }\n });\n\n Object.defineProperty(connection, \"setState\", {\n configurable: true,\n writable: true,\n value(stateOrFn: unknown | ((prev: unknown) => unknown)) {\n const raw = getRaw();\n const flags =\n raw != null && typeof raw === \"object\"\n ? extractInternalFlags(raw as Record<string, unknown>)\n : {};\n const hasFlags = Object.keys(flags).length > 0;\n\n let newUserState: unknown;\n if (typeof stateOrFn === \"function\") {\n // The callback sees only user-visible state.\n const userVisible = hasFlags\n ? stripInternalKeys(raw as Record<string, unknown>)\n : raw;\n newUserState = (stateOrFn as (prev: unknown) => unknown)(userVisible);\n } else {\n newUserState = stateOrFn;\n }\n\n if (hasFlags) {\n if (newUserState != null && typeof newUserState === \"object\") {\n return setRaw({\n ...(newUserState as Record<string, unknown>),\n ...flags\n });\n }\n // User set null: keep just the flags.\n return setRaw(flags);\n }\n return setRaw(newUserState);\n }\n });\n}\n\n/** The raw connection state, internal flags included. */\nexport function getConnectionRawState(\n connection: Connection\n): Record<string, unknown> | null {\n ensureConnectionWrapped(connection);\n return rawStateAccessors.get(connection)!.getRaw();\n}\n\n/** Read an internal flag from the raw connection state. */\nexport function getConnectionFlag(\n connection: Connection,\n key: string\n): unknown {\n ensureConnectionWrapped(connection);\n return rawStateAccessors.get(connection)!.getRaw()?.[key];\n}\n\n/**\n * Write an internal flag to the raw connection state. `undefined` removes\n * the key rather than storing a dead value; the last key removed leaves\n * `null`.\n */\nexport function setConnectionFlag(\n connection: Connection,\n key: string,\n value: unknown\n): void {\n ensureConnectionWrapped(connection);\n const accessors = rawStateAccessors.get(connection)!;\n const raw = accessors.getRaw() ?? {};\n if (value === undefined) {\n const { [key]: _, ...rest } = raw;\n accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);\n } else {\n accessors.setRaw({ ...raw, [key]: value });\n }\n}\n\nexport function isConnectionReadonly(connection: Connection): boolean {\n return !!getConnectionFlag(connection, CF_READONLY_KEY);\n}\n\nexport function setConnectionReadonly(\n connection: Connection,\n readonly: boolean\n): void {\n setConnectionFlag(connection, CF_READONLY_KEY, readonly ? true : undefined);\n}\n\nexport function isConnectionProtocolEnabled(connection: Connection): boolean {\n return !getConnectionFlag(connection, CF_NO_PROTOCOL_KEY);\n}\n\nexport function setConnectionProtocolEnabled(\n connection: Connection,\n enabled: boolean\n): void {\n setConnectionFlag(connection, CF_NO_PROTOCOL_KEY, enabled ? undefined : true);\n}\n","// Polyfill WebSocket status code constants for environments that don't have them\n// in order to support libraries that expect standards-compatible WebSocket\n// implementations (e.g. PartySocket)\n\nimport type {\n Connection,\n ConnectionSetStateFn,\n ConnectionState,\n LifecycleSockets\n} from \"../lifecycle\";\n\nif (!(\"OPEN\" in WebSocket)) {\n const WebSocketStatus = {\n // @ts-expect-error\n CONNECTING: WebSocket.READY_STATE_CONNECTING,\n // @ts-expect-error\n OPEN: WebSocket.READY_STATE_OPEN,\n // @ts-expect-error\n CLOSING: WebSocket.READY_STATE_CLOSING,\n // @ts-expect-error\n CLOSED: WebSocket.READY_STATE_CLOSED\n };\n\n Object.assign(WebSocket, WebSocketStatus);\n // @ts-expect-error\n Object.assign(WebSocket.prototype, WebSocketStatus);\n}\n\n/**\n * Store both platform attachments and user attachments in different namespaces\n */\ntype ConnectionAttachments = {\n __pk: {\n id: string;\n tags: string[];\n uri?: string;\n };\n __user?: unknown;\n};\n\nfunction tryGetManagedWebSocketMeta(\n ws: WebSocket\n): ConnectionAttachments[\"__pk\"] | null {\n try {\n // Avoid AttachmentCache.get() here: externally accepted sockets\n // can have an attachment without the managed __pk namespace.\n const attachment = WebSocket.prototype.deserializeAttachment.call(\n ws\n ) as unknown;\n if (!attachment || typeof attachment !== \"object\") {\n return null;\n }\n if (!(\"__pk\" in attachment)) {\n return null;\n }\n const pk = (attachment as ConnectionAttachments).__pk as unknown;\n if (!pk || typeof pk !== \"object\") {\n return null;\n }\n const { id, tags } = pk as {\n id?: unknown;\n tags?: unknown;\n };\n if (typeof id !== \"string\") {\n return null;\n }\n const { uri } = pk as { uri?: unknown };\n return {\n id,\n tags: Array.isArray(tags) ? tags : [],\n uri: typeof uri === \"string\" ? uri : undefined\n } satisfies ConnectionAttachments[\"__pk\"];\n } catch {\n return null;\n }\n}\n\nexport function isManagedWebSocket(ws: WebSocket): boolean {\n return tryGetManagedWebSocketMeta(ws) !== null;\n}\n\n/**\n * Cache websocket attachments to avoid having to rehydrate them on every property access.\n */\nclass AttachmentCache {\n #cache = new WeakMap<WebSocket, ConnectionAttachments>();\n\n get(ws: WebSocket): ConnectionAttachments {\n let attachment = this.#cache.get(ws);\n if (!attachment) {\n attachment = WebSocket.prototype.deserializeAttachment.call(\n ws\n ) as ConnectionAttachments;\n if (attachment !== undefined) {\n this.#cache.set(ws, attachment);\n } else {\n throw new Error(\"Missing managed WebSocket lifecycle attachment\");\n }\n }\n\n return attachment;\n }\n\n set(ws: WebSocket, attachment: ConnectionAttachments) {\n this.#cache.set(ws, attachment);\n WebSocket.prototype.serializeAttachment.call(ws, attachment);\n }\n}\n\nconst attachments = new AttachmentCache();\nconst connections = new WeakSet<Connection>();\nconst isWrapped = (ws: WebSocket): ws is Connection => {\n return connections.has(ws as Connection);\n};\n\n/**\n * Wraps a WebSocket with Connection fields that rehydrate the\n * socket attachments lazily only when requested.\n */\nexport const createConnection = (ws: WebSocket | Connection): Connection => {\n if (isWrapped(ws)) {\n return ws;\n }\n\n // if state was set on the socket before initializing the connection,\n // capture it here so we can persist it again\n let initialState;\n if (\"state\" in ws) {\n initialState = ws.state;\n delete ws.state;\n }\n\n const connection = Object.defineProperties(ws, {\n id: {\n configurable: true,\n get() {\n return attachments.get(ws).__pk.id;\n }\n },\n uri: {\n configurable: true,\n get() {\n return attachments.get(ws).__pk.uri ?? null;\n }\n },\n tags: {\n configurable: true,\n get() {\n // Default to [] for connections accepted before tags were stored\n return attachments.get(ws).__pk.tags ?? [];\n }\n },\n state: {\n configurable: true,\n get() {\n const attachment = attachments.get(ws);\n return (attachment.__user ?? null) as ConnectionState<unknown>;\n }\n },\n setState: {\n configurable: true,\n value: function setState<T>(setState: T | ConnectionSetStateFn<T>) {\n const state =\n setState instanceof Function\n ? setState((this as Connection<T>).state)\n : setState;\n attachments.set(ws, {\n ...attachments.get(ws),\n __user: state ?? null\n });\n return state as ConnectionState<T>;\n }\n }\n }) as Connection;\n\n if (initialState) {\n connection.setState(initialState);\n }\n\n connections.add(connection);\n return connection;\n};\n\nclass ConnectionIterator<T> implements IterableIterator<Connection<T>> {\n private index = 0;\n #sockets: WebSocket[] | undefined;\n constructor(\n private sockets: LifecycleSockets,\n private tag?: string\n ) {}\n\n [Symbol.iterator](): IterableIterator<Connection<T>> {\n return this;\n }\n\n next(): IteratorResult<Connection<T>, number | undefined> {\n const sockets =\n this.#sockets ?? (this.#sockets = this.sockets.get(this.tag));\n\n let socket: WebSocket;\n while ((socket = sockets[this.index++])) {\n // Only yield open sockets.\n if (socket.readyState === WebSocket.OPEN) {\n // Durable Objects hibernation APIs allow storing arbitrary sockets via\n // `state.acceptWebSocket()`. Ignore sockets without our attachment.\n if (!isManagedWebSocket(socket)) {\n continue;\n }\n const value = createConnection(socket) as Connection<T>;\n return { done: false, value };\n }\n }\n\n // reached the end of the iteratee\n return { done: true, value: undefined };\n }\n}\n\n/**\n * Deduplicate and validate connection tags.\n * Returns the final tag array (always includes the connection id as the first tag).\n */\nexport function prepareTags(\n connectionId: string,\n userTags: string[]\n): string[] {\n const tags = [connectionId, ...userTags.filter((t) => t !== connectionId)];\n\n // validate tags against documented restrictions\n // https://developers.cloudflare.com/durable-objects/api/hibernatable-websockets-api/#state-methods-for-websockets\n if (tags.length > 10) {\n throw new Error(\n \"A connection can only have 10 tags, including the default id tag.\"\n );\n }\n\n for (const tag of tags) {\n if (typeof tag !== \"string\") {\n throw new Error(`A connection tag must be a string. Received: ${tag}`);\n }\n if (tag === \"\") {\n throw new Error(\"A connection tag must not be an empty string.\");\n }\n if (tag.length > 256) {\n throw new Error(\"A connection tag must not exceed 256 characters\");\n }\n }\n\n return tags;\n}\n\n/** The platform-backed manager for hibernating WebSockets. */\nexport class ConnectionManager<TState = unknown> {\n constructor(private controller: LifecycleSockets) {}\n\n getConnection<T = TState>(id: string) {\n // TODO: Should we cache the connections?\n const sockets = this.controller.get(id);\n const matching = sockets.filter((ws) => {\n return tryGetManagedWebSocketMeta(ws)?.id === id;\n });\n\n if (matching.length === 0) return undefined;\n if (matching.length === 1)\n return createConnection(matching[0]) as Connection<T>;\n\n throw new Error(\n `More than one connection found for id ${id}. Did you mean to use getConnections(tag) instead?`\n );\n }\n\n getConnections<T = TState>(tag?: string | undefined) {\n return new ConnectionIterator<T>(this.controller, tag);\n }\n\n accept(connection: Connection, options: { tags: string[] }) {\n const tags = prepareTags(connection.id, options.tags);\n\n this.controller.accept(connection, tags);\n attachments.set(connection, {\n __pk: {\n id: connection.id,\n tags,\n uri: connection.uri ?? undefined\n },\n __user: null\n });\n\n return createConnection(connection);\n }\n}\n","import { RpcTarget } from \"cloudflare:workers\";\nimport { CAPNWEB_TRANSPORT_SEND } from \"./transport-protocol\";\n\n/** A named remote method ready to be exposed on a callables root. */\nexport type CallableInvoker = (...args: unknown[]) => unknown;\n\n/**\n * The single exposure policy for callable names. `Object.prototype` and\n * `RpcTarget.prototype` members are unreachable over Cap'n Web anyway\n * and are silently excluded; `then` is rejected loudly because exposing\n * it would make the remote stub thenable.\n */\nfunction assertExposable(name: string): boolean {\n if (name === \"then\") {\n throw new Error(\n 'A callables target cannot expose a method named \"then\" — it would make the remote stub thenable'\n );\n }\n if (name === CAPNWEB_TRANSPORT_SEND) {\n throw new Error(\n `A callables target cannot expose \"${CAPNWEB_TRANSPORT_SEND}\"; it is the transport's frame pipe`\n );\n }\n return !(\n name === \"constructor\" ||\n name in Object.prototype ||\n name in RpcTarget.prototype\n );\n}\n\n/**\n * The exposable prototype methods of a callables target, each bound to\n * invoke on the real instance (so private fields and `this` behave).\n *\n * Cap'n Web resolves methods on the prototype chain and rejects own\n * instance properties, so only prototype methods participate. The\n * nearest declaration wins for overridden names.\n *\n * @param target - The callables target to enumerate.\n * @returns Method names mapped to invokers on the target.\n */\nexport function exposableMethods(\n target: RpcTarget\n): ReadonlyMap<string, CallableInvoker> {\n const methods = new Map<string, CallableInvoker>();\n const seen = new Set<string>();\n let prototype: object | null = Object.getPrototypeOf(target);\n while (\n prototype &&\n prototype !== RpcTarget.prototype &&\n prototype !== Object.prototype\n ) {\n for (const name of Object.getOwnPropertyNames(prototype)) {\n if (seen.has(name)) continue;\n seen.add(name);\n if (!assertExposable(name)) continue;\n const descriptor = Object.getOwnPropertyDescriptor(prototype, name);\n if (!descriptor || typeof descriptor.value !== \"function\") continue;\n // SAFETY: `typeof descriptor.value === \"function\"` was checked\n // above; TypeScript cannot narrow a descriptor's `value` field.\n const method = descriptor.value as CallableInvoker;\n methods.set(name, (...args) => Reflect.apply(method, target, args));\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n return methods;\n}\n\n/**\n * Build a Cap'n Web session root exposing exactly the given methods.\n *\n * Cap'n Web resolves methods on the prototype chain, rejects own\n * instance properties, and breaks on Proxy-wrapped roots — so the root\n * is a private `RpcTarget` subclass whose prototype carries the methods\n * and nothing else.\n */\nexport function buildRoot(\n methods: ReadonlyMap<string, CallableInvoker>\n): RpcTarget {\n class Root extends RpcTarget {}\n for (const [name, invoke] of methods) {\n Object.defineProperty(Root.prototype, name, {\n value: invoke,\n writable: true,\n configurable: true,\n enumerable: false\n });\n }\n return new Root();\n}\n","import { newWebSocketRpcSession, type RpcStub } from \"capnweb\";\nimport type {\n Connection,\n ConnectionContext,\n ConnectionSetStateFn,\n ConnectionState\n} from \"../lifecycle\";\nimport { buildRoot, type CallableInvoker } from \"./callables-target\";\nimport { prepareTags } from \"./connection\";\nimport {\n CAPNWEB_TRANSPORT_SEND,\n type TransportClientEvents,\n type TransportMessage\n} from \"./transport-protocol\";\n\n/**\n * A non-hibernating connection with the public `Connection` contract,\n * backed by a Cap'n Web session instead of a hibernating socket. It lives\n * only in memory and disappears with the isolate.\n */\nclass CapnWebConnection extends EventTarget {\n readonly CONNECTING = WebSocket.CONNECTING;\n readonly OPEN = WebSocket.OPEN;\n readonly CLOSING = WebSocket.CLOSING;\n readonly CLOSED = WebSocket.CLOSED;\n readyState: number = WebSocket.OPEN;\n state: ConnectionState<unknown> = null;\n tags: readonly string[] = [];\n\n constructor(\n readonly id: string,\n readonly uri: string,\n private readonly pipe: {\n send(message: TransportMessage): void;\n close(code?: number, reason?: string): void;\n }\n ) {\n super();\n }\n\n send(message: TransportMessage): void {\n if (this.readyState !== WebSocket.OPEN) {\n throw new TypeError(\"WebSocket send() after close\");\n }\n this.pipe.send(message);\n }\n\n close(code?: number, reason?: string): void {\n if (this.readyState >= WebSocket.CLOSING) return;\n this.pipe.close(code, reason);\n this.readyState = WebSocket.CLOSING;\n }\n\n setState<T = unknown>(\n next: T | ConnectionSetStateFn<T> | null\n ): ConnectionState<T> {\n const state =\n typeof next === \"function\"\n ? (next as ConnectionSetStateFn<T>)(this.state as ConnectionState<T>)\n : next;\n this.state = state as ConnectionState<unknown>;\n return state as ConnectionState<T>;\n }\n}\n\n/** One live transport session. */\nexport type CapnWebSession = {\n readonly connection: Connection;\n /** Tear the session down; runs the close handler once. */\n dispose(): void;\n};\n\n/** What the capability supplies to run one session. */\nexport type CapnWebSessionOptions = {\n readonly request: Request;\n readonly connectionId: string;\n readonly tags: (\n connection: Connection,\n ctx: ConnectionContext\n ) => string[] | Promise<string[]>;\n readonly onConnect: (\n connection: Connection,\n ctx: ConnectionContext\n ) => Promise<void>;\n readonly onMessage: (\n connection: Connection,\n message: TransportMessage\n ) => Promise<void>;\n readonly onClose: (\n connection: Connection,\n code: number,\n reason: string,\n wasClean: boolean\n ) => Promise<void>;\n readonly onError: (connection: Connection, error: unknown) => Promise<void>;\n /**\n * Native methods served on the session root beside the frame pipe. Each\n * invoker already runs inside the host boundary for this connection.\n * Results pass by Cap'n Web semantics: an `RpcTarget` becomes a live\n * stub, a `ReadableStream` streams, and calls pipeline.\n */\n readonly callables: (\n connection: Connection\n ) => ReadonlyMap<string, CallableInvoker>;\n /**\n * Called once the connection exists, before `onConnect`, so it is already\n * visible in `getConnections()` while the connect handler runs — the same\n * ordering as a hibernating socket, which is accepted before `onConnect`.\n */\n readonly onOpen: (session: CapnWebSession) => void;\n /** Called exactly once when the session ends, before `onClose`. */\n readonly onDispose: (session: CapnWebSession) => void;\n};\n\n/**\n * Accept a Cap'n Web transport upgrade.\n *\n * The session root carries the frame pipe plus the host's native\n * callables. The client's protocol frames arrive through the pipe and are\n * handed to `onMessage`; the host's frames go out through the client's\n * `message` callback; `useAgent().stub` calls hit the callables directly.\n * The socket is a plain in-memory `WebSocketPair`, so it pins the Durable\n * Object and does not survive hibernation.\n */\nexport async function openCapnWebSession(\n options: CapnWebSessionOptions\n): Promise<{ response: Response; session: CapnWebSession }> {\n const { request, connectionId } = options;\n const pair = new WebSocketPair();\n const server = pair[0];\n server.accept();\n\n let client: RpcStub<TransportClientEvents> | undefined;\n let closed = false;\n let close = { code: 1000, reason: \"\", wasClean: true };\n\n const connection = new CapnWebConnection(connectionId, request.url, {\n send: (message) => {\n void client?.message(message).catch((error: unknown) => {\n if (!closed) console.error(\"Cap'n Web frame delivery failed:\", error);\n });\n },\n close: (code = 1000, reason = \"\") => {\n // Same contract as WebSocket.close(): a reserved code or an oversize\n // reason throws before anything changes, and the socket stays open\n // and tracked. Only a started handshake finishes the session.\n server.close(code, reason);\n close = { code, reason, wasClean: true };\n void finish();\n }\n }) as unknown as Connection & CapnWebConnection;\n\n const session: CapnWebSession = {\n connection,\n dispose: () => connection.close(1001, \"Session replaced\")\n };\n\n const finish = async () => {\n if (closed) return;\n closed = true;\n connection.readyState = WebSocket.CLOSED;\n try {\n client?.[Symbol.dispose]();\n } catch {\n // The session already ended with the socket.\n }\n options.onDispose(session);\n await options.onClose(connection, close.code, close.reason, close.wasClean);\n };\n\n const rootMethods = new Map<string, CallableInvoker>(\n options.callables(connection)\n );\n rootMethods.set(CAPNWEB_TRANSPORT_SEND, (message) =>\n options.onMessage(connection, message as TransportMessage)\n );\n client = newWebSocketRpcSession<TransportClientEvents>(\n server,\n buildRoot(rootMethods)\n );\n\n server.addEventListener(\n \"close\",\n (event) => {\n close = {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean\n };\n void finish();\n },\n { once: true }\n );\n server.addEventListener(\n \"error\",\n (event) => {\n if (closed) return;\n close = { ...close, wasClean: false };\n const error =\n event instanceof ErrorEvent\n ? (event.error ?? new Error(event.message))\n : new Error(\"Cap'n Web transport socket error\");\n void options\n .onError(connection, error)\n .catch((handlerError: unknown) => {\n console.error(\"Cap'n Web onError handler failed:\", handlerError);\n })\n .finally(finish);\n },\n { once: true }\n );\n\n const ctx = { request };\n // Same limits as the hibernating wire (count, emptiness, length), so a\n // handler sees one tag policy whichever transport the client chose.\n connection.tags = prepareTags(\n connectionId,\n await options.tags(connection, ctx)\n );\n options.onOpen(session);\n try {\n await options.onConnect(connection, ctx);\n } catch (error) {\n connection.close(1011, \"onConnect failed\");\n throw error;\n }\n\n return {\n response: new Response(null, { status: 101, webSocket: pair[1] }),\n session\n };\n}\n","import { RpcTarget } from \"cloudflare:workers\";\nimport { nanoid } from \"nanoid\";\nimport {\n LifecycleCapability,\n type CapabilityWebSocketUpgradeContext,\n type Connection,\n type ConnectionContext,\n type ConnectionSetStateFn,\n type ConnectionState\n} from \"../lifecycle\";\nimport { MessageType } from \"../types\";\nimport { camelCaseToKebabCase } from \"../utils\";\nimport {\n ConnectionManager,\n createConnection,\n isManagedWebSocket\n} from \"./connection\";\nimport {\n ensureConnectionWrapped,\n isConnectionProtocolEnabled,\n isConnectionReadonly,\n setConnectionProtocolEnabled,\n setConnectionReadonly\n} from \"./connection-flags\";\nimport { exposableMethods, type CallableInvoker } from \"./callables-target\";\nimport type {\n SyncedState,\n WebSocketHandlers,\n WebSocketMessage,\n WebSocketsOptions\n} from \"./options\";\nimport { openCapnWebSession, type CapnWebSession } from \"./transport\";\nimport { isCapnWebTransportUpgrade } from \"./transport-protocol\";\n\n/**\n * Reserved close codes the runtime synthesizes when there was no real\n * Close frame from the peer (1005 NoStatusReceived, 1006 AbnormalClosure,\n * 1015 TLSHandshake). They cannot appear in an outgoing Close frame, and\n * there is no peer left to receive a reciprocation.\n */\nfunction isReservedCloseCode(code: number): boolean {\n return code === 1005 || code === 1006 || code === 1015;\n}\n\n/**\n * Reciprocate a peer-initiated Close frame to complete the handshake, as\n * the Hibernation API contract requires. Best-effort: swallows errors\n * from already-closed sockets or invalid codes/reasons, and skips\n * reciprocation entirely for reserved codes (dead transport).\n */\nfunction reciprocateClose(ws: WebSocket, code: number, reason: string): void {\n if (isReservedCloseCode(code)) return;\n try {\n ws.close(code, reason);\n } catch {\n // Already closed, oversize reason, or another unrecoverable\n // invariant — the handshake is either done or out of our control.\n }\n}\n\n/** The `rpc` request frame `useAgent().call` and `AgentClient.call` send. */\ntype RpcRequest = {\n readonly type: \"rpc\";\n readonly id: string;\n readonly method: string;\n readonly args: unknown[];\n};\n\ntype RpcResponse =\n | { type: \"rpc\"; id: string; success: true; done: boolean; result: unknown }\n | { type: \"rpc\"; id: string; success: false; error: string };\n\n/** The `cf_agent_state` frame a client sends to update host state. */\ntype StateFrame = { readonly type: \"cf_agent_state\"; readonly state: unknown };\n\nfunction isStateFrame(value: unknown): value is StateFrame {\n if (typeof value !== \"object\" || value === null) return false;\n const frame = value as Record<string, unknown>;\n return frame.type === MessageType.CF_AGENT_STATE && \"state\" in frame;\n}\n\n/** Parse a text frame; anything that is not JSON is `undefined`. */\nfunction parseJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\nfunction isRpcRequest(value: unknown): value is RpcRequest {\n if (typeof value !== \"object\" || value === null) return false;\n const frame = value as Record<string, unknown>;\n return (\n frame.type === MessageType.RPC &&\n typeof frame.id === \"string\" &&\n typeof frame.method === \"string\" &&\n Array.isArray(frame.args)\n );\n}\n\n/**\n * Opt-in WebSocket support for Lifecycle Objects.\n *\n * Lifecycle itself does not model WebSockets — hosts that want them\n * install this capability, which owns the connection subsystem end to\n * end: it claims upgrades, dispatches `onConnect`/`onMessage`/`onClose`\n * inside the host invocation boundary, reciprocates close handshakes,\n * and answers `getConnections()`/`getConnection()`.\n *\n * ```ts\n * class Room extends DurableObject<Env> {\n * readonly webSockets = new WebSockets({\n * handlers: {\n * onConnect: (connection) => connection.send(\"welcome\"),\n * onMessage: (connection, message) => { ... }\n * },\n * callables: new RoomCallables()\n * });\n * readonly lifecycle = Lifecycle.install(this).use(this.webSockets);\n * }\n * ```\n *\n * Connections arrive on one of two wires, chosen by the client:\n *\n * - **cf-websocket** (default): accepted with the Hibernation API. Idle\n * clients stay connected while the Durable Object leaves memory.\n * - **capnweb** (`?__agents_transport=capnweb`): protocol frames through\n * one pipe method on a Cap'n Web session whose root also carries the\n * host's callables natively. Non-hibernating — the object stays pinned\n * while the connection is open.\n *\n * Both wires dispatch the same handlers and appear in `getConnections()`.\n * On both, the capability speaks the Agent protocol a plain host needs\n * for `useAgent` and `AgentClient`: it sends the identity frame on\n * connect, and it serves `callables` — as `rpc` JSON frames on the\n * WebSocket wire, and natively on the Cap'n Web session root, where an\n * `RpcTarget` result becomes a live stub and calls pipeline. `call()`\n * and `stub` work against a plain Durable Object exactly as against an\n * `Agent`. Pass a `State` capability as `state` and the hook's\n * `state`/`setState` work too: the current value is pushed on connect\n * and client updates are validated and applied; the state owner\n * broadcasts changes with `broadcastState()`. Per-connection readonly\n * and no-protocol flags live here as well, for every host.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class WebSockets extends LifecycleCapability {\n /** Claims every upgrade, so Lifecycle dispatches it after all others. */\n override readonly claims = \"catch-all\";\n\n readonly #handlers: WebSocketHandlers | undefined;\n /** Handlers added with `use`, run before the configured ones. */\n readonly #added: WebSocketHandlers[] = [];\n readonly #getConnectionTags: WebSocketsOptions[\"getConnectionTags\"];\n readonly #protocol: WebSocketsOptions[\"protocol\"];\n readonly #readonly: WebSocketsOptions[\"readonly\"];\n readonly #state: SyncedState | undefined;\n /**\n * Connections inside their connect sequence, before the state push.\n * `broadcastState()` skips them: reading state for the push can seed the\n * initial value, whose change broadcast would otherwise reach a\n * connection that is about to receive the same value directly.\n */\n readonly #connecting = new Set<Connection>();\n readonly #callables: ReadonlyMap<string, CallableInvoker>;\n readonly #sessions = new Map<string, CapnWebSession>();\n #manager: ConnectionManager | undefined;\n\n constructor(options: WebSocketsOptions = {}) {\n super(\"websockets\");\n this.#handlers = options.handlers;\n this.#getConnectionTags = options.getConnectionTags;\n this.#protocol = options.protocol ?? true;\n this.#readonly = options.readonly;\n this.#state = options.state;\n this.#callables = options.callables\n ? exposableMethods(options.callables)\n : new Map();\n }\n\n // ── Lifecycle capability hooks ─────────────────────────────────────────\n\n /**\n * Claim every upgrade, never declining: a Cap'n Web transport upgrade\n * becomes a session, everything else a tracked hibernating connection,\n * whether or not handlers or callables are configured. Handlers only add\n * behavior on connect, message, close, and error.\n */\n onWebSocketUpgrade({\n request\n }: CapabilityWebSocketUpgradeContext): Promise<Response> {\n return isCapnWebTransportUpgrade(request)\n ? this.#acceptCapnWebSession(request)\n : this.#acceptConnection(request);\n }\n\n /** Dispatch a platform message wake for a capability-owned socket. */\n async onWebSocketMessage(\n ws: WebSocket,\n message: WebSocketMessage\n ): Promise<boolean> {\n if (!isManagedWebSocket(ws)) return false;\n await this.#message(createConnection(ws), message);\n return true;\n }\n\n /** Dispatch and reciprocate a close wake for an owned socket. */\n async onWebSocketClose(\n ws: WebSocket,\n code: number,\n reason: string,\n wasClean: boolean\n ): Promise<boolean> {\n if (!isManagedWebSocket(ws)) return false;\n try {\n await this.#close(createConnection(ws), code, reason, wasClean);\n } finally {\n reciprocateClose(ws, code, reason);\n }\n return true;\n }\n\n /** Dispatch an error wake for an owned socket. */\n async onWebSocketError(ws: WebSocket, error: unknown): Promise<boolean> {\n if (!isManagedWebSocket(ws)) return false;\n await this.#error(createConnection(ws), error);\n return true;\n }\n\n /**\n * Close every owned connection during explicit host destruction. The\n * capability owns its sockets' lifetimes, so it also owns tearing\n * them down.\n */\n dispose(): void {\n for (const connection of this.getConnections()) {\n try {\n connection.close(1001, \"Durable Object destroyed\");\n } catch {\n // Already closed or mid-handshake — nothing left to tear down.\n }\n }\n }\n\n /**\n * Add handlers for another component sharing these connections, such as\n * a protocol of its own. They run before the configured handlers, and\n * their `onMessage` can claim a message by returning true.\n */\n use(handlers: WebSocketHandlers): void {\n this.#added.push(handlers);\n }\n\n // ── Connections ────────────────────────────────────────────────────────\n\n /** Open connections on either wire, optionally by tag. */\n *getConnections<TState = unknown>(\n tag?: string\n ): IterableIterator<Connection<TState>> {\n for (const { connection } of this.#sessions.values()) {\n if (connection.readyState !== WebSocket.OPEN) continue;\n if (!tag || connection.tags.includes(tag)) {\n yield connection as Connection<TState>;\n }\n }\n yield* this.#connectionManager.getConnections<TState>(tag);\n }\n\n /** One connection on either wire, by id. */\n getConnection<TState = unknown>(id: string): Connection<TState> | undefined {\n const session = this.#sessions.get(id)?.connection;\n if (session && session.readyState === WebSocket.OPEN) {\n return session as Connection<TState>;\n }\n return this.#connectionManager.getConnection<TState>(id);\n }\n\n get #connectionManager(): ConnectionManager {\n this.#manager ??= new ConnectionManager(this.lifecycle.sockets);\n return this.#manager;\n }\n\n // ── Wire-independent protocol ──────────────────────────────────────────\n\n async #connect(\n connection: Connection,\n ctx: ConnectionContext\n ): Promise<void> {\n ensureConnectionWrapped(connection);\n // Flags first, so they are set before the client can respond.\n if (this.#readonly?.(connection, ctx)) {\n setConnectionReadonly(connection, true);\n }\n if (this.#protocol !== false) {\n const enabled =\n typeof this.#protocol === \"function\"\n ? this.#protocol(connection, ctx)\n : true;\n if (enabled) {\n this.sendConnectFrames(connection);\n } else {\n setConnectionProtocolEnabled(connection, false);\n }\n }\n for (const handlers of [...this.#added, this.#handlers]) {\n await this.lifecycle.runInHostContext(\n () => handlers?.onConnect?.(connection, ctx),\n { connection, request: ctx.request }\n );\n }\n }\n\n async #message(\n connection: Connection,\n message: WebSocketMessage\n ): Promise<void> {\n if (\n this.#state &&\n this.#protocol !== false &&\n typeof message === \"string\"\n ) {\n const frame = parseJson(message);\n if (isStateFrame(frame)) {\n // Inside the host boundary, so the host's validator and change\n // hook see the sending connection through the ambient context.\n await this.lifecycle.runInHostContext(\n () => this.applyStateFrame(connection, frame),\n { connection }\n );\n return;\n }\n }\n if (\n this.#callables.size > 0 &&\n (await this.#answerRpc(connection, message))\n ) {\n return;\n }\n for (const handlers of this.#added) {\n const claimed = await this.lifecycle.runInHostContext(\n () => handlers.onMessage?.(connection, message),\n { connection }\n );\n if (claimed === true) return;\n }\n await this.lifecycle.runInHostContext(\n () => this.#handlers?.onMessage?.(connection, message),\n { connection }\n );\n }\n\n #close(\n connection: Connection,\n code: number,\n reason: string,\n wasClean: boolean\n ): Promise<unknown> {\n return this.#each((handlers) =>\n this.lifecycle.runInHostContext(\n () => handlers?.onClose?.(connection, code, reason, wasClean),\n { connection }\n )\n );\n }\n\n #error(connection: Connection, error: unknown): Promise<unknown> {\n return this.#each((handlers) =>\n this.lifecycle.runInHostContext(\n () => handlers?.onError?.(connection, error),\n { connection }\n )\n );\n }\n\n async #each(\n run: (handlers: WebSocketHandlers | undefined) => Promise<unknown>\n ): Promise<void> {\n for (const handlers of [...this.#added, this.#handlers])\n await run(handlers);\n }\n\n // ── Hibernating wire ───────────────────────────────────────────────────\n\n async #acceptConnection(request: Request): Promise<Response> {\n const { 0: clientWebSocket, 1: serverWebSocket } = new WebSocketPair();\n const url = new URL(request.url);\n // `||`, not `??`: an empty `?_pk=` value must fall back to a\n // generated id — an empty connection id would later throw in tag\n // validation and reject the upgrade.\n const connectionId = url.searchParams.get(\"_pk\") || nanoid();\n\n let connection: Connection = Object.assign(serverWebSocket, {\n id: connectionId,\n uri: request.url,\n tags: [] as string[],\n state: null as unknown as ConnectionState<unknown>,\n setState<T = unknown>(setState: T | ConnectionSetStateFn<T>) {\n // Pre-accept shim: hold state on the socket until accept()\n // persists it into the hibernation attachment.\n const state =\n setState instanceof Function\n ? setState(this.state as ConnectionState<T>)\n : setState;\n this.state = state as ConnectionState<T>;\n return this.state as ConnectionState<T>;\n }\n });\n\n const ctx = { request };\n const tags = this.#getConnectionTags\n ? await this.#getConnectionTags(connection, ctx)\n : [];\n\n // Hibernating WebSockets remain connected while the object is evicted.\n connection = this.#connectionManager.accept(connection, { tags });\n await this.#connect(connection, ctx);\n\n return new Response(null, { status: 101, webSocket: clientWebSocket });\n }\n\n // ── Cap'n Web wire ─────────────────────────────────────────────────────\n\n async #acceptCapnWebSession(request: Request): Promise<Response> {\n const connectionId =\n new URL(request.url).searchParams.get(\"_pk\") || nanoid();\n // A reconnect reusing the id replaces the previous session.\n this.#sessions.get(connectionId)?.dispose();\n\n const { response } = await openCapnWebSession({\n request,\n connectionId,\n tags: (connection, ctx) =>\n this.#getConnectionTags?.(connection, ctx) ?? [],\n onConnect: (connection, ctx) => this.#connect(connection, ctx),\n onMessage: (connection, message) => this.#message(connection, message),\n onClose: (connection, code, reason, wasClean) =>\n this.#close(connection, code, reason, wasClean).then(() => undefined),\n onError: (connection, error) =>\n this.#error(connection, error).then(() => undefined),\n callables: (connection) => this.#nativeCallables(connection),\n onOpen: (session) => this.#sessions.set(connectionId, session),\n onDispose: (ended) => {\n if (this.#sessions.get(connectionId) === ended) {\n this.#sessions.delete(connectionId);\n }\n }\n });\n return response;\n }\n\n // ── Protocol frames ────────────────────────────────────────────────────\n //\n // The Agent protocol a client (`useAgent`, `AgentClient`) speaks, owned\n // here for every host. With `protocol: true` the capability drives the\n // connect sequence and consumes state frames itself; with\n // `protocol: false` the host calls these at the moments it chooses.\n\n /**\n * Send the connect sequence: the identity frame, then the current state\n * when one is stored. The identity carries `stateFollows` in that case,\n * so clients resolve `ready` only once the state has landed. Nothing is\n * sent to a no-protocol connection. Identity defaults as for\n * `sendIdentity()`.\n */\n sendConnectFrames(\n connection: Connection,\n identity: { name: string; agent: string } = this.#defaultIdentity()\n ): void {\n if (!isConnectionProtocolEnabled(connection)) return;\n this.#connecting.add(connection);\n try {\n const current = this.#state?.get();\n // Serialized first: a flagged identity must never go out without\n // the state frame the client will wait for.\n const stateFrame =\n current === undefined\n ? undefined\n : JSON.stringify({\n type: MessageType.CF_AGENT_STATE,\n state: current\n });\n this.#sendFrame(connection, {\n type: MessageType.CF_AGENT_IDENTITY,\n name: identity.name,\n agent: identity.agent,\n ...(stateFrame !== undefined && { stateFollows: true })\n });\n if (stateFrame !== undefined) this.#send(connection, stateFrame);\n } finally {\n this.#connecting.delete(connection);\n }\n }\n\n /**\n * Send the identity frame alone, unless the connection is no-protocol.\n * Clients resolve `ready` on it, so a host that also pushes state on\n * connect should use `sendConnectFrames()`. The defaults are the Durable\n * Object's routed name and host class; a host whose public identity\n * differs — an `Agent` facet, whose routed name is an internal encoding\n * of its logical name — passes its own.\n */\n sendIdentity(\n connection: Connection,\n identity: { name: string; agent: string } = this.#defaultIdentity()\n ): void {\n if (!isConnectionProtocolEnabled(connection)) return;\n this.#sendFrame(connection, {\n type: MessageType.CF_AGENT_IDENTITY,\n name: identity.name,\n agent: identity.agent\n });\n }\n\n #defaultIdentity(): { name: string; agent: string } {\n return {\n name: this.lifecycle.name,\n agent: camelCaseToKebabCase(this.lifecycle.className)\n };\n }\n\n /**\n * Send the current state to one connection, unless nothing is stored\n * or the connection is no-protocol. Reading the state may seed the\n * initial value; see `#connecting`.\n */\n sendState(connection: Connection): void {\n if (!this.#state || !isConnectionProtocolEnabled(connection)) return;\n const current = this.#state.get();\n if (current === undefined) return;\n this.#sendFrame(connection, {\n type: MessageType.CF_AGENT_STATE,\n state: current\n });\n }\n\n /**\n * Apply a parsed `cf_agent_state` frame from a client. A readonly\n * connection is refused; a change the host's validator rejects is\n * logged in full server-side and answered with a generic\n * `cf_agent_state_error`. Broadcasting the accepted change is the state\n * owner's call, through its `onChanged` hook. Callers that drive the\n * protocol themselves call this inside their own invocation context;\n * the capability's automatic path does so via `runInHostContext`.\n *\n * @returns Whether the frame was a state frame (handled either way).\n */\n applyStateFrame(connection: Connection, frame: unknown): boolean {\n if (!this.#state || !isStateFrame(frame)) return false;\n if (isConnectionReadonly(connection)) {\n this.#sendFrame(connection, {\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"Connection is readonly\"\n });\n return true;\n }\n try {\n // `never` on the port keeps any `State<T>` assignable; the value\n // came off the wire, so the host's validator is what checks it.\n this.#state.set(frame.state as never, connection);\n } catch (error) {\n console.error(\"[WebSockets] State update rejected:\", error);\n this.#sendFrame(connection, {\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"State update rejected\"\n });\n }\n return true;\n }\n\n /**\n * Push the current state to every protocol-enabled connection except\n * the one a change came from, which already has the value it sent.\n * Wire a `State`'s `onChanged` to this.\n */\n broadcastState(except?: Connection | \"server\"): void {\n if (!this.#state) return;\n const current = this.#state.get();\n if (current === undefined) return;\n const frame = { type: MessageType.CF_AGENT_STATE, state: current };\n for (const connection of this.getConnections()) {\n // Object identity, not id: `_pk` is client-supplied, so two live\n // sockets can share an id, and excluding by id would starve the\n // other one. `createConnection` returns one wrapper per socket.\n if (connection === except) continue;\n if (this.#connecting.has(connection)) continue;\n if (!isConnectionProtocolEnabled(connection)) continue;\n this.#sendFrame(connection, frame);\n }\n }\n\n // ── Connection flags ───────────────────────────────────────────────────\n\n /** Whether the connection may update host state over the wire. */\n isReadonly(connection: Connection): boolean {\n return isConnectionReadonly(connection);\n }\n\n /** Mark a connection readonly, or writable again. */\n setReadonly(connection: Connection, readonly = true): void {\n setConnectionReadonly(connection, readonly);\n }\n\n /** Whether protocol text frames reach the connection. */\n isProtocolEnabled(connection: Connection): boolean {\n return isConnectionProtocolEnabled(connection);\n }\n\n /** Enable or suppress protocol text frames for a connection. */\n setProtocolEnabled(connection: Connection, enabled: boolean): void {\n setConnectionProtocolEnabled(connection, enabled);\n }\n\n /**\n * Send one protocol frame. Serialization is the caller's contract — every\n * frame built here is plain JSON — while a send failure is tolerated: the\n * peer may have disconnected between the wake and the send.\n */\n #sendFrame(connection: Connection, frame: Record<string, unknown>): void {\n this.#send(connection, JSON.stringify(frame));\n }\n\n /** Write one already-serialized frame, tolerating a closed peer. */\n #send(connection: Connection, text: string): void {\n try {\n connection.send(text);\n } catch {\n // The socket closed between the wake and the send.\n }\n }\n\n // ── Callables ──────────────────────────────────────────────────────────\n\n /**\n * The `callables` target as native Cap'n Web methods for one session:\n * every method dispatches through the host boundary with this\n * connection in scope and emits `rpc`/`rpc:error` events. Return values\n * keep Cap'n Web semantics — an `RpcTarget` comes back as a live stub.\n */\n #nativeCallables(\n connection: Connection\n ): ReadonlyMap<string, CallableInvoker> {\n const methods = new Map<string, CallableInvoker>();\n for (const [name, invoke] of this.#callables) {\n methods.set(name, (...args) =>\n this.#dispatchCallable(name, () => invoke(...args), connection)\n );\n }\n return methods;\n }\n\n /**\n * Answer one `rpc` frame against `callables`. A `ReadableStream`\n * result streams as `done: false` chunks followed by a final\n * `done: true` frame, matching the client's stream callbacks.\n *\n * @returns Whether the message was an `rpc` frame (answered or not).\n */\n async #answerRpc(\n connection: Connection,\n raw: WebSocketMessage\n ): Promise<boolean> {\n if (typeof raw !== \"string\") return false;\n let frame: unknown;\n try {\n frame = JSON.parse(raw);\n } catch {\n return false;\n }\n if (!isRpcRequest(frame)) return false;\n const { id, method, args } = frame;\n\n const invoke = this.#callables.get(method);\n if (!invoke) {\n this.#reply(connection, {\n type: \"rpc\",\n id,\n success: false,\n error: `Method ${method} does not exist`\n });\n return true;\n }\n\n try {\n const result = await this.#dispatchCallable(\n method,\n () => invoke(...args),\n connection\n );\n if (result instanceof RpcTarget) {\n // By-reference results only exist on the Cap'n Web wire; a JSON\n // frame would silently flatten the target to `{}`.\n throw new Error(\n `Method ${method} returns an RpcTarget, which only the capnweb transport can carry`\n );\n }\n if (result instanceof ReadableStream) {\n for await (const chunk of result) {\n this.#reply(connection, {\n type: \"rpc\",\n id,\n success: true,\n done: false,\n result: chunk\n });\n }\n this.#reply(connection, {\n type: \"rpc\",\n id,\n success: true,\n done: true,\n result: undefined\n });\n } else {\n this.#reply(connection, {\n type: \"rpc\",\n id,\n success: true,\n done: true,\n result\n });\n }\n } catch (error) {\n this.#reply(connection, {\n type: \"rpc\",\n id,\n success: false,\n error: error instanceof Error ? error.message : String(error)\n });\n }\n return true;\n }\n\n #reply(connection: Connection, response: RpcResponse): void {\n let text: string;\n try {\n text = JSON.stringify(response);\n } catch (error) {\n // A result that JSON cannot carry (a BigInt, a cycle) must still\n // settle the caller: answer with an error instead of silence.\n text = JSON.stringify({\n type: \"rpc\",\n id: response.id,\n success: false,\n error: `Result is not JSON-serializable: ${\n error instanceof Error ? error.message : String(error)\n }`\n } satisfies RpcResponse);\n }\n this.#send(connection, text);\n }\n\n async #dispatchCallable(\n name: string,\n invoke: () => unknown,\n connection: Connection\n ): Promise<unknown> {\n // Throws with installation guidance when the capability was never\n // installed with Lifecycle.use().\n const services = this.lifecycle;\n try {\n const result = await services.runInHostContext(invoke, { connection });\n services.events.emit(\"rpc\", {\n method: name,\n streaming: result instanceof ReadableStream\n });\n return result;\n } catch (error) {\n services.events.emit(\"rpc:error\", {\n method: name,\n error: error instanceof Error ? error.message : String(error)\n });\n throw error;\n }\n }\n}\n"],"mappings":"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"}