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,218 @@
1
+ 'use client'
2
+ import type { ReactNode } from 'react'
3
+ import { useEffect, useRef, useState } from 'react'
4
+ import { useSearchParams } from 'next/navigation'
5
+ import { Asterisk, Plus } from 'lucide-react'
6
+ import { FastLink } from '../components/fast-link'
7
+ import { type App, timeAgo } from './apps'
8
+ import { ContextMenu, type MenuItem } from './context-menu'
9
+ import { queryString } from './flags'
10
+
11
+ /** The clock the list's times read from: the server's at first, then ticking. */
12
+ function useNow(renderedAt: number): number {
13
+ const [now, setNow] = useState(renderedAt)
14
+ useEffect(() => {
15
+ const timer = setInterval(() => setNow(Date.now()), 30_000)
16
+ return () => clearInterval(timer)
17
+ }, [])
18
+ return now
19
+ }
20
+
21
+ export function AppList({
22
+ apps,
23
+ currentId,
24
+ renderedAt,
25
+ newAppId,
26
+ onRename,
27
+ onDelete,
28
+ }: {
29
+ /** Most recently prompted first. */
30
+ apps: App[]
31
+ currentId: string | null
32
+ renderedAt: number
33
+ newAppId: string
34
+ onRename: (app: { id: string; name: string }) => void
35
+ onDelete: (app: App) => void
36
+ }): ReactNode {
37
+ const now = useNow(renderedAt)
38
+ // Links keep the dev tools' state from app to app. A new app starts with
39
+ // the open app's harness; a listed one keeps its own.
40
+ const params = useSearchParams()
41
+ const query = queryString(new URLSearchParams(params))
42
+ const appQuery = (app: App): string => {
43
+ const own = new URLSearchParams(params)
44
+ own.delete('harness')
45
+ if (app.harness) own.set('harness', app.harness)
46
+ return queryString(own)
47
+ }
48
+ // Open dev tools also read each page's log, so they don't prefetch every
49
+ // app's in full.
50
+ const prefetch = params.has('devtools') ? null : true
51
+ return (
52
+ <>
53
+ <div className="a0-label">
54
+ <span>Apps</span>
55
+ <span className="a0-rule" />
56
+ <FastLink
57
+ href={`/a0/${newAppId}${query}`}
58
+ prefetch={prefetch}
59
+ className="a0-icon-button"
60
+ aria-label="New app"
61
+ title="New app"
62
+ >
63
+ <Plus size={14} />
64
+ </FastLink>
65
+ </div>
66
+ <nav aria-label="Apps">
67
+ {apps.map((app) => (
68
+ <AppItem
69
+ key={app.id}
70
+ app={app}
71
+ when={timeAgo({ at: app.promptedAt, now })}
72
+ current={app.id === currentId}
73
+ href={`/a0/${app.id}${appQuery(app)}`}
74
+ prefetch={prefetch}
75
+ onRename={(name) => onRename({ id: app.id, name })}
76
+ onDelete={() => onDelete(app)}
77
+ />
78
+ ))}
79
+ </nav>
80
+ </>
81
+ )
82
+ }
83
+
84
+ const under = (row: HTMLElement): { x: number; y: number } => {
85
+ const box = row.getBoundingClientRect()
86
+ return { x: box.left + 16, y: box.bottom }
87
+ }
88
+
89
+ /**
90
+ * Clicking the current app renames it in place. Right-clicking any app, or
91
+ * its context-menu key, opens its menu.
92
+ */
93
+ function AppItem({
94
+ app,
95
+ when,
96
+ current,
97
+ href,
98
+ prefetch,
99
+ onRename,
100
+ onDelete,
101
+ }: {
102
+ app: App
103
+ when: string
104
+ current: boolean
105
+ href: string
106
+ prefetch: boolean | null
107
+ onRename: (name: string) => void
108
+ onDelete: () => void
109
+ }): ReactNode {
110
+ const [editing, setEditing] = useState(false)
111
+ const [menu, setMenu] = useState<{ x: number; y: number } | null>(null)
112
+ const row = useRef<HTMLDivElement>(null)
113
+ const cancelled = useRef(false)
114
+ const rename = (): void => {
115
+ cancelled.current = false
116
+ setEditing(true)
117
+ }
118
+ const link = (): string => new URL(href, location.origin).href
119
+ const items: MenuItem[] = [
120
+ { label: 'Open in new tab', onSelect: () => window.open(link(), '_blank') },
121
+ {
122
+ label: 'Copy link',
123
+ onSelect: () => void navigator.clipboard.writeText(link()),
124
+ },
125
+ { label: 'Rename', onSelect: rename },
126
+ { label: 'Delete', onSelect: onDelete, danger: true },
127
+ ]
128
+ const icon = <Asterisk size={14} aria-hidden />
129
+ const lines = (
130
+ <span className="a0-app-lines">
131
+ <span className="a0-app-name">{app.name}</span>
132
+ <span className="a0-app-when">{when}</span>
133
+ </span>
134
+ )
135
+
136
+ if (editing)
137
+ return (
138
+ <div className="a0-app" data-current>
139
+ {icon}
140
+ <input
141
+ aria-label={`Rename ${app.name}`}
142
+ defaultValue={app.name}
143
+ maxLength={80}
144
+ autoFocus
145
+ onFocus={(event) => event.currentTarget.select()}
146
+ onBlur={(event) => {
147
+ setEditing(false)
148
+ const next = event.currentTarget.value.trim()
149
+ if (!cancelled.current && next && next !== app.name) onRename(next)
150
+ }}
151
+ onKeyDown={(event) => {
152
+ if (event.key === 'Enter') event.currentTarget.blur()
153
+ if (event.key === 'Escape') {
154
+ cancelled.current = true
155
+ event.currentTarget.blur()
156
+ }
157
+ }}
158
+ />
159
+ </div>
160
+ )
161
+
162
+ return (
163
+ <div
164
+ ref={row}
165
+ className="a0-app"
166
+ data-current={current || undefined}
167
+ data-menu={menu ? '' : undefined}
168
+ onContextMenu={(event) => {
169
+ event.preventDefault()
170
+ // The keyboard's menu key has no pointer, so it opens under the row.
171
+ setMenu(
172
+ event.clientX || event.clientY
173
+ ? { x: event.clientX, y: event.clientY }
174
+ : under(event.currentTarget),
175
+ )
176
+ }}
177
+ // Not every browser turns these keys into a contextmenu event.
178
+ onKeyDown={(event) => {
179
+ if (
180
+ event.key !== 'ContextMenu' &&
181
+ !(event.key === 'F10' && event.shiftKey)
182
+ )
183
+ return
184
+ event.preventDefault()
185
+ setMenu(under(event.currentTarget))
186
+ }}
187
+ >
188
+ {current ? (
189
+ <button
190
+ type="button"
191
+ className="a0-app-open"
192
+ aria-current="page"
193
+ title="Rename"
194
+ onClick={rename}
195
+ >
196
+ {icon}
197
+ {lines}
198
+ </button>
199
+ ) : (
200
+ <FastLink className="a0-app-open" href={href} prefetch={prefetch}>
201
+ {icon}
202
+ {lines}
203
+ </FastLink>
204
+ )}
205
+ {menu && (
206
+ <ContextMenu
207
+ at={menu}
208
+ items={items}
209
+ onClose={({ returnFocus }) => {
210
+ setMenu(null)
211
+ if (returnFocus)
212
+ row.current?.querySelector<HTMLElement>('.a0-app-open')?.focus()
213
+ }}
214
+ />
215
+ )}
216
+ </div>
217
+ )
218
+ }
@@ -0,0 +1,63 @@
1
+ 'use client'
2
+ import type { ReactNode } from 'react'
3
+ import { useEffect } from 'react'
4
+ import { useSearchParams } from 'next/navigation'
5
+ import { titleFromPrompt } from './apps'
6
+ import { Chat } from './chat'
7
+ import { ColumnEdge } from './columns'
8
+ import type { Harness } from './model'
9
+ import { checkApp, PreviewPane } from './preview-pane'
10
+ import { useSession } from './session'
11
+ import { useApps } from './shell'
12
+
13
+ /** One app: its chat with the agent, and the app it builds. */
14
+ export function AppView({
15
+ appId,
16
+ harness,
17
+ devtools,
18
+ }: {
19
+ appId: string
20
+ harness: Harness
21
+ /** Shown while the query has `devtools`. */
22
+ devtools: ReactNode
23
+ }): ReactNode {
24
+ const { listed, prompted, opened } = useApps()
25
+ const { state } = useSession()
26
+ const showDevtools = useSearchParams().has('devtools')
27
+ const app = listed(appId)
28
+ const prompt = state.messages
29
+ .find((message) => message.role === 'user')
30
+ ?.parts.flatMap((part) => (part.type === 'text' ? [part.text] : []))
31
+ .join(' ')
32
+ const name = app?.name ?? (prompt ? titleFromPrompt(prompt) : 'New app')
33
+ // A new app's sandbox opens on sight, so it's ready by the first prompt;
34
+ // if none comes, its idle check deletes it.
35
+ const newApp = state.messages.length === 0
36
+ useEffect(() => {
37
+ if (!newApp) return
38
+ opened(appId)
39
+ checkApp({ appId, newApp }).catch(() => {})
40
+ }, [appId])
41
+
42
+ return (
43
+ <>
44
+ <section aria-label="Chat" className="a0-chat">
45
+ <h1 className="a0-title">{name}</h1>
46
+ <Chat
47
+ harness={harness}
48
+ onPrompt={(text) =>
49
+ prompted({
50
+ id: appId,
51
+ name: titleFromPrompt(prompt ?? text),
52
+ harness,
53
+ })
54
+ }
55
+ autoFocus={!app}
56
+ />
57
+ <ColumnEdge column="chat" />
58
+ </section>
59
+ <PreviewPane appId={appId} />
60
+ {showDevtools && devtools}
61
+ </>
62
+ )
63
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod'
2
+ import { isAppId } from '../../../apps'
3
+ import { ensureApp } from '../../../sandbox'
4
+ import { checkWhenIdle } from '../../../sandbox-log'
5
+
6
+ const body = z.object({ newApp: z.boolean().default(false) })
7
+
8
+ /**
9
+ * Makes sure the app is up, and says whether it answers. The browser calls
10
+ * it while the app is on screen, which keeps its sandbox running. A new
11
+ * app's sandbox also gets its idle check; the check itself decides, so a
12
+ * wrong `newApp` costs nothing.
13
+ */
14
+ export async function POST(
15
+ request: Request,
16
+ context: { params: Promise<{ appId: string }> },
17
+ ): Promise<Response> {
18
+ const { appId } = await context.params
19
+ if (!isAppId(appId))
20
+ return Response.json({ error: 'Unknown app.' }, { status: 404 })
21
+ const { newApp } = body
22
+ .catch({ newApp: false })
23
+ .parse(await request.json().catch(() => ({})))
24
+ const { up, createdAt } = await ensureApp({ appId })
25
+ if (newApp) await checkWhenIdle({ appId, createdAt })
26
+ return Response.json({ up }, { headers: { 'cache-control': 'no-store' } })
27
+ }
@@ -0,0 +1,28 @@
1
+ import { inputs } from 'experimental-a2/ai'
2
+ import { isAppId } from '../../apps'
3
+ import { deleteAppSandbox } from '../../sandbox'
4
+ import { agentServers } from '../../server'
5
+
6
+ /**
7
+ * Stops the agent's current turn, so no later tool call brings the sandbox
8
+ * back, then deletes it. The conversation stays in the A2 log.
9
+ */
10
+ export async function DELETE(
11
+ _request: Request,
12
+ context: { params: Promise<{ appId: string }> },
13
+ ): Promise<Response> {
14
+ const { appId } = await context.params
15
+ if (!isAppId(appId))
16
+ return Response.json({ error: 'Unknown app.' }, { status: 404 })
17
+ // The app's agent is whichever harness's agent has its log.
18
+ await Promise.all(
19
+ Object.values(agentServers).map(async (server) => {
20
+ const session = server.session(appId)
21
+ const { state } = await session.state()
22
+ if (state.active)
23
+ await session.append(...inputs.stop({ turnId: state.active.turnId }))
24
+ }),
25
+ )
26
+ await deleteAppSandbox({ appId })
27
+ return Response.json({ ok: true })
28
+ }
@@ -0,0 +1,128 @@
1
+ import type { ContractEvent } from 'experimental-a2'
2
+ import { expect, it } from 'vitest'
3
+ import {
4
+ type App,
5
+ appList,
6
+ byLatestPrompt,
7
+ isAppId,
8
+ timeAgo,
9
+ titleFromPrompt,
10
+ } from './apps'
11
+ import { parseWidths, serializeWidths } from './cookies'
12
+
13
+ type ListEvents = typeof appList.events
14
+
15
+ const first = '6f1c1c3e-2f7a-4f0e-9d4e-5b8a9f1d2c3b'
16
+ const second = '0d9a8b7c-6e5f-4a3b-8c2d-1e0f9a8b7c6d'
17
+
18
+ const fold = (
19
+ ...events: [type: keyof ListEvents & string, payload: object, at: number][]
20
+ ): App[] =>
21
+ events.reduce(
22
+ (apps, [type, payload, at], index) =>
23
+ appList.reducer.fold(apps, {
24
+ id: `event-${index}`,
25
+ type,
26
+ payload,
27
+ index: index + 1,
28
+ sessionId: 'list-1',
29
+ createdAt: new Date(at),
30
+ } as ContractEvent<ListEvents>),
31
+ appList.reducer.initialState,
32
+ )
33
+
34
+ it('lists apps with the server time of their latest prompt', () => {
35
+ expect(
36
+ fold(
37
+ ['app.created', { appId: first, name: 'todo app' }, 1_000],
38
+ ['app.created', { appId: second, name: 'counter' }, 2_000],
39
+ ['app.prompted', { appId: first }, 3_000],
40
+ ),
41
+ ).toEqual([
42
+ { id: first, name: 'todo app', promptedAt: 3_000 },
43
+ { id: second, name: 'counter', promptedAt: 2_000 },
44
+ ])
45
+ })
46
+
47
+ it('renames and deletes apps, and lists each one once', () => {
48
+ expect(
49
+ fold(
50
+ ['app.created', { appId: first, name: 'todo app' }, 1_000],
51
+ ['app.created', { appId: first, name: 'again' }, 2_000],
52
+ ['app.renamed', { appId: first, name: 'Tasks' }, 3_000],
53
+ ['app.created', { appId: second, name: 'counter' }, 4_000],
54
+ ['app.deleted', { appId: second }, 5_000],
55
+ ),
56
+ ).toEqual([{ id: first, name: 'Tasks', promptedAt: 1_000 }])
57
+ })
58
+
59
+ it('sorts by the latest prompt first', () => {
60
+ const apps = [
61
+ { id: first, name: 'older', promptedAt: 1_000 },
62
+ { id: second, name: 'newer', promptedAt: 2_000 },
63
+ ]
64
+ expect(byLatestPrompt(apps).map((app) => app.name)).toEqual([
65
+ 'newer',
66
+ 'older',
67
+ ])
68
+ })
69
+
70
+ it('rejects names and ids the list would not show', () => {
71
+ const created = appList.events['app.created']
72
+ const valid = (payload: object): boolean =>
73
+ !('issues' in created['~standard'].validate(payload))
74
+ expect(valid({ appId: first, name: 'todo app' })).toBe(true)
75
+ expect(valid({ appId: first, name: ' ' })).toBe(false)
76
+ expect(valid({ appId: first, name: 'x'.repeat(81) })).toBe(false)
77
+ expect(valid({ appId: 'not-a-uuid', name: 'todo app' })).toBe(false)
78
+ expect(isAppId(first)).toBe(true)
79
+ expect(isAppId('not-a-uuid')).toBe(false)
80
+ })
81
+
82
+ it('names an app after the first line of its prompt, cut to fit', () => {
83
+ expect(titleFromPrompt(' make a todo app\nwith tags ')).toBe(
84
+ 'make a todo app',
85
+ )
86
+ const long = titleFromPrompt(
87
+ 'build a landing page for a coffee shop called Ember with a menu',
88
+ )
89
+ expect(long).toBe('build a landing page for a coffee shop…')
90
+ expect(long.length).toBeLessThanOrEqual(40)
91
+ })
92
+
93
+ it('says how long ago in words', () => {
94
+ const now = Date.UTC(2026, 8, 26, 12)
95
+ const ago = (ms: number): string => timeAgo({ at: now - ms, now })
96
+ expect(ago(-5_000)).toBe('just now')
97
+ expect(ago(30_000)).toBe('just now')
98
+ expect(ago(60_000)).toBe('1 minute ago')
99
+ expect(ago(5 * 60_000)).toBe('5 minutes ago')
100
+ expect(ago(3 * 60 * 60_000)).toBe('3 hours ago')
101
+ expect(ago(30 * 60 * 60_000)).toBe('yesterday')
102
+ expect(ago(10 * 24 * 60 * 60_000)).toBe('last week')
103
+ expect(ago(400 * 24 * 60 * 60_000)).toBe('last year')
104
+ })
105
+
106
+ it('reads the widths someone dragged to, and ignores bad ones', () => {
107
+ expect(parseWidths(undefined)).toEqual({ apps: 216, chat: null })
108
+ expect(parseWidths('240,520')).toEqual({ apps: 240, chat: 520 })
109
+ expect(parseWidths('240')).toEqual({ apps: 240, chat: null })
110
+ expect(parseWidths('9999,10')).toEqual({ apps: 216, chat: null })
111
+ expect(parseWidths('abc,def')).toEqual({ apps: 216, chat: null })
112
+ expect(parseWidths(serializeWidths({ apps: 200, chat: 480 }))).toEqual({
113
+ apps: 200,
114
+ chat: 480,
115
+ })
116
+ })
117
+
118
+ it("keeps the harness an app's agent runs, for its link", () => {
119
+ expect(
120
+ fold(
121
+ ['app.created', { appId: first, name: 'todo app', harness: 'fx' }, 1_000],
122
+ ['app.created', { appId: second, name: 'counter' }, 2_000],
123
+ ),
124
+ ).toEqual([
125
+ { id: first, name: 'todo app', promptedAt: 1_000, harness: 'fx' },
126
+ { id: second, name: 'counter', promptedAt: 2_000 },
127
+ ])
128
+ })
@@ -0,0 +1,102 @@
1
+ import { contract } from 'experimental-a2'
2
+ import { z } from 'zod'
3
+ import { type Harness, harnessSchema } from './model'
4
+
5
+ export const isAppId = (value: string): boolean =>
6
+ z.uuid().safeParse(value).success
7
+
8
+ /**
9
+ * An app is one conversation with the coding agent and one sandbox. It's
10
+ * listed with the time of its latest prompt, as the server recorded it, and
11
+ * the harness its agent runs when that's not the AI SDK's.
12
+ */
13
+ export type App = {
14
+ id: string
15
+ name: string
16
+ promptedAt: number
17
+ harness?: Harness
18
+ }
19
+
20
+ const appId = z.uuid()
21
+ const name = z.string().trim().min(1).max(80)
22
+
23
+ /**
24
+ * One browser's apps. Each app is a session of its own; this one lists the
25
+ * apps this browser has prompted, since knowing an app's id is what lets you
26
+ * open it.
27
+ */
28
+ export const appList = contract({
29
+ name: 'a0-apps',
30
+ events: {
31
+ 'app.created': z.object({
32
+ appId,
33
+ name,
34
+ harness: harnessSchema.optional(),
35
+ }),
36
+ 'app.prompted': z.object({ appId }),
37
+ 'app.renamed': z.object({ appId, name }),
38
+ 'app.deleted': z.object({ appId }),
39
+ },
40
+ reducer: {
41
+ name: 'a0-apps.v1',
42
+ initialState: [] as App[],
43
+ fold: (apps, event): App[] => {
44
+ const { appId: id } = event.payload
45
+ const promptedAt = event.createdAt.getTime()
46
+ switch (event.type) {
47
+ case 'app.created': {
48
+ if (apps.some((app) => app.id === id)) return apps
49
+ const { name: created, harness } = event.payload
50
+ return [
51
+ ...apps,
52
+ { id, name: created, promptedAt, ...(harness ? { harness } : {}) },
53
+ ]
54
+ }
55
+ case 'app.prompted':
56
+ return apps.map((app) =>
57
+ app.id === id ? { ...app, promptedAt } : app,
58
+ )
59
+ case 'app.renamed': {
60
+ const { name: renamed } = event.payload
61
+ return apps.map((app) =>
62
+ app.id === id ? { ...app, name: renamed } : app,
63
+ )
64
+ }
65
+ case 'app.deleted':
66
+ return apps.filter((app) => app.id !== id)
67
+ }
68
+ },
69
+ },
70
+ })
71
+
72
+ export const byLatestPrompt = (apps: readonly App[]): App[] =>
73
+ apps.toSorted((a, b) => b.promptedAt - a.promptedAt)
74
+
75
+ const maxTitle = 40
76
+
77
+ /** An app's name from its prompt: the first line, cut to fit. */
78
+ export function titleFromPrompt(prompt: string): string {
79
+ const line = (prompt.trim().split('\n')[0] ?? '').replace(/\s+/g, ' ')
80
+ return line.length > maxTitle
81
+ ? `${line.slice(0, maxTitle - 1).trimEnd()}…`
82
+ : line
83
+ }
84
+
85
+ const relative = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
86
+ const units = [
87
+ ['year', 365 * 24 * 60 * 60_000],
88
+ ['month', 30 * 24 * 60 * 60_000],
89
+ ['week', 7 * 24 * 60 * 60_000],
90
+ ['day', 24 * 60 * 60_000],
91
+ ['hour', 60 * 60_000],
92
+ ['minute', 60_000],
93
+ ] as const
94
+
95
+ /** How long ago, in words: "just now", "5 minutes ago", "yesterday". */
96
+ export function timeAgo({ at, now }: { at: number; now: number }): string {
97
+ const elapsed = now - at
98
+ for (const [unit, size] of units)
99
+ if (elapsed >= size)
100
+ return relative.format(-Math.floor(elapsed / size), unit)
101
+ return 'just now'
102
+ }