experimental-a2 0.20.0 → 0.22.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 (309) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-C7b-1arn.d.ts → actor-CqibLgjQ.d.ts} +15 -7
  4. package/dist/actor-CqibLgjQ.d.ts.map +1 -0
  5. package/dist/actor-client.d.ts +1 -1
  6. package/dist/actor-client.js +2 -2
  7. package/dist/actor-react.d.ts +3 -3
  8. package/dist/actor-react.js +5 -5
  9. package/dist/{actor-shared-t7w8xIKP.js → actor-shared-DFET5q16.js} +3 -3
  10. package/dist/actor-shared-DFET5q16.js.map +1 -0
  11. package/dist/actor.d.ts +1 -1
  12. package/dist/actor.js +54 -43
  13. package/dist/actor.js.map +1 -1
  14. package/dist/{ai-Cz3hqVhk.d.ts → ai-DAu77CDr.d.ts} +8 -8
  15. package/dist/{ai-Cz3hqVhk.d.ts.map → ai-DAu77CDr.d.ts.map} +1 -1
  16. package/dist/{ai-mMiWul1T.js → ai-EEfKyc-z.js} +9 -9
  17. package/dist/ai-EEfKyc-z.js.map +1 -0
  18. package/dist/ai-client.d.ts +2 -2
  19. package/dist/ai-client.js +2 -2
  20. package/dist/ai-fx.d.ts +4 -2
  21. package/dist/ai-fx.d.ts.map +1 -1
  22. package/dist/ai-fx.js +214 -67
  23. package/dist/ai-fx.js.map +1 -1
  24. package/dist/{ai-harness-CV6rXbB3.d.ts → ai-harness-DTjkAr2T.d.ts} +2 -2
  25. package/dist/{ai-harness-CV6rXbB3.d.ts.map → ai-harness-DTjkAr2T.d.ts.map} +1 -1
  26. package/dist/{ai-harness-Clbg5ei7.js → ai-harness-dQeJaR1t.js} +7 -3
  27. package/dist/ai-harness-dQeJaR1t.js.map +1 -0
  28. package/dist/ai-pi.d.ts +1 -1
  29. package/dist/ai-pi.js +3 -3
  30. package/dist/ai-pi.js.map +1 -1
  31. package/dist/ai-react.d.ts +5 -5
  32. package/dist/ai-react.js +2 -2
  33. package/dist/ai-server.d.ts +14 -17
  34. package/dist/ai-server.d.ts.map +1 -1
  35. package/dist/ai-server.js +86 -73
  36. package/dist/ai-server.js.map +1 -1
  37. package/dist/ai.d.ts +2 -2
  38. package/dist/ai.js +2 -2
  39. package/dist/{client-BhHLoNKF.js → client-BQS4i_V9.js} +29 -6
  40. package/dist/client-BQS4i_V9.js.map +1 -0
  41. package/dist/{client-h_DKFAjj.d.ts → client-CUMbS_38.d.ts} +3 -3
  42. package/dist/{client-h_DKFAjj.d.ts.map → client-CUMbS_38.d.ts.map} +1 -1
  43. package/dist/client.d.ts +3 -3
  44. package/dist/client.js +1 -1
  45. package/dist/{contract-BYKASlCV.js → contract-CWukt01d.js} +2 -2
  46. package/dist/contract-CWukt01d.js.map +1 -0
  47. package/dist/index.d.ts +5 -5
  48. package/dist/index.js +3 -3
  49. package/dist/{initial-snapshot-Bx-c0pDP.d.ts → initial-snapshot-D3Lve43o.d.ts} +4 -4
  50. package/dist/initial-snapshot-D3Lve43o.d.ts.map +1 -0
  51. package/dist/{internal-CscSY7K_.js → internal-CvsrprnU.js} +40 -16
  52. package/dist/internal-CvsrprnU.js.map +1 -0
  53. package/dist/otel.d.ts +1 -1
  54. package/dist/otel.js +1 -1
  55. package/dist/otel.js.map +1 -1
  56. package/dist/{react-BBXgHWFc.d.ts → react-BoHvC3v9.d.ts} +4 -4
  57. package/dist/{react-BBXgHWFc.d.ts.map → react-BoHvC3v9.d.ts.map} +1 -1
  58. package/dist/react.d.ts +1 -1
  59. package/dist/react.js +1 -1
  60. package/dist/{reducer-CqA59Q6U.d.ts → reducer-CYPHsSmd.d.ts} +2 -2
  61. package/dist/{reducer-CqA59Q6U.d.ts.map → reducer-CYPHsSmd.d.ts.map} +1 -1
  62. package/dist/{reducer-BAXc8JyF.js → reducer-CjmvZSAb.js} +2 -2
  63. package/dist/{reducer-BAXc8JyF.js.map → reducer-CjmvZSAb.js.map} +1 -1
  64. package/dist/runtime-consumer-CIeL33wj.js +12 -0
  65. package/dist/runtime-consumer-CIeL33wj.js.map +1 -0
  66. package/dist/scheduler-qstash.d.ts +2 -2
  67. package/dist/scheduler-qstash.js +3 -3
  68. package/dist/scheduler-task-X1SToDjP.js.map +1 -1
  69. package/dist/scheduler-vercel.d.ts +2 -2
  70. package/dist/scheduler-vercel.js +3 -3
  71. package/dist/scheduler-vercel.js.map +1 -1
  72. package/dist/{server-qyb5aJJG.js → server-DtFrWxi3.js} +412 -116
  73. package/dist/server-DtFrWxi3.js.map +1 -0
  74. package/dist/{server-DYAATFuT.d.ts → server-qgez0Xny.d.ts} +108 -41
  75. package/dist/server-qgez0Xny.d.ts.map +1 -0
  76. package/dist/server.browser.js +1 -1
  77. package/dist/server.browser.js.map +1 -1
  78. package/dist/server.d.ts +4 -4
  79. package/dist/server.js +2 -2
  80. package/dist/{session-clear-C-QwTXV1.d.ts → session-clear-D1PFe7xl.d.ts} +2 -2
  81. package/dist/session-clear-D1PFe7xl.d.ts.map +1 -0
  82. package/dist/{session-clear-DGI4jTQ5.js → session-clear-wHd5GCpZ.js} +5 -4
  83. package/dist/session-clear-wHd5GCpZ.js.map +1 -0
  84. package/dist/store-D0MhBvg6.d.ts +532 -0
  85. package/dist/store-D0MhBvg6.d.ts.map +1 -0
  86. package/dist/store-N8PXxDAS.js.map +1 -1
  87. package/dist/store-codec-DwrWlgQx.js +65 -0
  88. package/dist/store-codec-DwrWlgQx.js.map +1 -0
  89. package/dist/store-memory.d.ts +1 -1
  90. package/dist/store-memory.d.ts.map +1 -1
  91. package/dist/store-memory.js +406 -225
  92. package/dist/store-memory.js.map +1 -1
  93. package/dist/{store-polling-7WJV0YWP.js → store-polling-BZt2Rf3D.js} +2 -2
  94. package/dist/{store-polling-7WJV0YWP.js.map → store-polling-BZt2Rf3D.js.map} +1 -1
  95. package/dist/store-postgres.d.ts +1 -1
  96. package/dist/store-postgres.d.ts.map +1 -1
  97. package/dist/store-postgres.js +1598 -587
  98. package/dist/store-postgres.js.map +1 -1
  99. package/dist/store-presence-polling-JuAy2Ck2.js +111 -0
  100. package/dist/store-presence-polling-JuAy2Ck2.js.map +1 -0
  101. package/dist/store-redis-http.d.ts +1 -1
  102. package/dist/store-redis-http.js +4 -4
  103. package/dist/store-redis-notify-CsJw_hfD.js +3060 -0
  104. package/dist/store-redis-notify-CsJw_hfD.js.map +1 -0
  105. package/dist/store-redis.d.ts +1 -1
  106. package/dist/store-redis.d.ts.map +1 -1
  107. package/dist/store-redis.js +4 -5
  108. package/dist/store-redis.js.map +1 -1
  109. package/dist/store-sqlite.d.ts +1 -1
  110. package/dist/store-sqlite.d.ts.map +1 -1
  111. package/dist/store-sqlite.js +527 -299
  112. package/dist/store-sqlite.js.map +1 -1
  113. package/dist/stream-buffer-DrTyiIuo.js +57 -0
  114. package/dist/stream-buffer-DrTyiIuo.js.map +1 -0
  115. package/dist/{telemetry-Cyfqo6Qt.d.ts → telemetry-CWwsh-Gx.d.ts} +3 -3
  116. package/dist/telemetry-CWwsh-Gx.d.ts.map +1 -0
  117. package/dist/{wire-BKxH1vbP.js → wire-CV-Z7wz-.js} +6 -5
  118. package/dist/wire-CV-Z7wz-.js.map +1 -0
  119. package/docs/01-quickstart.mdx +21 -15
  120. package/docs/02-examples.mdx +1 -1
  121. package/docs/actors/01-introduction.mdx +13 -2
  122. package/docs/actors/02-concurrency.mdx +1 -1
  123. package/docs/agents/01-introduction.mdx +1 -1
  124. package/docs/agents/02-tools.mdx +12 -11
  125. package/docs/agents/03-conversations.mdx +36 -25
  126. package/docs/agents/04-harnesses.mdx +14 -7
  127. package/docs/client/03-presence.mdx +18 -14
  128. package/docs/contract/01-events.mdx +2 -2
  129. package/docs/contract/02-state.mdx +18 -14
  130. package/docs/contract/03-sessions.mdx +32 -25
  131. package/docs/index.mdx +29 -24
  132. package/docs/reference/01-core.mdx +7 -6
  133. package/docs/reference/02-server.mdx +250 -191
  134. package/docs/reference/04-ai.mdx +33 -23
  135. package/docs/reference/05-telemetry.mdx +27 -13
  136. package/docs/reference/06-errors.mdx +25 -19
  137. package/docs/reference/meta.ts +1 -1
  138. package/docs/schedulers/01-overview.mdx +8 -8
  139. package/docs/schedulers/02-vercel-queues.mdx +2 -2
  140. package/docs/schedulers/03-qstash.mdx +4 -4
  141. package/docs/server/01-consumers.mdx +418 -0
  142. package/docs/server/02-timers.mdx +31 -21
  143. package/docs/server/03-cancellation.mdx +52 -44
  144. package/docs/server/04-routes.mdx +4 -1
  145. package/docs/server/05-sql-projections.mdx +391 -0
  146. package/docs/server/06-guarantees.mdx +61 -51
  147. package/docs/stores/01-overview.mdx +3 -3
  148. package/docs/stores/02-redis.mdx +24 -10
  149. package/docs/stores/03-redis-http.mdx +8 -6
  150. package/docs/stores/04-postgres.mdx +65 -14
  151. package/docs/stores/05-sqlite.mdx +5 -3
  152. package/docs/upgrades/01-overview.mdx +31 -0
  153. package/docs/upgrades/78-0-22.mdx +115 -0
  154. package/docs/upgrades/79-0-21.mdx +165 -0
  155. package/docs/upgrades/80-0-20.mdx +43 -0
  156. package/docs/upgrades/81-0-19.mdx +33 -0
  157. package/docs/upgrades/82-0-18.mdx +33 -0
  158. package/docs/upgrades/83-0-17.mdx +69 -0
  159. package/docs/upgrades/meta.ts +3 -0
  160. package/examples/playground/DEPLOY.md +39 -7
  161. package/examples/playground/app/a0/chat.test.tsx +2 -2
  162. package/examples/playground/app/a0/sandbox-log.ts +17 -15
  163. package/examples/playground/app/a0/sandbox.ts +58 -13
  164. package/examples/playground/app/a0/server.ts +4 -4
  165. package/examples/playground/app/a2slack/a2slack.css +1067 -0
  166. package/examples/playground/app/a2slack/c/[channel]/page.tsx +20 -0
  167. package/examples/playground/app/a2slack/consumers/agent.ts +63 -0
  168. package/examples/playground/app/a2slack/consumers/feed.ts +164 -0
  169. package/examples/playground/app/a2slack/consumers/notify.ts +116 -0
  170. package/examples/playground/app/a2slack/consumers/search.ts +37 -0
  171. package/examples/playground/app/a2slack/consumers/triage.ts +31 -0
  172. package/examples/playground/app/a2slack/consumers/welcome.ts +25 -0
  173. package/examples/playground/app/a2slack/db/a2.ts +209 -0
  174. package/examples/playground/app/a2slack/db/index.ts +73 -0
  175. package/examples/playground/app/a2slack/db/migrations/0000_extensions.sql +4 -0
  176. package/examples/playground/app/a2slack/db/migrations/0001_workspace.sql +74 -0
  177. package/examples/playground/app/a2slack/db/migrations/0002_a2.sql +215 -0
  178. package/examples/playground/app/a2slack/db/migrations/0003_a2_batch.sql +67 -0
  179. package/examples/playground/app/a2slack/db/migrations/0004_a2_session_event_ids.sql +2 -0
  180. package/examples/playground/app/a2slack/db/migrations/meta/0000_snapshot.json +18 -0
  181. package/examples/playground/app/a2slack/db/migrations/meta/0001_snapshot.json +500 -0
  182. package/examples/playground/app/a2slack/db/migrations/meta/0002_snapshot.json +1159 -0
  183. package/examples/playground/app/a2slack/db/migrations/meta/0003_snapshot.json +1159 -0
  184. package/examples/playground/app/a2slack/db/migrations/meta/0004_snapshot.json +1165 -0
  185. package/examples/playground/app/a2slack/db/migrations/meta/_journal.json +41 -0
  186. package/examples/playground/app/a2slack/db/queries.ts +263 -0
  187. package/examples/playground/app/a2slack/db/schema.ts +145 -0
  188. package/examples/playground/app/a2slack/drills/a2slack.drill.ts +708 -0
  189. package/examples/playground/app/a2slack/drills/harness.ts +244 -0
  190. package/examples/playground/app/a2slack/events/route.ts +36 -0
  191. package/examples/playground/app/a2slack/identity.ts +44 -0
  192. package/examples/playground/app/a2slack/inbox/route.ts +8 -0
  193. package/examples/playground/app/a2slack/lag/data/route.ts +8 -0
  194. package/examples/playground/app/a2slack/lag/page.tsx +101 -0
  195. package/examples/playground/app/a2slack/lag.ts +73 -0
  196. package/examples/playground/app/a2slack/layout.tsx +43 -0
  197. package/examples/playground/app/a2slack/messages/route.ts +17 -0
  198. package/examples/playground/app/a2slack/model.test.ts +208 -0
  199. package/examples/playground/app/a2slack/model.ts +369 -0
  200. package/examples/playground/app/a2slack/models.test.ts +72 -0
  201. package/examples/playground/app/a2slack/page.tsx +10 -0
  202. package/examples/playground/app/a2slack/scheduler/route.ts +5 -0
  203. package/examples/playground/app/a2slack/search/route.ts +40 -0
  204. package/examples/playground/app/a2slack/search-index.ts +108 -0
  205. package/examples/playground/app/a2slack/server.test.ts +315 -0
  206. package/examples/playground/app/a2slack/server.ts +55 -0
  207. package/examples/playground/app/a2slack/sessions.ts +50 -0
  208. package/examples/playground/app/a2slack/thread/route.ts +8 -0
  209. package/examples/playground/app/a2slack/ui/ChannelView.tsx +87 -0
  210. package/examples/playground/app/a2slack/ui/Composer.tsx +117 -0
  211. package/examples/playground/app/a2slack/ui/DotsShadow.tsx +42 -0
  212. package/examples/playground/app/a2slack/ui/Feed.tsx +157 -0
  213. package/examples/playground/app/a2slack/ui/InboxContext.tsx +63 -0
  214. package/examples/playground/app/a2slack/ui/InboxView.tsx +82 -0
  215. package/examples/playground/app/a2slack/ui/Menu.tsx +128 -0
  216. package/examples/playground/app/a2slack/ui/MessageRow.tsx +314 -0
  217. package/examples/playground/app/a2slack/ui/NameGate.tsx +35 -0
  218. package/examples/playground/app/a2slack/ui/SearchContext.tsx +146 -0
  219. package/examples/playground/app/a2slack/ui/SearchResults.tsx +97 -0
  220. package/examples/playground/app/a2slack/ui/Shell.tsx +34 -0
  221. package/examples/playground/app/a2slack/ui/Sidebar.tsx +199 -0
  222. package/examples/playground/app/a2slack/ui/ThreadPanel.tsx +134 -0
  223. package/examples/playground/app/a2slack/ui/useInbox.ts +71 -0
  224. package/examples/playground/app/agent/server.ts +3 -3
  225. package/examples/playground/app/chat/[chatId]/chat-client.tsx +1 -1
  226. package/examples/playground/app/chat/server.ts +45 -35
  227. package/examples/playground/app/components/demo-icons.tsx +7 -0
  228. package/examples/playground/app/components/demos.tsx +7 -0
  229. package/examples/playground/app/orders/[orderId]/order-client.tsx +2 -2
  230. package/examples/playground/app/orders/page.tsx +1 -1
  231. package/examples/playground/app/orders/server.ts +49 -30
  232. package/examples/playground/app/recovery/[recoveryId]/recovery-client.tsx +14 -15
  233. package/examples/playground/app/recovery/page.tsx +4 -4
  234. package/examples/playground/app/recovery/server.ts +23 -32
  235. package/examples/playground/drizzle.config.ts +14 -0
  236. package/examples/playground/lib/store.ts +1 -1
  237. package/examples/playground/next.config.ts +6 -1
  238. package/examples/playground/package.json +12 -1
  239. package/examples/playground/scripts/migrate.mjs +31 -0
  240. package/examples/playground/vercel.json +9 -0
  241. package/examples/playground/vitest.drills.config.ts +32 -0
  242. package/package.json +5 -2
  243. package/sql/postgres/drizzle-schema.ts +209 -0
  244. package/sql/postgres/schema.sql +227 -67
  245. package/src/actor-shared.ts +10 -2
  246. package/src/actor.ts +101 -71
  247. package/src/ai-agent.ts +162 -111
  248. package/src/ai-control-server.ts +8 -8
  249. package/src/ai-fx.ts +324 -82
  250. package/src/ai-harness.ts +17 -2
  251. package/src/ai-pi.ts +2 -2
  252. package/src/ai-server.ts +2 -2
  253. package/src/ai.ts +7 -7
  254. package/src/client.ts +19 -2
  255. package/src/contract.ts +1 -1
  256. package/src/deterministic-id.ts +27 -4
  257. package/src/errors.ts +8 -5
  258. package/src/idempotent-replay.ts +0 -1
  259. package/src/index.ts +1 -1
  260. package/src/internal.ts +57 -16
  261. package/src/otel.ts +1 -1
  262. package/src/postgres-schema.ts +98 -57
  263. package/src/presence-recovery.ts +18 -11
  264. package/src/presence-tombstones.ts +52 -0
  265. package/src/push-envelope.ts +20 -0
  266. package/src/runtime-consumer.ts +10 -0
  267. package/src/scheduler-task.ts +2 -2
  268. package/src/scheduler-vercel.ts +1 -1
  269. package/src/server.browser.ts +1 -1
  270. package/src/server.ts +819 -218
  271. package/src/session-socket.ts +1 -1
  272. package/src/store-codec.ts +66 -0
  273. package/src/store-memory.ts +604 -286
  274. package/src/store-postgres.ts +2006 -857
  275. package/src/store-presence-polling.ts +59 -34
  276. package/src/store-redis-core.ts +1961 -1333
  277. package/src/store-redis-notify.ts +76 -26
  278. package/src/store-redis.ts +2 -3
  279. package/src/store-sqlite.ts +915 -516
  280. package/src/store.ts +241 -102
  281. package/src/telemetry.ts +2 -1
  282. package/src/wire.ts +1 -0
  283. package/dist/actor-C7b-1arn.d.ts.map +0 -1
  284. package/dist/actor-shared-t7w8xIKP.js.map +0 -1
  285. package/dist/ai-harness-Clbg5ei7.js.map +0 -1
  286. package/dist/ai-mMiWul1T.js.map +0 -1
  287. package/dist/client-BhHLoNKF.js.map +0 -1
  288. package/dist/contract-BYKASlCV.js.map +0 -1
  289. package/dist/idempotent-replay-JdgMQRRm.js +0 -21
  290. package/dist/idempotent-replay-JdgMQRRm.js.map +0 -1
  291. package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +0 -1
  292. package/dist/internal-CscSY7K_.js.map +0 -1
  293. package/dist/server-DYAATFuT.d.ts.map +0 -1
  294. package/dist/server-qyb5aJJG.js.map +0 -1
  295. package/dist/session-clear-C-QwTXV1.d.ts.map +0 -1
  296. package/dist/session-clear-DGI4jTQ5.js.map +0 -1
  297. package/dist/store-CyLUy86v.d.ts +0 -404
  298. package/dist/store-CyLUy86v.d.ts.map +0 -1
  299. package/dist/store-codec-DTG0Ftek.js +0 -10
  300. package/dist/store-codec-DTG0Ftek.js.map +0 -1
  301. package/dist/store-presence-polling-B1ixeqIS.js +0 -94
  302. package/dist/store-presence-polling-B1ixeqIS.js.map +0 -1
  303. package/dist/store-redis-notify-CM0AfLY0.js +0 -2544
  304. package/dist/store-redis-notify-CM0AfLY0.js.map +0 -1
  305. package/dist/stream-buffer-Cx7AAPGq.js +0 -23
  306. package/dist/stream-buffer-Cx7AAPGq.js.map +0 -1
  307. package/dist/telemetry-Cyfqo6Qt.d.ts.map +0 -1
  308. package/dist/wire-BKxH1vbP.js.map +0 -1
  309. package/docs/server/01-handlers.mdx +0 -227
@@ -1,5 +1,5 @@
1
- import { s as CreateClientOptions, t as A2Client } from "./client-h_DKFAjj.js";
2
- import { a as AI_STATE_REDUCER, i as AIState, r as AIMessageOf, t as AIEventDefs } from "./ai-Cz3hqVhk.js";
1
+ import { s as CreateClientOptions, t as A2Client } from "./client-CUMbS_38.js";
2
+ import { a as AI_STATE_REDUCER, i as AIState, r as AIMessageOf, t as AIEventDefs } from "./ai-DAu77CDr.js";
3
3
  //#region src/ai-client.d.ts
4
4
  /**
5
5
  * The structural shape of `typeof` an `agent({ name })` server: one whose
package/dist/ai-client.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as createClient } from "./client-BhHLoNKF.js";
2
- import { n as agentContract } from "./ai-mMiWul1T.js";
1
+ import { t as createClient } from "./client-BQS4i_V9.js";
2
+ import { n as agentContract } from "./ai-EEfKyc-z.js";
3
3
  //#region src/ai-client.ts
4
4
  /**
5
5
  * experimental-a2/ai/client — a client for an `agent()` route that needs no
package/dist/ai-fx.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { t as Harness } from "./ai-harness-CV6rXbB3.js";
1
+ import { t as Harness } from "./ai-harness-DTjkAr2T.js";
2
2
  //#region src/ai-fx.d.ts
3
3
  /**
4
4
  * The FX harness. Every model call FX makes is one durable step; A2 rebuilds
5
- * the kernel for each step from its latest checkpoint and the log since.
5
+ * the kernel for each step from its latest checkpoint and the log since,
6
+ * unless this process holds the kernel the step before left waiting on its
7
+ * tool calls.
6
8
  */
7
9
  declare function fx(): Harness<"fx", never>;
8
10
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"ai-fx.d.ts","names":[],"sources":["../src/ai-fx.ts"],"mappings":";;;;;;iBA4CgB,MAAM"}
1
+ {"version":3,"file":"ai-fx.d.ts","names":[],"sources":["../src/ai-fx.ts"],"mappings":";;;;;;;;iBA+CgB,MAAM"}
package/dist/ai-fx.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { n as HARNESS_PARKING } from "./internal-CvsrprnU.js";
1
2
  import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
2
- import { a as gatewaySessionAffinity, d as readHarness, i as gatewayCredential, n as deferred, p as saveHarness, r as defineHarness, s as harnessImages, t as Divergence, u as pending } from "./ai-harness-Clbg5ei7.js";
3
+ import { a as gatewaySessionAffinity, d as readHarness, i as gatewayCredential, n as deferred, p as saveHarness, r as defineHarness, s as harnessImages, t as Divergence, u as pending } from "./ai-harness-dQeJaR1t.js";
3
4
  import { t as schemaInput } from "./ai-tool-input-DmSqMUQi.js";
4
5
  import { asSchema } from "ai";
5
6
  //#region src/ai-fx.ts
@@ -9,12 +10,27 @@ import { asSchema } from "ai";
9
10
  */
10
11
  /**
11
12
  * The FX harness. Every model call FX makes is one durable step; A2 rebuilds
12
- * the kernel for each step from its latest checkpoint and the log since.
13
+ * the kernel for each step from its latest checkpoint and the log since,
14
+ * unless this process holds the kernel the step before left waiting on its
15
+ * tool calls.
13
16
  */
14
17
  function fx() {
18
+ const lots = /* @__PURE__ */ new WeakMap();
19
+ const lotOf = (scope) => {
20
+ let lot = lots.get(scope);
21
+ if (lot === void 0) {
22
+ lot = parkingLot();
23
+ lots.set(scope, lot);
24
+ }
25
+ return lot;
26
+ };
15
27
  return defineHarness("fx", {
16
28
  tools: {},
17
- step: runStep
29
+ step: (step) => runStep(step, lotOf(step.scope)),
30
+ release: ({ scope, sessionId }) => {
31
+ const entry = lots.get(scope)?.take(sessionId);
32
+ if (entry !== void 0) closeParked(entry);
33
+ }
18
34
  });
19
35
  }
20
36
  const SNAPSHOT_VERSION = 1;
@@ -27,10 +43,52 @@ function fail(state, error) {
27
43
  throw state.failure;
28
44
  }
29
45
  const diverged = (message) => new Divergence("FX", message);
30
- async function runStep(step) {
46
+ function closeParked(entry) {
47
+ entry.fxTurn.cancel();
48
+ entry.kernel.agent.close().catch(() => {});
49
+ }
50
+ /**
51
+ * One agent's parked kernels: one per session, at most `maxKernels`. Each is
52
+ * closed when its session has nothing left to run in this process (the
53
+ * agent's release), when its turn ends, or when another takes its place.
54
+ */
55
+ function parkingLot() {
56
+ const held = /* @__PURE__ */ new Map();
57
+ const take = (sessionId) => {
58
+ const entry = held.get(sessionId);
59
+ held.delete(sessionId);
60
+ return entry;
61
+ };
62
+ return {
63
+ take,
64
+ park(sessionId, entry) {
65
+ const replaced = take(sessionId);
66
+ if (replaced !== void 0) closeParked(replaced);
67
+ held.set(sessionId, entry);
68
+ const ended = () => {
69
+ if (held.get(sessionId) !== entry) return;
70
+ held.delete(sessionId);
71
+ closeParked(entry);
72
+ };
73
+ entry.fxTurn.result.then(ended, ended);
74
+ const oldest = held.keys().next().value;
75
+ if (held.size > HARNESS_PARKING.maxKernels && oldest !== void 0) {
76
+ const evicted = take(oldest);
77
+ if (evicted !== void 0) closeParked(evicted);
78
+ }
79
+ }
80
+ };
81
+ }
82
+ async function runStep(step, lot) {
31
83
  const { createFxAgent } = await loadLibfx();
32
84
  const credential = gatewayCredential("fx");
33
85
  const name = `${step.agentName}.a2.harness.fx`;
86
+ const definitions = await toolDefinitions(step.tools);
87
+ const settings = JSON.stringify([
88
+ kernelModel(step),
89
+ step.instructions,
90
+ definitions
91
+ ]);
34
92
  const { replayAll, ...first } = await readHarness({
35
93
  step,
36
94
  name,
@@ -41,16 +99,22 @@ async function runStep(step) {
41
99
  let stopped = false;
42
100
  const released = new AbortController();
43
101
  const network = AbortSignal.any([step.signal, released.signal]);
44
- let agent;
102
+ let kernel;
103
+ /** Whether this step left its kernel for the next one. */
104
+ let parked = false;
45
105
  let turn;
46
- const run = async (controller, turns) => {
106
+ const run = async (controller, turns, adopted) => {
47
107
  controller.enqueue({
48
108
  type: "start",
49
109
  messageId: step.responseMessageId
50
110
  });
111
+ if (adopted !== void 0) {
112
+ await resume(controller, turns.at(-1), adopted);
113
+ return;
114
+ }
51
115
  for (const plan of turns) {
52
- if (stopped) return;
53
- const fxTurn = agent.prompt(plan.prompt, { signal: step.signal });
116
+ if (stopped || step.signal.aborted) return;
117
+ const fxTurn = kernel.agent.prompt(plan.prompt);
54
118
  const state = {
55
119
  plan,
56
120
  fxTurn,
@@ -76,29 +140,82 @@ async function runStep(step) {
76
140
  if (result.stopReason !== expected) throw diverged(`a recorded turn ended with ${result.stopReason}, not ${expected}`);
77
141
  continue;
78
142
  }
79
- const outcome = await Promise.race([fxTurn.result.then((result) => ({
80
- ended: true,
81
- result
82
- })), state.toolsRequested.promise.then(() => ({ ended: false }))]).catch((error) => {
83
- throw state.failure ?? error;
84
- });
85
- if (state.failure) throw state.failure;
86
- await state.parsed;
87
- if (outcome.ended) {
88
- await drained;
89
- if (outcome.result.stopReason === "end_turn" && !step.signal.aborted) await saveCheckpoint();
90
- } else fxTurn.cancel();
91
- controller.enqueue({ type: "finish-step" });
92
- controller.enqueue({
93
- type: "finish",
94
- ...completion.finishReason === void 0 ? {} : { finishReason: completion.finishReason }
95
- });
143
+ await finishLive(controller, state, drained);
96
144
  }
97
145
  };
146
+ /** Continues a parked kernel: the results it waits on are in the log. */
147
+ const resume = async (controller, plan, adopted) => {
148
+ const state = {
149
+ plan,
150
+ fxTurn: adopted.fxTurn,
151
+ next: plan.calls.length,
152
+ served: plan.calls.at(-1).toolCalls,
153
+ answered: /* @__PURE__ */ new Set(),
154
+ live: false,
155
+ liveStep: false,
156
+ toolsRequested: deferred()
157
+ };
158
+ turn = state;
159
+ for (const text of plan.steers.get(plan.calls.length - 1) ?? []) await adopted.fxTurn.steer(text);
160
+ for (const waiting of kernel.waiting.splice(0)) try {
161
+ const answered = answer(state, waiting.toolName, waiting.input);
162
+ if (answered === void 0) fail(state, diverged(`no recorded result for ${waiting.toolName}`));
163
+ waiting.resolve(answered.output);
164
+ } catch (error) {
165
+ waiting.reject(error);
166
+ }
167
+ await finishLive(controller, state, adopted.drained);
168
+ };
169
+ const finishLive = async (controller, state, drained) => {
170
+ const outcome = await Promise.race([state.fxTurn.result.then((result) => ({
171
+ ended: true,
172
+ result
173
+ })), state.toolsRequested.promise.then(() => ({ ended: false }))]).catch((error) => {
174
+ throw state.failure ?? error;
175
+ });
176
+ if (state.failure) throw state.failure;
177
+ await state.parsed;
178
+ if (outcome.ended) {
179
+ if (outcome.result.stopReason === "cancelled" && !stopped && !step.signal.aborted) throw diverged("the turn was cancelled while this step ran it");
180
+ await drained;
181
+ if (outcome.result.stopReason === "end_turn" && !step.signal.aborted) await saveCheckpoint();
182
+ } else if (kernel.waiting.length > 0 && !stopped && !closed) {
183
+ lot.park(step.sessionId, {
184
+ kernel,
185
+ fxTurn: state.fxTurn,
186
+ drained,
187
+ generationId: step.generationId,
188
+ settings
189
+ });
190
+ parked = true;
191
+ } else state.fxTurn.cancel();
192
+ controller.enqueue({ type: "finish-step" });
193
+ controller.enqueue({
194
+ type: "finish",
195
+ ...completion.finishReason === void 0 ? {} : { finishReason: completion.finishReason }
196
+ });
197
+ };
198
+ /**
199
+ * Whether a parked kernel stands where this step's log does: made the same
200
+ * way, its model call the last one the log's live turn committed, and a
201
+ * recorded result for each tool call it waits on. A steered response
202
+ * continues the same turn, so its steps qualify too.
203
+ */
204
+ const adoptable = (entry, turns) => {
205
+ const plan = turns.at(-1);
206
+ if (entry.settings !== settings || plan?.end !== "live" || plan.generationId !== entry.generationId) return false;
207
+ const unanswered = [...plan.calls.at(-1)?.toolCalls ?? []];
208
+ return entry.kernel.waiting.every((waiting) => {
209
+ const at = unanswered.findIndex((call) => call.toolName === waiting.toolName && sameJson(call.input, waiting.input) && results.has(call.toolCallId));
210
+ if (at === -1) return false;
211
+ unanswered.splice(at, 1);
212
+ return true;
213
+ });
214
+ };
98
215
  const saveCheckpoint = async () => {
99
216
  let checkpoint;
100
217
  try {
101
- checkpoint = await agent.checkpoint();
218
+ checkpoint = await kernel.agent.checkpoint();
102
219
  } catch {
103
220
  return;
104
221
  }
@@ -119,7 +236,8 @@ async function runStep(step) {
119
236
  const state = turn;
120
237
  if (state.failure) throw state.failure;
121
238
  const body = decodeBody(init.body);
122
- const compaction = isCompaction(body);
239
+ const request = JSON.parse(body);
240
+ const compaction = request.toolChoice?.type === "none";
123
241
  const recorded = state.plan.calls[state.next];
124
242
  if (recorded !== void 0) {
125
243
  if (recorded.kind === "compaction" !== compaction) fail(state, diverged(`request ${state.next} is not a ${recorded.kind}`));
@@ -145,7 +263,7 @@ async function runStep(step) {
145
263
  state.live = true;
146
264
  return live(state, url, {
147
265
  ...init,
148
- body
266
+ body: withGatewayCaching(body, request)
149
267
  }, compaction);
150
268
  };
151
269
  const affinity = gatewaySessionAffinity({
@@ -158,7 +276,6 @@ async function runStep(step) {
158
276
  headers.set("x-session-affinity", affinity);
159
277
  const response = await fetch(url, {
160
278
  ...init,
161
- body: withGatewayCaching(init.body),
162
279
  headers,
163
280
  signal: network
164
281
  });
@@ -202,42 +319,67 @@ async function runStep(step) {
202
319
  headers: response.headers
203
320
  });
204
321
  };
205
- const hostTools = await kernelTools(step.tools, (toolName, toolInput) => {
206
- const state = turn;
207
- if (state.failure) throw state.failure;
322
+ /** The recorded result of a call from the step the kernel was served. */
323
+ const answer = (state, toolName, toolInput) => {
208
324
  const call = state.served.find((candidate) => candidate.toolName === toolName && !state.answered.has(candidate.toolCallId) && sameJson(candidate.input, toolInput));
209
325
  const result = call === void 0 ? void 0 : results.get(call.toolCallId);
210
- if (call !== void 0 && result !== void 0) {
211
- state.answered.add(call.toolCallId);
212
- if (result.error !== void 0) throw new Error(result.error);
213
- if (result.denied === true) throw new Error("The tool call was denied.");
214
- return result.output ?? null;
215
- }
326
+ if (call === void 0 || result === void 0) return void 0;
327
+ state.answered.add(call.toolCallId);
328
+ if (result.error !== void 0) throw new Error(result.error);
329
+ if (result.denied === true) throw new Error("The tool call was denied.");
330
+ return { output: result.output ?? null };
331
+ };
332
+ const hostTool = (toolName, toolInput) => {
333
+ const state = turn;
334
+ if (state.failure) throw state.failure;
335
+ const answered = answer(state, toolName, toolInput);
336
+ if (answered !== void 0) return answered.output;
216
337
  if (state.live) {
217
338
  state.toolsRequested.resolve();
218
- return pending(void 0);
339
+ return new Promise((resolve, reject) => {
340
+ kernel.waiting.push({
341
+ toolName,
342
+ input: toolInput,
343
+ resolve,
344
+ reject
345
+ });
346
+ });
219
347
  }
220
348
  if (state.plan.end === "interrupted") {
221
349
  state.fxTurn.cancel();
222
350
  return pending(void 0);
223
351
  }
224
352
  return fail(state, diverged(`no recorded result for ${toolName}`));
225
- });
226
- const plans = (turns) => Promise.all(turns.map((recorded) => turnPlan(recorded, step.signal)));
353
+ };
354
+ const hooks = {
355
+ fetch: hostFetch,
356
+ tool: hostTool
357
+ };
358
+ const planTurns = (turns) => Promise.all(turns.map((recorded) => turnPlan(recorded, step.signal)));
227
359
  let results = read.results;
228
360
  let controller;
229
361
  let closed = false;
230
362
  const emit = (chunk) => {
231
363
  if (!closed) controller.enqueue(chunk);
232
364
  };
233
- const create = (checkpoint) => createFxAgent({
234
- apiKey: credential.token,
235
- model: kernelModel(step),
236
- ...step.instructions.length === 0 ? {} : { instructions: step.instructions },
237
- tools: hostTools,
238
- ...checkpoint === void 0 ? {} : { checkpoint },
239
- fetch: hostFetch
240
- });
365
+ const create = async (checkpoint) => {
366
+ const created = {
367
+ hooks,
368
+ waiting: []
369
+ };
370
+ const agent = await createFxAgent({
371
+ apiKey: credential.token,
372
+ model: kernelModel(step),
373
+ ...step.instructions.length === 0 ? {} : { instructions: step.instructions },
374
+ tools: definitions.map((definition) => ({
375
+ ...definition,
376
+ execute: (toolInput) => created.hooks.tool(definition.name, toolInput)
377
+ })),
378
+ ...checkpoint === void 0 ? {} : { checkpoint },
379
+ fetch: (input, init) => created.hooks.fetch(input, init)
380
+ });
381
+ return Object.assign(created, { agent });
382
+ };
241
383
  return {
242
384
  stream: new ReadableStream({
243
385
  start(streamController) {
@@ -249,15 +391,23 @@ async function runStep(step) {
249
391
  step.signal.addEventListener("abort", abort, { once: true });
250
392
  (async () => {
251
393
  try {
252
- try {
253
- agent = await create(read.saved);
394
+ let turns = await planTurns(read.turns);
395
+ const candidate = step.signal.aborted ? void 0 : lot.take(step.sessionId);
396
+ const adopted = candidate !== void 0 && adoptable(candidate, turns) ? candidate : void 0;
397
+ if (candidate !== void 0 && adopted === void 0) closeParked(candidate);
398
+ if (adopted !== void 0) {
399
+ kernel = adopted.kernel;
400
+ kernel.hooks = hooks;
401
+ } else try {
402
+ kernel = await create(read.saved);
254
403
  } catch (error) {
255
404
  if (read.saved === void 0) throw error;
256
405
  read = await replayAll();
257
406
  results = read.results;
258
- agent = await create(void 0);
407
+ kernel = await create(void 0);
408
+ turns = await planTurns(read.turns);
259
409
  }
260
- await run(streamController, await plans(read.turns));
410
+ await run(streamController, turns, adopted);
261
411
  closed = true;
262
412
  streamController.close();
263
413
  } catch (error) {
@@ -266,7 +416,7 @@ async function runStep(step) {
266
416
  } finally {
267
417
  released.abort();
268
418
  step.signal.removeEventListener("abort", abort);
269
- await agent?.close().catch(() => {});
419
+ if (!parked) await kernel?.agent.close().catch(() => {});
270
420
  }
271
421
  })();
272
422
  },
@@ -283,20 +433,19 @@ async function runStep(step) {
283
433
  async function turnPlan(turn, signal) {
284
434
  const calls = [];
285
435
  const steers = /* @__PURE__ */ new Map();
286
- const steer = (at, inputs) => {
287
- if (inputs !== void 0) steers.set(Math.max(0, at), inputs.map(steerText));
288
- };
289
- steer(0, turn.generations.length === 0 ? turn.steers.get(0) : void 0);
290
436
  turn.generations.forEach((generation, index) => {
291
437
  calls.push(...recordedCalls(generation.chunks, generation.completed));
292
- steer(calls.length - 1, turn.steers.get(index));
438
+ const inputs = turn.steers.get(index);
439
+ if (inputs !== void 0) steers.set(calls.length - 1, inputs.map(steerText));
293
440
  });
294
441
  const images = await harnessImages({
295
442
  harness: "fx()",
296
443
  input: turn.prompt,
297
444
  signal
298
445
  });
446
+ const generationId = turn.generations.at(-1)?.completed.generationId;
299
447
  return {
448
+ ...generationId === void 0 ? {} : { generationId },
300
449
  prompt: images.length === 0 ? turn.prompt.text : [...images.map((image) => ({
301
450
  type: "image",
302
451
  data: image.data,
@@ -605,8 +754,8 @@ async function loadLibfx() {
605
754
  * asks for it; options the request already has take precedence. Every other
606
755
  * byte stays as the kernel wrote it, a tool input's spacing included.
607
756
  */
608
- function withGatewayCaching(body) {
609
- const options = JSON.parse(body).providerOptions;
757
+ function withGatewayCaching(body, request) {
758
+ const options = request.providerOptions;
610
759
  if (options === void 0) return body.replace(/^\{/, "{\"providerOptions\":{\"gateway\":{\"caching\":\"auto\"}},");
611
760
  const own = `"providerOptions":${JSON.stringify(options)}}`;
612
761
  if (!body.endsWith(own)) return body;
@@ -622,6 +771,7 @@ function withGatewayCaching(body) {
622
771
  function withAuth(headers, credential) {
623
772
  const result = new Headers(headers);
624
773
  result.set("ai-gateway-auth-method", credential.method);
774
+ if (result.has("authorization")) result.set("authorization", `Bearer ${credential.token}`);
625
775
  return result;
626
776
  }
627
777
  function kernelModel(step) {
@@ -634,12 +784,12 @@ function kernelModel(step) {
634
784
  ...fast ? { fast } : {}
635
785
  };
636
786
  }
637
- async function kernelTools(tools, execute) {
787
+ /** The agent's tools as the kernel takes them, without their execution. */
788
+ async function toolDefinitions(tools) {
638
789
  return Promise.all(Object.entries(tools).map(async ([toolName, tool]) => ({
639
790
  name: toolName,
640
791
  description: typeof tool.description === "string" ? tool.description : toolName,
641
- inputSchema: await asSchema(tool.inputSchema).jsonSchema,
642
- execute: (input) => execute(toolName, input)
792
+ inputSchema: await asSchema(tool.inputSchema).jsonSchema
643
793
  })));
644
794
  }
645
795
  const catalogCache = boundedCache({
@@ -674,9 +824,6 @@ function savedCheckpoint(state) {
674
824
  if (version !== SNAPSHOT_VERSION || typeof checkpoint !== "string") return void 0;
675
825
  return new Uint8Array(Buffer.from(checkpoint, "base64"));
676
826
  }
677
- function isCompaction(body) {
678
- return JSON.parse(body).toolChoice?.type === "none";
679
- }
680
827
  function decodeBody(body) {
681
828
  if (typeof body === "string") return body;
682
829
  if (body instanceof Uint8Array || body instanceof ArrayBuffer) return new TextDecoder().decode(body);