agents 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +21 -1
  2. package/dist/{agent-tool-types-CzGGB-20.d.ts → agent-routing-DE5zmCQ8.d.ts} +1844 -1336
  3. package/dist/agent-routing.d.ts +14 -0
  4. package/dist/agent-routing.js +187 -0
  5. package/dist/agent-routing.js.map +1 -0
  6. package/dist/agent-tool-types.d.ts +26 -26
  7. package/dist/{agent-tools-zR2d5uij.d.ts → agent-tools-DtXMTDGM.d.ts} +7 -7
  8. package/dist/agent-tools.d.ts +21 -21
  9. package/dist/agent-tools.js +2 -1
  10. package/dist/agent-tools.js.map +1 -1
  11. package/dist/browser/ai.js +6 -2
  12. package/dist/browser/ai.js.map +1 -1
  13. package/dist/browser/tanstack-ai.js.map +1 -1
  14. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  15. package/dist/callable-decorator.d.ts +18 -0
  16. package/dist/callable-decorator.js +71 -0
  17. package/dist/callable-decorator.js.map +1 -0
  18. package/dist/capability-BjSKYpzg.js +42 -0
  19. package/dist/capability-BjSKYpzg.js.map +1 -0
  20. package/dist/capability-runner-Be_-PLR1.d.ts +459 -0
  21. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  22. package/dist/channels/ai-sdk.d.ts +46 -0
  23. package/dist/channels/ai-sdk.js +120 -0
  24. package/dist/channels/ai-sdk.js.map +1 -0
  25. package/dist/channels/email.d.ts +95 -0
  26. package/dist/channels/email.js +323 -0
  27. package/dist/channels/email.js.map +1 -0
  28. package/dist/channels/index.d.ts +233 -0
  29. package/dist/channels/index.js +608 -0
  30. package/dist/channels/index.js.map +1 -0
  31. package/dist/channels/slack.d.ts +140 -0
  32. package/dist/channels/slack.js +614 -0
  33. package/dist/channels/slack.js.map +1 -0
  34. package/dist/channels/tanstack-ai.d.ts +39 -0
  35. package/dist/channels/tanstack-ai.js +17 -0
  36. package/dist/channels/tanstack-ai.js.map +1 -0
  37. package/dist/channels/telegram.d.ts +106 -0
  38. package/dist/channels/telegram.js +427 -0
  39. package/dist/channels/telegram.js.map +1 -0
  40. package/dist/channels/voice.d.ts +45 -0
  41. package/dist/channels/voice.js +122 -0
  42. package/dist/channels/voice.js.map +1 -0
  43. package/dist/chat/index.d.ts +2328 -2015
  44. package/dist/chat/index.js +891 -521
  45. package/dist/chat/index.js.map +1 -1
  46. package/dist/chat/react.d.ts +14 -1
  47. package/dist/chat/react.js +82 -52
  48. package/dist/chat/react.js.map +1 -1
  49. package/dist/chat/transport.js +1 -1
  50. package/dist/chat-sdk/index.d.ts +7 -7
  51. package/dist/chat-sdk/index.js +1 -1
  52. package/dist/{client-zqKcsyFa.js → client-jagG8a9_.js} +129 -37
  53. package/dist/client-jagG8a9_.js.map +1 -0
  54. package/dist/client.d.ts +1 -1
  55. package/dist/client.js +1 -1
  56. package/dist/{cloudflare-BduZwmYK.js → cloudflare-Dzvc7V2N.js} +10 -3
  57. package/dist/{cloudflare-BduZwmYK.js.map → cloudflare-Dzvc7V2N.js.map} +1 -1
  58. package/dist/context/index.d.ts +216 -0
  59. package/dist/context/index.js +454 -0
  60. package/dist/context/index.js.map +1 -0
  61. package/dist/current-agent-Da_C9a3b.d.ts +266 -0
  62. package/dist/current-agent-DhoDkSnH.js +51 -0
  63. package/dist/current-agent-DhoDkSnH.js.map +1 -0
  64. package/dist/diagnostics-BzvaX2UT.js +45 -0
  65. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  66. package/dist/diagnostics-C4jcz3VK.js +360 -0
  67. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  68. package/dist/{do-oauth-client-provider-VTZj2VtM.d.ts → do-oauth-client-provider-Tmf1vgKz.d.ts} +2 -2
  69. package/dist/{email-CL27preh.d.ts → email-7TatiTnl.d.ts} +38 -9
  70. package/dist/email-send.d.ts +15 -0
  71. package/dist/email-send.js +32 -0
  72. package/dist/email-send.js.map +1 -0
  73. package/dist/email.d.ts +14 -10
  74. package/dist/email.js.map +1 -1
  75. package/dist/{handler-stateless-C_bo-Ytq.d.ts → handler-stateless-DxYpJ_XF.d.ts} +3 -3
  76. package/dist/{handler-stateless-CIkKPETH.js → handler-stateless-VvrWSAVA.js} +5 -5
  77. package/dist/handler-stateless-VvrWSAVA.js.map +1 -0
  78. package/dist/index-BB0kqhIz.d.ts +101 -0
  79. package/dist/index-XDkuQ7zm.d.ts +89 -0
  80. package/dist/{index-BRnybD6X.d.ts → index-YSKgfgg9.d.ts} +21 -31
  81. package/dist/index.d.ts +113 -101
  82. package/dist/index.js +11 -7234
  83. package/dist/ingress-BfetZbMO.js +83 -0
  84. package/dist/ingress-BfetZbMO.js.map +1 -0
  85. package/dist/internal-CYlgHl1l.js +59 -0
  86. package/dist/internal-CYlgHl1l.js.map +1 -0
  87. package/dist/internal_context-BlxFEWfn.d.ts +19 -0
  88. package/dist/internal_context.d.ts +10 -4
  89. package/dist/internal_context.js +1 -10
  90. package/dist/{client-invoker-BNSZxAkv.d.ts → invoker-CG0_p_Wq.d.ts} +2 -2
  91. package/dist/{client-invoker-VNZ7X0nn.js → invoker-CHMnoxIA.js} +2 -2
  92. package/dist/invoker-CHMnoxIA.js.map +1 -0
  93. package/dist/lifecycle/index.d.ts +66 -0
  94. package/dist/lifecycle/index.js +4 -0
  95. package/dist/lifecycle-CMRGjZdw.js +1299 -0
  96. package/dist/lifecycle-CMRGjZdw.js.map +1 -0
  97. package/dist/mcp/{do-oauth-client-provider.d.ts → client/do-oauth-client-provider.d.ts} +1 -1
  98. package/dist/mcp/{do-oauth-client-provider.js → client/do-oauth-client-provider.js} +1 -1
  99. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -0
  100. package/dist/mcp/client/index.d.ts +42 -0
  101. package/dist/mcp/{client.js → client/index.js} +1 -1
  102. package/dist/mcp/{x402.d.ts → client/x402.d.ts} +2 -2
  103. package/dist/mcp/{x402.js → client/x402.js} +2 -2
  104. package/dist/mcp/client/x402.js.map +1 -0
  105. package/dist/mcp/index.d.ts +36 -36
  106. package/dist/mcp/index.js +14 -16
  107. package/dist/mcp/index.js.map +1 -1
  108. package/dist/mcp/{server.d.ts → server/index.d.ts} +1 -1
  109. package/dist/mcp/{server.js → server/index.js} +1 -1
  110. package/dist/observability/ai/index.js +50 -35
  111. package/dist/observability/ai/index.js.map +1 -1
  112. package/dist/observability/index.d.ts +4 -4
  113. package/dist/observability/index.js +3 -50
  114. package/dist/observability/index.js.map +1 -1
  115. package/dist/{protocol-Dqc2MQxo.js → protocol-B0nh6KNf.js} +19 -21
  116. package/dist/protocol-B0nh6KNf.js.map +1 -0
  117. package/dist/react.d.ts +4 -4
  118. package/dist/react.js +1 -1
  119. package/dist/{retries-CAvxtG9d.d.ts → retries-D9Ds-1lz.d.ts} +17 -6
  120. package/dist/retries.d.ts +8 -6
  121. package/dist/retries.js +13 -1
  122. package/dist/retries.js.map +1 -1
  123. package/dist/routing/index.d.ts +137 -0
  124. package/dist/routing/index.js +244 -0
  125. package/dist/routing/index.js.map +1 -0
  126. package/dist/sanitize-D9TujEK8.js +79 -0
  127. package/dist/sanitize-D9TujEK8.js.map +1 -0
  128. package/dist/schedule.d.ts +25 -94
  129. package/dist/schedule.js +1 -98
  130. package/dist/schedule.js.map +1 -1
  131. package/dist/scheduler-DD9NdYbF.js +665 -0
  132. package/dist/scheduler-DD9NdYbF.js.map +1 -0
  133. package/dist/scheduler-Dwh85ZGl.d.ts +223 -0
  134. package/dist/schedules/index.d.ts +22 -0
  135. package/dist/schedules/index.js +2 -0
  136. package/dist/schedules/parser.d.ts +79 -0
  137. package/dist/schedules/parser.js +103 -0
  138. package/dist/schedules/parser.js.map +1 -0
  139. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  140. package/dist/serializable.d.ts +1 -1
  141. package/dist/sessions/index.d.ts +441 -0
  142. package/dist/sessions/index.js +2063 -0
  143. package/dist/sessions/index.js.map +1 -0
  144. package/dist/skills/index.d.ts +99 -0
  145. package/dist/skills/index.js +254 -5
  146. package/dist/skills/index.js.map +1 -1
  147. package/dist/sql-error-CPY-GXyI.d.ts +12 -0
  148. package/dist/sql-error.d.ts +2 -0
  149. package/dist/sql-error.js +16 -0
  150. package/dist/sql-error.js.map +1 -0
  151. package/dist/src-DlSHshb2.js +6963 -0
  152. package/dist/src-DlSHshb2.js.map +1 -0
  153. package/dist/streams/index.d.ts +120 -0
  154. package/dist/streams/index.js +107 -0
  155. package/dist/streams/index.js.map +1 -0
  156. package/dist/streams-D6tJ0NN9.d.ts +370 -0
  157. package/dist/streams-DZKgAj9b.js +709 -0
  158. package/dist/streams-DZKgAj9b.js.map +1 -0
  159. package/dist/sub-routing.d.ts +12 -12
  160. package/dist/surface-bZZJqBka.js +17 -0
  161. package/dist/surface-bZZJqBka.js.map +1 -0
  162. package/dist/tasks/index.d.ts +64 -0
  163. package/dist/tasks/index.js +2 -0
  164. package/dist/tasks-BRJ5zgya.d.ts +517 -0
  165. package/dist/tasks-ylZgBjhj.js +1656 -0
  166. package/dist/tasks-ylZgBjhj.js.map +1 -0
  167. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  168. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  169. package/dist/text-stream-CpdiKrJB.js +272 -0
  170. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  171. package/dist/tokens-nHAKcN6M.js +52 -0
  172. package/dist/tokens-nHAKcN6M.js.map +1 -0
  173. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  174. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  175. package/dist/types-B7LojTe4.d.ts +202 -0
  176. package/dist/types-_Faxb570.d.ts +439 -0
  177. package/dist/voice/client.d.ts +226 -0
  178. package/dist/voice/client.js +932 -0
  179. package/dist/voice/client.js.map +1 -0
  180. package/dist/voice/errors.d.ts +43 -0
  181. package/dist/voice/errors.js +41 -0
  182. package/dist/voice/errors.js.map +1 -0
  183. package/dist/voice/index.d.ts +271 -0
  184. package/dist/voice/index.js +1812 -0
  185. package/dist/voice/index.js.map +1 -0
  186. package/dist/voice/react.d.ts +167 -0
  187. package/dist/voice/react.js +234 -0
  188. package/dist/voice/react.js.map +1 -0
  189. package/dist/voice/sfu.d.ts +71 -0
  190. package/dist/voice/sfu.js +157 -0
  191. package/dist/voice/sfu.js.map +1 -0
  192. package/dist/voice/text.d.ts +6 -0
  193. package/dist/voice/text.js +2 -0
  194. package/dist/voice/types.d.ts +58 -0
  195. package/dist/voice/types.js +18 -0
  196. package/dist/voice/types.js.map +1 -0
  197. package/dist/voice/workers-ai.d.ts +136 -0
  198. package/dist/voice/workers-ai.js +568 -0
  199. package/dist/voice/workers-ai.js.map +1 -0
  200. package/dist/websockets/index.d.ts +192 -0
  201. package/dist/websockets/index.js +2 -0
  202. package/dist/websockets-DUfRHPRq.js +502 -0
  203. package/dist/websockets-DUfRHPRq.js.map +1 -0
  204. package/dist/workflow-types.d.ts +25 -25
  205. package/dist/workflows.d.ts +22 -22
  206. package/dist/workflows.js +2 -1
  207. package/dist/workflows.js.map +1 -1
  208. package/dist/{ws-chat-transport-CIoOBbO7.js → ws-chat-transport-rWwta645.js} +152 -15
  209. package/dist/ws-chat-transport-rWwta645.js.map +1 -0
  210. package/docs/agent-class.md +29 -87
  211. package/docs/agent-tools.md +2 -1
  212. package/docs/channels.md +323 -0
  213. package/docs/chat-agents.md +19 -25
  214. package/docs/context.md +131 -0
  215. package/docs/durable-execution.md +1 -1
  216. package/docs/http-websockets.md +1 -11
  217. package/docs/human-in-the-loop.md +1 -1
  218. package/docs/index.md +16 -12
  219. package/docs/lifecycle.md +370 -0
  220. package/docs/long-running-agents.md +4 -6
  221. package/docs/mcp-client.md +55 -0
  222. package/docs/mcp-servers.md +5 -1
  223. package/docs/observability.md +11 -11
  224. package/docs/resumable-streaming.md +2 -2
  225. package/docs/routing.md +105 -0
  226. package/docs/scheduling.md +175 -15
  227. package/docs/server-driven-messages.md +1 -1
  228. package/docs/sessions.md +237 -871
  229. package/docs/streams.md +213 -0
  230. package/docs/sub-agents.md +185 -125
  231. package/docs/tasks.md +246 -0
  232. package/docs/voice.md +745 -0
  233. package/package.json +144 -33
  234. package/dist/cli/index.js +0 -26
  235. package/dist/cli/index.js.map +0 -1
  236. package/dist/client-invoker-VNZ7X0nn.js.map +0 -1
  237. package/dist/client-zqKcsyFa.js.map +0 -1
  238. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  239. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  240. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  241. package/dist/experimental/memory/session/index.d.ts +0 -670
  242. package/dist/experimental/memory/session/index.js +0 -2374
  243. package/dist/experimental/memory/session/index.js.map +0 -1
  244. package/dist/experimental/memory/utils/index.d.ts +0 -96
  245. package/dist/experimental/memory/utils/index.js +0 -79
  246. package/dist/experimental/memory/utils/index.js.map +0 -1
  247. package/dist/handler-stateless-CIkKPETH.js.map +0 -1
  248. package/dist/index.js.map +0 -1
  249. package/dist/internal_context-Dg4Cgjcu.d.ts +0 -37
  250. package/dist/internal_context.js.map +0 -1
  251. package/dist/mcp/client.d.ts +0 -42
  252. package/dist/mcp/do-oauth-client-provider.js.map +0 -1
  253. package/dist/mcp/x402.js.map +0 -1
  254. package/dist/protocol-Dqc2MQxo.js.map +0 -1
  255. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  256. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
  257. package/dist/ws-chat-transport-CIoOBbO7.js.map +0 -1
  258. /package/dist/{cli/index.d.ts → index-BVVgDSdq.d.ts} +0 -0
@@ -0,0 +1,608 @@
1
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
2
+ import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
3
+ import { t as isChannelMessageSurface } from "../surface-bZZJqBka.js";
4
+ import { c as unsupported, t as compositeDestinations } from "../internal-CYlgHl1l.js";
5
+ import { n as collectText, r as consumeChunks, t as matchesPath } from "../ingress-BfetZbMO.js";
6
+ //#region src/channels/fallback.ts
7
+ /**
8
+ * Build an inert fallback destination for a `ChannelHost` to resolve.
9
+ *
10
+ * The Host skips unavailable destinations, advances after confirmed failures,
11
+ * and stops after a delivered or uncertain result to avoid duplicates.
12
+ */
13
+ function fallback(surfaces) {
14
+ return {
15
+ channelKey: "fallback",
16
+ version: 1,
17
+ address: { surfaces },
18
+ label: surfaces.map((surface) => surface.label).join(", then ")
19
+ };
20
+ }
21
+ /**
22
+ * Advance only when a failed destination has not started reading the answer.
23
+ *
24
+ * Replaying an arbitrarily large consumed prefix requires an arbitrarily large
25
+ * buffer. Instead, each attempt gets a cancellation-shielded view of the same
26
+ * source. Once an attempt asks for its first chunk, its result is terminal and
27
+ * the source is never handed to another destination.
28
+ */
29
+ async function streamWithFallbackBeforeRead(resolve, destinations, chunks, options) {
30
+ const reader = chunks.getReader();
31
+ let drained = false;
32
+ function attempt() {
33
+ let startedReading = false;
34
+ return {
35
+ chunks: new ReadableStream({
36
+ async pull(controller) {
37
+ startedReading = true;
38
+ const result = await reader.read();
39
+ if (result.done) {
40
+ drained = true;
41
+ controller.close();
42
+ return;
43
+ }
44
+ controller.enqueue(result.value);
45
+ },
46
+ cancel() {}
47
+ }, { highWaterMark: 0 }),
48
+ startedReading: () => startedReading
49
+ };
50
+ }
51
+ try {
52
+ for (let index = 0; index < destinations.length - 1; index += 1) {
53
+ const destination = destinations[index];
54
+ if (!await resolve.isAvailable(destination)) continue;
55
+ const current = attempt();
56
+ const result = await resolve.stream(destination, current.chunks, options);
57
+ if (result.status !== "failed" || current.startedReading()) return result;
58
+ }
59
+ const final = attempt();
60
+ return await resolve.stream(destinations.at(-1), final.chunks, options);
61
+ } finally {
62
+ if (!drained) await reader.cancel().catch(() => {});
63
+ reader.releaseLock();
64
+ }
65
+ }
66
+ /** Build the ordinary Channel installed under the reserved fallback key. */
67
+ function fallbackChannel(resolve) {
68
+ async function run(surface, operation) {
69
+ const destinations = compositeDestinations(surface);
70
+ if (!destinations) return unsupported("FALLBACK_SURFACE_INVALID", "Fallback surface must contain at least one valid destination");
71
+ for (let index = 0; index < destinations.length - 1; index += 1) {
72
+ const destination = destinations[index];
73
+ if (await resolve.isAvailable(destination)) {
74
+ const result = await operation(destination);
75
+ if (result.status !== "failed") return result;
76
+ }
77
+ }
78
+ return operation(destinations.at(-1));
79
+ }
80
+ return {
81
+ deliver(surface, message, options) {
82
+ return run(surface, (destination) => resolve.deliver(destination, message, options));
83
+ },
84
+ async stream(surface, chunks, options) {
85
+ const destinations = compositeDestinations(surface);
86
+ if (!destinations) {
87
+ await chunks.cancel().catch(() => {});
88
+ return unsupported("FALLBACK_SURFACE_INVALID", "Fallback surface must contain at least one valid destination");
89
+ }
90
+ return streamWithFallbackBeforeRead(resolve, destinations, chunks, options);
91
+ },
92
+ requestApproval(surface, options) {
93
+ return run(surface, (destination) => resolve.requestApproval(destination, options));
94
+ },
95
+ async isAvailable(surface) {
96
+ const destinations = compositeDestinations(surface);
97
+ if (!destinations) return true;
98
+ for (const destination of destinations) if (await resolve.isAvailable(destination)) return true;
99
+ return false;
100
+ }
101
+ };
102
+ }
103
+ //#endregion
104
+ //#region src/channels/fanout.ts
105
+ function teeAll(source, count) {
106
+ const branches = [];
107
+ let rest = source;
108
+ for (let index = 0; index < count - 1; index += 1) {
109
+ const [branch, remainder] = rest.tee();
110
+ branches.push(branch);
111
+ rest = remainder;
112
+ }
113
+ branches.push(rest);
114
+ return branches;
115
+ }
116
+ /** Build an inert fanout destination for a `ChannelHost` to resolve. */
117
+ function fanout(surfaces) {
118
+ return {
119
+ channelKey: "fanout",
120
+ version: 1,
121
+ address: { surfaces },
122
+ label: surfaces.map((surface) => surface.label).join(" and ")
123
+ };
124
+ }
125
+ /** Build the ordinary Channel installed under the reserved fanout key. */
126
+ function fanoutChannel(resolve) {
127
+ async function run(surface, operation) {
128
+ const destinations = compositeDestinations(surface);
129
+ if (!destinations) return unsupported("FANOUT_SURFACE_INVALID", "Fanout surface must contain at least one valid destination");
130
+ return combine(await Promise.all(destinations.map(operation)));
131
+ }
132
+ function combine(results) {
133
+ if (results.every((result) => result.status === "delivered")) return { status: "delivered" };
134
+ if (results.every((result) => result.status === "failed")) return {
135
+ status: "failed",
136
+ retryable: results.every((result) => result.status === "failed" && result.retryable),
137
+ error: {
138
+ code: "FANOUT_DELIVERY_FAILED",
139
+ message: "Every fanout destination rejected the delivery"
140
+ }
141
+ };
142
+ return {
143
+ status: "uncertain",
144
+ error: {
145
+ code: "FANOUT_DELIVERY_UNCERTAIN",
146
+ message: "Fanout delivery was partial or had an uncertain destination outcome"
147
+ }
148
+ };
149
+ }
150
+ return {
151
+ deliver(surface, message, options) {
152
+ return run(surface, (destination) => resolve.deliver(destination, message, options));
153
+ },
154
+ async stream(surface, chunks, options) {
155
+ const destinations = compositeDestinations(surface);
156
+ if (!destinations) {
157
+ await chunks.cancel().catch(() => {});
158
+ return unsupported("FANOUT_SURFACE_INVALID", "Fanout surface must contain at least one valid destination");
159
+ }
160
+ const branches = teeAll(chunks, destinations.length);
161
+ return combine(await Promise.all(destinations.map(async (destination, index) => {
162
+ const branch = branches[index];
163
+ try {
164
+ return await resolve.stream(destination, branch, options);
165
+ } finally {
166
+ branch.cancel().catch(() => {});
167
+ }
168
+ })));
169
+ },
170
+ requestApproval(surface, options) {
171
+ return run(surface, (destination) => resolve.requestApproval(destination, options));
172
+ },
173
+ async isAvailable(surface) {
174
+ const destinations = compositeDestinations(surface);
175
+ if (!destinations) return true;
176
+ return (await Promise.all(destinations.map((destination) => resolve.isAvailable(destination)))).every(Boolean);
177
+ }
178
+ };
179
+ }
180
+ //#endregion
181
+ //#region src/channels/host/index.ts
182
+ const POLICY_KEYS = /* @__PURE__ */ new Set(["fallback", "fanout"]);
183
+ var _channels = /* @__PURE__ */ new WeakMap();
184
+ var _defaultRoute = /* @__PURE__ */ new WeakMap();
185
+ var _findUser = /* @__PURE__ */ new WeakMap();
186
+ var _onRoute = /* @__PURE__ */ new WeakMap();
187
+ var _onMessage = /* @__PURE__ */ new WeakMap();
188
+ var _onApprovalResponse = /* @__PURE__ */ new WeakMap();
189
+ var _ChannelHost_brand = /* @__PURE__ */ new WeakSet();
190
+ /**
191
+ * Authenticates and normalizes ingress through configured Channel adapters,
192
+ * resolves outbound surfaces, and awaits the application's durable handoff.
193
+ */
194
+ var ChannelHost = class {
195
+ constructor(options) {
196
+ _classPrivateMethodInitSpec(this, _ChannelHost_brand);
197
+ _classPrivateFieldInitSpec(this, _channels, void 0);
198
+ _classPrivateFieldInitSpec(this, _defaultRoute, void 0);
199
+ _classPrivateFieldInitSpec(this, _findUser, void 0);
200
+ _classPrivateFieldInitSpec(this, _onRoute, void 0);
201
+ _classPrivateFieldInitSpec(this, _onMessage, void 0);
202
+ _classPrivateFieldInitSpec(this, _onApprovalResponse, void 0);
203
+ for (const channelKey of Object.keys(options.channels)) if (POLICY_KEYS.has(channelKey)) throw new Error(`Channel key "${channelKey}" is reserved for a delivery policy`);
204
+ const channels = { ...options.channels };
205
+ _classPrivateFieldSet2(_channels, this, channels);
206
+ channels.fallback = fallbackChannel(this);
207
+ channels.fanout = fanoutChannel(this);
208
+ _classPrivateFieldSet2(_defaultRoute, this, options.defaultRoute);
209
+ _classPrivateFieldSet2(_findUser, this, options.findUser);
210
+ _classPrivateFieldSet2(_onRoute, this, options.onRoute);
211
+ _classPrivateFieldSet2(_onMessage, this, options.onMessage);
212
+ _classPrivateFieldSet2(_onApprovalResponse, this, options.onApprovalResponse);
213
+ }
214
+ async handleRequest(request) {
215
+ for (const [channelKey, channel] of Object.entries(_classPrivateFieldGet2(_channels, this))) {
216
+ const ingress = channel.ingress;
217
+ if (!ingress) continue;
218
+ try {
219
+ const result = await ingress.receive(request);
220
+ if (!result) continue;
221
+ for (const envelope of result.events) await _assertClassBrand(_ChannelHost_brand, this, _dispatch).call(this, channelKey, channel, envelope);
222
+ return result.response;
223
+ } catch {
224
+ return new Response("Failed to handle Channel event", { status: 500 });
225
+ }
226
+ }
227
+ }
228
+ async handleEmail(email) {
229
+ for (const [channelKey, channel] of Object.entries(_classPrivateFieldGet2(_channels, this))) {
230
+ const ingress = channel.emailIngress;
231
+ if (!ingress) continue;
232
+ const result = await ingress.receive(email);
233
+ if (!result) continue;
234
+ for (const envelope of result.events) await _assertClassBrand(_ChannelHost_brand, this, _dispatch).call(this, channelKey, channel, envelope);
235
+ return true;
236
+ }
237
+ return false;
238
+ }
239
+ /** Deliver through the configured Channel or composite named by the surface. */
240
+ deliver(surface, message, options) {
241
+ return _assertClassBrand(_ChannelHost_brand, this, _outbound).call(this, surface, (channel, destination) => {
242
+ if (!channel.deliver) return Promise.resolve(unsupported("CHANNEL_DELIVERY_UNSUPPORTED", `Channel "${destination.channelKey}" does not support delivery`));
243
+ return channel.deliver(destination, message, options);
244
+ });
245
+ }
246
+ /**
247
+ * Deliver a progressively generated answer to the Channel or composite
248
+ * named by the surface.
249
+ *
250
+ * A Channel that can stream consumes the stream itself. A Channel that
251
+ * cannot never learns it was a stream, because the Host collects the answer
252
+ * and calls `deliver` once.
253
+ */
254
+ async stream(surface, chunks, options = {}) {
255
+ if (!isChannelMessageSurface(surface)) {
256
+ await chunks.cancel().catch(() => {});
257
+ return invalidSurface();
258
+ }
259
+ const channel = _assertClassBrand(_ChannelHost_brand, this, _configuredChannel).call(this, surface.channelKey);
260
+ if (!channel.stream && !channel.deliver) {
261
+ await chunks.cancel().catch(() => {});
262
+ return unsupported("CHANNEL_DELIVERY_UNSUPPORTED", `Channel "${surface.channelKey}" does not support delivery`);
263
+ }
264
+ if (channel.stream) return channel.stream(surface, chunks, options);
265
+ return collectAndDeliver(channel, surface, chunks, options);
266
+ }
267
+ /** Request approval through the Channel or composite named by the surface. */
268
+ requestApproval(surface, options) {
269
+ return _assertClassBrand(_ChannelHost_brand, this, _outbound).call(this, surface, (channel, destination) => {
270
+ if (!channel.requestApproval) return Promise.resolve(unsupported("CHANNEL_APPROVAL_UNSUPPORTED", `Channel "${destination.channelKey}" does not support approval requests`));
271
+ return channel.requestApproval(destination, options);
272
+ });
273
+ }
274
+ /** Return the identity's configured Channel destination, when supported. */
275
+ contactSurface(identity) {
276
+ const surface = (Object.prototype.hasOwnProperty.call(_classPrivateFieldGet2(_channels, this), identity.channelKey) ? _classPrivateFieldGet2(_channels, this)[identity.channelKey] : void 0)?.contactSurface?.(identity);
277
+ return surface ? stampSurface(identity.channelKey, surface) : null;
278
+ }
279
+ /** Resolve whether a surface can currently be selected without delivery. */
280
+ async isAvailable(surface) {
281
+ if (!isChannelMessageSurface(surface)) return false;
282
+ return _assertClassBrand(_ChannelHost_brand, this, _configuredChannel).call(this, surface.channelKey).isAvailable?.(surface) ?? true;
283
+ }
284
+ };
285
+ async function _outbound(surface, operation) {
286
+ if (!isChannelMessageSurface(surface)) return invalidSurface();
287
+ return operation(_assertClassBrand(_ChannelHost_brand, this, _configuredChannel).call(this, surface.channelKey), surface);
288
+ }
289
+ function _configuredChannel(channelKey) {
290
+ const channel = Object.prototype.hasOwnProperty.call(_classPrivateFieldGet2(_channels, this), channelKey) ? _classPrivateFieldGet2(_channels, this)[channelKey] : void 0;
291
+ if (!channel) throw new Error(`Channel message surface names unknown configured Channel key "${channelKey}"`);
292
+ return channel;
293
+ }
294
+ async function _dispatch(channelKey, channel, envelope) {
295
+ const rawEvent = envelope.event;
296
+ const event = stampEvent(channelKey, rawEvent);
297
+ const route = await _assertClassBrand(_ChannelHost_brand, this, _route).call(this, channelKey, channel, event, envelope.raw);
298
+ const dispatchId = await createDispatchId(channelKey, event.eventId);
299
+ await _classPrivateFieldGet2(_onRoute, this)?.call(this, {
300
+ channelKey,
301
+ event,
302
+ route,
303
+ dispatchId
304
+ });
305
+ if (route === null) return;
306
+ if (event.type === "message") {
307
+ if (!_classPrivateFieldGet2(_onMessage, this)) throw new Error(`Channel "${channelKey}" received a message without an onMessage callback`);
308
+ await _classPrivateFieldGet2(_onMessage, this).call(this, {
309
+ channelKey,
310
+ route,
311
+ dispatchId,
312
+ message: event
313
+ });
314
+ return;
315
+ }
316
+ if (!_classPrivateFieldGet2(_onApprovalResponse, this)) throw new Error(`Channel "${channelKey}" received an approval response without an onApprovalResponse callback`);
317
+ await _classPrivateFieldGet2(_onApprovalResponse, this).call(this, {
318
+ channelKey,
319
+ route,
320
+ dispatchId,
321
+ response: event
322
+ });
323
+ }
324
+ async function _route(channelKey, channel, event, raw) {
325
+ const context = _assertClassBrand(_ChannelHost_brand, this, _routeContext).call(this, event);
326
+ const route = channel.route ? await channel.route(event, raw, context) : _classPrivateFieldGet2(_defaultRoute, this) ? await _classPrivateFieldGet2(_defaultRoute, this).call(this, event, raw, context) : event.thread.id;
327
+ if (route === void 0) throw new Error(`Channel route for "${channelKey}" returned undefined; return null to ignore an event`);
328
+ if (route !== null && typeof route !== "string") throw new Error(`Channel route for "${channelKey}" must return a string or null`);
329
+ return route;
330
+ }
331
+ function _routeContext(event) {
332
+ let linkedUser;
333
+ return { findUser: () => {
334
+ if (!linkedUser) {
335
+ const identity = event.actor?.identity;
336
+ const findUser = _classPrivateFieldGet2(_findUser, this);
337
+ linkedUser = identity && findUser ? Promise.resolve().then(() => findUser(identity)) : Promise.resolve(null);
338
+ }
339
+ return linkedUser;
340
+ } };
341
+ }
342
+ /**
343
+ * Serve a Channel that cannot stream by collecting the answer first.
344
+ *
345
+ * A generation that failed part-way still delivers what it produced, because
346
+ * losing the partial answer helps nobody, but the result is downgraded to
347
+ * `uncertain` since the reader received an incomplete answer.
348
+ */
349
+ function invalidSurface() {
350
+ return unsupported("CHANNEL_SURFACE_INVALID", "Cannot resolve an invalid Channel message surface");
351
+ }
352
+ async function collectAndDeliver(channel, surface, stream, options) {
353
+ const collected = await collectText(stream);
354
+ if (collected.interrupted && collected.text.length === 0) return {
355
+ status: "failed",
356
+ retryable: false,
357
+ error: {
358
+ code: "CHANNEL_STREAM_INTERRUPTED",
359
+ message: "The stream ended before producing any content to deliver"
360
+ }
361
+ };
362
+ const result = await channel.deliver(surface, {
363
+ ...options.title !== void 0 && { title: options.title },
364
+ markdown: collected.text
365
+ }, options.delivery ? { delivery: options.delivery } : void 0);
366
+ if (!collected.interrupted || result.status !== "delivered") return result;
367
+ return {
368
+ status: "uncertain",
369
+ ...result.reference !== void 0 && { reference: result.reference },
370
+ error: {
371
+ code: "CHANNEL_STREAM_INTERRUPTED",
372
+ message: "An incomplete answer was delivered because the stream ended early"
373
+ }
374
+ };
375
+ }
376
+ function stampSurface(channelKey, surface) {
377
+ return {
378
+ ...surface,
379
+ channelKey
380
+ };
381
+ }
382
+ function stampIdentity(channelKey, identity) {
383
+ return {
384
+ ...identity,
385
+ channelKey
386
+ };
387
+ }
388
+ function stampEvent(channelKey, event) {
389
+ return {
390
+ ...event,
391
+ ...event.replySurface && { replySurface: stampSurface(channelKey, event.replySurface) },
392
+ ...event.actor && { actor: {
393
+ ...event.actor,
394
+ ...event.actor.identity && { identity: stampIdentity(channelKey, event.actor.identity) }
395
+ } }
396
+ };
397
+ }
398
+ /** Hash an unambiguous tuple so dispatch identities remain safe to carry. */
399
+ async function createDispatchId(channelKey, eventId) {
400
+ const identity = new TextEncoder().encode(JSON.stringify([channelKey, eventId]));
401
+ const digest = await crypto.subtle.digest("SHA-256", identity);
402
+ return `sha256:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
403
+ }
404
+ //#endregion
405
+ //#region src/channels/identity.ts
406
+ const DEFAULT_IDENTITY_SCOPE = "default";
407
+ function normalizeIdentity(identity) {
408
+ return {
409
+ channelKey: identity.channelKey,
410
+ scope: identity.scope ?? DEFAULT_IDENTITY_SCOPE,
411
+ subject: identity.subject
412
+ };
413
+ }
414
+ /** Build a stable key for comparing or indexing a Channel identity. */
415
+ function identityKey(identity) {
416
+ const normalized = normalizeIdentity(identity);
417
+ return JSON.stringify([
418
+ normalized.channelKey,
419
+ normalized.scope,
420
+ normalized.subject
421
+ ]);
422
+ }
423
+ /** Raised when an operation would join identities already assigned to users. */
424
+ var UserIdentityConflictError = class extends Error {
425
+ constructor(conflicts, attemptedUserId) {
426
+ super(attemptedUserId ? `A channel identity is already linked to a different user than ${attemptedUserId}` : "Both channel identities are already linked to users");
427
+ this.conflicts = conflicts;
428
+ this.attemptedUserId = attemptedUserId;
429
+ this.code = "USER_IDENTITY_CONFLICT";
430
+ this.name = "UserIdentityConflictError";
431
+ }
432
+ };
433
+ const USERS_TABLE = "cf_channels_users_v1";
434
+ const LINKS_TABLE = "cf_channels_user_identity_links_v1";
435
+ function requireNonEmpty(label, value) {
436
+ if (value.length === 0) throw new TypeError(`${label} must be a non-empty string`);
437
+ }
438
+ function validatedIdentity(identity) {
439
+ const normalized = normalizeIdentity(identity);
440
+ requireNonEmpty("identity.channelKey", normalized.channelKey);
441
+ requireNonEmpty("identity.scope", normalized.scope);
442
+ requireNonEmpty("identity.subject", normalized.subject);
443
+ return normalized;
444
+ }
445
+ function sameIdentity(first, second) {
446
+ return identityKey(first) === identityKey(second);
447
+ }
448
+ function compareIdentities(first, second) {
449
+ return first.channelKey.localeCompare(second.channelKey) || first.scope.localeCompare(second.scope) || first.subject.localeCompare(second.subject);
450
+ }
451
+ /** Build the off-the-shelf user identity store over application-owned SQLite. */
452
+ function createUserIdentityStore(storage, options = {}) {
453
+ const createUserId = options.createUserId ?? (() => crypto.randomUUID());
454
+ storage.sql.exec(`
455
+ CREATE TABLE IF NOT EXISTS ${USERS_TABLE} (
456
+ user_id TEXT PRIMARY KEY
457
+ ) WITHOUT ROWID
458
+ `);
459
+ storage.sql.exec(`
460
+ CREATE TABLE IF NOT EXISTS ${LINKS_TABLE} (
461
+ channel_key TEXT NOT NULL,
462
+ scope TEXT NOT NULL,
463
+ subject TEXT NOT NULL,
464
+ user_id TEXT NOT NULL,
465
+ PRIMARY KEY (channel_key, scope, subject)
466
+ ) WITHOUT ROWID
467
+ `);
468
+ storage.sql.exec(`
469
+ CREATE INDEX IF NOT EXISTS ${LINKS_TABLE}_user
470
+ ON ${LINKS_TABLE} (user_id, channel_key, scope, subject)
471
+ `);
472
+ function linkedUserId(identity) {
473
+ return storage.sql.exec(`SELECT user_id FROM ${LINKS_TABLE}
474
+ WHERE channel_key = ? AND scope = ? AND subject = ?`, identity.channelKey, identity.scope, identity.subject).toArray()[0]?.user_id ?? null;
475
+ }
476
+ function readUser(userId) {
477
+ const user = storage.sql.exec(`SELECT user_id FROM ${USERS_TABLE} WHERE user_id = ?`, userId).toArray()[0];
478
+ if (!user) return null;
479
+ const channelIdentities = storage.sql.exec(`SELECT channel_key AS channelKey, scope, subject FROM ${LINKS_TABLE}
480
+ WHERE user_id = ?
481
+ ORDER BY channel_key, scope, subject`, userId).toArray().sort(compareIdentities);
482
+ return {
483
+ id: user.user_id,
484
+ channelIdentities
485
+ };
486
+ }
487
+ function insertUser(userId) {
488
+ return storage.sql.exec(`INSERT INTO ${USERS_TABLE} (user_id) VALUES (?)
489
+ ON CONFLICT (user_id) DO NOTHING
490
+ RETURNING user_id`, userId).toArray()[0] !== void 0;
491
+ }
492
+ function createUser() {
493
+ for (let attempt = 0; attempt < 10; attempt += 1) {
494
+ const userId = createUserId();
495
+ requireNonEmpty("createUserId() result", userId);
496
+ if (insertUser(userId)) return userId;
497
+ }
498
+ throw new Error("createUserId() repeatedly returned existing user IDs");
499
+ }
500
+ function insertLink(userId, identity) {
501
+ storage.sql.exec(`INSERT INTO ${LINKS_TABLE} (channel_key, scope, subject, user_id)
502
+ VALUES (?, ?, ?, ?)`, identity.channelKey, identity.scope, identity.subject, userId);
503
+ }
504
+ return {
505
+ async link(userId, identity) {
506
+ requireNonEmpty("userId", userId);
507
+ const normalized = validatedIdentity(identity);
508
+ return storage.transactionSync(() => {
509
+ const existingUserId = linkedUserId(normalized);
510
+ if (existingUserId && existingUserId !== userId) throw new UserIdentityConflictError([{
511
+ channelIdentity: normalized,
512
+ userId: existingUserId
513
+ }], userId);
514
+ insertUser(userId);
515
+ if (!existingUserId) insertLink(userId, normalized);
516
+ const user = readUser(userId);
517
+ if (!user) throw new Error("Linked user identity could not be read");
518
+ return user;
519
+ });
520
+ },
521
+ async findUser(identity) {
522
+ const userId = linkedUserId(validatedIdentity(identity));
523
+ return userId ? readUser(userId) : null;
524
+ },
525
+ async getUser(userId) {
526
+ requireNonEmpty("userId", userId);
527
+ return readUser(userId);
528
+ },
529
+ async listUsers() {
530
+ return storage.sql.exec(`SELECT user_id FROM ${USERS_TABLE} ORDER BY user_id`).toArray().map(({ user_id }) => readUser(user_id)).filter((user) => user !== null);
531
+ },
532
+ async linkChannelIdentities(first, second) {
533
+ const normalizedFirst = validatedIdentity(first);
534
+ const normalizedSecond = validatedIdentity(second);
535
+ if (sameIdentity(normalizedFirst, normalizedSecond)) throw new TypeError("Channel identities must be distinct");
536
+ return storage.transactionSync(() => {
537
+ const firstUserId = linkedUserId(normalizedFirst);
538
+ const secondUserId = linkedUserId(normalizedSecond);
539
+ if (firstUserId && secondUserId) throw new UserIdentityConflictError([{
540
+ channelIdentity: normalizedFirst,
541
+ userId: firstUserId
542
+ }, {
543
+ channelIdentity: normalizedSecond,
544
+ userId: secondUserId
545
+ }]);
546
+ const userId = firstUserId ?? secondUserId ?? createUser();
547
+ if (!firstUserId) insertLink(userId, normalizedFirst);
548
+ if (!secondUserId) insertLink(userId, normalizedSecond);
549
+ const user = readUser(userId);
550
+ if (!user) throw new Error("Linked user identity could not be read");
551
+ return user;
552
+ });
553
+ }
554
+ };
555
+ }
556
+ /** Join two Channel identities through a `UserIdentityStore`. */
557
+ function linkChannelIdentities(store, first, second) {
558
+ return store.linkChannelIdentities(first, second);
559
+ }
560
+ //#endregion
561
+ //#region src/channels/routes.ts
562
+ /**
563
+ * Common deterministic routing policies for normalized Channel events.
564
+ *
565
+ * Each one maps an event to a namespaced application route. Deciding whether
566
+ * an event is relevant at all is application policy: write that in your own
567
+ * `route` function and return `null` to ignore the event.
568
+ */
569
+ const routes = {
570
+ /**
571
+ * Give every event its own application route. Useful to kick off a
572
+ * new conversation for each ingress, and where you don't want subsequent
573
+ * messages routed back to that same conversation.
574
+ **/
575
+ perEvent(event) {
576
+ return `event:${event.eventId}`;
577
+ },
578
+ /** Send every event in the same thread to the same conversation */
579
+ perThread(event) {
580
+ return `thread:${event.thread.id}`;
581
+ },
582
+ /**
583
+ * Prefer the sender's own channel identity, then delegate to another route
584
+ * policy. Without a fallback, an event carrying no identity is ignored.
585
+ *
586
+ * This groups events that carry the *same* identity. It never infers that
587
+ * two different identities belong to one person: that is an explicit
588
+ * application decision, exposed to routing through `byUser`.
589
+ */
590
+ byIdentity(fallback) {
591
+ return (event, raw, context) => {
592
+ const identity = event.actor?.identity;
593
+ if (identity) return `identity:${identityKey(identity)}`;
594
+ return fallback ? fallback(event, raw, context) : null;
595
+ };
596
+ },
597
+ /** Prefer an explicitly linked user, then delegate to another route policy. */
598
+ byUser(fallback) {
599
+ return async (event, raw, context) => {
600
+ const user = await context.findUser();
601
+ return user ? `user:${user.id}` : fallback(event, raw, context);
602
+ };
603
+ }
604
+ };
605
+ //#endregion
606
+ export { ChannelHost, UserIdentityConflictError, consumeChunks, createUserIdentityStore, fallback, fallbackChannel, fanout, fanoutChannel, identityKey, isChannelMessageSurface, linkChannelIdentities, matchesPath, routes };
607
+
608
+ //# sourceMappingURL=index.js.map