experimental-a2 0.16.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (406) hide show
  1. package/CHANGELOG.md +373 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-ohPC-81x.d.ts → actor-Bjce9_5U.d.ts} +21 -11
  4. package/dist/actor-Bjce9_5U.d.ts.map +1 -0
  5. package/dist/actor-client.d.ts +2 -5
  6. package/dist/actor-client.d.ts.map +1 -1
  7. package/dist/actor-client.js +13 -4
  8. package/dist/actor-client.js.map +1 -1
  9. package/dist/actor-react.d.ts +5 -3
  10. package/dist/actor-react.d.ts.map +1 -1
  11. package/dist/actor-react.js +20 -10
  12. package/dist/actor-react.js.map +1 -1
  13. package/dist/{actor-shared-B5tJfzt-.js → actor-shared-t7w8xIKP.js} +12 -7
  14. package/dist/actor-shared-t7w8xIKP.js.map +1 -0
  15. package/dist/actor.d.ts +1 -1
  16. package/dist/actor.js +42 -23
  17. package/dist/actor.js.map +1 -1
  18. package/dist/{ai-DgOBltJ_.js → ai-BpOGm-zB.js} +621 -216
  19. package/dist/ai-BpOGm-zB.js.map +1 -0
  20. package/dist/{ai-CrEf6p_W.d.ts → ai-DrUaMyRt.d.ts} +114 -100
  21. package/dist/ai-DrUaMyRt.d.ts.map +1 -0
  22. package/dist/ai-client.d.ts +27 -0
  23. package/dist/ai-client.d.ts.map +1 -0
  24. package/dist/ai-client.js +29 -0
  25. package/dist/ai-client.js.map +1 -0
  26. package/dist/ai-fx.browser.d.ts +1 -0
  27. package/dist/ai-fx.browser.js +6 -0
  28. package/dist/ai-fx.browser.js.map +1 -0
  29. package/dist/ai-fx.d.ts +10 -0
  30. package/dist/ai-fx.d.ts.map +1 -0
  31. package/dist/ai-fx.js +634 -0
  32. package/dist/ai-fx.js.map +1 -0
  33. package/dist/ai-harness-BuLh_EYi.js +273 -0
  34. package/dist/ai-harness-BuLh_EYi.js.map +1 -0
  35. package/dist/ai-harness-DvsPeJeB.d.ts +26 -0
  36. package/dist/ai-harness-DvsPeJeB.d.ts.map +1 -0
  37. package/dist/ai-pi.browser.d.ts +1 -0
  38. package/dist/ai-pi.browser.js +6 -0
  39. package/dist/ai-pi.browser.js.map +1 -0
  40. package/dist/ai-pi.d.ts +17 -0
  41. package/dist/ai-pi.d.ts.map +1 -0
  42. package/dist/ai-pi.js +904 -0
  43. package/dist/ai-pi.js.map +1 -0
  44. package/dist/ai-react.d.ts +96 -0
  45. package/dist/ai-react.d.ts.map +1 -0
  46. package/dist/ai-react.js +142 -0
  47. package/dist/ai-react.js.map +1 -0
  48. package/dist/ai-server.browser.js +2 -2
  49. package/dist/ai-server.browser.js.map +1 -1
  50. package/dist/ai-server.d.ts +109 -43
  51. package/dist/ai-server.d.ts.map +1 -1
  52. package/dist/ai-server.js +526 -283
  53. package/dist/ai-server.js.map +1 -1
  54. package/dist/ai.d.ts +2 -2
  55. package/dist/ai.js +2 -2
  56. package/dist/bounded-cache-CPHWF-8h.js +41 -0
  57. package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
  58. package/dist/{client-BYzHjkwU.js → client-BReKqwZC.js} +447 -80
  59. package/dist/client-BReKqwZC.js.map +1 -0
  60. package/dist/{client-CzyacQpJ.d.ts → client-h_DKFAjj.d.ts} +14 -13
  61. package/dist/client-h_DKFAjj.d.ts.map +1 -0
  62. package/dist/client.d.ts +4 -2
  63. package/dist/client.js +1 -1
  64. package/dist/{contract-CKRg_E4q.js → contract-BYKASlCV.js} +12 -21
  65. package/dist/contract-BYKASlCV.js.map +1 -0
  66. package/dist/{idempotent-replay-DVOlyYbx.js → idempotent-replay-JdgMQRRm.js} +2 -2
  67. package/dist/{idempotent-replay-DVOlyYbx.js.map → idempotent-replay-JdgMQRRm.js.map} +1 -1
  68. package/dist/index.d.ts +6 -5
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +4 -3
  71. package/dist/{errors-DvhSXnxk.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +7 -3
  72. package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +1 -0
  73. package/dist/{internal-Dq2qYxou.js → internal-B2T3U4Rq.js} +29 -2
  74. package/dist/internal-B2T3U4Rq.js.map +1 -0
  75. package/dist/otel.d.ts +1 -1
  76. package/dist/react-BBXgHWFc.d.ts +86 -0
  77. package/dist/react-BBXgHWFc.d.ts.map +1 -0
  78. package/dist/react.d.ts +2 -122
  79. package/dist/react.js +107 -100
  80. package/dist/react.js.map +1 -1
  81. package/dist/reducer-BAXc8JyF.js +87 -0
  82. package/dist/reducer-BAXc8JyF.js.map +1 -0
  83. package/dist/{reducer-otzHjuJj.d.ts → reducer-CqA59Q6U.d.ts} +46 -30
  84. package/dist/reducer-CqA59Q6U.d.ts.map +1 -0
  85. package/dist/reducer-runtime-DQwz_J59.js +28 -0
  86. package/dist/reducer-runtime-DQwz_J59.js.map +1 -0
  87. package/dist/scheduler-qstash.d.ts +3 -3
  88. package/dist/scheduler-qstash.d.ts.map +1 -1
  89. package/dist/scheduler-qstash.js +33 -10
  90. package/dist/scheduler-qstash.js.map +1 -1
  91. package/dist/{scheduler-task-BpzhPnRS.js → scheduler-task-X1SToDjP.js} +18 -3
  92. package/dist/scheduler-task-X1SToDjP.js.map +1 -0
  93. package/dist/scheduler-vercel.d.ts +4 -9
  94. package/dist/scheduler-vercel.d.ts.map +1 -1
  95. package/dist/scheduler-vercel.js +25 -44
  96. package/dist/scheduler-vercel.js.map +1 -1
  97. package/dist/{server-BD5ckxZb.js → server-Dw_k_7kO.js} +904 -219
  98. package/dist/server-Dw_k_7kO.js.map +1 -0
  99. package/dist/{server-DbD7IJVK.d.ts → server-En7cbi3v.d.ts} +116 -26
  100. package/dist/server-En7cbi3v.d.ts.map +1 -0
  101. package/dist/server.d.ts +4 -4
  102. package/dist/server.js +2 -2
  103. package/dist/session-clear-Bo-XTFEy.d.ts +12 -0
  104. package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
  105. package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
  106. package/dist/session-clear-DGI4jTQ5.js.map +1 -0
  107. package/dist/{store-DyZM6fS5.d.ts → store-Djdv0bnZ.d.ts} +73 -3
  108. package/dist/store-Djdv0bnZ.d.ts.map +1 -0
  109. package/dist/store-N8PXxDAS.js.map +1 -1
  110. package/dist/store-memory.d.ts +1 -1
  111. package/dist/store-memory.d.ts.map +1 -1
  112. package/dist/store-memory.js +205 -66
  113. package/dist/store-memory.js.map +1 -1
  114. package/dist/{store-polling-CmxUbV93.js → store-polling-B5FcwJfo.js} +21 -4
  115. package/dist/store-polling-B5FcwJfo.js.map +1 -0
  116. package/dist/store-postgres.d.ts +1 -1
  117. package/dist/store-postgres.d.ts.map +1 -1
  118. package/dist/store-postgres.js +450 -108
  119. package/dist/store-postgres.js.map +1 -1
  120. package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-BAwS8RWn.js} +3 -3
  121. package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-BAwS8RWn.js.map} +1 -1
  122. package/dist/store-redis-http.d.ts +1 -1
  123. package/dist/store-redis-http.d.ts.map +1 -1
  124. package/dist/store-redis-http.js +293 -11
  125. package/dist/store-redis-http.js.map +1 -1
  126. package/dist/store-redis-notify-BRITti_o.js +2493 -0
  127. package/dist/store-redis-notify-BRITti_o.js.map +1 -0
  128. package/dist/store-redis.d.ts +1 -1
  129. package/dist/store-redis.d.ts.map +1 -1
  130. package/dist/store-redis.js +11 -11
  131. package/dist/store-redis.js.map +1 -1
  132. package/dist/store-sqlite.d.ts +1 -1
  133. package/dist/store-sqlite.d.ts.map +1 -1
  134. package/dist/store-sqlite.js +197 -33
  135. package/dist/store-sqlite.js.map +1 -1
  136. package/dist/stream-buffer-Cx7AAPGq.js +23 -0
  137. package/dist/stream-buffer-Cx7AAPGq.js.map +1 -0
  138. package/dist/{telemetry-B5jzpy6y.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
  139. package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
  140. package/dist/{wire-BO5wWCb1.js → wire-rSUglYo8.js} +132 -10
  141. package/dist/wire-rSUglYo8.js.map +1 -0
  142. package/docs/01-quickstart.mdx +50 -84
  143. package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
  144. package/docs/actors/01-introduction.mdx +48 -82
  145. package/docs/actors/02-concurrency.mdx +43 -70
  146. package/docs/actors/03-timers.mdx +28 -42
  147. package/docs/actors/04-routes.mdx +110 -137
  148. package/docs/actors/meta.ts +1 -1
  149. package/docs/agents/01-introduction.mdx +257 -0
  150. package/docs/agents/02-tools.mdx +247 -0
  151. package/docs/agents/03-conversations.mdx +538 -0
  152. package/docs/agents/04-harnesses.mdx +136 -0
  153. package/docs/agents/meta.ts +1 -0
  154. package/docs/client/01-react.mdx +294 -0
  155. package/docs/client/02-transports.mdx +86 -0
  156. package/docs/client/03-presence.mdx +224 -0
  157. package/docs/client/meta.ts +1 -0
  158. package/docs/contract/01-events.mdx +57 -0
  159. package/docs/contract/02-state.mdx +142 -0
  160. package/docs/contract/03-sessions.mdx +175 -0
  161. package/docs/index.mdx +112 -156
  162. package/docs/reference/01-core.mdx +139 -0
  163. package/docs/reference/02-server.mdx +855 -0
  164. package/docs/reference/03-client.mdx +301 -0
  165. package/docs/reference/04-ai.mdx +722 -0
  166. package/docs/reference/05-adapters.mdx +351 -0
  167. package/docs/reference/06-errors.mdx +138 -0
  168. package/docs/reference/meta.ts +1 -1
  169. package/docs/server/01-handlers.mdx +200 -0
  170. package/docs/server/02-timers.mdx +130 -0
  171. package/docs/server/03-cancellation.mdx +141 -0
  172. package/docs/server/04-routes.mdx +243 -0
  173. package/docs/server/05-production.mdx +322 -0
  174. package/docs/server/06-guarantees.mdx +123 -0
  175. package/examples/playground/DEPLOY.md +53 -7
  176. package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
  177. package/examples/playground/app/a0/[appId]/page.tsx +53 -0
  178. package/examples/playground/app/a0/a0.css +818 -0
  179. package/examples/playground/app/a0/app-list.tsx +218 -0
  180. package/examples/playground/app/a0/app-view.tsx +63 -0
  181. package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
  182. package/examples/playground/app/a0/apps/[appId]/route.ts +28 -0
  183. package/examples/playground/app/a0/apps.test.ts +128 -0
  184. package/examples/playground/app/a0/apps.ts +102 -0
  185. package/examples/playground/app/a0/chat.tsx +410 -0
  186. package/examples/playground/app/a0/columns.tsx +109 -0
  187. package/examples/playground/app/a0/context-menu.tsx +116 -0
  188. package/examples/playground/app/a0/cookies.ts +46 -0
  189. package/examples/playground/app/a0/crash-on-request.ts +72 -0
  190. package/examples/playground/app/a0/crashes/route.ts +3 -0
  191. package/examples/playground/app/a0/crashes.test.ts +33 -0
  192. package/examples/playground/app/a0/crashes.ts +28 -0
  193. package/examples/playground/app/a0/devtools.tsx +164 -0
  194. package/examples/playground/app/a0/events/route.ts +6 -0
  195. package/examples/playground/app/a0/flags.ts +30 -0
  196. package/examples/playground/app/a0/fx/events/route.ts +9 -0
  197. package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
  198. package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
  199. package/examples/playground/app/a0/layout.tsx +38 -0
  200. package/examples/playground/app/a0/list/route.ts +10 -0
  201. package/examples/playground/app/a0/model.test.ts +73 -0
  202. package/examples/playground/app/a0/model.ts +95 -0
  203. package/examples/playground/app/a0/no-photon.cjs +4 -0
  204. package/examples/playground/app/a0/no-quickjs.cjs +3 -0
  205. package/examples/playground/app/a0/page.tsx +14 -0
  206. package/examples/playground/app/a0/pi/events/route.ts +9 -0
  207. package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
  208. package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
  209. package/examples/playground/app/a0/preview-pane.tsx +145 -0
  210. package/examples/playground/app/a0/preview.test.ts +53 -0
  211. package/examples/playground/app/a0/preview.ts +26 -0
  212. package/examples/playground/app/a0/sandbox-log.ts +75 -0
  213. package/examples/playground/app/a0/sandbox-session.ts +152 -0
  214. package/examples/playground/app/a0/sandbox.ts +191 -0
  215. package/examples/playground/app/a0/sandboxes/scheduler/route.ts +6 -0
  216. package/examples/playground/app/a0/scheduler/route.ts +7 -0
  217. package/examples/playground/app/a0/server.ts +213 -0
  218. package/examples/playground/app/a0/session.ts +59 -0
  219. package/examples/playground/app/a0/shell.tsx +158 -0
  220. package/examples/playground/app/a0/short/events/route.ts +9 -0
  221. package/examples/playground/app/a0/splitter.tsx +120 -0
  222. package/examples/playground/app/agent/[agentId]/agent-client.tsx +144 -174
  223. package/examples/playground/app/agent/[agentId]/command-receipt.test.tsx +65 -0
  224. package/examples/playground/app/agent/[agentId]/command-receipt.tsx +27 -0
  225. package/examples/playground/app/agent/[agentId]/compaction-event.tsx +25 -24
  226. package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +119 -0
  227. package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +208 -165
  228. package/examples/playground/app/agent/[agentId]/page.tsx +2 -16
  229. package/examples/playground/app/agent/events/route.ts +5 -2
  230. package/examples/playground/app/agent/ingress.test.ts +101 -0
  231. package/examples/playground/app/agent/model-input.test.tsx +58 -0
  232. package/examples/playground/app/agent/model-input.tsx +115 -0
  233. package/examples/playground/app/agent/model.test.ts +73 -0
  234. package/examples/playground/app/agent/model.ts +58 -26
  235. package/examples/playground/app/agent/new-agent-session.tsx +37 -19
  236. package/examples/playground/app/agent/page.tsx +4 -4
  237. package/examples/playground/app/agent/server.ts +19 -15
  238. package/examples/playground/app/agent/session.ts +5 -6
  239. package/examples/playground/app/agent/telemetry.test.ts +189 -0
  240. package/examples/playground/app/agent/telemetry.ts +30 -0
  241. package/examples/playground/app/agent/trace.test.ts +23 -0
  242. package/examples/playground/app/agent/trace.ts +18 -0
  243. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +12 -12
  244. package/examples/playground/app/canvas/[canvasId]/page.tsx +1 -2
  245. package/examples/playground/app/canvas/[canvasId]/session.ts +2 -2
  246. package/examples/playground/app/canvas/model.ts +53 -53
  247. package/examples/playground/app/chat/[chatId]/agent-state.test.ts +176 -0
  248. package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +16 -1
  249. package/examples/playground/app/chat/[chatId]/chat-client.tsx +55 -77
  250. package/examples/playground/app/chat/[chatId]/chat-view.ts +37 -3
  251. package/examples/playground/app/chat/[chatId]/page.tsx +7 -15
  252. package/examples/playground/app/chat/[chatId]/session.ts +2 -19
  253. package/examples/playground/app/chat/agent/route.ts +9 -0
  254. package/examples/playground/app/chat/model.test.ts +46 -119
  255. package/examples/playground/app/chat/model.ts +82 -128
  256. package/examples/playground/app/chat/scheduler/route.ts +2 -2
  257. package/examples/playground/app/chat/server.test.ts +112 -0
  258. package/examples/playground/app/chat/server.ts +113 -117
  259. package/examples/playground/app/components/activity-feed.tsx +30 -1
  260. package/examples/playground/app/components/activity-history.test.tsx +35 -0
  261. package/examples/playground/app/components/demo-icons.tsx +89 -0
  262. package/examples/playground/app/components/demos.tsx +33 -0
  263. package/examples/playground/app/components/fast-link.test.tsx +58 -0
  264. package/examples/playground/app/components/fast-link.tsx +55 -0
  265. package/examples/playground/app/components/site-header.tsx +96 -0
  266. package/examples/playground/app/counter/counter-client.tsx +3 -3
  267. package/examples/playground/app/counter/model.test.ts +3 -3
  268. package/examples/playground/app/counter/model.ts +11 -21
  269. package/examples/playground/app/counter/page.tsx +2 -15
  270. package/examples/playground/app/counter/session.ts +2 -2
  271. package/examples/playground/app/documents/[documentId]/code-editor.tsx +12 -1
  272. package/examples/playground/app/documents/[documentId]/document-client.tsx +10 -11
  273. package/examples/playground/app/documents/[documentId]/page.tsx +1 -2
  274. package/examples/playground/app/documents/[documentId]/session.ts +2 -2
  275. package/examples/playground/app/documents/model.ts +27 -27
  276. package/examples/playground/app/globals.css +420 -207
  277. package/examples/playground/app/initial-state.test.tsx +54 -0
  278. package/examples/playground/app/layout.tsx +7 -23
  279. package/examples/playground/app/orders/[orderId]/page.tsx +1 -2
  280. package/examples/playground/app/orders/[orderId]/session.ts +2 -2
  281. package/examples/playground/app/orders/model.ts +49 -49
  282. package/examples/playground/app/page.tsx +13 -102
  283. package/examples/playground/app/recovery/[recoveryId]/page.tsx +1 -2
  284. package/examples/playground/app/recovery/[recoveryId]/session.ts +2 -2
  285. package/examples/playground/app/recovery/model.ts +30 -30
  286. package/examples/playground/instrumentation.ts +5 -0
  287. package/examples/playground/next.config.ts +17 -5
  288. package/examples/playground/package.json +13 -2
  289. package/examples/playground/scripts/a0-template.ts +77 -0
  290. package/examples/playground/vercel.json +36 -0
  291. package/package.json +29 -3
  292. package/src/actor-client.ts +16 -4
  293. package/src/actor-react.ts +25 -11
  294. package/src/actor-shared.ts +21 -6
  295. package/src/actor.ts +76 -31
  296. package/src/ai-agent-actions.ts +219 -0
  297. package/src/ai-agent.ts +2517 -0
  298. package/src/ai-app-state.ts +91 -0
  299. package/src/ai-client-state.ts +6 -3
  300. package/src/ai-client.ts +62 -0
  301. package/src/ai-context-schema.ts +25 -5
  302. package/src/ai-context.ts +90 -40
  303. package/src/ai-control-server.ts +92 -72
  304. package/src/ai-coordinator.ts +23 -22
  305. package/src/ai-fx.browser.ts +5 -0
  306. package/src/ai-fx.ts +833 -0
  307. package/src/ai-harness.ts +518 -0
  308. package/src/ai-message-base.ts +209 -0
  309. package/src/ai-message-projection.ts +262 -64
  310. package/src/ai-model-metadata.ts +11 -6
  311. package/src/ai-pi.browser.ts +5 -0
  312. package/src/ai-pi.ts +1263 -0
  313. package/src/ai-progress-batches.ts +26 -0
  314. package/src/ai-projector.ts +95 -14
  315. package/src/ai-react.ts +146 -0
  316. package/src/ai-sdk-step.ts +2 -2
  317. package/src/ai-server.browser.ts +2 -2
  318. package/src/ai-server.ts +23 -1965
  319. package/src/ai-stored-state.ts +48 -163
  320. package/src/ai.ts +339 -155
  321. package/src/bootstrap-stream.ts +72 -0
  322. package/src/bounded-cache.ts +55 -0
  323. package/src/client-render-session.ts +49 -0
  324. package/src/client.ts +688 -151
  325. package/src/contract.ts +92 -42
  326. package/src/deterministic-id.ts +37 -0
  327. package/src/equal-json.ts +32 -0
  328. package/src/errors.ts +13 -1
  329. package/src/index.ts +5 -1
  330. package/src/initial-snapshot.ts +39 -0
  331. package/src/internal.ts +52 -0
  332. package/src/libfx.d.ts +34 -0
  333. package/src/postgres-notification-scope.ts +14 -3
  334. package/src/react.ts +171 -206
  335. package/src/redis-http-reply.ts +256 -0
  336. package/src/redis-http-stream.ts +73 -0
  337. package/src/redis-http-subscriptions.ts +13 -5
  338. package/src/reducer-runtime.ts +52 -0
  339. package/src/reducer.ts +93 -11
  340. package/src/scheduler-qstash.ts +49 -20
  341. package/src/scheduler-task.ts +34 -2
  342. package/src/scheduler-vercel.ts +32 -84
  343. package/src/server-fetch.ts +139 -35
  344. package/src/server.ts +1133 -255
  345. package/src/session-clear.ts +23 -0
  346. package/src/session-socket.ts +154 -49
  347. package/src/sse.ts +71 -4
  348. package/src/store-memory.ts +252 -75
  349. package/src/store-polling.ts +18 -4
  350. package/src/store-postgres.ts +541 -114
  351. package/src/store-redis-core.ts +1450 -493
  352. package/src/store-redis-http.ts +18 -2
  353. package/src/store-redis-notify.ts +262 -85
  354. package/src/store-redis.ts +19 -9
  355. package/src/store-sqlite.ts +319 -45
  356. package/src/store.ts +79 -1
  357. package/src/stream-buffer.ts +43 -0
  358. package/src/telemetry.ts +14 -1
  359. package/src/wire.ts +241 -13
  360. package/dist/actor-ohPC-81x.d.ts.map +0 -1
  361. package/dist/actor-shared-B5tJfzt-.js.map +0 -1
  362. package/dist/ai-CrEf6p_W.d.ts.map +0 -1
  363. package/dist/ai-DgOBltJ_.js.map +0 -1
  364. package/dist/client-BYzHjkwU.js.map +0 -1
  365. package/dist/client-CzyacQpJ.d.ts.map +0 -1
  366. package/dist/contract-CKRg_E4q.js.map +0 -1
  367. package/dist/errors-DCk6ch5n.js.map +0 -1
  368. package/dist/errors-DvhSXnxk.d.ts.map +0 -1
  369. package/dist/internal-Dq2qYxou.js.map +0 -1
  370. package/dist/react.d.ts.map +0 -1
  371. package/dist/reducer-DEMjEY_O.js +0 -29
  372. package/dist/reducer-DEMjEY_O.js.map +0 -1
  373. package/dist/reducer-otzHjuJj.d.ts.map +0 -1
  374. package/dist/scheduler-task-BpzhPnRS.js.map +0 -1
  375. package/dist/server-BD5ckxZb.js.map +0 -1
  376. package/dist/server-DbD7IJVK.d.ts.map +0 -1
  377. package/dist/store-DyZM6fS5.d.ts.map +0 -1
  378. package/dist/store-polling-CmxUbV93.js.map +0 -1
  379. package/dist/store-redis-notify-BVLUfI3j.js +0 -1583
  380. package/dist/store-redis-notify-BVLUfI3j.js.map +0 -1
  381. package/dist/telemetry-B5jzpy6y.d.ts.map +0 -1
  382. package/dist/validate-XKT4FSNn.js +0 -30
  383. package/dist/validate-XKT4FSNn.js.map +0 -1
  384. package/dist/wire-BO5wWCb1.js.map +0 -1
  385. package/docs/concepts/01-contracts.mdx +0 -142
  386. package/docs/concepts/02-handlers.mdx +0 -284
  387. package/docs/concepts/03-durability.mdx +0 -314
  388. package/docs/concepts/04-state.mdx +0 -209
  389. package/docs/guides/01-timers.mdx +0 -185
  390. package/docs/guides/02-cancellation.mdx +0 -161
  391. package/docs/guides/03-react.mdx +0 -384
  392. package/docs/guides/04-local-first.mdx +0 -88
  393. package/docs/guides/05-production.mdx +0 -521
  394. package/docs/guides/06-ai-agents.mdx +0 -1318
  395. package/docs/guides/08-application-data.mdx +0 -113
  396. package/docs/guides/09-presence.mdx +0 -266
  397. package/docs/guides/10-transports.mdx +0 -221
  398. package/docs/reference/01-api.mdx +0 -1896
  399. package/docs/reference/02-errors.mdx +0 -149
  400. package/examples/playground/app/agent/[agentId]/compaction/route.ts +0 -14
  401. package/examples/playground/app/agent/compaction-settings.test.ts +0 -144
  402. package/examples/playground/app/agent/compaction-settings.ts +0 -49
  403. package/examples/playground/app/agent/compaction-timeline.test.ts +0 -377
  404. package/examples/playground/app/agent/compaction-timeline.ts +0 -208
  405. /package/docs/{concepts → contract}/meta.ts +0 -0
  406. /package/docs/{guides → server}/meta.ts +0 -0
package/dist/ai-server.js CHANGED
@@ -1,8 +1,10 @@
1
- import { n as validateSync } from "./validate-XKT4FSNn.js";
2
- import { t as A2Error } from "./errors-DCk6ch5n.js";
3
- import { f as consumeSchedulerSendFailure, p as installAmbientToolScopeStorage } from "./internal-Dq2qYxou.js";
4
- import { i as setServerFetchHooks, t as createServer } from "./server-BD5ckxZb.js";
5
- import { C as interruptUIMessage, S as progressBatches, _ as projectedMessage, a as events, b as upsertResponse, d as AI_EVENT_ID_PREFIX, f as aiEventId, g as advanceProjection, h as controlCommit, l as aiStateReducer, m as applyControlChanges, p as initialControlState, u as storedAIReducer, v as reduceToolActivity, w as pauseUIMessage, x as flattenProgressBatches, y as upsertMessage } from "./ai-DgOBltJ_.js";
1
+ import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
2
+ import { a as reducer, s as validateSync } from "./reducer-BAXc8JyF.js";
3
+ import { h as installAmbientToolScopeStorage, m as failedPreviousAttempt, p as consumeSchedulerSendFailure } from "./internal-B2T3U4Rq.js";
4
+ import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
5
+ import { a as CONSOLE_TELEMETRY, o as setServerFetchHooks, t as createServer } from "./server-Dw_k_7kO.js";
6
+ import { A as interruptUIMessage, C as reduceToolActivity, D as flattenProgressBatches, E as upsertResponse, M as assertMessageBase, N as restoreMessageBase, O as progressBatches, S as projectedMessage, T as upsertMessage, _ as applyControlChanges, a as events, b as findMessage, d as appSlice, f as isAgentContract, g as initialControlState, h as aiEventId, j as pauseUIMessage, k as progressOwnedBy, m as AI_EVENT_ID_PREFIX, n as agentContract, p as withAIStorage, u as appReducerOf, v as controlCommit, w as retainMessageBase, y as advanceProjection } from "./ai-BpOGm-zB.js";
7
+ import { a as harnessDriver, o as harnessLog, s as harnessStates, u as registerHarnessStates } from "./ai-harness-BuLh_EYi.js";
6
8
  import { AsyncLocalStorage } from "node:async_hooks";
7
9
  import { createHash } from "node:crypto";
8
10
  import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
@@ -118,7 +120,7 @@ const foldCoordinator = (state, event) => {
118
120
  }));
119
121
  const inputTokens = completion.usage?.inputTokens;
120
122
  const estimate = completion.inputTokenEstimate;
121
- return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 ? {
123
+ return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 && state.response.generation.model !== void 0 ? {
122
124
  ...uncalibrated,
123
125
  calibration: {
124
126
  model: state.response.generation.model,
@@ -218,7 +220,8 @@ const foldCoordinator = (state, event) => {
218
220
  default: return state;
219
221
  }
220
222
  };
221
- const aiCoordinatorReducer = (contract) => contract.reducer({
223
+ const aiCoordinatorReducer = (contract) => reducer({
224
+ contract,
222
225
  name: "a2.ai.coordinator.v6",
223
226
  initialState: {
224
227
  closed: false,
@@ -238,7 +241,9 @@ var ControlCancelled = class extends Error {};
238
241
  const callReadyForModel = (call) => call.terminal || call.call.providerExecuted === true && !call.call.supportsDeferredResults && call.response !== void 0;
239
242
  const approvalBlocksExecution = (call) => call.approval !== void 0 && call.response?.approved !== true;
240
243
  const createControlRuntime = (options) => {
241
- const reducer = options.agent.contract.reducer({
244
+ const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
245
+ const reducer$2 = reducer({
246
+ contract: options.contract,
242
247
  name: "a2.ai.control.v5",
243
248
  initialState: initialControlState()
244
249
  }).fold((state, event) => {
@@ -268,9 +273,9 @@ const createControlRuntime = (options) => {
268
273
  changes: event.payload.changes
269
274
  }) : state;
270
275
  });
271
- const coordinator = aiCoordinatorReducer(options.agent.contract);
276
+ const coordinator = aiCoordinatorReducer(options.contract);
272
277
  const handler = async (ctx) => {
273
- const snapshot = await ctx.session.state(reducer, { through: "latest" });
278
+ const snapshot = await ctx.session.state(reducer$2, { through: "latest" });
274
279
  const before = structuredClone(snapshot.state);
275
280
  const moves = [];
276
281
  const state = structuredClone(snapshot.state);
@@ -502,7 +507,7 @@ const createControlRuntime = (options) => {
502
507
  responseMessageId: response.responseMessageId,
503
508
  reason: "retry"
504
509
  },
505
- id: await aiEventId("a2.ai.request.retry", options.agent.contract.name, ctx.event.sessionId, command.request.retryId)
510
+ id: await aiEventId("a2.ai.request.retry", options.contract.name, ctx.event.sessionId, command.request.retryId)
506
511
  });
507
512
  } else reason = "stale-turn";
508
513
  break;
@@ -634,7 +639,7 @@ const createControlRuntime = (options) => {
634
639
  message: item.message,
635
640
  generate: item.generate
636
641
  },
637
- id: await aiEventId("a2.ai.admitted", options.agent.contract.name, ctx.event.sessionId, item.id)
642
+ id: await aiEventId("a2.ai.admitted", options.contract.name, ctx.event.sessionId, item.id)
638
643
  });
639
644
  if (!item.generate) continue;
640
645
  state.active = {
@@ -645,7 +650,7 @@ const createControlRuntime = (options) => {
645
650
  suspended: false,
646
651
  model: null
647
652
  };
648
- const requestId = await aiEventId("a2.ai.request.message", options.agent.contract.name, ctx.event.sessionId, item.id);
653
+ const requestId = await aiEventId("a2.ai.request.message", options.contract.name, ctx.event.sessionId, item.id);
649
654
  requestModel({
650
655
  request: {
651
656
  messageId: item.id,
@@ -685,7 +690,7 @@ const createControlRuntime = (options) => {
685
690
  const payload = ctx.event.payload;
686
691
  const { turnId, version } = "turnId" in payload ? payload : payload.control;
687
692
  for (const event of events) {
688
- const schema = options.agent.contract.events[event.type];
693
+ const schema = options.contract.events[event.type];
689
694
  const result = validateSync(schema, event.payload, `AI worker ${event.type}`);
690
695
  if (result.issues) throw new TypeError(result.issues.map((issue) => issue.message).join("; "));
691
696
  }
@@ -719,32 +724,39 @@ const createControlRuntime = (options) => {
719
724
  });
720
725
  const persisted = await ctx.session.append(name, ...progress, input);
721
726
  const index = persisted.at(-1).index;
722
- const stream = ctx.session.stream({ startAfter: index })[Symbol.asyncIterator]();
723
- const canonical = [];
724
- const wanted = new Set(lifecycle.map((event) => event.id));
725
- let rejectAbort;
726
- const aborted = new Promise((_, reject) => {
727
- rejectAbort = reject;
728
- });
729
- const onAbort = () => {
730
- rejectAbort(ctx.signal.reason);
731
- };
732
- ctx.signal.addEventListener("abort", onAbort, { once: true });
733
- try {
734
- ctx.signal.throwIfAborted();
735
- for (;;) {
736
- const item = await Promise.race([stream.next(), aborted]);
737
- if (item.done) throw new Error("AI control acknowledgement stream ended");
738
- if (wanted.has(item.value.id)) canonical.push(item.value);
739
- if (item.value.type === "ai.control.decided" && item.value.payload.commandId === input.id) {
740
- if (item.value.payload.outcome === "rejected") throw new ControlCancelled("stale AI work");
741
- return [...persisted.filter((event) => event.type !== "ai.work.reported"), ...canonical];
727
+ return telemetry.span("a2.ai.ack", {
728
+ "a2.contract": options.contract.name,
729
+ "a2.session_id": ctx.event.sessionId,
730
+ "a2.ai.ack.request_id": ctx.event.id,
731
+ "a2.ai.ack.report_id": input.id
732
+ }, async () => {
733
+ const stream = ctx.session.stream({ startAfter: index })[Symbol.asyncIterator]();
734
+ const canonical = [];
735
+ const wanted = new Set(lifecycle.map((event) => event.id));
736
+ let rejectAbort;
737
+ const aborted = new Promise((_, reject) => {
738
+ rejectAbort = reject;
739
+ });
740
+ const onAbort = () => {
741
+ rejectAbort(ctx.signal.reason);
742
+ };
743
+ ctx.signal.addEventListener("abort", onAbort, { once: true });
744
+ try {
745
+ ctx.signal.throwIfAborted();
746
+ for (;;) {
747
+ const item = await Promise.race([stream.next(), aborted]);
748
+ if (item.done) throw new Error("AI control acknowledgement stream ended");
749
+ if (wanted.has(item.value.id)) canonical.push(item.value);
750
+ if (item.value.type === "ai.control.decided" && item.value.payload.commandId === input.id) {
751
+ if (item.value.payload.outcome === "rejected") throw new ControlCancelled("stale AI work");
752
+ return [...persisted.filter((event) => event.type !== "ai.work.reported"), ...canonical];
753
+ }
742
754
  }
755
+ } finally {
756
+ ctx.signal.removeEventListener("abort", onAbort);
757
+ await stream.return?.();
743
758
  }
744
- } finally {
745
- ctx.signal.removeEventListener("abort", onAbort);
746
- await stream.return?.();
747
- }
759
+ });
748
760
  };
749
761
  const settled = ({ ctx, events }) => report({
750
762
  ctx,
@@ -761,7 +773,7 @@ const createControlRuntime = (options) => {
761
773
  append,
762
774
  settled,
763
775
  cancelled,
764
- reducer,
776
+ reducer: reducer$2,
765
777
  coordinator
766
778
  };
767
779
  };
@@ -802,19 +814,29 @@ const progress = (value) => {
802
814
  return count === value["length"];
803
815
  };
804
816
  const indexedEvents = (value, types) => Array.isArray(value) && value.every((event) => record(event) && index(event["index"]) && types.includes(event["type"]) && matches(events[event["type"]], event["payload"]));
817
+ const restorableBase = (options) => {
818
+ assertMessageBase(options.base);
819
+ return isMessage(restoreMessageBase({
820
+ current: options.current,
821
+ base: options.base
822
+ }));
823
+ };
805
824
  const projection = (value, messages) => {
806
825
  if (!record(value) || Object.keys(value).some((key) => ![
807
826
  "generationId",
808
827
  "responseMessageId",
809
828
  "promptThroughIndex",
810
829
  "completionIndex",
811
- "baseMessage",
830
+ "base",
812
831
  "baseCompaction",
813
832
  "batches",
814
833
  "toolEvents",
815
834
  "approvalEvents",
816
835
  "cursor"
817
- ].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["baseMessage"] !== void 0 && !isMessage(value["baseMessage"]) || value["baseCompaction"] !== void 0 && !compaction(value["baseCompaction"]) || !progress(value["batches"]) || !indexedEvents(value["toolEvents"], ["ai.tool.called", "ai.tool.result"]) || !indexedEvents(value["approvalEvents"], ["ai.approval.requested", "ai.approval.responded"])) return false;
836
+ ].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["base"] !== void 0 && !restorableBase({
837
+ base: value["base"],
838
+ current: messages.find((message) => message.id === value["responseMessageId"])
839
+ }) || value["baseCompaction"] !== void 0 && !compaction(value["baseCompaction"]) || !progress(value["batches"]) || !indexedEvents(value["toolEvents"], ["ai.tool.called", "ai.tool.result"]) || !indexedEvents(value["approvalEvents"], ["ai.approval.requested", "ai.approval.responded"])) return false;
818
840
  const cursor = value["cursor"];
819
841
  if (cursor === void 0 || cursor === null) return true;
820
842
  if (!record(cursor) || !index(cursor["throughIndex"]) || !record(cursor["stream"])) return false;
@@ -848,7 +870,7 @@ const authority = (value) => value === null || record(value) && Object.keys(valu
848
870
  "pausing",
849
871
  "paused"
850
872
  ].includes(String(value["phase"])));
851
- const contextSchema = () => ({ "~standard": {
873
+ const contextSchema = (app) => ({ "~standard": {
852
874
  version: 1,
853
875
  vendor: "a2-context",
854
876
  validate(value) {
@@ -861,7 +883,8 @@ const contextSchema = () => ({ "~standard": {
861
883
  "authority",
862
884
  "generation",
863
885
  "activeProjection",
864
- "messageIndexes"
886
+ "messageIndexes",
887
+ ...app === void 0 ? [] : ["app"]
865
888
  ];
866
889
  try {
867
890
  if (!record(value) || keys.some((key) => !Object.hasOwn(value, key)) || Object.keys(value).some((key) => !keys.includes(key))) return invalid;
@@ -873,7 +896,7 @@ const contextSchema = () => ({ "~standard": {
873
896
  modelId,
874
897
  limits: entry["limits"]
875
898
  }))) || !indexes(value["messageIndexes"], messages)) return invalid;
876
- if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || ![
899
+ if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || !index(generation["startIndex"]) || ![
877
900
  "streaming",
878
901
  "completed",
879
902
  "paused",
@@ -884,6 +907,7 @@ const contextSchema = () => ({ "~standard": {
884
907
  if (current !== null && (!projection(current, messages) || !record(current) || current["generationId"] !== owner?.["generationId"] || current["responseMessageId"] !== owner?.["responseMessageId"])) return invalid;
885
908
  if (generation !== null && generation["phase"] !== "superseded" && current === null) return invalid;
886
909
  if (value["closed"] && (generation !== null || current !== null)) return invalid;
910
+ if (app !== void 0 && !record(value["app"])) return invalid;
887
911
  return { value };
888
912
  } catch {
889
913
  return invalid;
@@ -911,14 +935,24 @@ const replaceResponse = ({ state, message, index }) => {
911
935
  }
912
936
  };
913
937
  };
914
- const calledTools = (projection) => /* @__PURE__ */ new Set([...projection.baseMessage?.parts.flatMap((part) => "toolCallId" in part ? [part.toolCallId] : []) ?? [], ...projection.toolEvents.filter((event) => event.type === "ai.tool.called").map((event) => event.payload.toolCallId)]);
938
+ const calledTools = ({ projection, current }) => /* @__PURE__ */ new Set([...restoreMessageBase({
939
+ current,
940
+ base: projection.base
941
+ })?.parts.flatMap((part) => "toolCallId" in part ? [part.toolCallId] : []) ?? [], ...projection.toolEvents.filter((event) => event.type === "ai.tool.called").map((event) => event.payload.toolCallId)]);
915
942
  const renderProjection = ({ state, index }) => {
916
943
  const projection = state.activeProjection;
917
- let message = projectedMessage(projection);
918
- if (projection.baseMessage === void 0 && projection.batches.length === 0 && message.parts.length === 0) return state;
944
+ const current = findMessage(state.messages, projection.responseMessageId);
945
+ let message = projectedMessage({
946
+ projection,
947
+ current
948
+ });
949
+ if (projection.base === void 0 && projection.batches.length === 0 && message.parts.length === 0) return state;
919
950
  if (state.generation?.phase === "paused") message = pauseUIMessage({
920
951
  message,
921
- toolCallIds: calledTools(projection)
952
+ toolCallIds: calledTools({
953
+ projection,
954
+ current
955
+ })
922
956
  });
923
957
  if (state.generation?.phase === "failed") message = interruptUIMessage(message, `Generation failed before tool completion: ${state.generation.error}`);
924
958
  return replaceResponse({
@@ -936,9 +970,13 @@ const renderProjection = ({ state, index }) => {
936
970
  const generationBase = (state) => {
937
971
  const projection = state.activeProjection;
938
972
  if (!projection) return state;
973
+ const base = restoreMessageBase({
974
+ current: findMessage(state.messages, projection.responseMessageId),
975
+ base: projection.base
976
+ });
939
977
  return {
940
978
  ...state,
941
- messages: projection.baseMessage === void 0 ? state.messages.filter((message) => message.id !== projection.responseMessageId) : upsertMessage(state.messages, projection.baseMessage),
979
+ messages: base === void 0 ? state.messages.filter((message) => message.id !== projection.responseMessageId) : upsertMessage(state.messages, base),
942
980
  compaction: projection.baseCompaction ?? null
943
981
  };
944
982
  };
@@ -957,22 +995,37 @@ const endGeneration = (state) => ({
957
995
  activeProjection: null
958
996
  });
959
997
  const ownsGeneration = (state, owner) => state.generation?.owner.generationId === owner.generationId && state.generation.owner.requestId === owner.requestId && state.generation.phase !== "superseded";
960
- const createContextReducer = ({ agent }) => {
961
- const reducer = agent.contract.reducer({
962
- name: "a2.ai.context.v3",
963
- initialState: {
964
- messages: [],
965
- compaction: null,
966
- modelMetadata: {},
967
- closed: false,
968
- authority: null,
969
- generation: null,
970
- activeProjection: null,
971
- messageIndexes: {}
972
- },
973
- stateSchema: contextSchema()
974
- }).fold((state, event) => reduceContext(state, event));
975
- return storedAIReducer(reducer);
998
+ const createContextReducer = ({ contract }) => {
999
+ const app = appReducerOf(contract);
1000
+ const initialState = {
1001
+ messages: [],
1002
+ compaction: null,
1003
+ modelMetadata: {},
1004
+ closed: false,
1005
+ authority: null,
1006
+ generation: null,
1007
+ activeProjection: null,
1008
+ messageIndexes: {},
1009
+ ...app === void 0 ? {} : { app: app.initialState }
1010
+ };
1011
+ const reducer$1 = reducer({
1012
+ contract,
1013
+ name: app === void 0 ? "a2.ai.context.v6" : `${app.name}+a2.ai.context.v6`,
1014
+ initialState,
1015
+ stateSchema: contextSchema(app)
1016
+ }).fold((state, event) => {
1017
+ const after = retainMessageBase({
1018
+ before: state,
1019
+ after: reduceContext(state, event)
1020
+ });
1021
+ if (app === void 0) return after;
1022
+ const next = app.fold(state.app, event);
1023
+ return next === state.app ? after : {
1024
+ ...after,
1025
+ app: appSlice(next)
1026
+ };
1027
+ });
1028
+ return withAIStorage(reducer$1);
976
1029
  };
977
1030
  const reduceContext = (state, event) => {
978
1031
  if (state.closed) return state;
@@ -1029,6 +1082,7 @@ const reduceContext = (state, event) => {
1029
1082
  ...base,
1030
1083
  generation: {
1031
1084
  owner,
1085
+ startIndex: event.index,
1032
1086
  phase: "streaming",
1033
1087
  ...previous?.owner.responseMessageId === owner.responseMessageId && previous.responseIndex !== void 0 ? { responseIndex: previous.responseIndex } : {}
1034
1088
  },
@@ -1036,7 +1090,7 @@ const reduceContext = (state, event) => {
1036
1090
  generationId: owner.generationId,
1037
1091
  responseMessageId: owner.responseMessageId,
1038
1092
  promptThroughIndex: owner.promptThroughIndex ?? event.index - 1,
1039
- ...baseMessage === void 0 ? {} : { baseMessage },
1093
+ ...baseMessage === void 0 ? {} : { base: { partCount: baseMessage.parts.length } },
1040
1094
  baseCompaction: base.compaction,
1041
1095
  batches: progressBatches(),
1042
1096
  toolEvents: [],
@@ -1046,7 +1100,12 @@ const reduceContext = (state, event) => {
1046
1100
  }
1047
1101
  case "ai.generation.progress": {
1048
1102
  const payload = event.payload;
1049
- if (!ownsGeneration(state, payload) || state.generation.owner.responseMessageId !== payload.responseMessageId || state.generation.phase !== "streaming" || !state.activeProjection) return state;
1103
+ const generation = state.generation;
1104
+ if (generation === null || generation.phase !== "streaming" || !progressOwnedBy({
1105
+ payload,
1106
+ owner: generation.owner,
1107
+ startIndex: generation.startIndex
1108
+ }) || !state.activeProjection) return state;
1050
1109
  const projection = state.activeProjection;
1051
1110
  const progress = advanceProjection({
1052
1111
  projection,
@@ -1125,9 +1184,12 @@ const reduceContext = (state, event) => {
1125
1184
  approvalEvents: projection.approvalEvents.filter((item) => item.index <= cutoff)
1126
1185
  };
1127
1186
  let next = generationBase(state);
1128
- if (retained.baseMessage !== void 0 || retained.batches.length > 0) next = replaceResponse({
1187
+ if (retained.base !== void 0 || retained.batches.length > 0) next = replaceResponse({
1129
1188
  state: next,
1130
- message: interruptUIMessage(projectedMessage(retained)),
1189
+ message: interruptUIMessage(projectedMessage({
1190
+ projection: retained,
1191
+ current: findMessage(state.messages, retained.responseMessageId)
1192
+ })),
1131
1193
  index: event.index
1132
1194
  });
1133
1195
  return endGeneration(next);
@@ -1139,7 +1201,10 @@ const reduceContext = (state, event) => {
1139
1201
  case "ai.generation.paused": {
1140
1202
  const { generationId } = event.payload;
1141
1203
  if (state.generation?.owner.generationId !== generationId || state.generation.phase === "failed" || state.generation.phase === "superseded" || !state.activeProjection) return state;
1142
- const toolCallIds = calledTools(state.activeProjection);
1204
+ const toolCallIds = calledTools({
1205
+ projection: state.activeProjection,
1206
+ current: findMessage(state.messages, state.activeProjection.responseMessageId)
1207
+ });
1143
1208
  return renderProjection({
1144
1209
  state: {
1145
1210
  ...state,
@@ -1242,9 +1307,9 @@ const reduceContext = (state, event) => {
1242
1307
  ...projection,
1243
1308
  cursor: null
1244
1309
  };
1245
- delete activeProjection.baseMessage;
1310
+ delete activeProjection.base;
1246
1311
  const baseMessage = messages.find((message) => message.id === projection.responseMessageId);
1247
- if (baseMessage !== void 0) activeProjection.baseMessage = baseMessage;
1312
+ if (baseMessage !== void 0) activeProjection.base = { partCount: baseMessage.parts.length };
1248
1313
  const compaction = {
1249
1314
  status: "completed",
1250
1315
  generationId: payload.generationId,
@@ -1378,9 +1443,15 @@ const catalogUrl = "https://ai-gateway.vercel.sh/v1/models";
1378
1443
  const catalogLifetimeMs = 36e5;
1379
1444
  const catalogTimeoutMs = 5e3;
1380
1445
  let catalog;
1446
+ /**
1447
+ * The model's AI Gateway ID: the model string, unless an AI SDK global
1448
+ * provider resolves it to a model that is not Gateway's.
1449
+ */
1381
1450
  const gatewayModelId = (model) => {
1382
- if (typeof model === "string") return globalThis.AI_SDK_DEFAULT_PROVIDER === void 0 ? model : void 0;
1383
- return model.provider === "gateway" ? model.modelId : void 0;
1451
+ const provider = globalThis.AI_SDK_DEFAULT_PROVIDER;
1452
+ if (provider === void 0) return model;
1453
+ if (typeof provider.languageModel !== "function") return void 0;
1454
+ return provider.languageModel(model).provider === "gateway" ? model : void 0;
1384
1455
  };
1385
1456
  const readCatalog = () => {
1386
1457
  if (catalog && catalog.expiresAt > Date.now()) return catalog.promise;
@@ -1467,23 +1538,24 @@ const measuredInputTokens = (options) => {
1467
1538
  return previous !== void 0 && previous.model === options.model && options.estimate >= previous.estimate ? Math.ceil(previous.inputTokens + options.estimate - previous.estimate) : options.estimate;
1468
1539
  };
1469
1540
  //#endregion
1470
- //#region src/ai-server.ts
1541
+ //#region src/ai-agent.ts
1471
1542
  /**
1472
- * experimental-a2/ai/server — the server-only implementation of an experimental-a2/ai definition.
1473
- *
1474
- * `createHandlers()` exposes the ordinary A2 handler table;
1475
- * `createAgentServer()` is its batteries-included assembly with createServer.
1543
+ * The server-only implementation of the experimental-a2/ai protocol: the
1544
+ * handler table and `agent()`, its assembly as an ordinary A2 server.
1476
1545
  */
1477
- function validateAgentIngress(context) {
1478
- const rejected = context.events.find((event) => {
1479
- if (event.type !== "ai.control.requested") return true;
1480
- const command = event.payload;
1481
- if (command["action"] === "request-input" || command["action"] === "tool-result") return true;
1482
- if (command["action"] === "send" || command["action"] === "edit" || command["action"] === "steer") return command["message"]?.role !== "user";
1483
- return false;
1484
- });
1546
+ const isAgentIngressEvent = (event) => {
1547
+ if (event.type !== "ai.control.requested") return false;
1548
+ const command = event.payload;
1549
+ if (typeof command !== "object" || command === null) return false;
1550
+ const action = command.action;
1551
+ if (action === "request-input" || action === "tool-result") return false;
1552
+ if (action === "send" || action === "edit" || action === "steer") return command.message?.role === "user";
1553
+ return true;
1554
+ };
1555
+ const validateAgentIngress = ({ context, applicationEvents }) => {
1556
+ const rejected = context.events.find((event) => Object.hasOwn(events, event.type) ? !isAgentIngressEvent(event) : !applicationEvents);
1485
1557
  if (rejected !== void 0) throw new A2Error("INVALID_PAYLOAD", `event '${rejected.type}' is server-only for an AI agent`);
1486
- }
1558
+ };
1487
1559
  const checkAbort = (signal) => {
1488
1560
  if (!signal.aborted) return false;
1489
1561
  const reason = signal.reason;
@@ -1501,18 +1573,31 @@ const resolve = async (value, context) => {
1501
1573
  checkAbort(context.signal);
1502
1574
  return result;
1503
1575
  };
1504
- const modelName = (model) => {
1505
- if (typeof model === "string") return model;
1506
- if ("modelId" in model && typeof model.modelId === "string") return model.modelId;
1507
- return "custom";
1576
+ const withModelSettings = (options) => {
1577
+ const { generation, settings } = options;
1578
+ if (settings.reasoning === void 0 && settings.speed === void 0) return generation;
1579
+ const { speed: _speed, ...gateway } = generation.providerOptions?.["gateway"] ?? {};
1580
+ return {
1581
+ ...generation,
1582
+ ...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
1583
+ ...settings.speed === void 0 ? {} : { providerOptions: {
1584
+ ...generation.providerOptions,
1585
+ gateway: settings.speed === "fast" ? {
1586
+ ...gateway,
1587
+ speed: "fast"
1588
+ } : gateway
1589
+ } }
1590
+ };
1508
1591
  };
1592
+ const instructionTexts = (instructions) => instructions === void 0 ? [] : typeof instructions === "string" ? [instructions] : (Array.isArray(instructions) ? instructions : [instructions]).map((message) => message.content);
1509
1593
  const errorMessage = (error) => error instanceof Error ? error.message : String(error);
1510
1594
  const toolScopeStorage = installAmbientToolScopeStorage(() => new AsyncLocalStorage());
1511
1595
  /** Run `fn` with `ctx` as the ambient tool handler context, for direct tool tests. */
1512
1596
  function runWithHandlerContext(ctx, fn) {
1513
1597
  return toolScopeStorage.run({ context: ctx }, fn);
1514
1598
  }
1515
- const promptCacheKey = (sessionId, generationId) => `${sessionId}\u001f${generationId}`;
1599
+ /** Sessions whose latest step prompt one process keeps for that step's tools. */
1600
+ const PROMPT_SESSIONS = 64;
1516
1601
  const asyncIterator = (value) => {
1517
1602
  if (typeof value !== "object" || value === null) return void 0;
1518
1603
  const factory = Reflect.get(value, Symbol.asyncIterator);
@@ -1520,6 +1605,49 @@ const asyncIterator = (value) => {
1520
1605
  return factory.call(value);
1521
1606
  };
1522
1607
  const isBoundaryChunk = (chunk) => chunk !== void 0 && (chunk.type === "text-end" || chunk.type === "reasoning-end" || chunk.type === "tool-input-available" || chunk.type === "tool-input-error" || chunk.type === "tool-output-available" || chunk.type === "tool-output-error" || chunk.type === "tool-output-denied" || chunk.type === "tool-approval-request" || chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error");
1608
+ const DELTA_KEYS = {
1609
+ "text-delta": /* @__PURE__ */ new Set([
1610
+ "type",
1611
+ "id",
1612
+ "delta",
1613
+ "providerMetadata"
1614
+ ]),
1615
+ "reasoning-delta": /* @__PURE__ */ new Set([
1616
+ "type",
1617
+ "id",
1618
+ "delta",
1619
+ "providerMetadata"
1620
+ ]),
1621
+ "tool-input-delta": /* @__PURE__ */ new Set([
1622
+ "type",
1623
+ "toolCallId",
1624
+ "inputTextDelta"
1625
+ ])
1626
+ };
1627
+ const isDeltaChunk = (chunk) => Object.hasOwn(DELTA_KEYS, chunk.type) && Object.keys(chunk).every((key) => DELTA_KEYS[chunk.type].has(key)) && typeof (chunk.type === "tool-input-delta" ? chunk.inputTextDelta : chunk.delta) === "string";
1628
+ const joinDeltas = (left, right) => {
1629
+ if (left.type === "tool-input-delta") return right.type === "tool-input-delta" && right.toolCallId === left.toolCallId ? {
1630
+ ...left,
1631
+ inputTextDelta: left.inputTextDelta + right.inputTextDelta
1632
+ } : void 0;
1633
+ if (right.type === "tool-input-delta" || right.type !== left.type || right.id !== left.id) return void 0;
1634
+ const providerMetadata = right.providerMetadata !== void 0 ? right.providerMetadata : left.providerMetadata;
1635
+ return {
1636
+ ...left,
1637
+ delta: left.delta + right.delta,
1638
+ ...providerMetadata === void 0 ? {} : { providerMetadata }
1639
+ };
1640
+ };
1641
+ const mergeDeltas = (chunks) => {
1642
+ const merged = [];
1643
+ for (const chunk of chunks) {
1644
+ const previous = merged.at(-1);
1645
+ const joined = previous !== void 0 && isDeltaChunk(previous) && isDeltaChunk(chunk) ? joinDeltas(previous, chunk) : void 0;
1646
+ if (joined === void 0) merged.push(chunk);
1647
+ else merged[merged.length - 1] = joined;
1648
+ }
1649
+ return merged;
1650
+ };
1523
1651
  const nextOrTimer = async (next, delayMs) => {
1524
1652
  let timer;
1525
1653
  try {
@@ -1541,7 +1669,7 @@ async function generateWithAISDK(options) {
1541
1669
  ...context.generation,
1542
1670
  headers: Object.keys(headers).some((key) => key.toLowerCase() === "x-session-affinity") ? headers : {
1543
1671
  ...headers,
1544
- "x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.request.sessionId])).digest("hex")
1672
+ "x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.event.sessionId])).digest("hex")
1545
1673
  },
1546
1674
  providerOptions: {
1547
1675
  ...context.generation.providerOptions,
@@ -1556,7 +1684,7 @@ async function generateWithAISDK(options) {
1556
1684
  tools: context.tools,
1557
1685
  messages: context.messages,
1558
1686
  modelMessages: context.modelMessages,
1559
- responseMessageId: context.responseMessageId,
1687
+ responseMessageId: context.event.payload.responseMessageId,
1560
1688
  abortSignal: context.signal,
1561
1689
  ...context.instructions === void 0 ? {} : { instructions: context.instructions },
1562
1690
  settings: generation,
@@ -1575,9 +1703,13 @@ async function* consumeGeneration(options) {
1575
1703
  const pending = [];
1576
1704
  let streamedFinishReason;
1577
1705
  let streamedError;
1578
- const maxChunks = options.progress?.maxChunks ?? 16;
1579
- const maxDelayMs = options.progress?.maxDelayMs ?? 30;
1706
+ const maxChunks = options.progress?.maxChunks ?? 128;
1707
+ const maxDelayMs = options.progress?.maxDelayMs ?? 0;
1580
1708
  let lastFlush = Date.now();
1709
+ const batch = () => ({
1710
+ type: "progress",
1711
+ chunks: mergeDeltas(pending.splice(0))
1712
+ });
1581
1713
  const reader = options.source.stream.getReader();
1582
1714
  let pendingChunk = reader.read();
1583
1715
  try {
@@ -1587,10 +1719,7 @@ async function* consumeGeneration(options) {
1587
1719
  const remaining = Math.max(0, maxDelayMs - (Date.now() - lastFlush));
1588
1720
  const outcome = await nextOrTimer(pendingChunk, remaining);
1589
1721
  if (outcome.type === "timer") {
1590
- yield {
1591
- type: "progress",
1592
- chunks: pending.splice(0)
1593
- };
1722
+ yield batch();
1594
1723
  lastFlush = Date.now();
1595
1724
  continue;
1596
1725
  }
@@ -1603,18 +1732,12 @@ async function* consumeGeneration(options) {
1603
1732
  if (chunk.type === "error") streamedError = chunk.errorText;
1604
1733
  pendingChunk = reader.read();
1605
1734
  if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
1606
- yield {
1607
- type: "progress",
1608
- chunks: pending.splice(0)
1609
- };
1735
+ yield batch();
1610
1736
  lastFlush = Date.now();
1611
1737
  }
1612
1738
  }
1613
1739
  } catch (error) {
1614
- if (pending.length > 0) yield {
1615
- type: "progress",
1616
- chunks: pending.splice(0)
1617
- };
1740
+ if (pending.length > 0) yield batch();
1618
1741
  throw error;
1619
1742
  } finally {
1620
1743
  pendingChunk.catch(() => {});
@@ -1628,16 +1751,10 @@ async function* consumeGeneration(options) {
1628
1751
  try {
1629
1752
  completion = options.source.completion?.();
1630
1753
  } catch (error) {
1631
- if (pending.length > 0) yield {
1632
- type: "progress",
1633
- chunks: pending.splice(0)
1634
- };
1754
+ if (pending.length > 0) yield batch();
1635
1755
  throw error;
1636
1756
  }
1637
- if (pending.length > 0) yield {
1638
- type: "progress",
1639
- chunks: pending.splice(0)
1640
- };
1757
+ if (pending.length > 0) yield batch();
1641
1758
  if (streamedError !== void 0) throw new Error(streamedError);
1642
1759
  const finishReason = completion?.finishReason ?? streamedFinishReason;
1643
1760
  yield {
@@ -1688,8 +1805,7 @@ const summarize = async (options) => {
1688
1805
  modelMessages: [...options.context.modelMessages, {
1689
1806
  role: "user",
1690
1807
  content: instruction
1691
- }],
1692
- responseMessageId: await aiEventId("a2.ai.summary", options.context.generationId)
1808
+ }]
1693
1809
  },
1694
1810
  messageMetadata: void 0
1695
1811
  });
@@ -1775,7 +1891,7 @@ const lifecycleEvents = async (options) => {
1775
1891
  ...chunk.title === void 0 ? {} : { title: chunk.title }
1776
1892
  };
1777
1893
  take(payload.toolCallId);
1778
- const classification = approvalClassification(options.tools, options.generation, chunk.toolName);
1894
+ const classification = options.approvals === false ? "automatic" : approvalClassification(options.tools, options.generation, chunk.toolName);
1779
1895
  if (classification === "automatic") result.push(await toolCalledEvent(payload));
1780
1896
  else pending.push({
1781
1897
  call: payload,
@@ -1916,36 +2032,79 @@ const validateCompaction = (options) => {
1916
2032
  }
1917
2033
  return compaction;
1918
2034
  };
1919
- /**
1920
- * Build the ordinary A2 handler table for the built-in agent protocol.
1921
- * Application handlers can be spread beside this table.
1922
- */
2035
+ const AI_SDK_HARNESS_OPTIONS = [
2036
+ "generation",
2037
+ "generate",
2038
+ "compaction",
2039
+ "messageMetadata"
2040
+ ];
2041
+ const assertNoLoopOptions = (options) => {
2042
+ const harness = options.harness?.type ?? "ai-sdk";
2043
+ for (const key of AI_SDK_HARNESS_OPTIONS) {
2044
+ if (!Object.hasOwn(options, key)) continue;
2045
+ throw new TypeError(harness === "ai-sdk" ? `${key} belongs to the harness: agent({ harness: { type: 'ai-sdk', ${key} } })` : `${key} is an option of the AI SDK harness; ${harness}() runs its own loop`);
2046
+ }
2047
+ };
1923
2048
  function createHandlers(options) {
1924
- if (options.model === void 0) throw new TypeError("createHandlers requires model");
2049
+ if (options.model === void 0) throw new TypeError("agent requires model");
1925
2050
  if (options.progress?.maxChunks !== void 0 && (!Number.isInteger(options.progress.maxChunks) || options.progress.maxChunks < 1)) throw new TypeError("progress.maxChunks must be a positive integer");
1926
2051
  if (options.progress?.maxDelayMs !== void 0 && (!Number.isFinite(options.progress.maxDelayMs) || options.progress.maxDelayMs < 0)) throw new TypeError("progress.maxDelayMs must be a non-negative number");
1927
2052
  if (options.maxSteps !== void 0 && options.maxSteps !== Number.POSITIVE_INFINITY && (!Number.isInteger(options.maxSteps) || options.maxSteps < 1)) throw new TypeError("maxSteps must be a positive integer or Infinity");
1928
- const configuredCompaction = options.compaction ?? (options.generate === void 0 ? {} : false);
2053
+ assertNoLoopOptions(options);
2054
+ const configured = options.harness;
2055
+ const loop = configured?.type === "ai-sdk" ? configured : {};
2056
+ const harness = configured === void 0 || configured.type === "ai-sdk" ? void 0 : harnessDriver(configured);
2057
+ const states = options.harnessStates ?? harnessStates();
2058
+ if (harness !== void 0) for (const [name, tool] of Object.entries(options.tools ?? {})) {
2059
+ const needsApproval = tool.needsApproval;
2060
+ if (needsApproval !== void 0 && needsApproval !== false) throw new TypeError(`a harness runs tools without approval; '${name}' sets needsApproval`);
2061
+ }
2062
+ const configuredCompaction = loop.compaction ?? (loop.generate === void 0 && harness === void 0 ? {} : false);
1929
2063
  const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
1930
2064
  compaction: configuredCompaction,
1931
- explicit: options.compaction !== void 0,
1932
- generation: options.generation,
2065
+ explicit: loop.compaction !== void 0,
2066
+ generation: typeof loop.generation === "function" ? void 0 : loop.generation,
1933
2067
  tools: options.tools
1934
2068
  });
1935
- const tools = options.tools ?? {};
1936
- const generation = options.generation ?? {};
2069
+ const tools = harness === void 0 ? options.tools ?? {} : {
2070
+ ...harness.tools,
2071
+ ...options.tools
2072
+ };
2073
+ const toolRecovery = options.toolRecovery ?? {};
2074
+ for (const [name, recovery] of Object.entries(toolRecovery)) {
2075
+ if (!Object.hasOwn(tools, name)) throw new TypeError(`toolRecovery names '${name}', which is not one of the agent's tools`);
2076
+ if (typeof tools[name].execute !== "function") throw new TypeError(`toolRecovery names '${name}', which has no execute function`);
2077
+ if (recovery !== "rerun" && recovery !== "report") throw new TypeError(`toolRecovery for '${name}' must be 'rerun' or 'report'`);
2078
+ }
2079
+ const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
1937
2080
  const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY;
1938
- const control = createControlRuntime({ agent: options.agent });
2081
+ const control = createControlRuntime({
2082
+ contract: options.contract,
2083
+ telemetry
2084
+ });
2085
+ const controlHandler = (ctx) => telemetry.span("a2.ai.control", {
2086
+ "a2.contract": options.contract.name,
2087
+ "a2.session_id": ctx.event.sessionId,
2088
+ "a2.ai.control.type": ctx.event.type,
2089
+ "a2.ai.control.id": ctx.event.id,
2090
+ "a2.ai.control.attempt": ctx.attempt
2091
+ }, () => control.handler(ctx));
1939
2092
  const coordinator = control.coordinator;
1940
- const contextReducer = createContextReducer({ agent: options.agent });
2093
+ const contextReducer = createContextReducer({ contract: options.contract });
1941
2094
  const readContext = async (session, through) => {
1942
- const snapshot = await session.state(contextReducer, { through });
1943
- return {
1944
- state: contextReducer.view(snapshot.state),
1945
- index: snapshot.index
1946
- };
2095
+ return await session.state(contextReducer, { through });
2096
+ };
2097
+ const prompts = boundedCache({
2098
+ maxEntries: PROMPT_SESSIONS,
2099
+ maxBytes: PROMPT_SESSIONS
2100
+ });
2101
+ const cachePrompt = ({ sessionId, generationId, messages }) => prompts.set(sessionId, {
2102
+ generationId,
2103
+ messages
2104
+ }, 1);
2105
+ const forgetPrompt = (sessionId, generationId) => {
2106
+ if (prompts.get(sessionId)?.generationId === generationId) prompts.delete(sessionId);
1947
2107
  };
1948
- const promptCache = /* @__PURE__ */ new Map();
1949
2108
  const resultEvent = async (call, suffix, result) => ({
1950
2109
  type: "ai.tool.result",
1951
2110
  id: await aiEventId("a2.ai.tool.result", call.generationId, call.toolCallId, suffix),
@@ -1968,25 +2127,32 @@ function createHandlers(options) {
1968
2127
  });
1969
2128
  const promptMessages = (input) => {
1970
2129
  const { ctx, call, generation: owner } = input;
1971
- const key = promptCacheKey(ctx.event.sessionId, call.generationId);
1972
- const cached = promptCache.get(key);
1973
- if (cached) return cached;
2130
+ const sessionId = ctx.event.sessionId;
2131
+ const cached = prompts.get(sessionId);
2132
+ if (cached?.generationId === call.generationId) return cached.messages;
1974
2133
  const computation = (async () => {
1975
2134
  const frontier = owner.promptThroughIndex;
1976
2135
  if (frontier === void 0) throw new TypeError("AI work requires a prompt checkpoint");
1977
2136
  const snapshot = await readContext(ctx.session, ctx.event.index);
1978
2137
  if (snapshot.state.generation?.owner.generationId !== owner.generationId || snapshot.state.generation.owner.requestId !== owner.requestId || snapshot.state.activeProjection?.generationId !== owner.generationId) throw new TypeError("Tool prompt checkpoint does not own its generation");
1979
2138
  const state = generationBase(snapshot.state);
1980
- return modelContext({
2139
+ return telemetry.span("a2.ai.context", {
2140
+ "a2.contract": options.contract.name,
2141
+ "a2.session_id": ctx.event.sessionId,
2142
+ "a2.ai.context.request_id": call.requestId,
2143
+ "a2.ai.context.phase": "tool"
2144
+ }, () => modelContext({
1981
2145
  messages: state.messages.filter((message) => state.messageIndexes[message.id] <= frontier),
1982
2146
  state,
1983
2147
  tools
1984
- });
2148
+ }));
1985
2149
  })();
1986
- promptCache.set(key, computation);
1987
- computation.catch(() => {
1988
- if (promptCache.get(key) === computation) promptCache.delete(key);
2150
+ cachePrompt({
2151
+ sessionId,
2152
+ generationId: call.generationId,
2153
+ messages: computation
1989
2154
  });
2155
+ computation.catch(() => forgetPrompt(sessionId, call.generationId));
1990
2156
  return computation;
1991
2157
  };
1992
2158
  const toolExecutionFailure = async (ctx, call, error) => {
@@ -1995,13 +2161,14 @@ function createHandlers(options) {
1995
2161
  if (schedulerFailure === "retryable") throw error;
1996
2162
  return resultEvent(call, `${ctx.event.id}:execution:error`, { error: errorMessage(error) });
1997
2163
  };
1998
- const runToolExecution = async (ctx, call, execute, messages) => {
2164
+ const runToolExecution = async (ctx, call, execute, messages, sandbox) => {
1999
2165
  let output;
2000
2166
  try {
2001
2167
  output = await execute(call.input, {
2002
2168
  toolCallId: call.toolCallId,
2003
2169
  messages,
2004
- abortSignal: ctx.signal
2170
+ abortSignal: ctx.signal,
2171
+ ...sandbox === void 0 ? {} : { experimental_sandbox: sandbox }
2005
2172
  });
2006
2173
  } catch (error) {
2007
2174
  return toolExecutionFailure(ctx, call, error);
@@ -2052,13 +2219,27 @@ function createHandlers(options) {
2052
2219
  const { ctx, call } = input;
2053
2220
  const execute = tools[call.toolName]?.execute;
2054
2221
  if (execute === void 0) return resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' has no server executor` });
2222
+ const report = toolRecovery[call.toolName] === "report";
2223
+ const interrupted = () => resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' was interrupted and may have partly run.` });
2224
+ if (report && ctx.attempt > 1 && !failedPreviousAttempt.has(ctx)) return interrupted();
2055
2225
  const messages = await promptMessages(input);
2226
+ const sandbox = harness?.sandbox === void 0 ? void 0 : await resolve(harness.sandbox, {
2227
+ session: { id: ctx.session.id },
2228
+ signal: ctx.signal
2229
+ });
2056
2230
  if (checkAbort(ctx.signal)) return;
2057
2231
  const scope = {
2058
- contract: options.agent.contract,
2232
+ contract: options.contract,
2059
2233
  context: ctx
2060
2234
  };
2061
- return toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages));
2235
+ const run = () => toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages, sandbox));
2236
+ if (!report) return run();
2237
+ try {
2238
+ return await run() ?? await interrupted();
2239
+ } catch {
2240
+ checkAbort(ctx.signal);
2241
+ return interrupted();
2242
+ }
2062
2243
  };
2063
2244
  const handleToolExecution = async (ctx) => {
2064
2245
  try {
@@ -2115,109 +2296,124 @@ function createHandlers(options) {
2115
2296
  state,
2116
2297
  coordinator: coordinatorState
2117
2298
  }),
2299
+ state: snapshot.state.app ?? {},
2118
2300
  session: { state: (reducer, readOptions) => ctx.session.state(reducer, {
2119
2301
  ...readOptions,
2120
2302
  through: readOptions?.through ?? snapshot.index
2121
2303
  }) },
2122
2304
  signal: ctx.signal
2123
2305
  };
2124
- let generationStarted = false;
2125
- try {
2126
- const resolvedModel = await resolve(options.model, resolverContext);
2127
- if (resolvedModel === void 0) throw new TypeError("the model resolver returned undefined");
2128
- if (checkAbort(ctx.signal)) return;
2129
- const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
2130
- if (checkAbort(ctx.signal)) return;
2131
- const compaction = typeof configuredCompaction === "function" ? validateCompaction({
2132
- compaction: await resolve(configuredCompaction, resolverContext),
2133
- explicit: true,
2134
- generation: options.generation,
2135
- tools: options.tools
2136
- }) : staticCompaction;
2137
- if (checkAbort(ctx.signal)) return;
2138
- if (request.reason === "tool" && responseStepCount >= maxSteps) {
2139
- const source = response.source?.generation;
2140
- if (source === void 0) return;
2141
- return {
2142
- type: "ai.generation.failed",
2143
- id: await aiEventId("a2.ai.step-limit", requestId),
2144
- payload: {
2145
- requestId: source.requestId,
2146
- messageId: source.messageId,
2147
- generationId: source.generationId,
2148
- responseMessageId,
2149
- error: `agent exceeded the ${maxSteps}-step limit`,
2150
- stepLimit: true
2151
- }
2152
- };
2153
- }
2154
- const started = {
2155
- requestId,
2156
- messageId: request.messageId,
2157
- generationId,
2158
- responseMessageId,
2159
- attempt,
2160
- model: modelName(resolvedModel),
2161
- promptThroughIndex: snapshot.index
2306
+ if (request.reason === "tool" && responseStepCount >= maxSteps) {
2307
+ const source = response.source?.generation;
2308
+ if (source === void 0) return;
2309
+ return {
2310
+ type: "ai.generation.failed",
2311
+ id: await aiEventId("a2.ai.step-limit", requestId),
2312
+ payload: {
2313
+ requestId: source.requestId,
2314
+ messageId: source.messageId,
2315
+ generationId: source.generationId,
2316
+ responseMessageId,
2317
+ error: `agent exceeded the ${maxSteps}-step limit`,
2318
+ stepLimit: true
2319
+ }
2162
2320
  };
2163
- const catalogModelId = gatewayModelId(resolvedModel);
2164
- const gatewayOptions = options.generation?.providerOptions?.["gateway"];
2165
- const usesFallbackModels = Array.isArray(gatewayOptions?.["models"]) && gatewayOptions["models"].length > 0;
2166
- const discoversMetadata = compaction !== false && !("shouldCompact" in compaction) && compaction.thresholdTokens === void 0 && !usesFallbackModels && catalogModelId !== void 0;
2167
- const startEvents = [];
2168
- if (discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId)) startEvents.push({
2321
+ }
2322
+ const startEvents = async (started, metadataModelId) => {
2323
+ const events = [];
2324
+ if (metadataModelId !== void 0) events.push({
2169
2325
  type: "ai.model.metadata.requested",
2170
- id: await aiEventId("a2.ai.model.metadata", options.agent.contract.name, ctx.event.sessionId, catalogModelId),
2171
- payload: { modelId: catalogModelId }
2326
+ id: await aiEventId("a2.ai.model.metadata", options.contract.name, ctx.event.sessionId, metadataModelId),
2327
+ payload: { modelId: metadataModelId }
2172
2328
  });
2173
2329
  if (previous) {
2174
- const payload = previous;
2175
2330
  const superseded = {
2176
2331
  requestId,
2177
- messageId: payload.messageId,
2178
- generationId: payload.generationId,
2179
- responseMessageId: payload.responseMessageId,
2332
+ messageId: previous.messageId,
2333
+ generationId: previous.generationId,
2334
+ responseMessageId: previous.responseMessageId,
2180
2335
  error: "generation attempt was superseded after an incomplete run",
2181
2336
  superseded: true
2182
2337
  };
2183
- startEvents.push({
2338
+ events.push({
2184
2339
  type: "ai.generation.failed",
2185
- id: await aiEventId("a2.ai.superseded", payload.generationId),
2340
+ id: await aiEventId("a2.ai.superseded", previous.generationId),
2186
2341
  payload: superseded
2187
2342
  });
2188
2343
  }
2189
- startEvents.push({
2344
+ events.push({
2190
2345
  type: "ai.generation.started",
2191
2346
  id: generationId,
2192
2347
  payload: started
2193
2348
  });
2349
+ return events;
2350
+ };
2351
+ const startedPayload = (model) => ({
2352
+ requestId,
2353
+ messageId: request.messageId,
2354
+ generationId,
2355
+ responseMessageId,
2356
+ attempt,
2357
+ ...model === void 0 ? {} : { model },
2358
+ promptThroughIndex: snapshot.index
2359
+ });
2360
+ let resolvedModel;
2361
+ let resolving = true;
2362
+ let generationStarted = false;
2363
+ try {
2364
+ const choice = await resolve(options.model, resolverContext);
2365
+ if (choice === void 0) throw new TypeError("the model resolver returned undefined");
2366
+ const settings = typeof choice === "string" ? { model: choice } : choice;
2367
+ const model = settings.model;
2368
+ if (typeof model !== "string" || model === "") throw new TypeError("the model must be an AI Gateway model ID");
2369
+ resolvedModel = model;
2370
+ if (checkAbort(ctx.signal)) return;
2371
+ const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
2372
+ if (checkAbort(ctx.signal)) return;
2373
+ const resolvedGeneration = await resolve(loop.generation ?? {}, resolverContext);
2374
+ if (checkAbort(ctx.signal)) return;
2375
+ if (resolvedGeneration === null || typeof resolvedGeneration !== "object" || Array.isArray(resolvedGeneration)) throw new TypeError("the generation resolver must return settings");
2376
+ const generation = withModelSettings({
2377
+ generation: resolvedGeneration,
2378
+ settings
2379
+ });
2380
+ const compaction = typeof configuredCompaction === "function" || typeof loop.generation === "function" ? validateCompaction({
2381
+ compaction: typeof configuredCompaction === "function" ? await resolve(configuredCompaction, resolverContext) : staticCompaction,
2382
+ explicit: loop.compaction !== void 0,
2383
+ generation,
2384
+ tools: options.tools
2385
+ }) : staticCompaction;
2386
+ if (checkAbort(ctx.signal)) return;
2387
+ resolving = false;
2388
+ const catalogModelId = gatewayModelId(model);
2389
+ const gatewayOptions = generation.providerOptions?.["gateway"];
2390
+ const usesFallbackModels = Array.isArray(gatewayOptions?.["models"]) && gatewayOptions["models"].length > 0;
2391
+ const discoversMetadata = compaction !== false && !("shouldCompact" in compaction) && compaction.thresholdTokens === void 0 && !usesFallbackModels && catalogModelId !== void 0;
2194
2392
  const generationEvents = await control.append({
2195
2393
  ctx,
2196
2394
  name: "generation-start",
2197
- events: startEvents
2395
+ events: await startEvents(startedPayload(model), discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId) ? catalogModelId : void 0)
2198
2396
  });
2397
+ const startIndex = generationEvents.find((event) => event.id === generationId).index;
2199
2398
  generationStarted = true;
2200
2399
  if (checkAbort(ctx.signal)) return;
2201
2400
  const promptCoordinatorState = coordinatorState;
2202
- const messages = contextMessages({
2203
- state,
2204
- coordinator: promptCoordinatorState
2205
- });
2401
+ const { messages } = resolverContext;
2206
2402
  let generationMessages = messages;
2207
- let modelMessages = await modelContext({
2403
+ let modelMessages = await telemetry.span("a2.ai.context", {
2404
+ "a2.contract": options.contract.name,
2405
+ "a2.session_id": ctx.event.sessionId,
2406
+ "a2.ai.context.request_id": requestId,
2407
+ "a2.ai.context.phase": "generation"
2408
+ }, () => modelContext({
2208
2409
  messages,
2209
2410
  state,
2210
2411
  tools
2211
- });
2412
+ }));
2212
2413
  const baseContext = {
2213
- request: ctx.event,
2214
- requestId,
2414
+ ...resolverContext,
2215
2415
  generationId,
2216
- responseMessageId,
2217
- messages,
2218
2416
  modelMessages,
2219
- session: resolverContext.session,
2220
- signal: ctx.signal,
2221
2417
  model: resolvedModel,
2222
2418
  tools,
2223
2419
  ...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
@@ -2247,7 +2443,7 @@ function createHandlers(options) {
2247
2443
  });
2248
2444
  const inputTokens = measuredInputTokens({
2249
2445
  estimate: inputTokenEstimate,
2250
- model: modelName(resolvedModel),
2446
+ model: resolvedModel,
2251
2447
  calibration: coordinatorState.calibration
2252
2448
  });
2253
2449
  const threshold = policy.thresholdTokens ?? (limits === void 0 ? void 0 : Math.floor(Math.min(limits.contextWindow * .75, limits.contextWindow - (generation.maxOutputTokens ?? 0))));
@@ -2282,14 +2478,20 @@ function createHandlers(options) {
2282
2478
  }
2283
2479
  }]
2284
2480
  }));
2285
- const result = !("shouldCompact" in policy) ? {
2481
+ const result = await telemetry.span("a2.ai.compaction", {
2482
+ "a2.contract": options.contract.name,
2483
+ "a2.session_id": ctx.event.sessionId,
2484
+ "a2.ai.compaction.request_id": requestId,
2485
+ "a2.ai.compaction.generation_id": generationId,
2486
+ "a2.ai.compaction.policy": "shouldCompact" in policy ? "custom" : "automatic"
2487
+ }, async () => !("shouldCompact" in policy) ? {
2286
2488
  messages: [],
2287
2489
  ...await summarize({
2288
- agentName: options.agent.contract.name,
2490
+ agentName: options.contract.name,
2289
2491
  context: baseContext,
2290
2492
  instructions: policy.instructions
2291
2493
  })
2292
- } : { messages: await policy.compact(compactionContext) };
2494
+ } : { messages: await policy.compact(compactionContext) });
2293
2495
  if (checkAbort(ctx.signal)) return;
2294
2496
  const completed = {
2295
2497
  generationId,
@@ -2313,7 +2515,7 @@ function createHandlers(options) {
2313
2515
  }
2314
2516
  }
2315
2517
  const currentState = foldAIEvents({
2316
- reducer: contextReducer[aiStateReducer],
2518
+ reducer: contextReducer,
2317
2519
  events: generationEvents,
2318
2520
  state
2319
2521
  });
@@ -2321,12 +2523,21 @@ function createHandlers(options) {
2321
2523
  state: currentState,
2322
2524
  coordinator: promptCoordinatorState
2323
2525
  });
2324
- if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await modelContext({
2526
+ if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await telemetry.span("a2.ai.context", {
2527
+ "a2.contract": options.contract.name,
2528
+ "a2.session_id": ctx.event.sessionId,
2529
+ "a2.ai.context.request_id": requestId,
2530
+ "a2.ai.context.phase": "refresh"
2531
+ }, () => modelContext({
2325
2532
  messages: generationMessages,
2326
2533
  state: currentState,
2327
2534
  tools
2535
+ }));
2536
+ cachePrompt({
2537
+ sessionId: ctx.event.sessionId,
2538
+ generationId,
2539
+ messages: Promise.resolve(modelMessages)
2328
2540
  });
2329
- promptCache.set(promptCacheKey(ctx.event.sessionId, generationId), Promise.resolve(modelMessages));
2330
2541
  if (tracksInput && (inputTokenEstimate === void 0 || compacted)) inputTokenEstimate = await estimateInputTokens({
2331
2542
  messages: modelMessages,
2332
2543
  instructions: resolvedInstructions,
@@ -2335,26 +2546,34 @@ function createHandlers(options) {
2335
2546
  let pendingToolCalls = [];
2336
2547
  if (checkAbort(ctx.signal)) return;
2337
2548
  const generateContext = {
2338
- request: ctx.event,
2339
- requestId,
2340
- generationId,
2341
- responseMessageId,
2549
+ ...baseContext,
2342
2550
  messages: generationMessages,
2343
- modelMessages,
2344
- session: resolverContext.session,
2345
- signal: ctx.signal,
2346
- model: resolvedModel,
2347
- tools,
2348
- ...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
2349
- generation: options.generation ?? {}
2551
+ modelMessages
2350
2552
  };
2351
- const custom = options.generate !== void 0;
2352
2553
  const updates = consumeGeneration({
2353
- source: options.generate === void 0 ? await generateWithAISDK({
2354
- agentName: options.agent.contract.name,
2554
+ source: harness !== void 0 ? await harness.step({
2555
+ agentName: options.contract.name,
2556
+ sessionId: ctx.event.sessionId,
2557
+ requestIndex: ctx.event.index,
2558
+ generationId,
2559
+ responseMessageId,
2560
+ throughIndex: snapshot.index,
2561
+ messages: generationMessages,
2562
+ model,
2563
+ ...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
2564
+ ...settings.speed === void 0 ? {} : { speed: settings.speed },
2565
+ instructions: instructionTexts(resolvedInstructions),
2566
+ tools,
2567
+ log: harnessLog({
2568
+ states,
2569
+ session: ctx.session
2570
+ }),
2571
+ signal: ctx.signal
2572
+ }) : loop.generate === void 0 ? await generateWithAISDK({
2573
+ agentName: options.contract.name,
2355
2574
  context: generateContext,
2356
- messageMetadata: options.messageMetadata
2357
- }) : { stream: await options.generate(generateContext) },
2575
+ messageMetadata: loop.messageMetadata
2576
+ }) : { stream: await loop.generate(generateContext) },
2358
2577
  ...options.progress === void 0 ? {} : { progress: options.progress }
2359
2578
  });
2360
2579
  let sequence = 0;
@@ -2366,11 +2585,7 @@ function createHandlers(options) {
2366
2585
  continue;
2367
2586
  }
2368
2587
  const progress = {
2369
- requestId,
2370
- messageId: request.messageId,
2371
- generationId,
2372
- responseMessageId,
2373
- sequence,
2588
+ startIndex,
2374
2589
  chunks: update.chunks
2375
2590
  };
2376
2591
  const lifecycle = await lifecycleEvents({
@@ -2382,7 +2597,7 @@ function createHandlers(options) {
2382
2597
  pending: pendingToolCalls,
2383
2598
  tools,
2384
2599
  generation,
2385
- custom
2600
+ approvals: harness === void 0
2386
2601
  });
2387
2602
  pendingToolCalls = lifecycle.pending;
2388
2603
  await control.append({
@@ -2411,10 +2626,11 @@ function createHandlers(options) {
2411
2626
  id: await aiEventId("a2.ai.completed", generationId),
2412
2627
  payload: completed
2413
2628
  };
2414
- const unresolved = options.generate ? pendingToolCalls.filter((pending) => pending.classification !== "automatic") : [];
2629
+ const unresolved = loop.generate ? pendingToolCalls.filter((pending) => pending.classification !== "automatic") : [];
2415
2630
  if (unresolved.length > 0) throw new Error(`generation ended with unresolved tool authorization for '${unresolved[0].call.toolName}'`);
2416
- const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || options.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
2631
+ const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || loop.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
2417
2632
  if (finish.finishReason === "tool-calls") return [...pendingEvents, completionEvent];
2633
+ forgetPrompt(ctx.event.sessionId, generationId);
2418
2634
  return [
2419
2635
  ...pendingEvents,
2420
2636
  completionEvent,
@@ -2431,7 +2647,13 @@ function createHandlers(options) {
2431
2647
  throw error;
2432
2648
  }
2433
2649
  if (checkAbort(ctx.signal)) return;
2434
- if (!generationStarted) throw error;
2650
+ if (!generationStarted && !resolving) throw error;
2651
+ if (!generationStarted) await control.append({
2652
+ ctx,
2653
+ name: "generation-start",
2654
+ events: await startEvents(startedPayload(resolvedModel))
2655
+ });
2656
+ forgetPrompt(ctx.event.sessionId, generationId);
2435
2657
  const failed = {
2436
2658
  requestId,
2437
2659
  messageId: request.messageId,
@@ -2446,10 +2668,6 @@ function createHandlers(options) {
2446
2668
  };
2447
2669
  }
2448
2670
  };
2449
- const clearPromptCache = (sessionId) => {
2450
- const prefix = `${sessionId}\u001f`;
2451
- for (const key of promptCache.keys()) if (key.startsWith(prefix)) promptCache.delete(key);
2452
- };
2453
2671
  return {
2454
2672
  "ai.model.metadata.requested": { handler: async (ctx) => {
2455
2673
  const limits = await readModelLimits({
@@ -2474,29 +2692,16 @@ function createHandlers(options) {
2474
2692
  if ((command.action === "send" || command.action === "steer") && event.id !== command.message.id) throw new A2Error("INVALID_PAYLOAD", "AI input event ID must equal message.id");
2475
2693
  return "a2.ai.control";
2476
2694
  },
2477
- handler: control.handler
2695
+ handler: controlHandler
2478
2696
  },
2479
2697
  "ai.work.reported": {
2480
2698
  lane: "a2.ai.control",
2481
- handler: control.handler
2699
+ handler: controlHandler
2482
2700
  },
2483
- "ai.message.completed": { handler: async (ctx) => {
2484
- clearPromptCache(ctx.event.sessionId);
2485
- } },
2486
- "ai.message.interrupted": { handler: async (ctx) => {
2487
- clearPromptCache(ctx.event.sessionId);
2488
- } },
2489
2701
  "ai.session.closed": {
2490
2702
  lane: "a2.ai.control",
2491
- handler: async (ctx) => {
2492
- clearPromptCache(ctx.event.sessionId);
2493
- return control.handler(ctx);
2494
- }
2703
+ handler: controlHandler
2495
2704
  },
2496
- "ai.generation.failed": { handler: (ctx) => {
2497
- promptCache.delete(promptCacheKey(ctx.event.sessionId, ctx.event.payload.generationId));
2498
- return Promise.resolve();
2499
- } },
2500
2705
  "ai.generation.requested": {
2501
2706
  lane: "a2.ai.model",
2502
2707
  abortOn: {
@@ -2507,7 +2712,12 @@ function createHandlers(options) {
2507
2712
  },
2508
2713
  "ai.session.closed": true
2509
2714
  },
2510
- handler: async (ctx) => {
2715
+ handler: (ctx) => telemetry.span("a2.ai.generate", {
2716
+ "a2.contract": options.contract.name,
2717
+ "a2.session_id": ctx.event.sessionId,
2718
+ "a2.ai.generate.request_id": ctx.event.id,
2719
+ "a2.ai.generate.attempt": ctx.attempt
2720
+ }, async () => {
2511
2721
  try {
2512
2722
  return control.settled({
2513
2723
  ctx,
@@ -2523,9 +2733,10 @@ function createHandlers(options) {
2523
2733
  });
2524
2734
  throw error;
2525
2735
  }
2526
- }
2736
+ })
2527
2737
  },
2528
2738
  "ai.tool.execution.requested": {
2739
+ ...options.toolLane === void 0 ? {} : { lane: options.toolLane },
2529
2740
  abortOn: {
2530
2741
  "ai.control.requested": (event, trigger) => event.payload.action === "stop" && event.payload.turnId === trigger.payload.turnId,
2531
2742
  "ai.generation.failed": (event, trigger) => event.payload.generationId === trigger.payload.call.generationId,
@@ -2535,37 +2746,69 @@ function createHandlers(options) {
2535
2746
  },
2536
2747
  "ai.session.closed": true
2537
2748
  },
2538
- handler: handleToolExecution
2749
+ handler: (ctx) => telemetry.span("a2.ai.tool", {
2750
+ "a2.contract": options.contract.name,
2751
+ "a2.session_id": ctx.event.sessionId,
2752
+ "a2.ai.tool.request_id": ctx.event.payload.call.requestId,
2753
+ "a2.ai.tool.call_id": ctx.event.payload.call.toolCallId,
2754
+ "a2.ai.tool.name": ctx.event.payload.call.toolName,
2755
+ "a2.ai.tool.attempt": ctx.attempt
2756
+ }, () => handleToolExecution(ctx))
2539
2757
  }
2540
2758
  };
2541
2759
  }
2542
- /** Assemble an A2 server with the built-in agent handlers and app extensions. */
2543
- function createAgentServer(options) {
2544
- const { agent: definition, model, tools, instructions, generation, maxSteps, messageMetadata, generate, compaction, progress, handlers, ...serverOptions } = options;
2760
+ function agent(options) {
2761
+ assertNoLoopOptions(options);
2762
+ const { model, tools, instructions, maxSteps, harness, toolRecovery, progress, toolLane, handlers, ...rest } = options;
2763
+ let contract;
2764
+ let serverOptions;
2765
+ if ("contract" in rest) {
2766
+ const { contract: shared, ...remaining } = rest;
2767
+ if ("name" in remaining) throw new TypeError("agent takes either name or contract, not both");
2768
+ if (!isAgentContract(shared)) throw new TypeError("agent({ contract }) takes an agentContract()");
2769
+ contract = shared;
2770
+ serverOptions = remaining;
2771
+ } else {
2772
+ const { name, events, messageSchema, ...remaining } = rest;
2773
+ contract = agentContract({
2774
+ name,
2775
+ ...events === void 0 ? {} : { events },
2776
+ ...messageSchema === void 0 ? {} : { messageSchema }
2777
+ });
2778
+ serverOptions = remaining;
2779
+ }
2780
+ const states = harnessStates();
2545
2781
  const builtIns = createHandlers({
2546
- agent: definition,
2782
+ contract,
2547
2783
  model,
2784
+ harnessStates: states,
2785
+ ...serverOptions.telemetry === void 0 ? {} : { telemetry: serverOptions.telemetry },
2548
2786
  ...tools === void 0 ? {} : { tools },
2549
2787
  ...instructions === void 0 ? {} : { instructions },
2550
- ...generation === void 0 ? {} : { generation },
2551
2788
  ...maxSteps === void 0 ? {} : { maxSteps },
2552
- ...messageMetadata === void 0 ? {} : { messageMetadata },
2553
- ...generate === void 0 ? {} : { generate },
2554
- ...compaction === void 0 ? {} : { compaction },
2555
- ...progress === void 0 ? {} : { progress }
2789
+ ...harness === void 0 ? {} : { harness },
2790
+ ...toolRecovery === void 0 ? {} : { toolRecovery },
2791
+ ...progress === void 0 ? {} : { progress },
2792
+ ...toolLane === void 0 ? {} : { toolLane }
2556
2793
  });
2794
+ for (const type of Object.keys(handlers ?? {})) if (Object.hasOwn(builtIns, type)) throw new TypeError(`agent handles '${type}' itself`);
2557
2795
  const server = createServer({
2558
2796
  ...serverOptions,
2559
- contract: definition.contract,
2797
+ contract,
2560
2798
  handlers: {
2561
2799
  ...builtIns,
2562
2800
  ...handlers
2563
2801
  }
2564
2802
  });
2565
- setServerFetchHooks(server, { validateIngress: validateAgentIngress });
2803
+ registerHarnessStates(server, states);
2804
+ const applicationEvents = "contract" in rest;
2805
+ setServerFetchHooks(server, { validateIngress: (context) => validateAgentIngress({
2806
+ context,
2807
+ applicationEvents
2808
+ }) });
2566
2809
  return server;
2567
2810
  }
2568
2811
  //#endregion
2569
- export { createAgentServer, createHandlers, runWithHandlerContext };
2812
+ export { agent, runWithHandlerContext };
2570
2813
 
2571
2814
  //# sourceMappingURL=ai-server.js.map