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
package/src/contract.ts CHANGED
@@ -1,15 +1,9 @@
1
- /**
2
- * The contract — a2's primary noun. A named event vocabulary, shared by
3
- * everything: the server implements it (experimental-a2/server's `createServer`),
4
- * reducers derive from it (`contract.reducer`), the browser types its
5
- * pushes off it. Isomorphic by construction: this module imports
6
- * nothing but schema plumbing.
7
- *
8
- * The contract says what can be *said*; the server says how it's
9
- * *reacted to*; a reducer says how it's *seen*.
10
- */
11
-
12
- import { makeReducerBuilder, type ReducerBuilder } from './reducer.ts'
1
+ import {
2
+ makeReducerBuilder,
3
+ type Reducer,
4
+ type RegisteredReducer,
5
+ } from './reducer.ts'
6
+ import { RESERVED_EVENT_PREFIX } from './session-clear.ts'
13
7
  import type { StandardSchemaV1 } from './standard-schema.ts'
14
8
  import { assertSyncSchema } from './validate.ts'
15
9
 
@@ -121,6 +115,7 @@ export type ReducerOptions<Seed, S> = {
121
115
  export type Contract<
122
116
  D extends EventDefs = EventDefs,
123
117
  P extends PresenceDefs = Record<never, never>,
118
+ R = RegisteredReducer<D, P> | undefined,
124
119
  > = {
125
120
  /** Identity — prefixes storage keys and queue messages. */
126
121
  readonly name: string
@@ -130,19 +125,7 @@ export type Contract<
130
125
  readonly presence: Readonly<P>
131
126
  /** Preserve literal types for a handler-returned event batch. */
132
127
  readonly batch: EventBatchFactory<D>
133
- /**
134
- * Derive a view from this contract. The reducer's `name` is its
135
- * identity and snapshot cache key: rename it when the fold's logic
136
- * changes. Two steps by design: this call fixes the state and event
137
- * types, so `.fold()` receives fully concrete types — literal unions
138
- * in your state survive, with zero annotations. (A single call can't
139
- * do this: TypeScript never contextually types the returns of a
140
- * context-sensitive argument against generics inferred in the same
141
- * call.)
142
- */
143
- reducer<Seed, S = Seed>(
144
- options: ReducerOptions<Seed, S>,
145
- ): ReducerBuilder<D, S, P>
128
+ readonly reducer: R
146
129
  }
147
130
 
148
131
  /**
@@ -150,21 +133,77 @@ export type Contract<
150
133
  * must be synchronous — async ones are rejected here, at definition
151
134
  * time. The result is a plain, importable, isomorphic value.
152
135
  */
153
- export function contract<
154
- D extends EventDefs,
155
- P extends PresenceDefs = Record<never, never>,
156
- >(options: {
157
- /** Identity — prefixes storage keys and queue messages. */
136
+ type ContractOptions<D extends EventDefs, P extends PresenceDefs> = {
158
137
  name: string
159
- /** The vocabulary: event name → payload schema (Standard Schema). */
160
138
  events: D
161
- /**
162
- * Optional second vocabulary: presence field → value schema.
163
- * Per-participant ephemeral state, replicated last-writer-wins and
164
- * never stored in the log — reducers cannot see it.
165
- */
166
139
  presence?: P
167
- }): Contract<D, P> {
140
+ }
141
+
142
+ export function contract<
143
+ D extends EventDefs,
144
+ P extends PresenceDefs = Record<never, never>,
145
+ Schema extends StandardSchemaV1 = StandardSchemaV1,
146
+ >(
147
+ options: ContractOptions<D, P> & {
148
+ reducer: {
149
+ name: string
150
+ initialState: StandardSchemaV1.InferInput<NoInfer<Schema>>
151
+ stateSchema: Schema
152
+ fold: (
153
+ state: StandardSchemaV1.InferOutput<Schema>,
154
+ event: ContractEvent<NoInfer<D>>,
155
+ ) => StandardSchemaV1.InferOutput<Schema>
156
+ }
157
+ },
158
+ ): Contract<D, P, Reducer<D, StandardSchemaV1.InferOutput<Schema>, P>>
159
+ export function contract<
160
+ D extends EventDefs,
161
+ P extends PresenceDefs = Record<never, never>,
162
+ S = unknown,
163
+ >(
164
+ options: ContractOptions<D, P> & {
165
+ reducer: {
166
+ name: string
167
+ initialState: S
168
+ fold: (state: NoInfer<S>, event: ContractEvent<NoInfer<D>>) => NoInfer<S>
169
+ }
170
+ },
171
+ ): Contract<D, P, Reducer<D, S, P>>
172
+ export function contract<
173
+ D extends EventDefs,
174
+ P extends PresenceDefs = Record<never, never>,
175
+ R extends RegisteredReducer<D, P> = RegisteredReducer<D, P>,
176
+ >(options: ContractOptions<D, P> & { reducer: R }): Contract<D, P, R>
177
+ export function contract<
178
+ D extends EventDefs,
179
+ P extends PresenceDefs = Record<never, never>,
180
+ >(
181
+ options: ContractOptions<D, P> & { reducer?: undefined },
182
+ ): Contract<D, P, undefined>
183
+ export function contract(options: AnyContractOptions): unknown {
184
+ for (const type of Object.keys(options.events ?? {})) {
185
+ if (type.startsWith(RESERVED_EVENT_PREFIX)) {
186
+ throw new TypeError(
187
+ `contract '${String(options.name)}': event types starting with '${RESERVED_EVENT_PREFIX}' are reserved`,
188
+ )
189
+ }
190
+ }
191
+ return defineContract(options)
192
+ }
193
+
194
+ /** A2's own contracts, which may declare reserved `a2.` event types. */
195
+ export const internalContract: typeof contract =
196
+ defineContract as typeof contract
197
+
198
+ type AnyContractOptions = ContractOptions<EventDefs, PresenceDefs> & {
199
+ reducer?:
200
+ | (ReducerOptions<unknown, unknown> & {
201
+ fold: (state: never, event: never) => unknown
202
+ })
203
+ | undefined
204
+ }
205
+
206
+ function defineContract(options: AnyContractOptions): unknown {
168
207
  const { name } = options
169
208
  if (typeof name !== 'string' || name.length === 0) {
170
209
  throw new TypeError('contract name must be a non-empty string')
@@ -183,7 +222,7 @@ export function contract<
183
222
  }
184
223
  const events = Object.freeze({ ...defs })
185
224
 
186
- const presenceDefs = options.presence ?? ({} as P)
225
+ const presenceDefs = options.presence ?? {}
187
226
  for (const [field, schema] of Object.entries(presenceDefs)) {
188
227
  if (typeof schema?.['~standard']?.validate !== 'function') {
189
228
  throw new TypeError(
@@ -198,9 +237,20 @@ export function contract<
198
237
  name,
199
238
  events,
200
239
  presence,
201
- batch: (...items) => items,
202
- reducer(reducerOptions) {
203
- return makeReducerBuilder(events, presence, reducerOptions)
204
- },
240
+ batch: <const E extends readonly AppendInput<EventDefs>[]>(
241
+ ...items: E
242
+ ): E => items,
243
+ reducer:
244
+ options.reducer === undefined
245
+ ? undefined
246
+ : {
247
+ ...options.reducer,
248
+ ...makeReducerBuilder(events, presence, options.reducer).fold(
249
+ options.reducer.fold as (
250
+ state: unknown,
251
+ event: ContractEvent<EventDefs>,
252
+ ) => unknown,
253
+ ),
254
+ },
205
255
  }
206
256
  }
@@ -14,6 +14,7 @@ const APPEND_NAMESPACE = 'a2:handler-append:v2'
14
14
  const RETURN_NAMESPACE = 'a2:handler-return:v1'
15
15
  const SCHEDULE_NAMESPACE = 'a2:schedule:v1'
16
16
  const SCHEDULED_EVENT_NAMESPACE = 'a2:scheduled-event:v1'
17
+ const SCHEDULE_CLEAR_NAMESPACE = 'a2:schedule-clear:v1'
17
18
 
18
19
  async function deterministicIdFromInput(input: string): Promise<string> {
19
20
  const digest = await crypto.subtle.digest(
@@ -47,11 +48,18 @@ export async function deterministicReturnedEventId(
47
48
  return deterministicId([RETURN_NAMESPACE, triggerEventId, itemOrdinal])
48
49
  }
49
50
 
51
+ /**
52
+ * The id of a scheduled append. `clearIndex` is the lifetime the trigger was
53
+ * claimed in; it joins the input only when positive, so a trigger id reused
54
+ * after a clear schedules a distinct task while sessions never cleared keep
55
+ * the ids they always had.
56
+ */
50
57
  export async function deterministicScheduleId(
51
58
  contract: string,
52
59
  sessionId: string,
53
60
  triggerEventId: string | null,
54
61
  name: string,
62
+ clearIndex = 0,
55
63
  ): Promise<string> {
56
64
  return deterministicIdFromInput(
57
65
  JSON.stringify([
@@ -60,6 +68,35 @@ export async function deterministicScheduleId(
60
68
  sessionId,
61
69
  triggerEventId,
62
70
  name,
71
+ ...(clearIndex > 0 ? [clearIndex] : []),
72
+ ]),
73
+ )
74
+ }
75
+
76
+ export async function deterministicScheduleClearId({
77
+ contract,
78
+ sessionId,
79
+ triggerEventId,
80
+ clearIndex,
81
+ name,
82
+ ifLastIndex,
83
+ }: {
84
+ contract: string
85
+ sessionId: string
86
+ triggerEventId: string | null
87
+ clearIndex: number
88
+ name: string
89
+ ifLastIndex: number
90
+ }): Promise<string> {
91
+ return deterministicIdFromInput(
92
+ JSON.stringify([
93
+ SCHEDULE_CLEAR_NAMESPACE,
94
+ contract,
95
+ sessionId,
96
+ triggerEventId,
97
+ clearIndex,
98
+ name,
99
+ ifLastIndex,
63
100
  ]),
64
101
  )
65
102
  }
@@ -0,0 +1,32 @@
1
+ export const sameValue = (left: unknown, right: unknown): boolean => {
2
+ if (Object.is(left, right)) return true
3
+ if (
4
+ typeof left !== 'object' ||
5
+ left === null ||
6
+ typeof right !== 'object' ||
7
+ right === null
8
+ )
9
+ return false
10
+ const prototype = Object.getPrototypeOf(left)
11
+ if (
12
+ prototype !== Object.getPrototypeOf(right) ||
13
+ (prototype !== Object.prototype &&
14
+ prototype !== Array.prototype &&
15
+ prototype !== null)
16
+ )
17
+ return false
18
+ if (
19
+ Array.isArray(left) &&
20
+ (!Array.isArray(right) || left.length !== right.length)
21
+ )
22
+ return false
23
+ const keys = Reflect.ownKeys(left)
24
+ return (
25
+ keys.length === Reflect.ownKeys(right).length &&
26
+ keys.every(
27
+ (key) =>
28
+ Object.hasOwn(right, key) &&
29
+ sameValue(Reflect.get(left, key), Reflect.get(right, key)),
30
+ )
31
+ )
32
+ }
package/src/errors.ts CHANGED
@@ -3,7 +3,8 @@ export type A2ServerErrorCode =
3
3
  | 'FORBIDDEN' // external ingress was denied by server.fetch authorization
4
4
  | 'UNKNOWN_EVENT_TYPE' // event type not in the machine's `events` map
5
5
  | 'PARTIAL_DUPLICATE_BATCH' // batch mixed already-appended and fresh events
6
- | 'SUPERSEDED_ATTEMPT' // handler append from an attempt a recovery claim replaced
6
+ | 'SUPERSEDED_ATTEMPT' // handler append from an attempt a recovery claim or a clear replaced
7
+ | 'SESSION_CLEARED' // a read or call reached across the session's latest clear
7
8
  | 'CLAIM_EXPIRED' // ctx.signal abort reason: the attempt's lease lapsed without renewal
8
9
  | 'STORE_UNAVAILABLE' // store backend failure — retryable, nothing was written
9
10
  | 'STORE_NOT_CONFIGURED' // production boot with no `store` passed
@@ -33,6 +34,17 @@ export class A2Error extends Error {
33
34
  }
34
35
  }
35
36
 
37
+ /** A handler write whose attempt no longer owns its triggering event. */
38
+ export function supersededAttemptError(
39
+ sessionId: string,
40
+ cause: { index: number; attempt: number },
41
+ ): A2Error {
42
+ return new A2Error(
43
+ 'SUPERSEDED_ATTEMPT',
44
+ `attempt ${cause.attempt} no longer owns event ${cause.index} in session '${sessionId}'`,
45
+ )
46
+ }
47
+
36
48
  /**
37
49
  * Wrap an arbitrary thrown value as STORE_UNAVAILABLE, preserving the
38
50
  * original as `cause`. A2Errors pass through untouched — they already
package/src/index.ts CHANGED
@@ -22,9 +22,11 @@ export type {
22
22
  ReducerOptions,
23
23
  } from './contract.ts'
24
24
 
25
- export type { Reducer, ReducerBuilder } from './reducer.ts'
25
+ export { reducer } from './reducer.ts'
26
+ export type { Reducer, ReducerBuilder, StateSnapshot } from './reducer.ts'
26
27
 
27
28
  export { A2Error, NonRetriableError } from './errors.ts'
29
+ export type { SessionCleared } from './session-clear.ts'
28
30
  export type { A2ErrorCode, A2ServerErrorCode } from './errors.ts'
29
31
 
30
32
  export type {
@@ -36,3 +38,5 @@ export type {
36
38
 
37
39
  export type { Event } from './store.ts'
38
40
  export type { StandardSchemaV1 } from './standard-schema.ts'
41
+
42
+ export type { InitialSnapshot } from './initial-snapshot.ts'
@@ -0,0 +1,39 @@
1
+ import type { StateSnapshot } from './reducer.ts'
2
+
3
+ export type InitialSnapshot<S> =
4
+ | StateSnapshot<S>
5
+ | null
6
+ | undefined
7
+ | Promise<StateSnapshot<S> | null | undefined>
8
+
9
+ export function isInitialPromise<S>(
10
+ initial: InitialSnapshot<S>,
11
+ ): initial is Promise<StateSnapshot<S> | null | undefined> {
12
+ return (
13
+ initial !== null &&
14
+ typeof initial === 'object' &&
15
+ 'then' in initial &&
16
+ typeof initial.then === 'function'
17
+ )
18
+ }
19
+
20
+ export function observeInitial<S>(options: {
21
+ promise: Promise<StateSnapshot<S> | null | undefined>
22
+ settled(
23
+ result: { value: StateSnapshot<S> | null | undefined } | { error: unknown },
24
+ ): void
25
+ }): () => void {
26
+ let listener: typeof options.settled | undefined = options.settled
27
+ const deliver = (result: Parameters<typeof options.settled>[0]): void => {
28
+ const current = listener
29
+ listener = undefined
30
+ current?.(result)
31
+ }
32
+ void Promise.resolve(options.promise).then(
33
+ (value) => deliver({ value }),
34
+ (error: unknown) => deliver({ error }),
35
+ )
36
+ return () => {
37
+ listener = undefined
38
+ }
39
+ }
package/src/internal.ts CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { ScheduledEvent } from './scheduler-task.ts'
7
7
  import type { DrainableServer } from './server.ts'
8
+ import type { Event } from './store.ts'
8
9
 
9
10
  export type DrainOutcome = 'busy' | 'stalled' | 'settled'
10
11
 
@@ -62,11 +63,23 @@ export type ServerInternals = {
62
63
  schedulerAppend(
63
64
  sessionId: string,
64
65
  events: readonly ScheduledEvent[],
66
+ originIndex?: number,
65
67
  ): Promise<void>
68
+ /** Deliver a scheduler-owned conditional clear, deletion included. */
69
+ schedulerClear(sessionId: string, ifLastIndex: number): Promise<void>
70
+ /** `session.history` with clear markers kept; reads start at the latest one. */
71
+ historyWithMarkers(sessionId: string, gte: number): Promise<Event[]>
66
72
  }
67
73
 
68
74
  export const serverInternals: WeakMap<object, ServerInternals> = new WeakMap()
69
75
 
76
+ /**
77
+ * Handler contexts whose previous attempt ended in a failure the handler
78
+ * threw, as opposed to a claim that lapsed (a crash, a timeout, a frozen
79
+ * process). Only the attempt's own outcome is known, not how far it got.
80
+ */
81
+ export const failedPreviousAttempt: WeakSet<object> = new WeakSet()
82
+
70
83
  const objectLike = (value: unknown): value is object =>
71
84
  (typeof value === 'object' && value !== null) || typeof value === 'function'
72
85
 
@@ -305,6 +318,45 @@ export const NOTIFY_TIMINGS: {
305
318
  safetyReadMs: 10_000,
306
319
  }
307
320
 
321
+ /**
322
+ * Bounds for each server instance's in-memory reducer-state cache. Sizes are
323
+ * encoded JSON lengths, re-measured every `measureEvery` folded events, so
324
+ * the byte budget is approximate. Mutable only as a white-box test seam.
325
+ */
326
+ export const STATE_CACHE: {
327
+ maxEntries: number
328
+ maxBytes: number
329
+ /** Events a cached state may advance before it writes a snapshot. */
330
+ snapshotEvery: number
331
+ /** Events a warm read may fold; longer tails read the stored snapshot. */
332
+ maxTail: number
333
+ /** Events folded between re-measuring a cached state's encoded size. */
334
+ measureEvery: number
335
+ } = {
336
+ maxEntries: 1_000,
337
+ maxBytes: 32 * 1024 * 1024,
338
+ snapshotEvery: 128,
339
+ maxTail: 255,
340
+ measureEvery: 16,
341
+ }
342
+
343
+ /**
344
+ * Warm state-read tails for stores that can serve one in a single request:
345
+ * events from `fromIndex` (inclusive) through `throughIndex` or the newest
346
+ * event, or null when that needs more than one request. Like every store
347
+ * read, a tail starts no lower than the latest clear marker. Keyed by the exact
348
+ * store object, so a wrapper built by spreading or proxying a store reads
349
+ * through its own `readHistory` instead.
350
+ */
351
+ export const stateTailReaders: WeakMap<
352
+ object,
353
+ (
354
+ sessionId: string,
355
+ fromIndex: number,
356
+ throughIndex?: number,
357
+ ) => Promise<Event[] | null>
358
+ > = new WeakMap()
359
+
308
360
  export const STREAM_TIMINGS: {
309
361
  /** Cadence of `: ping` comment frames from `sseResponse`. */
310
362
  sseHeartbeatMs: number
package/src/libfx.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ // The subset of libfx's agent API that experimental-a2/ai/fx uses; libfx
2
+ // ships no type declarations.
3
+ declare module 'libfx' {
4
+ export type FxHostTool = {
5
+ name: string
6
+ description: string
7
+ inputSchema: object
8
+ execute(input: unknown, context: { signal: AbortSignal }): unknown
9
+ }
10
+
11
+ export type FxTurn = AsyncIterable<{ type: string }> & {
12
+ result: Promise<{ stopReason: string }>
13
+ steer(input: string): Promise<void>
14
+ cancel(): void
15
+ }
16
+
17
+ export type FxAgent = {
18
+ prompt(input: string, options?: { signal?: AbortSignal }): FxTurn
19
+ checkpoint(): Promise<Uint8Array>
20
+ close(): Promise<void>
21
+ }
22
+
23
+ export function createFxAgent(options: {
24
+ apiKey: string
25
+ model?: string | { id: string; effort?: string; fast?: boolean }
26
+ instructions?: string | string[]
27
+ tools?: FxHostTool[]
28
+ checkpoint?: Uint8Array
29
+ fetch?: (
30
+ input: string | URL | Request,
31
+ init?: RequestInit,
32
+ ) => Promise<Response>
33
+ }): Promise<FxAgent>
34
+ }
@@ -65,12 +65,15 @@ export function postgresNotificationScope(
65
65
  [Symbol.asyncIterator]() {
66
66
  let stopped = false
67
67
  let after = startAfter
68
- let buffer: Event[] = []
68
+ let buffer: Array<Event | undefined> = []
69
+ let position = 0
69
70
  let version = 0
70
71
  let waiting: Sleeper | undefined
71
72
  let lease: ReturnType<PostgresNotifications['watch']> | undefined
72
73
  const stop = (): void => {
73
74
  stopped = true
75
+ buffer = []
76
+ position = 0
74
77
  waiting?.cancel()
75
78
  lease?.stop()
76
79
  state.stops.delete(stop)
@@ -92,16 +95,24 @@ export function postgresNotificationScope(
92
95
  for (;;) {
93
96
  if (stopped || state.closed)
94
97
  return { done: true, value: undefined }
95
- const row = buffer.shift()
98
+ const row = buffer[position]
96
99
  if (row) {
97
100
  after = row.index
101
+ buffer[position] = undefined
102
+ position += 1
103
+ if (position === buffer.length) {
104
+ buffer = []
105
+ position = 0
106
+ }
98
107
  return { done: false, value: row }
99
108
  }
100
109
  const before = version
101
110
  // oxlint-disable-next-line no-await-in-loop -- cursor catch-up
102
- buffer = await read(after)
111
+ const rows = await read(after)
103
112
  if (stopped || state.closed)
104
113
  return { done: true, value: undefined }
114
+ buffer = rows
115
+ position = 0
105
116
  if (buffer.length || before !== version) continue
106
117
  waiting = defaultSleep(NOTIFY_TIMINGS.safetyReadMs)
107
118
  // oxlint-disable-next-line no-await-in-loop -- wait for a hint or the safety read