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,91 @@
1
+ import type { AIState } from './ai.ts'
2
+ import type { ContractEvent, EventDefs } from './contract.ts'
3
+
4
+ /** An application reducer folded beside the AI protocol, from events alone. */
5
+ export type AppReducer<D extends EventDefs, X extends object> = {
6
+ /** Snapshot identity of the application state. Rename it when `fold` changes. */
7
+ name: string
8
+ initialState: X
9
+ fold: (state: X, event: ContractEvent<D>) => X
10
+ }
11
+
12
+ // Every AIState key, so application state is exactly the rest of a merged state.
13
+ const aiStateKeys: Record<keyof AIState, true> = {
14
+ inbox: true,
15
+ pendingQueueCommands: true,
16
+ active: true,
17
+ starting: true,
18
+ receipt: true,
19
+ pausedGenerationIds: true,
20
+ session: true,
21
+ messages: true,
22
+ status: true,
23
+ activeGeneration: true,
24
+ activeRequestId: true,
25
+ activeRequestReason: true,
26
+ activeRequestSourceGenerationId: true,
27
+ activeResponseMessageId: true,
28
+ activeProjection: true,
29
+ responseOwners: true,
30
+ terminalRequestIds: true,
31
+ terminalGenerations: true,
32
+ pendingApprovals: true,
33
+ pendingInputs: true,
34
+ tools: true,
35
+ compaction: true,
36
+ modelMetadata: true,
37
+ usage: true,
38
+ error: true,
39
+ }
40
+
41
+ export const isAIStateKey = (key: string): boolean =>
42
+ Object.hasOwn(aiStateKeys, key)
43
+
44
+ const keep = (state: object, ai: boolean): Record<string, unknown> => {
45
+ const kept: Record<string, unknown> = {}
46
+ for (const [key, value] of Object.entries(state))
47
+ if (isAIStateKey(key) === ai) kept[key] = value
48
+ return kept
49
+ }
50
+
51
+ /** The application part of a merged state: every key `AIState` does not own. */
52
+ export const appSlice = <X extends object>(state: object): X =>
53
+ keep(state, false) as X
54
+
55
+ /** A merged state with its application part replaced. */
56
+ export const withAppSlice = <S extends object>(state: S, app: object): S =>
57
+ ({ ...keep(state, true), ...keep(app, false) }) as S
58
+
59
+ // agentContract() registers every reducer it builds here, keyed by the reducer
60
+ // so spread contracts keep it: agent() serves only these, and folds their
61
+ // application state into the model-context checkpoint every generation reads.
62
+ const agentReducers = new WeakMap<
63
+ object,
64
+ AppReducer<EventDefs, object> | null
65
+ >()
66
+
67
+ export const registerAgentReducer = (
68
+ reducer: object,
69
+ app: AppReducer<EventDefs, object> | undefined,
70
+ ): void => {
71
+ agentReducers.set(reducer, app ?? null)
72
+ }
73
+
74
+ const reducerOf = (contract: { reducer?: unknown }): object | undefined =>
75
+ typeof contract.reducer === 'object' && contract.reducer !== null
76
+ ? contract.reducer
77
+ : undefined
78
+
79
+ export const isAgentContract = (contract: { reducer?: unknown }): boolean => {
80
+ const reducer = reducerOf(contract)
81
+ return reducer !== undefined && agentReducers.has(reducer)
82
+ }
83
+
84
+ export const appReducerOf = (contract: {
85
+ reducer?: unknown
86
+ }): AppReducer<EventDefs, object> | undefined => {
87
+ const reducer = reducerOf(contract)
88
+ return reducer === undefined
89
+ ? undefined
90
+ : (agentReducers.get(reducer) ?? undefined)
91
+ }
@@ -1,7 +1,10 @@
1
1
  import type { UIMessage } from 'ai'
2
2
  import type { AIState } from './ai.ts'
3
3
  import type { ControlCommand, InboxItem } from './ai-control.ts'
4
- import { interruptGenerationProjection } from './ai-message-projection.ts'
4
+ import {
5
+ interruptGenerationProjection,
6
+ settleAbandonedCompaction,
7
+ } from './ai-message-projection.ts'
5
8
 
6
9
  export type QueueCommand<M extends UIMessage> = Extract<
7
10
  ControlCommand<M>,
@@ -200,7 +203,7 @@ export function projectAIClientState<M extends UIMessage>(
200
203
  projection.responseMessageId,
201
204
  stop.lastSeenIndex ?? Number.POSITIVE_INFINITY,
202
205
  ) ?? displayed)
203
- return {
206
+ return settleAbandonedCompaction(displayed, {
204
207
  ...stopped,
205
208
  active: null,
206
209
  status: paused ? 'paused' : 'idle',
@@ -213,5 +216,5 @@ export function projectAIClientState<M extends UIMessage>(
213
216
  pendingApprovals: [],
214
217
  pendingInputs: [],
215
218
  error: null,
216
- }
219
+ })
217
220
  }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * experimental-a2/ai/client — a client for an `agent()` route that needs no
3
+ * contract: the AI protocol and its `AIState` reducer are library code, and
4
+ * the agent's types arrive through a type-only `typeof` import.
5
+ *
6
+ * ```ts
7
+ * import type { assistant } from '@/server/assistant' // erased at build
8
+ * const client = createAgentClient<typeof assistant>({ api: '/api/agent' })
9
+ * await client.session(id).push(...inputs.message(message))
10
+ * ```
11
+ */
12
+
13
+ import {
14
+ agentContract,
15
+ type AI_STATE_REDUCER,
16
+ type AIEventDefs,
17
+ type AIMessageOf,
18
+ type AIState,
19
+ } from './ai.ts'
20
+ import {
21
+ createClient,
22
+ type A2Client,
23
+ type CreateClientOptions,
24
+ } from './client.ts'
25
+
26
+ /**
27
+ * The structural shape of `typeof` an `agent({ name })` server: one whose
28
+ * state the built-in reducer folds. Agents built from an extended contract
29
+ * use `createClient({ contract })` instead.
30
+ */
31
+ export type AnyAgent = {
32
+ readonly contract: {
33
+ readonly events: object
34
+ readonly reducer: { readonly name: typeof AI_STATE_REDUCER }
35
+ }
36
+ }
37
+
38
+ export type AgentMessage<A extends AnyAgent> = AIMessageOf<
39
+ A['contract']['events']
40
+ >
41
+
42
+ export type AgentClient<A extends AnyAgent = AnyAgent> = A2Client<
43
+ AIEventDefs<AgentMessage<A>>,
44
+ AIState<AgentMessage<A>>
45
+ >
46
+
47
+ export type CreateAgentClientOptions = Omit<
48
+ CreateClientOptions<AIEventDefs, AIState>,
49
+ 'contract'
50
+ >
51
+
52
+ const protocol = agentContract({ name: 'a2.ai' })
53
+
54
+ /**
55
+ * A client for the built-in AI protocol. Agents built from a shared
56
+ * `agentContract()` use `createClient({ contract })` instead.
57
+ */
58
+ export function createAgentClient<A extends AnyAgent = AnyAgent>(
59
+ options: CreateAgentClientOptions,
60
+ ): AgentClient<A> {
61
+ return createClient({ ...options, contract: protocol }) as AgentClient<A>
62
+ }
@@ -1,3 +1,4 @@
1
+ import { assertMessageBase, restoreMessageBase } from './ai-message-base.ts'
1
2
  import type { UIMessage } from 'ai'
2
3
  import { events } from './ai.ts'
3
4
  import type { AIContextState } from './ai-context.ts'
@@ -103,6 +104,16 @@ const indexedEvents = (
103
104
  ),
104
105
  )
105
106
 
107
+ const restorableBase = (options: {
108
+ base: unknown
109
+ current: UIMessage | undefined
110
+ }): boolean => {
111
+ assertMessageBase(options.base)
112
+ return isMessage(
113
+ restoreMessageBase({ current: options.current, base: options.base }),
114
+ )
115
+ }
116
+
106
117
  const projection = (value: unknown, messages: UIMessage[]): boolean => {
107
118
  if (
108
119
  !record(value) ||
@@ -113,7 +124,7 @@ const projection = (value: unknown, messages: UIMessage[]): boolean => {
113
124
  'responseMessageId',
114
125
  'promptThroughIndex',
115
126
  'completionIndex',
116
- 'baseMessage',
127
+ 'base',
117
128
  'baseCompaction',
118
129
  'batches',
119
130
  'toolEvents',
@@ -126,7 +137,13 @@ const projection = (value: unknown, messages: UIMessage[]): boolean => {
126
137
  !index(value['promptThroughIndex']) ||
127
138
  (value['completionIndex'] !== undefined &&
128
139
  !index(value['completionIndex'])) ||
129
- (value['baseMessage'] !== undefined && !isMessage(value['baseMessage'])) ||
140
+ (value['base'] !== undefined &&
141
+ !restorableBase({
142
+ base: value['base'],
143
+ current: messages.find(
144
+ (message) => message.id === value['responseMessageId'],
145
+ ),
146
+ })) ||
130
147
  (value['baseCompaction'] !== undefined &&
131
148
  !compaction(value['baseCompaction'])) ||
132
149
  !progress(value['batches']) ||
@@ -200,9 +217,9 @@ const authority = (value: unknown): boolean =>
200
217
  'paused',
201
218
  ].includes(String(value['phase']))))
202
219
 
203
- export const contextSchema = <M extends UIMessage>(): StandardSchemaV1<
204
- AIContextState<M>
205
- > => ({
220
+ export const contextSchema = <M extends UIMessage>(
221
+ app?: object,
222
+ ): StandardSchemaV1<AIContextState<M>> => ({
206
223
  '~standard': {
207
224
  version: 1,
208
225
  vendor: 'a2-context',
@@ -217,6 +234,7 @@ export const contextSchema = <M extends UIMessage>(): StandardSchemaV1<
217
234
  'generation',
218
235
  'activeProjection',
219
236
  'messageIndexes',
237
+ ...(app === undefined ? [] : ['app']),
220
238
  ]
221
239
  try {
222
240
  if (
@@ -254,6 +272,7 @@ export const contextSchema = <M extends UIMessage>(): StandardSchemaV1<
254
272
  generation !== null &&
255
273
  (!record(generation) ||
256
274
  !matches(events['ai.generation.started'], generation['owner']) ||
275
+ !index(generation['startIndex']) ||
257
276
  ![
258
277
  'streaming',
259
278
  'completed',
@@ -287,6 +306,7 @@ export const contextSchema = <M extends UIMessage>(): StandardSchemaV1<
287
306
  return invalid
288
307
  if (value['closed'] && (generation !== null || current !== null))
289
308
  return invalid
309
+ if (app !== undefined && !record(value['app'])) return invalid
290
310
  return { value: value as AIContextState<M> }
291
311
  } catch {
292
312
  return invalid
package/src/ai-context.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import { restoreMessageBase } from './ai-message-base.ts'
2
+ import { reducer as makeReducer } from './reducer.ts'
1
3
  import type { UIMessage } from 'ai'
2
4
  import type {
3
- AgentDefinition,
4
5
  ApprovalRequestedPayload,
5
6
  ApprovalRespondedPayload,
6
7
  CompactionCompletedPayload,
@@ -8,7 +9,6 @@ import type {
8
9
  CompactionState,
9
10
  GenerationCompletedPayload,
10
11
  GenerationFailedPayload,
11
- GenerationProgressPayload,
12
12
  GenerationRequestedPayload,
13
13
  GenerationStartedPayload,
14
14
  MessageCreatedPayload,
@@ -21,9 +21,11 @@ import type {
21
21
  } from './ai.ts'
22
22
  import type { ControlCommit } from './ai-control.ts'
23
23
  import { contextSchema } from './ai-context-schema.ts'
24
- import type { ContractEvent, EventDefs } from './contract.ts'
24
+ import type { Contract, ContractEvent, EventDefs } from './contract.ts'
25
25
  import {
26
26
  projectedMessage,
27
+ retainMessageBase,
28
+ findMessage,
27
29
  advanceProjection,
28
30
  reduceToolActivity,
29
31
  upsertMessage,
@@ -34,15 +36,16 @@ import { interruptUIMessage, pauseUIMessage } from './ai-projector.ts'
34
36
  import {
35
37
  flattenProgressBatches,
36
38
  progressBatches,
39
+ progressOwnedBy,
40
+ type StoredProgressPayload,
37
41
  } from './ai-progress-batches.ts'
38
- import { storedAIReducer, type AIStoredReducer } from './ai-stored-state.ts'
42
+ import { appReducerOf, appSlice } from './ai-app-state.ts'
43
+ import { withAIStorage } from './ai-stored-state.ts'
44
+ import type { Reducer } from './reducer.ts'
39
45
 
40
46
  export type AIModelContext<M extends UIMessage = UIMessage> = {
41
47
  messages: M[]
42
- compaction: Omit<
43
- CompactionState<M>,
44
- 'messages' | 'retainedMessageIds' | 'usage'
45
- > | null
48
+ compaction: Omit<CompactionState, 'usage'> | null
46
49
  modelMetadata: Record<string, ModelMetadataState>
47
50
  }
48
51
 
@@ -58,12 +61,16 @@ export type AIContextState<M extends UIMessage> = AIModelContext<M> & {
58
61
  > | null
59
62
  generation: {
60
63
  owner: GenerationStartedPayload
64
+ /** Log index of the owner's `ai.generation.started`. */
65
+ startIndex: number
61
66
  phase: 'streaming' | 'completed' | 'paused' | 'failed' | 'superseded'
62
67
  error?: string
63
68
  responseIndex?: number
64
69
  } | null
65
- activeProjection: MessageProjection<M> | null
70
+ activeProjection: MessageProjection | null
66
71
  messageIndexes: Record<string, number>
72
+ /** The contract's application state, when `agentContract()` has a reducer. */
73
+ app?: object
67
74
  }
68
75
 
69
76
  const replaceResponse = <M extends UIMessage>({
@@ -96,12 +103,16 @@ const replaceResponse = <M extends UIMessage>({
96
103
  }
97
104
  }
98
105
 
99
- const calledTools = <M extends UIMessage>(
100
- projection: MessageProjection<M>,
101
- ): Set<string> =>
106
+ const calledTools = <M extends UIMessage>({
107
+ projection,
108
+ current,
109
+ }: {
110
+ projection: MessageProjection
111
+ current: M | undefined
112
+ }): Set<string> =>
102
113
  new Set([
103
- ...(projection.baseMessage?.parts.flatMap((part) =>
104
- 'toolCallId' in part ? [part.toolCallId] : [],
114
+ ...(restoreMessageBase({ current, base: projection.base })?.parts.flatMap(
115
+ (part) => ('toolCallId' in part ? [part.toolCallId] : []),
105
116
  ) ?? []),
106
117
  ...projection.toolEvents
107
118
  .filter((event) => event.type === 'ai.tool.called')
@@ -116,15 +127,19 @@ const renderProjection = <M extends UIMessage>({
116
127
  index: number
117
128
  }): AIContextState<M> => {
118
129
  const projection = state.activeProjection!
119
- let message = projectedMessage(projection)
130
+ const current = findMessage(state.messages, projection.responseMessageId)
131
+ let message = projectedMessage({ projection, current })
120
132
  if (
121
- projection.baseMessage === undefined &&
133
+ projection.base === undefined &&
122
134
  projection.batches.length === 0 &&
123
135
  message.parts.length === 0
124
136
  )
125
137
  return state
126
138
  if (state.generation?.phase === 'paused')
127
- message = pauseUIMessage({ message, toolCallIds: calledTools(projection) })
139
+ message = pauseUIMessage({
140
+ message,
141
+ toolCallIds: calledTools({ projection, current }),
142
+ })
128
143
  if (state.generation?.phase === 'failed')
129
144
  message = interruptUIMessage(
130
145
  message,
@@ -142,14 +157,18 @@ export const generationBase = <M extends UIMessage>(
142
157
  ): AIContextState<M> => {
143
158
  const projection = state.activeProjection
144
159
  if (!projection) return state
160
+ const base = restoreMessageBase({
161
+ current: findMessage(state.messages, projection.responseMessageId),
162
+ base: projection.base,
163
+ })
145
164
  return {
146
165
  ...state,
147
166
  messages:
148
- projection.baseMessage === undefined
167
+ base === undefined
149
168
  ? state.messages.filter(
150
169
  (message) => message.id !== projection.responseMessageId,
151
170
  )
152
- : upsertMessage(state.messages, projection.baseMessage),
171
+ : upsertMessage(state.messages, base),
153
172
  compaction: projection.baseCompaction ?? null,
154
173
  }
155
174
  }
@@ -182,10 +201,11 @@ const ownsGeneration = <M extends UIMessage>(
182
201
  state.generation.phase !== 'superseded'
183
202
 
184
203
  export const createContextReducer = <M extends UIMessage, D extends EventDefs>({
185
- agent,
204
+ contract,
186
205
  }: {
187
- agent: AgentDefinition<M, D>
188
- }): AIStoredReducer<D, AIContextState<M>> => {
206
+ contract: Contract<D, Record<never, never>, unknown>
207
+ }): Reducer<D, AIContextState<M>> => {
208
+ const app = appReducerOf(contract)
189
209
  const initialState: AIContextState<M> = {
190
210
  messages: [],
191
211
  compaction: null,
@@ -195,15 +215,26 @@ export const createContextReducer = <M extends UIMessage, D extends EventDefs>({
195
215
  generation: null,
196
216
  activeProjection: null,
197
217
  messageIndexes: {},
218
+ ...(app === undefined ? {} : { app: app.initialState }),
198
219
  }
199
- const reducer = agent.contract
200
- .reducer({
201
- name: 'a2.ai.context.v3',
202
- initialState,
203
- stateSchema: contextSchema<M>(),
220
+ const reducer = makeReducer({
221
+ contract,
222
+ // The application state rides in this checkpoint so every generation
223
+ // reads it without another state read.
224
+ name:
225
+ app === undefined ? 'a2.ai.context.v6' : `${app.name}+a2.ai.context.v6`,
226
+ initialState,
227
+ stateSchema: contextSchema<M>(app),
228
+ }).fold((state, event) => {
229
+ const after = retainMessageBase({
230
+ before: state,
231
+ after: reduceContext(state, event),
204
232
  })
205
- .fold((state, event) => reduceContext(state, event))
206
- return storedAIReducer(reducer)
233
+ if (app === undefined) return after
234
+ const next = app.fold(state.app!, event as ContractEvent<EventDefs>)
235
+ return next === state.app ? after : { ...after, app: appSlice(next) }
236
+ })
237
+ return withAIStorage(reducer)
207
238
  }
208
239
 
209
240
  const reduceContext = <M extends UIMessage, D extends EventDefs>(
@@ -297,6 +328,7 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
297
328
  ...base,
298
329
  generation: {
299
330
  owner,
331
+ startIndex: event.index,
300
332
  phase: 'streaming',
301
333
  ...(previous?.owner.responseMessageId === owner.responseMessageId &&
302
334
  previous.responseIndex !== undefined
@@ -307,7 +339,9 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
307
339
  generationId: owner.generationId,
308
340
  responseMessageId: owner.responseMessageId,
309
341
  promptThroughIndex: owner.promptThroughIndex ?? event.index - 1,
310
- ...(baseMessage === undefined ? {} : { baseMessage }),
342
+ ...(baseMessage === undefined
343
+ ? {}
344
+ : { base: { partCount: baseMessage.parts.length } }),
311
345
  baseCompaction: base.compaction,
312
346
  batches: progressBatches(),
313
347
  toolEvents: [],
@@ -316,12 +350,16 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
316
350
  }
317
351
  }
318
352
  case 'ai.generation.progress': {
319
- const payload = event.payload as GenerationProgressPayload
353
+ const payload = event.payload as StoredProgressPayload
354
+ const generation = state.generation
320
355
  if (
321
- !ownsGeneration(state, payload) ||
322
- state.generation!.owner.responseMessageId !==
323
- payload.responseMessageId ||
324
- state.generation!.phase !== 'streaming' ||
356
+ generation === null ||
357
+ generation.phase !== 'streaming' ||
358
+ !progressOwnedBy({
359
+ payload,
360
+ owner: generation.owner,
361
+ startIndex: generation.startIndex,
362
+ }) ||
325
363
  !state.activeProjection
326
364
  )
327
365
  return state
@@ -433,10 +471,15 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
433
471
  ),
434
472
  }
435
473
  let next = generationBase(state)
436
- if (retained.baseMessage !== undefined || retained.batches.length > 0)
474
+ if (retained.base !== undefined || retained.batches.length > 0)
437
475
  next = replaceResponse({
438
476
  state: next,
439
- message: interruptUIMessage(projectedMessage(retained)),
477
+ message: interruptUIMessage(
478
+ projectedMessage({
479
+ projection: retained,
480
+ current: findMessage(state.messages, retained.responseMessageId),
481
+ }),
482
+ ),
440
483
  index: event.index,
441
484
  })
442
485
  return endGeneration(next)
@@ -458,7 +501,13 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
458
501
  !state.activeProjection
459
502
  )
460
503
  return state
461
- const toolCallIds = calledTools(state.activeProjection)
504
+ const toolCallIds = calledTools({
505
+ projection: state.activeProjection,
506
+ current: findMessage(
507
+ state.messages,
508
+ state.activeProjection.responseMessageId,
509
+ ),
510
+ })
462
511
  return renderProjection({
463
512
  state: {
464
513
  ...state,
@@ -617,11 +666,12 @@ const reduceContext = <M extends UIMessage, D extends EventDefs>(
617
666
  ),
618
667
  ]
619
668
  const activeProjection = { ...projection, cursor: null }
620
- delete activeProjection.baseMessage
669
+ delete activeProjection.base
621
670
  const baseMessage = messages.find(
622
671
  (message) => message.id === projection.responseMessageId,
623
672
  )
624
- if (baseMessage !== undefined) activeProjection.baseMessage = baseMessage
673
+ if (baseMessage !== undefined)
674
+ activeProjection.base = { partCount: baseMessage.parts.length }
625
675
  const compaction: AIModelContext<M>['compaction'] = {
626
676
  status: 'completed',
627
677
  generationId: payload.generationId,