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
@@ -1,209 +0,0 @@
1
- ---
2
- title: Reading state
3
- description: "A session's state is a fold over its log: raw history when you want facts, a reducer when you want the current view."
4
- ---
5
-
6
- ## History
7
-
8
- ```ts
9
- // anywhere on the server:
10
- const events = await ordersServer.session(orderId).history()
11
- ```
12
-
13
- Everything that happened in this session, oldest first. Always the raw log,
14
- never a summary, never a snapshot. This is the session's audit trail and
15
- debugging story, and it is also fine to use inside handlers for questions like
16
- "did the shop already start?" Pass inclusive `gte` or `lte` indexes to read a
17
- bounded slice.
18
-
19
- ## Reducers
20
-
21
- For a computed view, derive a reducer from the contract and fold:
22
-
23
- ```ts contracts.ts
24
- import { z } from 'zod'
25
- import * as a2 from 'experimental-a2'
26
-
27
- export const orders = a2.contract({
28
- name: 'orders',
29
- events: {
30
- created: z.object({ shopId: z.string(), items: z.array(z.string()) }),
31
- 'shop.notified': z.object({}),
32
- expired: z.object({}),
33
- },
34
- })
35
- ```
36
-
37
- ```ts reducer.ts
38
- import { z } from 'zod'
39
- import { orders } from './contracts'
40
-
41
- export const ordersReducer = orders
42
- .reducer({
43
- name: 'order-status',
44
- initialState: { status: 'new' },
45
- stateSchema: z.object({
46
- status: z.enum(['new', 'created', 'notified', 'expired']),
47
- shopId: z.string().optional(),
48
- }),
49
- })
50
- .fold((state, event) => {
51
- switch (event.type) {
52
- case 'created':
53
- return { status: 'created', shopId: event.payload.shopId }
54
- case 'shop.notified':
55
- return { ...state, status: 'notified' }
56
- case 'expired':
57
- return { ...state, status: 'expired' }
58
- default:
59
- return state
60
- }
61
- })
62
- ```
63
-
64
- ```ts
65
- // anywhere on the server, e.g. a server component before first paint:
66
- const { state, index } = await ordersServer
67
- .session(orderId)
68
- .state(ordersReducer)
69
- ```
70
-
71
- Handlers receive the same session interface for their triggering session:
72
-
73
- ```ts server.ts
74
- import { createServer } from 'experimental-a2/server'
75
- import { orders } from './contracts'
76
- import { ordersReducer } from './reducer'
77
-
78
- export const ordersServer = createServer({
79
- contract: orders,
80
- handlers: {
81
- created: async ({ session }) => {
82
- const { state, index } = await session.state(ordersReducer)
83
- void state
84
- void index
85
- },
86
- },
87
- })
88
- ```
89
-
90
- A reducer is a name (its identity, more on that below), `initialState`, an
91
- optional `stateSchema`, and the pure `fold`, `(state, event) => state`. It is
92
- derived from the contract, so the events type themselves; the two-step shape
93
- fixes the state and event types before `.fold()` receives them. No type
94
- arguments or annotations are needed, and literal unions survive the fold.
95
- `state()` returns the result with `index`, the last log position included. The
96
- fold includes every event through that index and none after it. The browser
97
- resumes its live stream from that boundary. See [Live UI](/guides/react).
98
-
99
- A root session reads the latest committed frontier by default. A handler's
100
- session is causally scoped, so the same call stops at its triggering event:
101
-
102
- ```ts causal-server.ts
103
- import { createServer } from 'experimental-a2/server'
104
- import { orders } from './contracts'
105
- import { ordersReducer } from './reducer'
106
-
107
- export const causalOrdersServer = createServer({
108
- contract: orders,
109
- handlers: {
110
- created: async ({ event, session }) => {
111
- const atTrigger = await session.state(ordersReducer)
112
- // atTrigger.index === event.index
113
-
114
- const current = await session.state(ordersReducer, {
115
- through: 'latest',
116
- })
117
- void current
118
- },
119
- },
120
- })
121
- ```
122
-
123
- The trigger boundary is stable across concurrent appends and retries. Use the
124
- explicit latest read for joins or other logic that intentionally observes later
125
- events. A numeric `{ through: index }` reads any inclusive log boundary;
126
- `through: 0` returns `initialState`.
127
-
128
- A bounded handler read also keeps that exact folded checkpoint available while
129
- the triggering event is unfinished. This is automatic. When concurrent work
130
- advances the reducer's latest snapshot, A2 retains the older checkpoint until
131
- every handler event using it completes or dead-letters. There is no TTL, history
132
- limit, or retention setting to tune.
133
-
134
- Root reads and handler reads with `{ through: 'latest' }` do not retain
135
- historical checkpoints. A root numeric read can use an older checkpoint that an
136
- active handler already retained, but querying an old boundary does not keep it
137
- around or write a stale snapshot behind the current head. If no suitable
138
- checkpoint exists, A2 folds the bounded log.
139
-
140
- The snapshot and its remaining event tail come back in one consistent store
141
- operation. A missing snapshot or one rejected by `stateSchema` rebuilds from the
142
- log. An operational storage-read failure propagates with its backend diagnostics;
143
- it does not trigger a full-log read. Existing A2 errors pass through, and other
144
- errors become `STORE_UNAVAILABLE` with the original error as their cause.
145
- `state()` is observational: it never runs handlers or waits for pending work.
146
- Its index marks committed history, not handler completion.
147
-
148
- A latest read and a following `ctx.session.append(name, ...events)` are separate
149
- operations. Concurrent appends and retries can move the frontier between them.
150
- For joins, read with `{ through: 'latest' }`, use a monotone readiness check
151
- (once ready, always ready), and give the output event a stable explicit `id`.
152
- Repeated attempts then converge on the same append.
153
-
154
- `stateSchema` declares the state's shape once. Without it, the state type
155
- is inferred from `initialState`, fine while every fold arm returns the
156
- same shape. With it, the schema is the type (and the seed may lean on its
157
- defaults), `initialState` is validated at definition, and anywhere A2
158
- rehydrates folded state instead of refolding raw events, [server
159
- snapshots](#snapshots-are-a-cache), the [browser
160
- cache](/guides/local-first): a cached fold that fails the schema is
161
- discarded and refolded, catching shape drift a stale `name` can't.
162
-
163
- Note what these modules import: schemas and `experimental-a2`. Never `experimental-a2/server`,
164
- never a store backend. Contract and reducer are isomorphic by
165
- construction; the browser runs the same reducer. More on the split in
166
- [Live UI](/guides/react#keep-the-backend-out-of-the-bundle). (In a
167
- server-only app you can keep the contract next to `createServer`
168
- instead of in its own file.)
169
-
170
- ## Snapshots are a cache
171
-
172
- Folding a long session on every read would get slow, so the store backend
173
- caches folded state as a snapshot. You never interact with it, except for
174
- one string.
175
-
176
- Each session and reducer has one latest snapshot. Older snapshots exist only
177
- while unfinished handler events need their exact state boundary. Handler
178
- completion and dead-lettering release those references in the same store
179
- operation and remove any historical snapshot with no remaining reader. Several
180
- handlers can share one checkpoint; it stays until the last reference leaves.
181
-
182
- Snapshots are keyed by the reducer's `name`, which makes the name do two
183
- jobs. It's the identity: two different reducers over the same session
184
- never fight over a cache entry, because they have different names. And
185
- it's the invalidation knob. Changed the fold's logic? Change the name (a
186
- `-v2` suffix works). Snapshots stored under the old name are simply
187
- ignored; the next read refolds from raw events and caches under the new
188
- name. That's the entire cache invalidation story: one string.
189
-
190
- Snapshot write-back runs in platform `waitUntil` after the state is ready. One
191
- same-tick group of reads for a reducer and session reads the widest required log
192
- range once, folds it once, and writes the needed prefixes together. A failed cache
193
- write does not fail the completed state read. A2 reports it through the
194
- `a2.snapshot` telemetry span, or `console.error` by default, with session, reducer,
195
- checkpoint index, and batch count. It does not attach snapshot contents. The next
196
- read folds the missing tail again.
197
-
198
- Deleting every snapshot is always safe. The log rebuilds them.
199
-
200
- ## Events don't change meaning
201
-
202
- The log is append-only, and events are immutable in meaning: `created`
203
- means forever what it meant when it was written. When a payload needs a new
204
- shape, add a new event type (`created.v2`) rather than redefining the old
205
- one.
206
-
207
- This is why reducers accumulate switch cases over time, and why they never
208
- migrate anything: old sessions keep their old events, new sessions write
209
- new ones, and the same fold handles both.
@@ -1,185 +0,0 @@
1
- ---
2
- title: Timers and delays
3
- description: Schedule a typed session event for later with the same adapter that handles recovery.
4
- ---
5
-
6
- ## Schedule from a handler
7
-
8
- Configure one scheduler for the server, then call
9
- `session.schedule(name, timing, ...events)`. This schedules an `expired` event
10
- for five days after the durable `created` event:
11
-
12
- ```ts server/orders.ts
13
- import { createServer } from 'experimental-a2/server'
14
- import { vercelQueues } from 'experimental-a2/scheduler-vercel'
15
- import { orders } from '@/contracts'
16
-
17
- export const scheduler = vercelQueues()
18
-
19
- export const ordersServer = createServer({
20
- contract: orders,
21
- scheduler,
22
- handlers: {
23
- created: async ({ session }) => {
24
- await session.schedule(
25
- 'expire-order',
26
- { delay: '5d' },
27
- { type: 'expired', payload: {} },
28
- )
29
- },
30
- expired: async ({ session }) => {
31
- const events = await session.history()
32
- if (events.some((event) => event.type === 'shop.started')) return
33
- // your expiry side effect goes here
34
- },
35
- },
36
- })
37
- ```
38
-
39
- The same scheduler route handles recovery watchdogs and scheduled events. Mount
40
- it once as shown in
41
- [Going to production](/guides/production#2-add-a-scheduler-for-handlers-and-timers).
42
-
43
- `timing` is exactly one of these shapes:
44
-
45
- ```ts
46
- // anywhere on the server:
47
- type ScheduleTiming =
48
- | { delay: `${number}${'ms' | 's' | 'm' | 'h' | 'd'}`; at?: never }
49
- | { at: Date; delay?: never }
50
- ```
51
-
52
- The template type checks the unit suffix. At runtime, the number must be an
53
- unsigned base-10 decimal without leading zeros, finite, and greater than zero.
54
- A2 rejects `0s`, signs, exponent notation, malformed strings, and invalid
55
- dates.
56
-
57
- The requested target is the earliest useful delivery time, not an exact
58
- execution deadline. Adapters encode provider timing in whole-second slots. A
59
- target that is already due publishes immediately.
60
-
61
- The call awaits provider acceptance and returns `void`. No event enters the
62
- store until the scheduler delivers the task.
63
-
64
- ## Schedule from ordinary server code
65
-
66
- Root sessions expose the same method. Use `{ at }` when a caller may retry and
67
- the target time must stay fixed:
68
-
69
- ```ts app/api/trials/route.ts
70
- import { z } from 'zod'
71
- import { ordersServer } from '@/server/orders'
72
-
73
- const scheduleTrial = z.object({
74
- orderId: z.string(),
75
- expiresAt: z.iso.datetime().transform((value) => new Date(value)),
76
- })
77
-
78
- export async function POST(request: Request) {
79
- const body = scheduleTrial.parse(await request.json())
80
- await ordersServer.session(body.orderId).schedule(
81
- 'expire-order',
82
- { at: body.expiresAt },
83
- { type: 'expired', payload: {} },
84
- )
85
- return Response.json({ scheduled: true }, { status: 202 })
86
- }
87
- ```
88
-
89
- A root `{ delay: '30s' }` starts from the wall clock captured by that call. A
90
- retry 10 seconds later calculates a delivery 10 seconds later too. An absolute
91
- `{ at }` preserves the original target. Inside a handler, relative delays are
92
- already retry-stable: A2 anchors them to the triggering event's durable
93
- `createdAt`, not the retry's clock.
94
-
95
- ## Identity and retries
96
-
97
- `name` identifies one logical schedule. On a root session its scope is the
98
- contract and session. In a handler it also includes the triggering event id, so
99
- different events can both use a local name such as `expire-order` while retries
100
- of one event converge.
101
-
102
- Keep the same name, timing, and events on every retry. A2 derives stable ids for
103
- events whose `id` you omit. Provider deduplication folds repeated sends while
104
- its deduplication window is open. After that window, duplicate deliveries
105
- still append once because they carry the same event ids. A changed input under
106
- the same identity conflicts when it produces a different validated event at
107
- delivery.
108
-
109
- A2 does not store a timer-intent registry, so it cannot compare every retry
110
- with the first call before sending. The stable provider task and event ids are
111
- the durable convergence mechanism.
112
-
113
- ## What arrives later
114
-
115
- Scheduled payloads travel inside the provider message. Before validation, A2
116
- snapshots each payload into the same plain JSON tree the provider will deliver.
117
- Encode a `Date` as an ISO string and a custom class as explicit JSON data. A2
118
- rejects `undefined`, functions, symbols, bigint values, cycles, accessors, and
119
- non-plain prototypes. Shared object references become independent JSON values;
120
- reference identity is not part of a scheduled payload. The task carries that
121
- snapshotted schema input. At delivery, A2 validates it through
122
- an ordinary top-level append with fixed ids. A schema transform produces the
123
- stored payload from that original input, rather than receiving its earlier
124
- validation output as new input.
125
-
126
- That means scheduled events:
127
-
128
- - enter the log only when delivered;
129
- - have `cause: null`, like an ordinary server append;
130
- - run handlers and lanes normally;
131
- - update reducers, streams, and live clients normally; and
132
- - tolerate at-least-once delivery through their stable ids.
133
-
134
- If the deployment receiving a timer removes or changes its event schema,
135
- delivery can fail validation and remain visible as a retrying scheduler error.
136
- Vercel Queues pins timers to their publishing deployment by default. This
137
- cross-deployment compatibility concern applies when
138
- `scheduledAppends: 'deploymentless'` is selected and to adapters that target a
139
- stable URL, such as QStash.
140
-
141
- ## Stale timers
142
-
143
- The order shipped on day two. Its expiry event still arrives on day five. The
144
- recommended pattern is the guard in the first example: let the event land, read
145
- the session, and return when it no longer applies. The log still records the
146
- fact that the timer fired.
147
-
148
- A2 has no cancellation, reschedule, cron, or timer-listing API. `name` is an
149
- idempotency key, not a handle. Model repeated schedules as session events and
150
- have a handler schedule the next occurrence explicitly.
151
-
152
- ## Provider limits
153
-
154
- One scheduled task must fit the active provider's maximum delay:
155
-
156
- | Adapter | Maximum one-shot delay |
157
- | --- | --- |
158
- | Vercel Queues | 6 days |
159
- | QStash free | 7 days |
160
- | QStash usage-based | 1 year |
161
- | QStash fixed | no fixed maximum |
162
-
163
- These are provider limits. A2 does not silently split a longer delay into
164
- several tasks. Vercel Queues retains the message for seven days; A2 reserves
165
- the final day for delivery and retries instead of making the delay equal the
166
- message's lifetime. Leave at least one second of margin at a QStash maximum
167
- because its `notBefore` timestamp uses whole Unix seconds.
168
-
169
- ## Deploy safely
170
-
171
- Vercel Queues pins scheduled appends and recovery watchdogs to their publishing
172
- deployment by default. `scheduledAppends: 'deploymentless'` removes affinity
173
- only for timers. Select it only when every eligible consumer for the topic can
174
- decode pending tasks and validate their events. Recovery remains pinned.
175
-
176
- New scheduler routes accept older recovery messages, which supports adapter
177
- upgrades for schedulers that deliberately cross deployments.
178
-
179
- :::warning
180
- When using deploymentless Vercel timers or a stable callback URL, do not roll
181
- back to an A2 version without timer delivery while timer tasks are still
182
- outstanding. An older route can acknowledge one as a recovery message without
183
- appending its events. Roll forward, or first wait for the tasks to deliver or
184
- remove them through the provider.
185
- :::
@@ -1,161 +0,0 @@
1
- ---
2
- title: Cancellation
3
- description: There is no abort() API. Cancelling is appending, and the running handler finds out through a signal.
4
- ---
5
-
6
- ## Cancelling is appending
7
-
8
- A user presses stop on a streaming AI response. In A2 that's not a special
9
- operation with its own machinery. It's an event:
10
-
11
- ```ts
12
- // in the browser: push from useSession (see Live UI)
13
- push({ type: 'cancelled', payload: { lastSeenIndex: index } })
14
- ```
15
-
16
- Same route, same auth, same log as every other event. Two things then
17
- happen, at two different speeds.
18
-
19
- ## The running handler stops
20
-
21
- A handler doing abortable work opts in by naming the events that should
22
- interrupt it:
23
-
24
- ```ts server/chat.ts
25
- import { createServer } from 'experimental-a2/server'
26
- import { chat } from '@/contracts'
27
-
28
- export const chatServer = createServer({
29
- contract: chat,
30
- handlers: {
31
- generate: {
32
- abortOn: ['cancelled'],
33
- handler: async (ctx) => {
34
- // your abortable work; hand it ctx.signal:
35
- // await streamText({ signal: ctx.signal, ... })
36
- },
37
- },
38
- },
39
- })
40
- ```
41
-
42
- While the handler runs, A2 watches the session's log. The moment a
43
- `cancelled` event lands (or one already landed before the handler
44
- started), `ctx.signal` fires. Handlers without `abortOn` pay nothing
45
- for the watch: no subscription is held for them.
46
-
47
- Every handler's signal, with or without `abortOn`, also guards the run's
48
- durable claim. While a handler runs, A2 renews its claim on a heartbeat,
49
- and a failed renewal retries promptly while the lease can still be saved.
50
- A short stall is free: blocking the event loop for less than the lease's
51
- slack costs nothing, because an overdue beat fires the moment the loop
52
- wakes. If no renewal lands before the lease lapses, the signal fires with
53
- an `A2Error` reason of code `CLAIM_EXPIRED`. That decision is local (no
54
- store round trip), so it works even while the store is unreachable, and
55
- it means: assume a recovery run is taking over, stop external work now.
56
- If a successor has provably claimed the event, the reason is
57
- `SUPERSEDED_ATTEMPT` instead; by then a lapsed run's signal has usually
58
- already fired. A superseded run can no longer write to the log or
59
- complete; wiring `ctx.signal` into your external calls is what stops it
60
- from racing its successor outside A2.
61
-
62
- The right response depends on the reason, and the default wiring gets
63
- every case correct: pass `ctx.signal` to your I/O and let the abort
64
- propagate. A propagated lease abort (`CLAIM_EXPIRED` or
65
- `SUPERSEDED_ATTEMPT`, which is exactly what `fetch(url, { signal })`
66
- rejects with) makes A2 surrender the attempt: no completion recorded,
67
- no failure budget spent, and the event recovers normally. A user
68
- cancellation (`abortOn`) is the one case to catch and return normally,
69
- because the stop is the outcome and the completion should count.
70
- Return normally after a lease abort only when the work is actually
71
- done: a lapsed run that finished, with no successor claimed yet, still
72
- completes and its completion counts. Any other throw is a real failure
73
- and spends the retry budget.
74
-
75
- When one session multiplexes work (several generations over its
76
- lifetime), match by *instance*, not just type, with a predicate:
77
-
78
- ```ts
79
- // server/chat.ts, the generate entry, targeted by instance:
80
- generate: {
81
- abortOn: {
82
- // only the cancel that names this run fires the signal
83
- cancelled: (event, trigger) => event.payload.of === trigger.id,
84
- },
85
- handler: async (ctx) => {
86
- // ...
87
- },
88
- }
89
- ```
90
-
91
- The pushing side already knows the id it's cancelling; it's in the
92
- `events` feed the hook exposes.
93
-
94
- Handlers are concurrent by default. A `cancelled` handler may therefore run
95
- while the interrupted handler is still unwinding. The signal is the
96
- preemption channel; the event is the durable record.
97
-
98
- When cleanup must wait for the interrupted handler, put both event types in
99
- one lane. The event fires the signal as soon as it is appended, but its own
100
- handler waits for earlier work in that lane:
101
-
102
- ```ts server/chat-with-cleanup.ts
103
- import { createServer } from 'experimental-a2/server'
104
- import { chat } from '@/contracts'
105
-
106
- export const chatServer = createServer({
107
- contract: chat,
108
- handlers: {
109
- generate: {
110
- lane: 'generation',
111
- abortOn: ['cancelled'],
112
- handler: async (ctx) => {
113
- // your abortable work; hand it ctx.signal:
114
- // await streamText({ signal: ctx.signal, ... })
115
- },
116
- },
117
- cancelled: {
118
- lane: 'generation',
119
- handler: async () => {
120
- // your cleanup, after generate has returned
121
- },
122
- },
123
- },
124
- })
125
- ```
126
-
127
- ## The view cuts
128
-
129
- Chunks in flight during the cancel round-trip still land in the log after
130
- `cancelled`. That's correct. They're true history; the model really did
131
- generate them. Keeping them out of what the user sees is the reducer's job:
132
-
133
- ```ts reducer.ts
134
- case 'chunk':
135
- return state.cancelled
136
- ? state
137
- : { ...state, chunks: [...state.chunks, { index: event.index, delta: event.payload.delta }] }
138
- case 'cancelled':
139
- return {
140
- ...state,
141
- cancelled: true,
142
- chunks: state.chunks.filter((c) => c.index <= event.payload.lastSeenIndex),
143
- }
144
- ```
145
-
146
- `lastSeenIndex` is the client's stream frontier, a number it already
147
- tracks to resume subscriptions. Cutting on it makes the trim exact and
148
- clock-free: chunks the log ordered before `cancelled` but the user never
149
- saw are removed retroactively, so the optimistic view and the
150
- authoritative refold agree on the same result. No wall clocks, no skew.
151
-
152
- And because the client pushes `cancelled`
153
- [optimistically](/guides/react#the-client-component), its own fold cuts
154
- instantly. Stragglers still arriving over the stream hit `state.cancelled`
155
- and vanish from the view.
156
-
157
- :::tip
158
- Keep chunks at per-chunk granularity in state until the session reaches a
159
- terminal event, then compact them into one string. That's reducer design,
160
- fully yours.
161
- :::