experimental-a2 0.16.1 → 0.18.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 (406) hide show
  1. package/CHANGELOG.md +373 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-ohPC-81x.d.ts → actor-Bjce9_5U.d.ts} +21 -11
  4. package/dist/actor-Bjce9_5U.d.ts.map +1 -0
  5. package/dist/actor-client.d.ts +2 -5
  6. package/dist/actor-client.d.ts.map +1 -1
  7. package/dist/actor-client.js +13 -4
  8. package/dist/actor-client.js.map +1 -1
  9. package/dist/actor-react.d.ts +5 -3
  10. package/dist/actor-react.d.ts.map +1 -1
  11. package/dist/actor-react.js +20 -10
  12. package/dist/actor-react.js.map +1 -1
  13. package/dist/{actor-shared-B5tJfzt-.js → actor-shared-t7w8xIKP.js} +12 -7
  14. package/dist/actor-shared-t7w8xIKP.js.map +1 -0
  15. package/dist/actor.d.ts +1 -1
  16. package/dist/actor.js +42 -23
  17. package/dist/actor.js.map +1 -1
  18. package/dist/{ai-DgOBltJ_.js → ai-BpOGm-zB.js} +621 -216
  19. package/dist/ai-BpOGm-zB.js.map +1 -0
  20. package/dist/{ai-CrEf6p_W.d.ts → ai-DrUaMyRt.d.ts} +114 -100
  21. package/dist/ai-DrUaMyRt.d.ts.map +1 -0
  22. package/dist/ai-client.d.ts +27 -0
  23. package/dist/ai-client.d.ts.map +1 -0
  24. package/dist/ai-client.js +29 -0
  25. package/dist/ai-client.js.map +1 -0
  26. package/dist/ai-fx.browser.d.ts +1 -0
  27. package/dist/ai-fx.browser.js +6 -0
  28. package/dist/ai-fx.browser.js.map +1 -0
  29. package/dist/ai-fx.d.ts +10 -0
  30. package/dist/ai-fx.d.ts.map +1 -0
  31. package/dist/ai-fx.js +634 -0
  32. package/dist/ai-fx.js.map +1 -0
  33. package/dist/ai-harness-BuLh_EYi.js +273 -0
  34. package/dist/ai-harness-BuLh_EYi.js.map +1 -0
  35. package/dist/ai-harness-DvsPeJeB.d.ts +26 -0
  36. package/dist/ai-harness-DvsPeJeB.d.ts.map +1 -0
  37. package/dist/ai-pi.browser.d.ts +1 -0
  38. package/dist/ai-pi.browser.js +6 -0
  39. package/dist/ai-pi.browser.js.map +1 -0
  40. package/dist/ai-pi.d.ts +17 -0
  41. package/dist/ai-pi.d.ts.map +1 -0
  42. package/dist/ai-pi.js +904 -0
  43. package/dist/ai-pi.js.map +1 -0
  44. package/dist/ai-react.d.ts +96 -0
  45. package/dist/ai-react.d.ts.map +1 -0
  46. package/dist/ai-react.js +142 -0
  47. package/dist/ai-react.js.map +1 -0
  48. package/dist/ai-server.browser.js +2 -2
  49. package/dist/ai-server.browser.js.map +1 -1
  50. package/dist/ai-server.d.ts +109 -43
  51. package/dist/ai-server.d.ts.map +1 -1
  52. package/dist/ai-server.js +526 -283
  53. package/dist/ai-server.js.map +1 -1
  54. package/dist/ai.d.ts +2 -2
  55. package/dist/ai.js +2 -2
  56. package/dist/bounded-cache-CPHWF-8h.js +41 -0
  57. package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
  58. package/dist/{client-BYzHjkwU.js → client-BReKqwZC.js} +447 -80
  59. package/dist/client-BReKqwZC.js.map +1 -0
  60. package/dist/{client-CzyacQpJ.d.ts → client-h_DKFAjj.d.ts} +14 -13
  61. package/dist/client-h_DKFAjj.d.ts.map +1 -0
  62. package/dist/client.d.ts +4 -2
  63. package/dist/client.js +1 -1
  64. package/dist/{contract-CKRg_E4q.js → contract-BYKASlCV.js} +12 -21
  65. package/dist/contract-BYKASlCV.js.map +1 -0
  66. package/dist/{idempotent-replay-DVOlyYbx.js → idempotent-replay-JdgMQRRm.js} +2 -2
  67. package/dist/{idempotent-replay-DVOlyYbx.js.map → idempotent-replay-JdgMQRRm.js.map} +1 -1
  68. package/dist/index.d.ts +6 -5
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +4 -3
  71. package/dist/{errors-DvhSXnxk.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +7 -3
  72. package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +1 -0
  73. package/dist/{internal-Dq2qYxou.js → internal-B2T3U4Rq.js} +29 -2
  74. package/dist/internal-B2T3U4Rq.js.map +1 -0
  75. package/dist/otel.d.ts +1 -1
  76. package/dist/react-BBXgHWFc.d.ts +86 -0
  77. package/dist/react-BBXgHWFc.d.ts.map +1 -0
  78. package/dist/react.d.ts +2 -122
  79. package/dist/react.js +107 -100
  80. package/dist/react.js.map +1 -1
  81. package/dist/reducer-BAXc8JyF.js +87 -0
  82. package/dist/reducer-BAXc8JyF.js.map +1 -0
  83. package/dist/{reducer-otzHjuJj.d.ts → reducer-CqA59Q6U.d.ts} +46 -30
  84. package/dist/reducer-CqA59Q6U.d.ts.map +1 -0
  85. package/dist/reducer-runtime-DQwz_J59.js +28 -0
  86. package/dist/reducer-runtime-DQwz_J59.js.map +1 -0
  87. package/dist/scheduler-qstash.d.ts +3 -3
  88. package/dist/scheduler-qstash.d.ts.map +1 -1
  89. package/dist/scheduler-qstash.js +33 -10
  90. package/dist/scheduler-qstash.js.map +1 -1
  91. package/dist/{scheduler-task-BpzhPnRS.js → scheduler-task-X1SToDjP.js} +18 -3
  92. package/dist/scheduler-task-X1SToDjP.js.map +1 -0
  93. package/dist/scheduler-vercel.d.ts +4 -9
  94. package/dist/scheduler-vercel.d.ts.map +1 -1
  95. package/dist/scheduler-vercel.js +25 -44
  96. package/dist/scheduler-vercel.js.map +1 -1
  97. package/dist/{server-BD5ckxZb.js → server-Dw_k_7kO.js} +904 -219
  98. package/dist/server-Dw_k_7kO.js.map +1 -0
  99. package/dist/{server-DbD7IJVK.d.ts → server-En7cbi3v.d.ts} +116 -26
  100. package/dist/server-En7cbi3v.d.ts.map +1 -0
  101. package/dist/server.d.ts +4 -4
  102. package/dist/server.js +2 -2
  103. package/dist/session-clear-Bo-XTFEy.d.ts +12 -0
  104. package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
  105. package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
  106. package/dist/session-clear-DGI4jTQ5.js.map +1 -0
  107. package/dist/{store-DyZM6fS5.d.ts → store-Djdv0bnZ.d.ts} +73 -3
  108. package/dist/store-Djdv0bnZ.d.ts.map +1 -0
  109. package/dist/store-N8PXxDAS.js.map +1 -1
  110. package/dist/store-memory.d.ts +1 -1
  111. package/dist/store-memory.d.ts.map +1 -1
  112. package/dist/store-memory.js +205 -66
  113. package/dist/store-memory.js.map +1 -1
  114. package/dist/{store-polling-CmxUbV93.js → store-polling-B5FcwJfo.js} +21 -4
  115. package/dist/store-polling-B5FcwJfo.js.map +1 -0
  116. package/dist/store-postgres.d.ts +1 -1
  117. package/dist/store-postgres.d.ts.map +1 -1
  118. package/dist/store-postgres.js +450 -108
  119. package/dist/store-postgres.js.map +1 -1
  120. package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-BAwS8RWn.js} +3 -3
  121. package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-BAwS8RWn.js.map} +1 -1
  122. package/dist/store-redis-http.d.ts +1 -1
  123. package/dist/store-redis-http.d.ts.map +1 -1
  124. package/dist/store-redis-http.js +293 -11
  125. package/dist/store-redis-http.js.map +1 -1
  126. package/dist/store-redis-notify-BRITti_o.js +2493 -0
  127. package/dist/store-redis-notify-BRITti_o.js.map +1 -0
  128. package/dist/store-redis.d.ts +1 -1
  129. package/dist/store-redis.d.ts.map +1 -1
  130. package/dist/store-redis.js +11 -11
  131. package/dist/store-redis.js.map +1 -1
  132. package/dist/store-sqlite.d.ts +1 -1
  133. package/dist/store-sqlite.d.ts.map +1 -1
  134. package/dist/store-sqlite.js +197 -33
  135. package/dist/store-sqlite.js.map +1 -1
  136. package/dist/stream-buffer-Cx7AAPGq.js +23 -0
  137. package/dist/stream-buffer-Cx7AAPGq.js.map +1 -0
  138. package/dist/{telemetry-B5jzpy6y.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
  139. package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
  140. package/dist/{wire-BO5wWCb1.js → wire-rSUglYo8.js} +132 -10
  141. package/dist/wire-rSUglYo8.js.map +1 -0
  142. package/docs/01-quickstart.mdx +50 -84
  143. package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
  144. package/docs/actors/01-introduction.mdx +48 -82
  145. package/docs/actors/02-concurrency.mdx +43 -70
  146. package/docs/actors/03-timers.mdx +28 -42
  147. package/docs/actors/04-routes.mdx +110 -137
  148. package/docs/actors/meta.ts +1 -1
  149. package/docs/agents/01-introduction.mdx +257 -0
  150. package/docs/agents/02-tools.mdx +247 -0
  151. package/docs/agents/03-conversations.mdx +538 -0
  152. package/docs/agents/04-harnesses.mdx +136 -0
  153. package/docs/agents/meta.ts +1 -0
  154. package/docs/client/01-react.mdx +294 -0
  155. package/docs/client/02-transports.mdx +86 -0
  156. package/docs/client/03-presence.mdx +224 -0
  157. package/docs/client/meta.ts +1 -0
  158. package/docs/contract/01-events.mdx +57 -0
  159. package/docs/contract/02-state.mdx +142 -0
  160. package/docs/contract/03-sessions.mdx +175 -0
  161. package/docs/index.mdx +112 -156
  162. package/docs/reference/01-core.mdx +139 -0
  163. package/docs/reference/02-server.mdx +855 -0
  164. package/docs/reference/03-client.mdx +301 -0
  165. package/docs/reference/04-ai.mdx +722 -0
  166. package/docs/reference/05-adapters.mdx +351 -0
  167. package/docs/reference/06-errors.mdx +138 -0
  168. package/docs/reference/meta.ts +1 -1
  169. package/docs/server/01-handlers.mdx +200 -0
  170. package/docs/server/02-timers.mdx +130 -0
  171. package/docs/server/03-cancellation.mdx +141 -0
  172. package/docs/server/04-routes.mdx +243 -0
  173. package/docs/server/05-production.mdx +322 -0
  174. package/docs/server/06-guarantees.mdx +123 -0
  175. package/examples/playground/DEPLOY.md +53 -7
  176. package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
  177. package/examples/playground/app/a0/[appId]/page.tsx +53 -0
  178. package/examples/playground/app/a0/a0.css +818 -0
  179. package/examples/playground/app/a0/app-list.tsx +218 -0
  180. package/examples/playground/app/a0/app-view.tsx +63 -0
  181. package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
  182. package/examples/playground/app/a0/apps/[appId]/route.ts +28 -0
  183. package/examples/playground/app/a0/apps.test.ts +128 -0
  184. package/examples/playground/app/a0/apps.ts +102 -0
  185. package/examples/playground/app/a0/chat.tsx +410 -0
  186. package/examples/playground/app/a0/columns.tsx +109 -0
  187. package/examples/playground/app/a0/context-menu.tsx +116 -0
  188. package/examples/playground/app/a0/cookies.ts +46 -0
  189. package/examples/playground/app/a0/crash-on-request.ts +72 -0
  190. package/examples/playground/app/a0/crashes/route.ts +3 -0
  191. package/examples/playground/app/a0/crashes.test.ts +33 -0
  192. package/examples/playground/app/a0/crashes.ts +28 -0
  193. package/examples/playground/app/a0/devtools.tsx +164 -0
  194. package/examples/playground/app/a0/events/route.ts +6 -0
  195. package/examples/playground/app/a0/flags.ts +30 -0
  196. package/examples/playground/app/a0/fx/events/route.ts +9 -0
  197. package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
  198. package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
  199. package/examples/playground/app/a0/layout.tsx +38 -0
  200. package/examples/playground/app/a0/list/route.ts +10 -0
  201. package/examples/playground/app/a0/model.test.ts +73 -0
  202. package/examples/playground/app/a0/model.ts +95 -0
  203. package/examples/playground/app/a0/no-photon.cjs +4 -0
  204. package/examples/playground/app/a0/no-quickjs.cjs +3 -0
  205. package/examples/playground/app/a0/page.tsx +14 -0
  206. package/examples/playground/app/a0/pi/events/route.ts +9 -0
  207. package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
  208. package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
  209. package/examples/playground/app/a0/preview-pane.tsx +145 -0
  210. package/examples/playground/app/a0/preview.test.ts +53 -0
  211. package/examples/playground/app/a0/preview.ts +26 -0
  212. package/examples/playground/app/a0/sandbox-log.ts +75 -0
  213. package/examples/playground/app/a0/sandbox-session.ts +152 -0
  214. package/examples/playground/app/a0/sandbox.ts +191 -0
  215. package/examples/playground/app/a0/sandboxes/scheduler/route.ts +6 -0
  216. package/examples/playground/app/a0/scheduler/route.ts +7 -0
  217. package/examples/playground/app/a0/server.ts +213 -0
  218. package/examples/playground/app/a0/session.ts +59 -0
  219. package/examples/playground/app/a0/shell.tsx +158 -0
  220. package/examples/playground/app/a0/short/events/route.ts +9 -0
  221. package/examples/playground/app/a0/splitter.tsx +120 -0
  222. package/examples/playground/app/agent/[agentId]/agent-client.tsx +144 -174
  223. package/examples/playground/app/agent/[agentId]/command-receipt.test.tsx +65 -0
  224. package/examples/playground/app/agent/[agentId]/command-receipt.tsx +27 -0
  225. package/examples/playground/app/agent/[agentId]/compaction-event.tsx +25 -24
  226. package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +119 -0
  227. package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +208 -165
  228. package/examples/playground/app/agent/[agentId]/page.tsx +2 -16
  229. package/examples/playground/app/agent/events/route.ts +5 -2
  230. package/examples/playground/app/agent/ingress.test.ts +101 -0
  231. package/examples/playground/app/agent/model-input.test.tsx +58 -0
  232. package/examples/playground/app/agent/model-input.tsx +115 -0
  233. package/examples/playground/app/agent/model.test.ts +73 -0
  234. package/examples/playground/app/agent/model.ts +58 -26
  235. package/examples/playground/app/agent/new-agent-session.tsx +37 -19
  236. package/examples/playground/app/agent/page.tsx +4 -4
  237. package/examples/playground/app/agent/server.ts +19 -15
  238. package/examples/playground/app/agent/session.ts +5 -6
  239. package/examples/playground/app/agent/telemetry.test.ts +189 -0
  240. package/examples/playground/app/agent/telemetry.ts +30 -0
  241. package/examples/playground/app/agent/trace.test.ts +23 -0
  242. package/examples/playground/app/agent/trace.ts +18 -0
  243. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +12 -12
  244. package/examples/playground/app/canvas/[canvasId]/page.tsx +1 -2
  245. package/examples/playground/app/canvas/[canvasId]/session.ts +2 -2
  246. package/examples/playground/app/canvas/model.ts +53 -53
  247. package/examples/playground/app/chat/[chatId]/agent-state.test.ts +176 -0
  248. package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +16 -1
  249. package/examples/playground/app/chat/[chatId]/chat-client.tsx +55 -77
  250. package/examples/playground/app/chat/[chatId]/chat-view.ts +37 -3
  251. package/examples/playground/app/chat/[chatId]/page.tsx +7 -15
  252. package/examples/playground/app/chat/[chatId]/session.ts +2 -19
  253. package/examples/playground/app/chat/agent/route.ts +9 -0
  254. package/examples/playground/app/chat/model.test.ts +46 -119
  255. package/examples/playground/app/chat/model.ts +82 -128
  256. package/examples/playground/app/chat/scheduler/route.ts +2 -2
  257. package/examples/playground/app/chat/server.test.ts +112 -0
  258. package/examples/playground/app/chat/server.ts +113 -117
  259. package/examples/playground/app/components/activity-feed.tsx +30 -1
  260. package/examples/playground/app/components/activity-history.test.tsx +35 -0
  261. package/examples/playground/app/components/demo-icons.tsx +89 -0
  262. package/examples/playground/app/components/demos.tsx +33 -0
  263. package/examples/playground/app/components/fast-link.test.tsx +58 -0
  264. package/examples/playground/app/components/fast-link.tsx +55 -0
  265. package/examples/playground/app/components/site-header.tsx +96 -0
  266. package/examples/playground/app/counter/counter-client.tsx +3 -3
  267. package/examples/playground/app/counter/model.test.ts +3 -3
  268. package/examples/playground/app/counter/model.ts +11 -21
  269. package/examples/playground/app/counter/page.tsx +2 -15
  270. package/examples/playground/app/counter/session.ts +2 -2
  271. package/examples/playground/app/documents/[documentId]/code-editor.tsx +12 -1
  272. package/examples/playground/app/documents/[documentId]/document-client.tsx +10 -11
  273. package/examples/playground/app/documents/[documentId]/page.tsx +1 -2
  274. package/examples/playground/app/documents/[documentId]/session.ts +2 -2
  275. package/examples/playground/app/documents/model.ts +27 -27
  276. package/examples/playground/app/globals.css +420 -207
  277. package/examples/playground/app/initial-state.test.tsx +54 -0
  278. package/examples/playground/app/layout.tsx +7 -23
  279. package/examples/playground/app/orders/[orderId]/page.tsx +1 -2
  280. package/examples/playground/app/orders/[orderId]/session.ts +2 -2
  281. package/examples/playground/app/orders/model.ts +49 -49
  282. package/examples/playground/app/page.tsx +13 -102
  283. package/examples/playground/app/recovery/[recoveryId]/page.tsx +1 -2
  284. package/examples/playground/app/recovery/[recoveryId]/session.ts +2 -2
  285. package/examples/playground/app/recovery/model.ts +30 -30
  286. package/examples/playground/instrumentation.ts +5 -0
  287. package/examples/playground/next.config.ts +17 -5
  288. package/examples/playground/package.json +13 -2
  289. package/examples/playground/scripts/a0-template.ts +77 -0
  290. package/examples/playground/vercel.json +36 -0
  291. package/package.json +29 -3
  292. package/src/actor-client.ts +16 -4
  293. package/src/actor-react.ts +25 -11
  294. package/src/actor-shared.ts +21 -6
  295. package/src/actor.ts +76 -31
  296. package/src/ai-agent-actions.ts +219 -0
  297. package/src/ai-agent.ts +2517 -0
  298. package/src/ai-app-state.ts +91 -0
  299. package/src/ai-client-state.ts +6 -3
  300. package/src/ai-client.ts +62 -0
  301. package/src/ai-context-schema.ts +25 -5
  302. package/src/ai-context.ts +90 -40
  303. package/src/ai-control-server.ts +92 -72
  304. package/src/ai-coordinator.ts +23 -22
  305. package/src/ai-fx.browser.ts +5 -0
  306. package/src/ai-fx.ts +833 -0
  307. package/src/ai-harness.ts +518 -0
  308. package/src/ai-message-base.ts +209 -0
  309. package/src/ai-message-projection.ts +262 -64
  310. package/src/ai-model-metadata.ts +11 -6
  311. package/src/ai-pi.browser.ts +5 -0
  312. package/src/ai-pi.ts +1263 -0
  313. package/src/ai-progress-batches.ts +26 -0
  314. package/src/ai-projector.ts +95 -14
  315. package/src/ai-react.ts +146 -0
  316. package/src/ai-sdk-step.ts +2 -2
  317. package/src/ai-server.browser.ts +2 -2
  318. package/src/ai-server.ts +23 -1965
  319. package/src/ai-stored-state.ts +48 -163
  320. package/src/ai.ts +339 -155
  321. package/src/bootstrap-stream.ts +72 -0
  322. package/src/bounded-cache.ts +55 -0
  323. package/src/client-render-session.ts +49 -0
  324. package/src/client.ts +688 -151
  325. package/src/contract.ts +92 -42
  326. package/src/deterministic-id.ts +37 -0
  327. package/src/equal-json.ts +32 -0
  328. package/src/errors.ts +13 -1
  329. package/src/index.ts +5 -1
  330. package/src/initial-snapshot.ts +39 -0
  331. package/src/internal.ts +52 -0
  332. package/src/libfx.d.ts +34 -0
  333. package/src/postgres-notification-scope.ts +14 -3
  334. package/src/react.ts +171 -206
  335. package/src/redis-http-reply.ts +256 -0
  336. package/src/redis-http-stream.ts +73 -0
  337. package/src/redis-http-subscriptions.ts +13 -5
  338. package/src/reducer-runtime.ts +52 -0
  339. package/src/reducer.ts +93 -11
  340. package/src/scheduler-qstash.ts +49 -20
  341. package/src/scheduler-task.ts +34 -2
  342. package/src/scheduler-vercel.ts +32 -84
  343. package/src/server-fetch.ts +139 -35
  344. package/src/server.ts +1133 -255
  345. package/src/session-clear.ts +23 -0
  346. package/src/session-socket.ts +154 -49
  347. package/src/sse.ts +71 -4
  348. package/src/store-memory.ts +252 -75
  349. package/src/store-polling.ts +18 -4
  350. package/src/store-postgres.ts +541 -114
  351. package/src/store-redis-core.ts +1450 -493
  352. package/src/store-redis-http.ts +18 -2
  353. package/src/store-redis-notify.ts +262 -85
  354. package/src/store-redis.ts +19 -9
  355. package/src/store-sqlite.ts +319 -45
  356. package/src/store.ts +79 -1
  357. package/src/stream-buffer.ts +43 -0
  358. package/src/telemetry.ts +14 -1
  359. package/src/wire.ts +241 -13
  360. package/dist/actor-ohPC-81x.d.ts.map +0 -1
  361. package/dist/actor-shared-B5tJfzt-.js.map +0 -1
  362. package/dist/ai-CrEf6p_W.d.ts.map +0 -1
  363. package/dist/ai-DgOBltJ_.js.map +0 -1
  364. package/dist/client-BYzHjkwU.js.map +0 -1
  365. package/dist/client-CzyacQpJ.d.ts.map +0 -1
  366. package/dist/contract-CKRg_E4q.js.map +0 -1
  367. package/dist/errors-DCk6ch5n.js.map +0 -1
  368. package/dist/errors-DvhSXnxk.d.ts.map +0 -1
  369. package/dist/internal-Dq2qYxou.js.map +0 -1
  370. package/dist/react.d.ts.map +0 -1
  371. package/dist/reducer-DEMjEY_O.js +0 -29
  372. package/dist/reducer-DEMjEY_O.js.map +0 -1
  373. package/dist/reducer-otzHjuJj.d.ts.map +0 -1
  374. package/dist/scheduler-task-BpzhPnRS.js.map +0 -1
  375. package/dist/server-BD5ckxZb.js.map +0 -1
  376. package/dist/server-DbD7IJVK.d.ts.map +0 -1
  377. package/dist/store-DyZM6fS5.d.ts.map +0 -1
  378. package/dist/store-polling-CmxUbV93.js.map +0 -1
  379. package/dist/store-redis-notify-BVLUfI3j.js +0 -1583
  380. package/dist/store-redis-notify-BVLUfI3j.js.map +0 -1
  381. package/dist/telemetry-B5jzpy6y.d.ts.map +0 -1
  382. package/dist/validate-XKT4FSNn.js +0 -30
  383. package/dist/validate-XKT4FSNn.js.map +0 -1
  384. package/dist/wire-BO5wWCb1.js.map +0 -1
  385. package/docs/concepts/01-contracts.mdx +0 -142
  386. package/docs/concepts/02-handlers.mdx +0 -284
  387. package/docs/concepts/03-durability.mdx +0 -314
  388. package/docs/concepts/04-state.mdx +0 -209
  389. package/docs/guides/01-timers.mdx +0 -185
  390. package/docs/guides/02-cancellation.mdx +0 -161
  391. package/docs/guides/03-react.mdx +0 -384
  392. package/docs/guides/04-local-first.mdx +0 -88
  393. package/docs/guides/05-production.mdx +0 -521
  394. package/docs/guides/06-ai-agents.mdx +0 -1318
  395. package/docs/guides/08-application-data.mdx +0 -113
  396. package/docs/guides/09-presence.mdx +0 -266
  397. package/docs/guides/10-transports.mdx +0 -221
  398. package/docs/reference/01-api.mdx +0 -1896
  399. package/docs/reference/02-errors.mdx +0 -149
  400. package/examples/playground/app/agent/[agentId]/compaction/route.ts +0 -14
  401. package/examples/playground/app/agent/compaction-settings.test.ts +0 -144
  402. package/examples/playground/app/agent/compaction-settings.ts +0 -49
  403. package/examples/playground/app/agent/compaction-timeline.test.ts +0 -377
  404. package/examples/playground/app/agent/compaction-timeline.ts +0 -208
  405. /package/docs/{concepts → contract}/meta.ts +0 -0
  406. /package/docs/{guides → server}/meta.ts +0 -0
@@ -0,0 +1,23 @@
1
+ import { A2Error } from './errors.ts'
2
+ import type { Event } from './store.ts'
3
+
4
+ /** A2's own event types start with this; application contracts cannot. */
5
+ export const RESERVED_EVENT_PREFIX = 'a2.'
6
+
7
+ /** Reserved type of the marker a clear appends. */
8
+ export const CLEAR_EVENT_TYPE = 'a2.cleared'
9
+
10
+ /** The marker `session.stream()` yields where a clear ended a lifetime. */
11
+ export type SessionCleared = Event & {
12
+ type: typeof CLEAR_EVENT_TYPE
13
+ payload: null
14
+ }
15
+
16
+ /** Accepts any stream item, including presence patches and snapshots. */
17
+ export function isSessionCleared(item: object): item is SessionCleared {
18
+ return (item as { type?: unknown }).type === CLEAR_EVENT_TYPE
19
+ }
20
+
21
+ export function sessionClearedError(message: string): A2Error {
22
+ return new A2Error('SESSION_CLEARED', message)
23
+ }
@@ -15,10 +15,18 @@ import type { ParsedPushEvent, ParsedPushPresence } from './push-envelope.ts'
15
15
  import type { Session } from './server.ts'
16
16
  import { parsePresenceSibling, parsePushEvents } from './push-envelope.ts'
17
17
  import {
18
+ type StateSnapshotFrame,
19
+ type SocketSubscribeEntry,
20
+ type SubscriptionStart,
21
+ type WireVersion,
18
22
  SOCKET_PING_FRAME,
19
23
  asA2Error,
24
+ compactEventJson,
25
+ heldEventBatch,
26
+ isStreamEvent,
20
27
  socketAckFor,
21
28
  socketErrorAckFor,
29
+ socketEventsFor,
22
30
  socketFrameFor,
23
31
  socketSubscribedFor,
24
32
  socketUnsubscribedFor,
@@ -78,7 +86,9 @@ export type SocketSession = {
78
86
  stream(opts: {
79
87
  startAfter: number
80
88
  presence?: boolean
81
- }): AsyncIterable<Event | PresencePatch | PresenceSnapshot>
89
+ }): AsyncIterable<
90
+ Event | PresencePatch | PresenceSnapshot | StateSnapshotFrame
91
+ >
82
92
  append(...events: ParsedPushEvent[]): Promise<Event[]>
83
93
  setPresence?(patch: ParsedPushPresence): Promise<void>
84
94
  }
@@ -238,8 +248,12 @@ export type SessionsSocketResolve<D extends EventDefs> = (
238
248
  sessionId: string,
239
249
  /** The entry's resume frontier — `stream({ startAfter })`. */
240
250
  startAfter: number,
251
+ selection?: SubscriptionStart,
241
252
  ) =>
242
- Pick<Session<D>, 'stream'> | null | Promise<Pick<Session<D>, 'stream'> | null>
253
+ | Pick<Session<D>, 'stream'>
254
+ | Pick<SocketSession, 'stream'>
255
+ | null
256
+ | Promise<Pick<Session<D>, 'stream'> | Pick<SocketSession, 'stream'> | null>
243
257
 
244
258
  export type SessionsSocketOptions = {
245
259
  /** The `stream()` presence opt-in for every session on the socket —
@@ -248,6 +262,8 @@ export type SessionsSocketOptions = {
248
262
  /** Epoch ms: close cleanly (code 1000) at this time, ahead of a known
249
263
  * platform deadline, so clients reconnect on our schedule. */
250
264
  deadline?: number
265
+ /** `2` sends live events as `events` batches (the client's `wire=2`). */
266
+ wire?: WireVersion
251
267
  /** Runs after frame parsing and before append or presence I/O. */
252
268
  gatePush?(
253
269
  sessionId: string,
@@ -262,32 +278,48 @@ export type SessionSocketOptions = SessionsSocketOptions & {
262
278
 
263
279
  type SocketSubscription = {
264
280
  target: SocketSession
265
- iterator: AsyncIterator<Event | PresencePatch | PresenceSnapshot>
281
+ iterator: AsyncIterator<
282
+ Event | PresencePatch | PresenceSnapshot | StateSnapshotFrame
283
+ >
266
284
  stopped: boolean
285
+ attempt?: number
267
286
  }
268
287
 
269
- const socketSubscription = (
270
- target: SocketSession,
271
- startAfter: number,
272
- presence: boolean,
273
- ): SocketSubscription => ({
274
- target,
275
- iterator: (presence
276
- ? target.stream({ startAfter, presence: true })
277
- : target.stream({ startAfter }))[Symbol.asyncIterator](),
278
- stopped: false,
279
- })
288
+ const socketSubscription = (options: {
289
+ target: SocketSession
290
+ startAfter: number
291
+ presence: boolean
292
+ attempt?: number | undefined
293
+ }): SocketSubscription => {
294
+ const { target, startAfter, presence, attempt } = options
295
+ return {
296
+ target,
297
+ iterator: (presence
298
+ ? target.stream({ startAfter, presence: true })
299
+ : target.stream({ startAfter }))[Symbol.asyncIterator](),
300
+ stopped: false,
301
+ ...(attempt === undefined ? {} : { attempt }),
302
+ }
303
+ }
280
304
 
281
305
  const stopSubscription = (subscription: SocketSubscription): void => {
282
306
  subscription.stopped = true
283
307
  void subscription.iterator.return?.()?.catch(() => {})
284
308
  }
285
309
 
286
- const pumpSubscription = async (
287
- shell: SocketShell,
288
- subscription: SocketSubscription,
289
- frameFor: (item: Event | PresencePatch | PresenceSnapshot) => string,
290
- ): Promise<void> => {
310
+ /**
311
+ * Sends a subscription's items until it ends. With `batch`, an event and
312
+ * the events its iterator already holds go out as one frame.
313
+ */
314
+ const pumpSubscription = async (options: {
315
+ shell: SocketShell
316
+ subscription: SocketSubscription
317
+ frameFor: (
318
+ item: Event | PresencePatch | PresenceSnapshot | StateSnapshotFrame,
319
+ ) => string
320
+ batch?: (events: string[]) => string
321
+ }): Promise<void> => {
322
+ const { shell, subscription, frameFor, batch } = options
291
323
  for (;;) {
292
324
  while (
293
325
  !shell.torn() &&
@@ -301,7 +333,16 @@ const pumpSubscription = async (
301
333
  // oxlint-disable-next-line no-await-in-loop -- stream pump
302
334
  const { value, done } = await subscription.iterator.next()
303
335
  if (shell.torn() || subscription.stopped || done) return
304
- shell.send(frameFor(value))
336
+ if (!batch || !isStreamEvent(value)) {
337
+ shell.send(frameFor(value))
338
+ continue
339
+ }
340
+ const { events } = heldEventBatch({
341
+ first: value,
342
+ iterator: subscription.iterator,
343
+ encode: compactEventJson,
344
+ })
345
+ shell.send(batch(events))
305
346
  }
306
347
  }
307
348
 
@@ -370,16 +411,16 @@ const applySocketPresence = async (
370
411
 
371
412
  export function sessionSocket<D extends EventDefs>(
372
413
  sessionId: string,
373
- session: Pick<Session<D>, 'stream'>,
414
+ session: Pick<Session<D>, 'stream'> | Pick<SocketSession, 'stream'>,
374
415
  socket: A2Socket,
375
416
  options?: SessionSocketOptions,
376
417
  ): void {
377
418
  const target = session as unknown as SocketSession
378
- const subscription = socketSubscription(
419
+ const subscription = socketSubscription({
379
420
  target,
380
- options?.startAfter ?? 0,
381
- options?.presence === true,
382
- )
421
+ startAfter: options?.startAfter ?? 0,
422
+ presence: options?.presence === true,
423
+ })
383
424
 
384
425
  const handleFrame = (frame: Record<string, unknown>): void => {
385
426
  switch (frame['kind']) {
@@ -458,7 +499,14 @@ export function sessionSocket<D extends EventDefs>(
458
499
  options?.deadline,
459
500
  )
460
501
 
461
- void pumpSubscription(shell, subscription, socketFrameFor).then(
502
+ void pumpSubscription({
503
+ shell,
504
+ subscription,
505
+ frameFor: socketFrameFor,
506
+ ...(options?.wire === 2
507
+ ? { batch: (events) => socketEventsFor(events) }
508
+ : {}),
509
+ }).then(
462
510
  () => shell.shutdown(1000),
463
511
  () => shell.shutdown(1011, 'stream failed'),
464
512
  )
@@ -466,17 +514,46 @@ export function sessionSocket<D extends EventDefs>(
466
514
 
467
515
  const parseSubscribeEntries = (
468
516
  value: unknown,
469
- ): Array<{ id: string; index: number }> | null => {
517
+ ): SocketSubscribeEntry[] | null => {
470
518
  if (!Array.isArray(value) || value.length === 0) return null
471
- const entries: Array<{ id: string; index: number }> = []
519
+ const entries: SocketSubscribeEntry[] = []
472
520
  for (const entry of value) {
473
521
  if (entry === null || typeof entry !== 'object') return null
474
- const { id, index } = entry as Record<string, unknown>
522
+ const { id, attempt, index, bootstrap, reducer } = entry as Record<
523
+ string,
524
+ unknown
525
+ >
475
526
  if (typeof id !== 'string' || id.length === 0) return null
476
- if (typeof index !== 'number' || !Number.isInteger(index) || index < 0) {
527
+ if (
528
+ attempt !== undefined &&
529
+ (typeof attempt !== 'number' ||
530
+ !Number.isSafeInteger(attempt) ||
531
+ attempt < 0)
532
+ )
477
533
  return null
534
+ if (
535
+ reducer !== undefined &&
536
+ (typeof reducer !== 'string' || reducer.length === 0)
537
+ )
538
+ return null
539
+ const lane = { id, ...(attempt === undefined ? {} : { attempt }) }
540
+ if (bootstrap === true) {
541
+ if (index !== undefined || typeof reducer !== 'string') return null
542
+ entries.push({ ...lane, bootstrap: true, reducer })
543
+ } else {
544
+ if (
545
+ bootstrap !== undefined ||
546
+ typeof index !== 'number' ||
547
+ !Number.isSafeInteger(index) ||
548
+ index < 0
549
+ )
550
+ return null
551
+ entries.push({
552
+ ...lane,
553
+ index,
554
+ ...(reducer === undefined ? {} : { reducer: reducer as string }),
555
+ })
478
556
  }
479
- entries.push({ id, index })
480
557
  }
481
558
  return entries
482
559
  }
@@ -509,53 +586,81 @@ export function sessionsSocket<D extends EventDefs>(
509
586
  id: string,
510
587
  subscription: SocketSubscription,
511
588
  ): Promise<void> => {
589
+ const { attempt } = subscription
512
590
  try {
513
- await pumpSubscription(shell, subscription, (item) =>
514
- socketFrameFor(item, id),
515
- )
591
+ await pumpSubscription({
592
+ shell,
593
+ subscription,
594
+ frameFor: (item) => socketFrameFor(item, id),
595
+ ...(options?.wire === 2
596
+ ? { batch: (events) => socketEventsFor(events, id) }
597
+ : {}),
598
+ })
516
599
  if (shell.torn() || subscription.stopped) return
517
600
  retire(id, subscription)
518
- shell.send(socketUnsubscribedFor(id))
601
+ shell.send(socketUnsubscribedFor({ sessionId: id, attempt }))
519
602
  } catch (error) {
520
603
  if (shell.torn() || subscription.stopped) return
521
604
  retire(id, subscription)
522
- shell.send(socketUnsubscribedFor(id, 'stream failed', asA2Error(error)))
605
+ shell.send(
606
+ socketUnsubscribedFor({
607
+ sessionId: id,
608
+ attempt,
609
+ reason: 'stream failed',
610
+ error: asA2Error(error),
611
+ }),
612
+ )
523
613
  }
524
614
  }
525
615
 
526
616
  const startSubscription = async (
527
- id: string,
528
- index: number,
617
+ entry: SocketSubscribeEntry,
529
618
  ): Promise<void> => {
619
+ const { id, attempt } = entry
620
+ const index = entry.index ?? 0
530
621
  const existing = subscriptions.get(id)
531
622
  if (existing) {
532
623
  stopSubscription(existing)
533
624
  subscriptions.delete(id)
534
625
  }
535
- let session: Pick<Session<D>, 'stream'> | null
626
+ let session:
627
+ Pick<Session<D>, 'stream'> | Pick<SocketSession, 'stream'> | null
536
628
  try {
537
- session = await resolve(id, index)
629
+ session = await resolve(id, index, entry)
538
630
  } catch (error) {
539
631
  if (!shell.torn()) {
540
- shell.send(socketUnsubscribedFor(id, 'stream failed', asA2Error(error)))
632
+ shell.send(
633
+ socketUnsubscribedFor({
634
+ sessionId: id,
635
+ attempt,
636
+ reason: 'stream failed',
637
+ error: asA2Error(error),
638
+ }),
639
+ )
541
640
  }
542
641
  return
543
642
  }
544
643
  if (shell.torn()) return
545
644
  if (session === null) {
546
645
  shell.send(
547
- socketUnsubscribedFor(
548
- id,
549
- 'subscribe rejected',
550
- new A2Error('FORBIDDEN', 'the subscription is not authorized'),
551
- ),
646
+ socketUnsubscribedFor({
647
+ sessionId: id,
648
+ attempt,
649
+ reason: 'subscribe rejected',
650
+ error: new A2Error('FORBIDDEN', 'the subscription is not authorized'),
651
+ }),
552
652
  )
553
653
  return
554
654
  }
555
655
  const target = session as unknown as SocketSession
556
- const subscription = socketSubscription(target, index, presence)
656
+ const subscription = socketSubscription({
657
+ target,
658
+ startAfter: index,
659
+ presence,
660
+ attempt,
661
+ })
557
662
  subscriptions.set(id, subscription)
558
- shell.send(socketSubscribedFor(id))
663
+ shell.send(socketSubscribedFor({ sessionId: id, attempt }))
559
664
  void runSubscription(id, subscription)
560
665
  }
561
666
 
@@ -628,7 +733,7 @@ export function sessionsSocket<D extends EventDefs>(
628
733
  return
629
734
  }
630
735
  for (const entry of entries) {
631
- control(() => startSubscription(entry.id, entry.index))
736
+ control(() => startSubscription(entry))
632
737
  }
633
738
  return
634
739
  }
package/src/sse.ts CHANGED
@@ -12,14 +12,31 @@ import type { PresencePatch, PresenceSnapshot } from './contract.ts'
12
12
  import { invocationDeadlineMs } from './platform.ts'
13
13
  import { streamActivities } from './stream-activity.ts'
14
14
  import {
15
+ isSerializedEvent,
16
+ parseSerializedEvent,
17
+ takeBuffered,
18
+ type HeldEvent,
19
+ } from './stream-buffer.ts'
20
+ import {
21
+ type StateSnapshotFrame,
22
+ type WireVersion,
23
+ EVENT_WRITE_CHARS,
24
+ compactEventJson,
25
+ heldEventBatch,
26
+ isStreamEvent,
27
+ stateSnapshotToWire,
15
28
  eventToWire,
29
+ serializedEventToWireJson,
16
30
  presencePatchToWire,
17
31
  presenceSnapshotToWire,
18
32
  } from './wire.ts'
19
33
 
20
34
  /**
21
35
  * Pipe a live event iterable into an SSE `Response`. Each event is one
22
- * frame — `id:` carries the event-log index, `data:` the JSON event. A
36
+ * frame — `id:` carries the event-log index, `data:` the JSON event.
37
+ * Frames for events the iterable already holds are written together. With
38
+ * `wire: 2` those events share one frame instead: `data:` is a JSON array of
39
+ * `CompactWireEvent`s and `id:` the last one's index. A
23
40
  * `stream({ presence: true })` iterable also yields presence items,
24
41
  * which ride as named frames old clients skip: `event:
25
42
  * presence-snapshot` first (the map, ISO dates), then `event: presence`
@@ -34,8 +51,12 @@ import {
34
51
  * a platform-timeout failure.
35
52
  */
36
53
  export function sseResponse(
37
- iterable: AsyncIterable<Event | PresencePatch | PresenceSnapshot>,
54
+ iterable: AsyncIterable<
55
+ Event | PresencePatch | PresenceSnapshot | StateSnapshotFrame
56
+ >,
57
+ options: { wire?: WireVersion } = {},
38
58
  ): Response {
59
+ const write = options.wire === 2 ? batchedFrames : eventFrames
39
60
  const iterator = iterable[Symbol.asyncIterator]()
40
61
  const encoder = new TextEncoder()
41
62
  let heartbeat: ReturnType<typeof setInterval> | undefined
@@ -121,7 +142,7 @@ export function sseResponse(
121
142
  controller.close()
122
143
  return
123
144
  }
124
- controller.enqueue(encoder.encode(frameFor(value)))
145
+ controller.enqueue(encoder.encode(write(value, iterator)))
125
146
  } catch (error) {
126
147
  if (closed) return
127
148
  closed = true
@@ -147,12 +168,58 @@ export function sseResponse(
147
168
  })
148
169
  }
149
170
 
150
- function frameFor(item: Event | PresencePatch | PresenceSnapshot): string {
171
+ type StreamItem =
172
+ HeldEvent | PresencePatch | PresenceSnapshot | StateSnapshotFrame
173
+
174
+ /** Version 1: one frame per event, then each event the iterator holds. */
175
+ function eventFrames(first: StreamItem, iterator: object): string {
176
+ let frames = frameFor(first)
177
+ while (frames.length < EVENT_WRITE_CHARS) {
178
+ const event = takeBuffered(iterator)
179
+ if (!event) break
180
+ frames += frameFor(event)
181
+ }
182
+ return frames
183
+ }
184
+
185
+ /**
186
+ * Version 2: events this write carries share one frame, a JSON array whose
187
+ * `id:` is its last index. Held events are always events, so only `first`
188
+ * can be a snapshot or presence frame.
189
+ */
190
+ function batchedFrames(first: StreamItem, iterator: object): string {
191
+ const lead = isStreamEvent(first) ? '' : frameFor(first)
192
+ const head = isStreamEvent(first) ? first : takeBuffered(iterator)
193
+ if (!head) return lead
194
+ const { events, last } = heldEventBatch({
195
+ first: head,
196
+ iterator,
197
+ encode: compactJsonLine,
198
+ })
199
+ return `${lead}id: ${last.index}\ndata: [${events.join(',')}]\n\n`
200
+ }
201
+
202
+ // JSON.stringify output has no raw line breaks; any other stored text is
203
+ // re-serialized so it stays on its data: line.
204
+ const compactJsonLine = (event: HeldEvent): string =>
205
+ isSerializedEvent(event) && /[\r\n]/.test(event.payloadJson)
206
+ ? compactEventJson(parseSerializedEvent(event))
207
+ : compactEventJson(event)
208
+
209
+ function frameFor(item: StreamItem): string {
210
+ if ('kind' in item)
211
+ return `event: a2-snapshot\ndata: ${JSON.stringify(stateSnapshotToWire(item))}\n\n`
151
212
  if ('snapshot' in item) {
152
213
  return `event: presence-snapshot\ndata: ${JSON.stringify(presenceSnapshotToWire(item))}\n\n`
153
214
  }
154
215
  if ('participant' in item) {
155
216
  return `event: presence\ndata: ${JSON.stringify(presencePatchToWire(item))}\n\n`
156
217
  }
218
+ // JSON.stringify output has no raw line breaks; any other stored text is
219
+ // re-serialized so it stays on its data: line.
220
+ if (isSerializedEvent(item))
221
+ return /[\r\n]/.test(item.payloadJson)
222
+ ? `id: ${item.index}\ndata: ${JSON.stringify(eventToWire(parseSerializedEvent(item)))}\n\n`
223
+ : `id: ${item.index}\ndata: ${serializedEventToWireJson(item)}\n\n`
157
224
  return `id: ${item.index}\ndata: ${JSON.stringify(eventToWire(item))}\n\n`
158
225
  }