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,72 @@
1
+ import 'server-only'
2
+ import type { AIState } from 'experimental-a2/ai'
3
+ import { type AppMessage, appAgent } from './model'
4
+ import type { agentServer, crashServer } from './server'
5
+
6
+ type AppSession = ReturnType<typeof agentServer.session>
7
+ type CrashLog = ReturnType<typeof crashServer.session>
8
+
9
+ const working = (state: AIState<AppMessage>): boolean =>
10
+ state.status === 'generating' ||
11
+ state.status === 'waiting' ||
12
+ !!state.pendingQueueCommands?.length
13
+
14
+ /** Resolves once the app's agent stops working. */
15
+ async function workDone(app: AppSession): Promise<void> {
16
+ const { state: initial, index } = await app.state()
17
+ let state = initial
18
+ if (!working(state)) return
19
+ for await (const event of app.stream({ startAfter: index })) {
20
+ // A cleared app has nothing left to work on.
21
+ if (event.type === 'a2.cleared') return
22
+ state = appAgent.reducer.fold(state, event)
23
+ if (!working(state)) return
24
+ }
25
+ }
26
+
27
+ async function listen({
28
+ app,
29
+ log,
30
+ }: {
31
+ app: AppSession
32
+ log: CrashLog
33
+ }): Promise<void> {
34
+ const crash = async (): Promise<never> => {
35
+ // Recorded first, so the resumed work doesn't crash again.
36
+ await log.append({ type: 'crashed', payload: {} })
37
+ process.exit(1)
38
+ }
39
+ const { state: pending, index } = await log.state()
40
+ if (pending) return crash()
41
+ const requests = log.stream({ startAfter: index })[Symbol.asyncIterator]()
42
+ // When the work ends, closing the stream ends the loop below.
43
+ const close = (): void => void requests.return?.()
44
+ void workDone(app).then(close, close)
45
+ for await (const event of { [Symbol.asyncIterator]: () => requests })
46
+ if (event.type === 'crash.requested') return crash()
47
+ }
48
+
49
+ // One listener per app in this process, while its agent works here.
50
+ const listening = new Map<string, Promise<void>>()
51
+
52
+ /**
53
+ * The dev tools' crash: while the app's agent works in this process, a
54
+ * request in its crash log ends the process at once, mid-stream or
55
+ * mid-command, and the scheduler resumes the turn in a fresh invocation.
56
+ * Each step calls this, so work resumed elsewhere gets a listener too.
57
+ */
58
+ export function crashOnRequest({
59
+ appId,
60
+ app,
61
+ log,
62
+ }: {
63
+ appId: string
64
+ app: AppSession
65
+ log: CrashLog
66
+ }): Promise<void> {
67
+ const current = listening.get(appId)
68
+ if (current) return current
69
+ const started = listen({ app, log }).finally(() => listening.delete(appId))
70
+ listening.set(appId, started)
71
+ return started
72
+ }
@@ -0,0 +1,3 @@
1
+ import { crashEvents } from '../server'
2
+
3
+ export { crashEvents as GET, crashEvents as POST }
@@ -0,0 +1,33 @@
1
+ import type { ContractEvent } from 'experimental-a2'
2
+ import { expect, it } from 'vitest'
3
+ import { crashLog, crashLogId, isCrashLogId } from './crashes'
4
+
5
+ type CrashEvents = typeof crashLog.events
6
+
7
+ const pending = (...types: (keyof CrashEvents & string)[]): boolean =>
8
+ types.reduce(
9
+ (state, type, index) =>
10
+ crashLog.reducer.fold(state, {
11
+ id: `event-${index}`,
12
+ type,
13
+ payload: {},
14
+ index: index + 1,
15
+ sessionId: 'log-1',
16
+ createdAt: new Date(index * 1000),
17
+ } as ContractEvent<CrashEvents>),
18
+ crashLog.reducer.initialState,
19
+ )
20
+
21
+ it('holds a crash from its request until it happens', () => {
22
+ expect(pending()).toBe(false)
23
+ expect(pending('crash.requested')).toBe(true)
24
+ expect(pending('crash.requested', 'crashed')).toBe(false)
25
+ expect(pending('crash.requested', 'crashed', 'crash.requested')).toBe(true)
26
+ })
27
+
28
+ it("names one crash log per app, and only an app's", () => {
29
+ const appId = '6f1c1c3e-2f7a-4f0e-9d4e-5b8a9f1d2c3b'
30
+ expect(isCrashLogId(crashLogId(appId))).toBe(true)
31
+ expect(isCrashLogId(appId)).toBe(false)
32
+ expect(isCrashLogId('not-a-uuid:crashes')).toBe(false)
33
+ })
@@ -0,0 +1,28 @@
1
+ import { contract } from 'experimental-a2'
2
+ import { z } from 'zod'
3
+ import { isAppId } from './apps'
4
+
5
+ /**
6
+ * The dev tools' crashes for one app, in a log of their own so the app's
7
+ * log stays its conversation: a request, then the crash that carried it
8
+ * out. The state is whether one is still pending.
9
+ */
10
+ export const crashLog = contract({
11
+ name: 'a0-crashes',
12
+ events: {
13
+ 'crash.requested': z.object({}),
14
+ crashed: z.object({}),
15
+ },
16
+ reducer: {
17
+ name: 'a0-crashes.v1',
18
+ initialState: false as boolean,
19
+ fold: (_pending, event) => event.type === 'crash.requested',
20
+ },
21
+ })
22
+
23
+ const suffix = ':crashes'
24
+
25
+ export const crashLogId = (appId: string): string => `${appId}${suffix}`
26
+
27
+ export const isCrashLogId = (id: string): boolean =>
28
+ id.endsWith(suffix) && isAppId(id.slice(0, -suffix.length))
@@ -0,0 +1,164 @@
1
+ 'use client'
2
+ import type { ReactNode } from 'react'
3
+ import { memo, useEffect, useState } from 'react'
4
+ import { useSearchParams } from 'next/navigation'
5
+ import { X, Zap } from 'lucide-react'
6
+ import { crashLogId } from './crashes'
7
+ import { setFlag, toggleDevtools } from './flags'
8
+ import { logPage } from './model'
9
+ import { useCrashLog, useSession } from './session'
10
+
11
+ type LogEvent = ReturnType<typeof useSession>['events'][number]
12
+
13
+ const gap = (ms: number): string =>
14
+ ms < 1000 ? `+${Math.round(ms)}ms` : `+${(ms / 1000).toFixed(2)}s`
15
+
16
+ /**
17
+ * The app's raw A2 log, and ways to break the function running its agent:
18
+ * a crash, or a 5-second time limit, so the recovery is there to watch.
19
+ */
20
+ export function DevTools({
21
+ appId,
22
+ deployed,
23
+ crashesAllowed,
24
+ }: {
25
+ appId: string
26
+ /** Function limits and crashes only mean something on Vercel. */
27
+ deployed: boolean
28
+ crashesAllowed: boolean
29
+ }): ReactNode {
30
+ const { state, events, index, history, hydrated, loadHistory } = useSession()
31
+ const short = useSearchParams().get('limit') === '5s'
32
+ const crashes = useCrashLog({ sessionId: crashLogId(appId) })
33
+ const [error, setError] = useState<string | null>(null)
34
+
35
+ const load = (options: { before?: number }): void => {
36
+ loadHistory({ ...options, limit: logPage }).catch((cause: unknown) =>
37
+ setError(cause instanceof Error ? cause.message : String(cause)),
38
+ )
39
+ }
40
+ // Opening reads the latest page. The client skips what it already holds,
41
+ // such as the server's seed, so this reads nothing when there's one.
42
+ useEffect(() => {
43
+ if (hydrated && !history.complete) load({ before: index + 1 })
44
+ }, [hydrated])
45
+
46
+ const crash = (): void => {
47
+ setError(null)
48
+ crashes
49
+ .push({ type: 'crash.requested', payload: {} })
50
+ .catch((cause: unknown) =>
51
+ setError(cause instanceof Error ? cause.message : String(cause)),
52
+ )
53
+ }
54
+
55
+ const localOnly = deployed ? undefined : "next dev doesn't limit functions"
56
+ return (
57
+ <section aria-label="Dev tools" className="a0-devtools">
58
+ <header className="a0-devtools-bar">
59
+ <span className="a0-devtools-title">
60
+ Log <span>{events.length} events</span>
61
+ </span>
62
+ {error && (
63
+ <span role="alert" className="a0-error">
64
+ {error}
65
+ </span>
66
+ )}
67
+ <label className="a0-devtools-switch" title={localOnly}>
68
+ <input
69
+ type="checkbox"
70
+ checked={short}
71
+ disabled={!deployed}
72
+ onChange={(event) =>
73
+ setFlag({
74
+ name: 'limit',
75
+ value: event.currentTarget.checked ? '5s' : null,
76
+ })
77
+ }
78
+ />
79
+ 5-second functions
80
+ </label>
81
+ {/* A crash only means something while the agent works. */}
82
+ {state.active && (
83
+ <button
84
+ type="button"
85
+ className="a0-ghost a0-devtools-crash"
86
+ disabled={!crashesAllowed || crashes.state}
87
+ title={
88
+ crashesAllowed
89
+ ? 'Ends the process running the agent, right now'
90
+ : 'Crashes need a preview deployment, or A0_CRASHES=on'
91
+ }
92
+ onClick={crash}
93
+ >
94
+ <Zap size={13} aria-hidden />
95
+ {crashes.state ? 'Crashing…' : 'Crash'}
96
+ </button>
97
+ )}
98
+ <button
99
+ type="button"
100
+ className="a0-icon-button"
101
+ aria-label="Close dev tools"
102
+ title="Close (⌘J)"
103
+ onClick={toggleDevtools}
104
+ >
105
+ <X size={14} />
106
+ </button>
107
+ </header>
108
+ {/* Reversed, so the view stays pinned to the newest event. */}
109
+ <div className="a0-log-scroll">
110
+ <ol className="a0-log">
111
+ {!history.complete && (
112
+ <li>
113
+ <button
114
+ type="button"
115
+ className="a0-ghost a0-log-older"
116
+ disabled={history.loading}
117
+ onClick={() => load({})}
118
+ >
119
+ {history.loading ? 'Loading…' : 'Load older'}
120
+ </button>
121
+ </li>
122
+ )}
123
+ {events.map((event, position) => (
124
+ <LogRow
125
+ key={event.id}
126
+ event={event}
127
+ previous={events[position - 1]}
128
+ />
129
+ ))}
130
+ </ol>
131
+ </div>
132
+ </section>
133
+ )
134
+ }
135
+
136
+ // Rows keep their events' identity, so a new event renders only its own row.
137
+ const LogRow = memo(function LogRow({
138
+ event,
139
+ previous,
140
+ }: {
141
+ event: LogEvent
142
+ previous: LogEvent | undefined
143
+ }): ReactNode {
144
+ const payload = JSON.stringify(event.payload)
145
+ return (
146
+ <li>
147
+ <details className="a0-log-row">
148
+ <summary title={event.createdAt.toISOString()}>
149
+ <span className="a0-log-index">{event.index}</span>
150
+ <span className="a0-log-gap">
151
+ {previous
152
+ ? gap(event.createdAt.getTime() - previous.createdAt.getTime())
153
+ : ''}
154
+ </span>
155
+ <span className="a0-log-type">{event.type}</span>
156
+ <code>
157
+ {payload.length > 240 ? `${payload.slice(0, 240)}…` : payload}
158
+ </code>
159
+ </summary>
160
+ <pre>{JSON.stringify(event.payload, null, 2)}</pre>
161
+ </details>
162
+ </li>
163
+ )
164
+ })
@@ -0,0 +1,6 @@
1
+ import { appEvents } from '../server'
2
+
3
+ export { appEvents as GET, appEvents as POST }
4
+
5
+ // Agent work started by a push runs after the response, up to this long.
6
+ export const maxDuration = 300
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The dev tools' state lives in the query: `?devtools` while they're open,
3
+ * and `limit=5s` for the 5-second switch. Setting a flag is browser-only.
4
+ */
5
+
6
+ /** A query string for a URL, with bare flags as `?devtools`, not `?devtools=`. */
7
+ export function queryString(params: URLSearchParams): string {
8
+ const query = params.toString().replace(/=(?=&|$)/g, '')
9
+ return query && `?${query}`
10
+ }
11
+
12
+ /** Sets or clears one flag, in place, without a navigation. */
13
+ export function setFlag({
14
+ name,
15
+ value,
16
+ }: {
17
+ name: 'devtools' | 'limit'
18
+ value: string | null
19
+ }): void {
20
+ const params = new URLSearchParams(location.search)
21
+ if (value === null) params.delete(name)
22
+ else params.set(name, value)
23
+ history.replaceState(null, '', `${location.pathname}${queryString(params)}`)
24
+ }
25
+
26
+ export const toggleDevtools = (): void =>
27
+ setFlag({
28
+ name: 'devtools',
29
+ value: new URLSearchParams(location.search).has('devtools') ? null : '',
30
+ })
@@ -0,0 +1,9 @@
1
+ import { harnessEvents } from '../../server'
2
+
3
+ /** The events of apps whose agent runs FX's loop. */
4
+ const events = harnessEvents('fx')
5
+
6
+ export { events as GET, events as POST }
7
+
8
+ // Agent work started by a push runs after the response, up to this long.
9
+ export const maxDuration = 300
@@ -0,0 +1,7 @@
1
+ import { agentServers, appSchedulers } from '../../server'
2
+
3
+ export const POST =
4
+ appSchedulers.fx?.handler(agentServers.fx) ??
5
+ (() => new Response('a0 fx scheduler is not configured', { status: 503 }))
6
+
7
+ export const maxDuration = 300
@@ -0,0 +1,11 @@
1
+ import { harnessEvents } from '../../../server'
2
+
3
+ /**
4
+ * Pushes from the dev tools' 5-second switch. Agent work they start stops
5
+ * with the function, and the scheduler resumes it in a full-length one.
6
+ */
7
+ const events = harnessEvents('fx')
8
+
9
+ export { events as POST }
10
+
11
+ export const maxDuration = 5
@@ -0,0 +1,38 @@
1
+ import type { Metadata } from 'next'
2
+ import type { ReactNode } from 'react'
3
+ import { cookies } from 'next/headers'
4
+ import { appList, isAppId } from './apps'
5
+ import { listCookie, parseWidths, widthsCookie } from './cookies'
6
+ import { listServer } from './server'
7
+ import { A0Shell } from './shell'
8
+ import './a0.css'
9
+
10
+ export const metadata: Metadata = { title: 'A0 · a2 example' }
11
+
12
+ /** The apps list and the columns stay put while the app beside them changes. */
13
+ export default async function A0Layout({
14
+ children,
15
+ }: {
16
+ children: ReactNode
17
+ }): Promise<ReactNode> {
18
+ const jar = await cookies()
19
+ const saved = jar.get(listCookie)?.value
20
+ const listId = saved && isAppId(saved) ? saved : null
21
+ const list = listId
22
+ ? { id: listId, initial: await listServer.session(listId).state() }
23
+ : {
24
+ // Becomes this browser's list with its first write.
25
+ id: crypto.randomUUID(),
26
+ initial: { state: appList.reducer.initialState, index: 0 },
27
+ }
28
+ return (
29
+ <A0Shell
30
+ list={list}
31
+ widths={parseWidths(jar.get(widthsCookie)?.value)}
32
+ renderedAt={Date.now()}
33
+ newAppId={crypto.randomUUID()}
34
+ >
35
+ {children}
36
+ </A0Shell>
37
+ )
38
+ }
@@ -0,0 +1,10 @@
1
+ import { isAppId } from '../apps'
2
+ import { listServer } from '../server'
3
+
4
+ function list(request: Request): Promise<Response> {
5
+ return listServer.fetch(request, {
6
+ authorize: (operation) => isAppId(operation.sessionId),
7
+ })
8
+ }
9
+
10
+ export { list as GET, list as POST }
@@ -0,0 +1,73 @@
1
+ import type { ContractEvent } from 'experimental-a2'
2
+ import { expect, it } from 'vitest'
3
+ import {
4
+ appAgent,
5
+ defaultModelChoice,
6
+ harnessAgents,
7
+ harnessFrom,
8
+ } from './model'
9
+
10
+ const chosen = (payload: unknown): ContractEvent<typeof appAgent.events> =>
11
+ ({
12
+ id: 'choice',
13
+ index: 1,
14
+ sessionId: 'app',
15
+ createdAt: new Date(0),
16
+ type: 'model.chosen',
17
+ payload,
18
+ }) as ContractEvent<typeof appAgent.events>
19
+
20
+ const validate = (payload: unknown) =>
21
+ appAgent.events['model.chosen']['~standard'].validate(payload)
22
+
23
+ it('defaults to Opus 5.5 in fast mode', () => {
24
+ expect(appAgent.reducer.initialState.modelChoice).toEqual({
25
+ model: 'anthropic/claude-opus-5.5',
26
+ reasoning: 'provider-default',
27
+ fast: true,
28
+ })
29
+ expect(defaultModelChoice).toEqual(appAgent.reducer.initialState.modelChoice)
30
+ })
31
+
32
+ it("keeps the latest choice in the app's state", () => {
33
+ const choice = {
34
+ model: 'openai/gpt-5.6-luna',
35
+ reasoning: 'high',
36
+ fast: false,
37
+ }
38
+ const state = appAgent.reducer.fold(
39
+ appAgent.reducer.initialState,
40
+ chosen(choice),
41
+ )
42
+ expect(state.modelChoice).toEqual(choice)
43
+ expect(state.messages).toEqual([])
44
+ })
45
+
46
+ it('fills in defaults and rejects choices a browser could write badly', () => {
47
+ expect(validate({ model: ' anthropic/claude-sonnet-5 ' })).toEqual({
48
+ value: {
49
+ model: 'anthropic/claude-sonnet-5',
50
+ reasoning: 'provider-default',
51
+ fast: false,
52
+ },
53
+ })
54
+ for (const payload of [
55
+ {},
56
+ { model: ' ' },
57
+ { model: 'openai/gpt-5.6-luna', reasoning: 'maximum' },
58
+ { model: 'openai/gpt-5.6-luna', fast: 'yes' },
59
+ ])
60
+ expect(validate(payload)).toHaveProperty('issues')
61
+ })
62
+
63
+ it("reads the app's harness from its URL, the AI SDK's by default", () => {
64
+ expect(harnessFrom('fx')).toBe('fx')
65
+ expect(harnessFrom(null)).toBe('ai-sdk')
66
+ expect(harnessFrom('other')).toBe('ai-sdk')
67
+ // Each harness's agent keeps its own logs.
68
+ expect(Object.values(harnessAgents).map((agent) => agent.name)).toEqual([
69
+ 'a0',
70
+ 'a0-fx',
71
+ 'a0-pi',
72
+ ])
73
+ })
@@ -0,0 +1,95 @@
1
+ import type { UIMessage } from 'ai'
2
+ import { agentContract } from 'experimental-a2/ai'
3
+ import { z } from 'zod'
4
+
5
+ /** Log events the dev tools read at a time. */
6
+ export const logPage = 200
7
+
8
+ /** The port the agent serves its Next.js app on, and the preview shows. */
9
+ export const appPort = 3000
10
+
11
+ export const reasoningSchema = z.enum([
12
+ 'provider-default',
13
+ 'none',
14
+ 'minimal',
15
+ 'low',
16
+ 'medium',
17
+ 'high',
18
+ 'xhigh',
19
+ ])
20
+
21
+ /** What the app's next request runs with. The browser picks it and the log keeps it. */
22
+ const modelChoiceSchema = z.object({
23
+ model: z.string().trim().min(1),
24
+ reasoning: reasoningSchema.default('provider-default'),
25
+ fast: z.boolean().default(false),
26
+ })
27
+
28
+ export type ModelChoice = z.output<typeof modelChoiceSchema>
29
+
30
+ export const defaultModelChoice: ModelChoice = {
31
+ model: 'anthropic/claude-opus-5.5',
32
+ reasoning: 'provider-default',
33
+ fast: true,
34
+ }
35
+
36
+ export type AppMessage = UIMessage
37
+
38
+ /**
39
+ * The loop an app's agent runs: the AI SDK's, FX's, or Pi's. An
40
+ * app picks it before its first message and keeps it.
41
+ */
42
+ export const harnessSchema = z.enum(['ai-sdk', 'fx', 'pi'])
43
+
44
+ export type Harness = z.output<typeof harnessSchema>
45
+
46
+ export const harnessLabels: Record<Harness, string> = {
47
+ 'ai-sdk': 'AI SDK',
48
+ fx: 'FX',
49
+ pi: 'Pi',
50
+ }
51
+
52
+ /** The harness an app's URL names, `?harness=fx`; the AI SDK's without one. */
53
+ export const harnessFrom = (value: unknown): Harness =>
54
+ harnessSchema.safeParse(value).data ?? 'ai-sdk'
55
+
56
+ const appContract = (name: string) =>
57
+ agentContract({
58
+ name,
59
+ events: { 'model.chosen': modelChoiceSchema },
60
+ reducer: {
61
+ name: 'a0.model-choice.v1',
62
+ initialState: { modelChoice: defaultModelChoice },
63
+ fold: (state, event) =>
64
+ event.type === 'model.chosen' ? { modelChoice: event.payload } : state,
65
+ },
66
+ })
67
+
68
+ /** The coding agent's contract, shared by the server and the browser. */
69
+ export const appAgent = appContract('a0')
70
+
71
+ /**
72
+ * Each harness's agent keeps its own logs. They differ only in name, so the
73
+ * browser follows any of them with `appAgent`.
74
+ */
75
+ export const harnessAgents = {
76
+ 'ai-sdk': appAgent,
77
+ fx: appContract('a0-fx'),
78
+ pi: appContract('a0-pi'),
79
+ } satisfies Record<Harness, typeof appAgent>
80
+
81
+ export const toolLabels: Record<string, string> = {
82
+ bash: 'Running a command',
83
+ show_preview: 'Showing the app',
84
+ // Pi's own tools.
85
+ read: 'Reading a file',
86
+ write: 'Writing a file',
87
+ edit: 'Editing a file',
88
+ }
89
+
90
+ /** While the model is still writing a call's input. */
91
+ export const writingLabels: Record<string, string> = {
92
+ bash: 'Writing a command',
93
+ write: 'Writing a file',
94
+ edit: 'Writing an edit',
95
+ }
@@ -0,0 +1,4 @@
1
+ // Stands in for @silvia-odwyer/photon-node, whose WebAssembly the playground's
2
+ // bundler cannot trace. Pi treats a photon that fails to load as no image
3
+ // processing.
4
+ throw new Error('photon is not available in the playground')
@@ -0,0 +1,3 @@
1
+ // Stands in for quickjs-wasi, whose WebAssembly the playground's bundler
2
+ // cannot trace. Only Pi's codemode extension imports it, and A0 never starts it.
3
+ module.exports = {}
@@ -0,0 +1,14 @@
1
+ import { redirect } from 'next/navigation'
2
+ import { queryString } from './flags'
3
+
4
+ /** A new app is just an id with no log yet; the query keeps the dev tools. */
5
+ export default async function NewApp({
6
+ searchParams,
7
+ }: {
8
+ searchParams: Promise<Record<string, string | string[] | undefined>>
9
+ }): Promise<never> {
10
+ const params = new URLSearchParams()
11
+ for (const [name, value] of Object.entries(await searchParams))
12
+ for (const one of [value ?? []].flat()) params.append(name, one)
13
+ redirect(`/a0/${crypto.randomUUID()}${queryString(params)}`)
14
+ }
@@ -0,0 +1,9 @@
1
+ import { harnessEvents } from '../../server'
2
+
3
+ /** The events of apps whose agent runs Pi's loop. */
4
+ const events = harnessEvents('pi')
5
+
6
+ export { events as GET, events as POST }
7
+
8
+ // Agent work started by a push runs after the response, up to this long.
9
+ export const maxDuration = 300
@@ -0,0 +1,7 @@
1
+ import { agentServers, appSchedulers } from '../../server'
2
+
3
+ export const POST =
4
+ appSchedulers.pi?.handler(agentServers.pi) ??
5
+ (() => new Response('a0 pi scheduler is not configured', { status: 503 }))
6
+
7
+ export const maxDuration = 300
@@ -0,0 +1,11 @@
1
+ import { harnessEvents } from '../../../server'
2
+
3
+ /**
4
+ * Pushes from the dev tools' 5-second switch. Agent work they start stops
5
+ * with the function, and the scheduler resumes it in a full-length one.
6
+ */
7
+ const events = harnessEvents('pi')
8
+
9
+ export { events as POST }
10
+
11
+ export const maxDuration = 5