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,257 @@
1
+ ---
2
+ title: Introduction
3
+ description: Build an AI SDK agent whose messages, streaming, tools, and recovery live in an A2 event log.
4
+ ---
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ pnpm add experimental-a2 ai zod
10
+ ```
11
+
12
+ ## Define the agent
13
+
14
+ ```ts server/assistant.ts
15
+ import { agent } from 'experimental-a2/ai/server'
16
+
17
+ export const assistant = agent({
18
+ name: 'support-agent',
19
+ model: 'openai/gpt-5.6-terra',
20
+ instructions: 'Help the customer. Be concise.',
21
+ })
22
+ ```
23
+
24
+ `agent()` is the whole server: the AI protocol, the agent's loop, and A2's
25
+ store, scheduler, and handlers. `name` is its identity. The loop is the
26
+ agent's `harness`. By default it's `{ type: 'ai-sdk' }`: each response runs as
27
+ durable one-step `streamText()` generations, tuned with `harness.generation`
28
+ and `maxSteps`, listed under [`agent()`](/reference/ai#agentoptions). The same
29
+ agent can run [FX's or Pi's loop](/agents/harnesses) instead.
30
+
31
+ ## Expose the route
32
+
33
+ ```ts app/api/agent/route.ts
34
+ import { assistant } from '@/server/assistant'
35
+
36
+ export const GET = assistant.fetch
37
+ export const POST = assistant.fetch
38
+ ```
39
+
40
+ `GET` streams events and `POST` accepts the browser's pushes. The route never
41
+ calls the model: `fetch` accepts user messages and controls, and rejects every
42
+ server-authored event with `400`. The route is where you'd do auth, or any
43
+ other checks, before `assistant.fetch(request, { authorize })` applies
44
+ per-operation policy.
45
+
46
+ ## Render the conversation
47
+
48
+ Fold the initial state on the server and hand it to a client component:
49
+
50
+ ```tsx app/agent/[sessionId]/page.tsx
51
+ import { assistant } from '@/server/assistant'
52
+ import { Chat } from './chat'
53
+
54
+ export default async function AgentPage({
55
+ params,
56
+ }: {
57
+ params: Promise<{ sessionId: string }>
58
+ }) {
59
+ const { sessionId } = await params
60
+ const initial = await assistant.session(sessionId).state()
61
+ return <Chat sessionId={sessionId} initial={initial} />
62
+ }
63
+ ```
64
+
65
+ An empty session folds to the initial `AIState`; its log is created when the
66
+ first message is pushed. `useAgent()` keeps that state live and returns the
67
+ actions a chat needs:
68
+
69
+ ```tsx app/agent/[sessionId]/chat.tsx
70
+ 'use client'
71
+ import type { FormEvent } from 'react'
72
+ import { useState } from 'react'
73
+ import type { StateSnapshot } from 'experimental-a2'
74
+ import type { AIState } from 'experimental-a2/ai'
75
+ import { useAgent } from 'experimental-a2/ai/react'
76
+ import type { assistant } from '@/server/assistant'
77
+
78
+ const indicatorLabel = {
79
+ starting: 'Starting…',
80
+ thinking: 'Thinking…',
81
+ compacting: 'Compacting…',
82
+ }
83
+
84
+ export function Chat({
85
+ sessionId,
86
+ initial,
87
+ }: {
88
+ sessionId: string
89
+ initial: StateSnapshot<AIState>
90
+ }) {
91
+ const { messages, status, indicator, sendMessage } =
92
+ useAgent<typeof assistant>({ api: '/api/agent', id: sessionId, initial })
93
+ const [draft, setDraft] = useState('')
94
+ const [error, setError] = useState<string | null>(null)
95
+
96
+ async function send(event: FormEvent<HTMLFormElement>): Promise<void> {
97
+ event.preventDefault()
98
+ const text = draft.trim()
99
+ if (!text) return
100
+ setDraft('')
101
+ setError(null)
102
+ try {
103
+ await sendMessage(text)
104
+ } catch (cause) {
105
+ setDraft(text)
106
+ setError(cause instanceof Error ? cause.message : String(cause))
107
+ }
108
+ }
109
+
110
+ return (
111
+ <main>
112
+ <section aria-label="Conversation">
113
+ {messages.map((message) => (
114
+ <article key={message.id}>
115
+ <strong>{message.role === 'user' ? 'You' : 'Agent'}</strong>
116
+ {message.parts.map((part, index) =>
117
+ part.type === 'text' ? <p key={index}>{part.text}</p> : null,
118
+ )}
119
+ </article>
120
+ ))}
121
+ {indicator ? (
122
+ <p role="status">{indicatorLabel[indicator]}</p>
123
+ ) : null}
124
+ </section>
125
+
126
+ <form onSubmit={send}>
127
+ <input
128
+ aria-label="Message"
129
+ value={draft}
130
+ onChange={(event) => setDraft(event.currentTarget.value)}
131
+ />
132
+ <button disabled={!draft.trim() || status === 'closed'}>Send</button>
133
+ </form>
134
+
135
+ {error ? <p role="alert">{error}</p> : null}
136
+ </main>
137
+ )
138
+ }
139
+ ```
140
+
141
+ The `import type` keeps server code out of the bundle. The hook returns the
142
+ session's state plus `messages`, `status`, `indicator`, and actions; see
143
+ [`useAgent()`](/reference/ai#useagentoptions).
144
+
145
+ `sendMessage()` takes a string, sent as one text part with a fresh message ID,
146
+ or a complete `UIMessage`. Every action returns the same result as `push()`: it
147
+ resolves once the command events are stored, and `.confirmed` resolves when the
148
+ stream delivers them back.
149
+
150
+ Pass `{ generate: false }` to add a user message without starting a turn, as in
151
+ `sendMessage('Order #4411 shipped this morning.', { generate: false })`. The
152
+ next generating user message includes earlier passive messages in its model
153
+ context; passive messages sent after it wait for the next one.
154
+
155
+ ## Start a session from another page
156
+
157
+ Wait for the durable append before navigating, so the destination's server
158
+ render sees the message. `createAgentClient()` is the same client outside React:
159
+
160
+ ```ts app/agent/client.ts
161
+ 'use client'
162
+ import { createAgentClient } from 'experimental-a2/ai/client'
163
+ import type { assistant } from '@/server/assistant'
164
+
165
+ export const assistantClient = createAgentClient<typeof assistant>({
166
+ api: '/api/agent',
167
+ })
168
+ ```
169
+
170
+ ```ts app/agent/open-agent.ts
171
+ 'use client'
172
+ import { inputs } from 'experimental-a2/ai'
173
+ import { assistantClient } from './client'
174
+
175
+ export async function openAgent({
176
+ sessionId,
177
+ text,
178
+ router,
179
+ }: {
180
+ sessionId: string
181
+ text: string
182
+ router: { push(href: string): void }
183
+ }): Promise<void> {
184
+ await assistantClient.session(sessionId).push(
185
+ ...inputs.message({
186
+ id: crypto.randomUUID(),
187
+ role: 'user',
188
+ parts: [{ type: 'text', text }],
189
+ }),
190
+ )
191
+ router.push(`/agent/${sessionId}`)
192
+ }
193
+ ```
194
+
195
+ Pass the same client to the destination's hook,
196
+ `useAgent<typeof assistant>({ client: assistantClient, id: sessionId, initial })`,
197
+ so it picks up the live session the push created and reconciles the server
198
+ render without replacing it. Idle client session objects expire after five
199
+ minutes by default; set `gcTime` on `createAgentClient()` to change that.
200
+
201
+ ## Choose the model
202
+
203
+ `model` is an AI Gateway model ID, under every harness, or `ModelSettings` to
204
+ choose its reasoning level and speed with it:
205
+
206
+ ```ts server/fast-assistant.ts
207
+ import { agent } from 'experimental-a2/ai/server'
208
+
209
+ export const fastAssistant = agent({
210
+ name: 'fast-support',
211
+ model: { model: 'openai/gpt-5.6-terra', reasoning: 'low', speed: 'fast' },
212
+ })
213
+ ```
214
+
215
+ `speed: 'fast'` prefers AI Gateway's faster tier when the model offers one.
216
+ `reasoningLevels` from `experimental-a2/ai` lists the levels for a picker. See
217
+ [`ModelSettings`](/reference/ai#modelsettings). A resolver can also choose the
218
+ model for each generation from your app's state, such as a plan; see
219
+ [Add your own events and state](/agents/conversations#add-your-own-events-and-state).
220
+
221
+ ## What happens after a send
222
+
223
+ One generating user message becomes a durable sequence:
224
+
225
+ ```text
226
+ browser ai.control.requested durable input command
227
+ server ai.message.created input admitted
228
+ server ai.control.committed accepted state changes
229
+ server ai.control.decided command receipt
230
+ server ai.generation.requested scheduled from durable facts
231
+ server ai.generation.started
232
+ server ai.generation.progress batched UIMessageChunk[]
233
+ server ai.tool.called when present
234
+ server ai.approval.requested when present
235
+ server ai.tool.result after concurrent execution or denial
236
+ server ai.generation.completed closes this model step
237
+ server ai.generation.requested after all sibling tools are terminal
238
+ ... another one-step generation
239
+ server ai.message.completed
240
+ server ai.generation.requested next queued user turn, when present
241
+ ```
242
+
243
+ Tool results and generation completion can arrive in either order; the next
244
+ step waits for both. The SSE stream delivers these events to the same reducer,
245
+ which applies the streamed chunks to the current `UIMessage`; the exported
246
+ `deriveUIMessages()` does the same over a raw history.
247
+
248
+ Model calls for a session never overlap. A message sent while a response is
249
+ active enters the durable log immediately, but its turn waits until that
250
+ response, including every tool step and approval, finishes. Inbox order is
251
+ arrival order and can be edited; see
252
+ [Inbox and turn controls](/agents/conversations#inbox-and-turn-controls).
253
+
254
+ The hook's actions read [`AIState`](/reference/ai#aistate)'s ownership
255
+ bookkeeping, such as `activeGeneration` and `activeRequestId`, for you; the
256
+ lower-level `inputs` builders need it explicitly. A2-generated IDs use the
257
+ reserved `a2.ai:` namespace; treat them as opaque.
@@ -0,0 +1,247 @@
1
+ ---
2
+ title: Tools and approvals
3
+ description: "Give an agent tools, ask for approval before they run, and interrupt or retry a turn."
4
+ ---
5
+
6
+ ## Add tools and approval
7
+
8
+ ```ts server/with-tools.ts
9
+ import { tool } from 'ai'
10
+ import { z } from 'zod'
11
+ import { agent } from 'experimental-a2/ai/server'
12
+
13
+ const tools = {
14
+ closeTicket: tool({
15
+ description: 'Close a resolved support ticket',
16
+ inputSchema: z.object({ ticketId: z.string() }),
17
+ execute: async ({ ticketId }, { toolCallId }) => {
18
+ // your side effect; toolCallId makes a stable idempotency key:
19
+ // await closeTicket(ticketId, { idempotencyKey: toolCallId })
20
+ return { ticketId, closed: true }
21
+ },
22
+ }),
23
+ }
24
+
25
+ export const toolsAssistant = agent({
26
+ name: 'support-tools',
27
+ model: 'openai/gpt-5.6-terra',
28
+ tools,
29
+ harness: {
30
+ type: 'ai-sdk',
31
+ generation: {
32
+ toolApproval: {
33
+ closeTicket: 'user-approval',
34
+ },
35
+ },
36
+ },
37
+ })
38
+ ```
39
+
40
+ Tools are ordinary AI SDK `tool()` definitions, passed through untouched.
41
+ Approval policy lives in `harness.generation.toolApproval`, beside the other
42
+ per-step settings. Later examples that import `assistant` use the agent from
43
+ [Agents](/agents/introduction#define-the-agent).
44
+
45
+ ### Read the handler context
46
+
47
+ ```ts server/set-reminder.ts
48
+ import { tool } from 'ai'
49
+ import { handlerContext, inputs } from 'experimental-a2/ai'
50
+ import { z } from 'zod'
51
+
52
+ export const setReminder = tool({
53
+ description: 'Set a reminder for yourself',
54
+ inputSchema: z.object({
55
+ delaySeconds: z.number().int().min(1).max(6 * 24 * 60 * 60),
56
+ reminder: z.string(),
57
+ }),
58
+ execute: async ({ delaySeconds, reminder }, { toolCallId }) => {
59
+ const ctx = handlerContext()
60
+ await ctx.session.schedule(
61
+ `reminder:${toolCallId}`,
62
+ { delay: `${delaySeconds}s` },
63
+ ...inputs.message({
64
+ id: `reminder:${ctx.event.id}`,
65
+ role: 'user',
66
+ parts: [{ type: 'text', text: `Reminder: ${reminder}` }],
67
+ }),
68
+ )
69
+
70
+ return { scheduled: true, delaySeconds }
71
+ },
72
+ })
73
+ ```
74
+
75
+ `handlerContext()` returns the running tool's durable handler context: `event`,
76
+ `attempt`, `session`, and `signal`. It works anywhere below `execute`, including
77
+ awaited helpers, and throws outside a tool execution. Pass a shared
78
+ `agentContract()` to type application events; A2 checks it against the
79
+ executing agent. See [`handlerContext()`](/reference/ai#handlercontextcontract)
80
+ for the event payload.
81
+
82
+ This tool schedules a reminder as a new user message. `ctx.session` belongs to
83
+ the executing agent, so `schedule()` uses that agent's scheduler: add
84
+ `setReminder` to its `tools` and configure a [scheduler](/server/production).
85
+ Naming the timer after `toolCallId` and the message after the triggering
86
+ event's ID makes a retry converge on the same timer and message, even if a
87
+ provider reuses tool-call IDs. The six-day maximum is Vercel Queues'
88
+ [delay limit](/server/timers#provider-limits); adjust it for your scheduler. A
89
+ transient or ambiguous scheduler failure retries the handler with the same
90
+ identity and target time; a deterministic rejection or a missing scheduler is
91
+ an ordinary tool error.
92
+
93
+ To test a context-reading tool, call it inside `runWithHandlerContext(ctx, fn)`
94
+ from `experimental-a2/ai/server`; within `fn`, `handlerContext()` returns `ctx`.
95
+
96
+ ### Answer approvals
97
+
98
+ ```tsx app/tools/[sessionId]/approval-controls.tsx
99
+ 'use client'
100
+ import { useAgent } from 'experimental-a2/ai/react'
101
+ import type { toolsAssistant } from '@/server/with-tools'
102
+
103
+ export function ApprovalControls({ sessionId }: { sessionId: string }) {
104
+ const { state, approve, deny } = useAgent<typeof toolsAssistant>({
105
+ api: '/api/tools',
106
+ id: sessionId,
107
+ })
108
+
109
+ return state.pendingApprovals.map((approval) => (
110
+ <div key={approval.approvalId}>
111
+ <span>Allow tool call {approval.toolCallId}?</span>
112
+ <button onClick={() => void approve(approval)}>Allow</button>
113
+ <button
114
+ onClick={() => void deny(approval, { reason: 'Denied by the user' })}
115
+ >
116
+ Deny
117
+ </button>
118
+ </div>
119
+ ))
120
+ }
121
+ ```
122
+
123
+ Instead of running a tool that needs approval, A2 records the AI SDK's approval
124
+ request as `ai.approval.requested`, and the reducer adds it to
125
+ `state.pendingApprovals`. `approve()` and `deny()` copy
126
+ the request, message, generation, and approval IDs from it, so a delayed click
127
+ cannot authorize a later model step. The decision updates the approval part in
128
+ the message, and a built-in handler then runs the approved tool or records the
129
+ denied result.
130
+
131
+ A policy can also be a function that returns `'user-approval'` or
132
+ `'approved'` from the validated input. It runs during the model step and again
133
+ on recovery for the same call, so keep it deterministic over the input; an
134
+ impure predicate can fork one call's flow.
135
+
136
+ `state.pendingInputs` works the same way for application-defined input: answer
137
+ one with `respond(input, value)`. The value stays in raw history and
138
+ `state.pendingInputs`; to make it model context, resolve `instructions`
139
+ dynamically or replace `generate`.
140
+
141
+ ### How tools run
142
+
143
+ Validation errors, execution errors, denials, and preliminary and final outputs
144
+ all become durable `ai.tool.result` events; a preliminary output keeps the tool
145
+ `running` until the final one. Dynamic-tool, provider-executed, provider
146
+ metadata, and tool metadata fields carry through to the message. Independent
147
+ tools run concurrently as soon as their inputs and authorization are ready,
148
+ with no fixed limit. Set `toolLane: 'tools'` when local tools must run one at a
149
+ time, for example because they share a sandbox. The next model step starts
150
+ once the current one closes and every sibling tool has a success, error, or
151
+ denied result.
152
+
153
+ An approved provider-executed call can satisfy that join through its response. A
154
+ provider tool with deferred-result support waits for its provider result: your
155
+ authenticated callback submits it from trusted server code with
156
+ `inputs.toolResult(result)`, and the controller checks it against the admitted
157
+ call. Browser pushes reject it.
158
+
159
+ ## Interrupt and retry
160
+
161
+ ```tsx app/agent/[sessionId]/turn-controls.tsx
162
+ 'use client'
163
+ import { useAgent } from 'experimental-a2/ai/react'
164
+ import type { assistant } from '@/server/assistant'
165
+
166
+ export function TurnControls({ sessionId }: { sessionId: string }) {
167
+ const { state, status, stop, retry } = useAgent<typeof assistant>({
168
+ api: '/api/agent',
169
+ id: sessionId,
170
+ })
171
+
172
+ if (status === 'failed')
173
+ return <button onClick={() => void retry()}>Retry</button>
174
+ return state.active ? (
175
+ <button onClick={() => void stop()}>Stop</button>
176
+ ) : null
177
+ }
178
+ ```
179
+
180
+ `stop()` sends the log frontier the rendered state showed, not whatever arrived
181
+ before the click was handled. The client previews Stop at once (a rejection
182
+ restores the turn), and the response rewinds to that frontier, keeping the
183
+ partial text the user saw. Tools completed by then stay completed, and accepted
184
+ tools still awaiting completion become `output-error`. Tool calls whose
185
+ arguments were still streaming are drafts: they leave the conversation and later
186
+ prompts, while their progress stays in the raw log. Later events cannot
187
+ reactivate a stopped response.
188
+
189
+ Once Stop is persisted, A2 aborts the turn's running model and tool work.
190
+ Cancellation is cooperative: tools must honor their abort signal. A Stop for an
191
+ older turn cannot cancel its successor.
192
+
193
+ `retry()` reruns the failed model call with a fresh `retryId` for each click:
194
+ resending one retry is safe, and a later retry stays distinct. Earlier
195
+ completed steps, their tool results, and the committed compaction summary
196
+ remain; the failed call's uncommitted step leaves the prompt and response.
197
+ Later user messages stay queued until the failed response is retried or
198
+ interrupted. Conversation forks and edit-and-resend of admitted messages are
199
+ yours to build.
200
+
201
+ The lower-level `inputs.interrupt()` takes exactly one owner, so a delayed
202
+ interruption cannot stop later work. Before the generation starts, pass
203
+ `activeRequestId` as `requestId` and `activeResponseMessageId` as `messageId`.
204
+ Once `activeGeneration` exists, pass its `generationId` and `responseMessageId`
205
+ instead. After the generation completes, copy the owner from a pending approval,
206
+ pending input, or running tool while the response waits.
207
+
208
+ ## Append from the server
209
+
210
+ Webhooks, jobs, and other backends start turns with the same inputs and
211
+ `append()`:
212
+
213
+ ```ts server/append-message.ts
214
+ import { inputs } from 'experimental-a2/ai'
215
+ import { assistant } from './assistant'
216
+
217
+ export async function appendServerMessage(sessionId: string, text: string) {
218
+ await assistant.session(sessionId).append(
219
+ ...inputs.message({
220
+ id: crypto.randomUUID(),
221
+ role: 'user',
222
+ parts: [{ type: 'text', text }],
223
+ }),
224
+ )
225
+ }
226
+ ```
227
+
228
+ A connected browser still receives the events over SSE, without an optimistic
229
+ overlay for an interaction that began elsewhere.
230
+
231
+ ## The built-in inputs
232
+
233
+ The hook's actions build their commands with `inputs`, the same pure,
234
+ isomorphic builders you pass to raw `push()` and server `append()`:
235
+ `message()` and the passive `seed()` for messages; `approval()`,
236
+ `input()`, and `requestInput()` for pending requests; `retry()`, `stop()`,
237
+ `steer()`, `interrupt()`, `pause()`, and `resume()` for turns; `queue.edit()`,
238
+ `queue.move()`, `queue.remove()`, and `queue.sendNow()` for the inbox; and
239
+ `toolResult()` for deferred provider results. See
240
+ [`inputs`](/reference/ai#inputs) for each signature, ID rules, and payloads.
241
+
242
+ Browser pushes accept user messages, approval and input responses,
243
+ interruptions, and retries. `inputs.requestInput()`, `inputs.toolResult()`, and
244
+ non-user `inputs.seed()` messages are for trusted server appends. `inputs` has
245
+ no session lifecycle methods: the log begins with the first append, and apps
246
+ that use `ai.session.created` or `ai.session.closed` append them from trusted
247
+ server code.