experimental-a2 0.17.0 → 0.18.1

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 (221) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-DBbe5xeE.d.ts → actor-C7b-1arn.d.ts} +5 -5
  4. package/dist/{actor-DBbe5xeE.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
  5. package/dist/actor-client.d.ts +1 -1
  6. package/dist/actor-react.d.ts +3 -3
  7. package/dist/actor-react.js +1 -1
  8. package/dist/actor.d.ts +1 -1
  9. package/dist/actor.js +2 -2
  10. package/dist/{ai-vpGtcaCB.d.ts → ai-BMLlI2Ff.d.ts} +3 -3
  11. package/dist/{ai-vpGtcaCB.d.ts.map → ai-BMLlI2Ff.d.ts.map} +1 -1
  12. package/dist/{ai-UrWfKeuv.js → ai-D6mGlO8j.js} +2 -2
  13. package/dist/{ai-UrWfKeuv.js.map → ai-D6mGlO8j.js.map} +1 -1
  14. package/dist/ai-client.d.ts +2 -2
  15. package/dist/ai-client.js +2 -2
  16. package/dist/ai-fx.browser.d.ts +1 -0
  17. package/dist/ai-fx.browser.js +6 -0
  18. package/dist/ai-fx.browser.js.map +1 -0
  19. package/dist/ai-fx.d.ts +10 -0
  20. package/dist/ai-fx.d.ts.map +1 -0
  21. package/dist/ai-fx.js +692 -0
  22. package/dist/ai-fx.js.map +1 -0
  23. package/dist/ai-harness-B2suP2Qh.d.ts +26 -0
  24. package/dist/ai-harness-B2suP2Qh.d.ts.map +1 -0
  25. package/dist/ai-harness-BuLh_EYi.js +273 -0
  26. package/dist/ai-harness-BuLh_EYi.js.map +1 -0
  27. package/dist/ai-pi.browser.d.ts +1 -0
  28. package/dist/ai-pi.browser.js +6 -0
  29. package/dist/ai-pi.browser.js.map +1 -0
  30. package/dist/ai-pi.d.ts +17 -0
  31. package/dist/ai-pi.d.ts.map +1 -0
  32. package/dist/ai-pi.js +950 -0
  33. package/dist/ai-pi.js.map +1 -0
  34. package/dist/ai-react.d.ts +5 -5
  35. package/dist/ai-react.js +2 -2
  36. package/dist/ai-server.d.ts +47 -25
  37. package/dist/ai-server.d.ts.map +1 -1
  38. package/dist/ai-server.js +113 -40
  39. package/dist/ai-server.js.map +1 -1
  40. package/dist/ai-tool-input-DmSqMUQi.js +40 -0
  41. package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
  42. package/dist/ai.d.ts +1 -1
  43. package/dist/ai.js +1 -1
  44. package/dist/bounded-cache-CPHWF-8h.js +41 -0
  45. package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
  46. package/dist/{client-COaiaDub.js → client-BhHLoNKF.js} +3 -3
  47. package/dist/{client-COaiaDub.js.map → client-BhHLoNKF.js.map} +1 -1
  48. package/dist/{client-qRnRUzBS.d.ts → client-h_DKFAjj.d.ts} +3 -3
  49. package/dist/{client-qRnRUzBS.d.ts.map → client-h_DKFAjj.d.ts.map} +1 -1
  50. package/dist/client.d.ts +3 -3
  51. package/dist/client.js +1 -1
  52. package/dist/index.d.ts +5 -5
  53. package/dist/{initial-snapshot-BrLso5x_.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +2 -2
  54. package/dist/{initial-snapshot-BrLso5x_.d.ts.map → initial-snapshot-Bx-c0pDP.d.ts.map} +1 -1
  55. package/dist/{internal-CbVvEwad.js → internal-CscSY7K_.js} +11 -3
  56. package/dist/internal-CscSY7K_.js.map +1 -0
  57. package/dist/otel.d.ts +1 -1
  58. package/dist/{react-BbJ-g6Uu.d.ts → react-BBXgHWFc.d.ts} +4 -4
  59. package/dist/{react-BbJ-g6Uu.d.ts.map → react-BBXgHWFc.d.ts.map} +1 -1
  60. package/dist/react.d.ts +1 -1
  61. package/dist/react.js +1 -1
  62. package/dist/reducer-BAXc8JyF.js.map +1 -1
  63. package/dist/{reducer-BYu6DT7h.d.ts → reducer-CqA59Q6U.d.ts} +2 -2
  64. package/dist/{reducer-BYu6DT7h.d.ts.map → reducer-CqA59Q6U.d.ts.map} +1 -1
  65. package/dist/scheduler-qstash.d.ts +2 -2
  66. package/dist/scheduler-qstash.js +3 -3
  67. package/dist/scheduler-qstash.js.map +1 -1
  68. package/dist/scheduler-vercel.d.ts +7 -7
  69. package/dist/scheduler-vercel.d.ts.map +1 -1
  70. package/dist/scheduler-vercel.js +9 -10
  71. package/dist/scheduler-vercel.js.map +1 -1
  72. package/dist/{server-Rj64fNvX.js → server-D-Y4pqwu.js} +126 -67
  73. package/dist/server-D-Y4pqwu.js.map +1 -0
  74. package/dist/{server-CGM8WzRG.d.ts → server-DYAATFuT.d.ts} +42 -7
  75. package/dist/server-DYAATFuT.d.ts.map +1 -0
  76. package/dist/server.d.ts +4 -4
  77. package/dist/server.js +1 -1
  78. package/dist/{session-clear-Dshpuhff.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
  79. package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
  80. package/dist/{store-Gpkq7WBo.d.ts → store-CyLUy86v.d.ts} +53 -5
  81. package/dist/store-CyLUy86v.d.ts.map +1 -0
  82. package/dist/store-N8PXxDAS.js.map +1 -1
  83. package/dist/store-memory.d.ts +1 -1
  84. package/dist/store-memory.js +56 -11
  85. package/dist/store-memory.js.map +1 -1
  86. package/dist/{store-polling-4_y8lETm.js → store-polling-7WJV0YWP.js} +2 -2
  87. package/dist/{store-polling-4_y8lETm.js.map → store-polling-7WJV0YWP.js.map} +1 -1
  88. package/dist/store-postgres.d.ts +1 -1
  89. package/dist/store-postgres.d.ts.map +1 -1
  90. package/dist/store-postgres.js +106 -25
  91. package/dist/store-postgres.js.map +1 -1
  92. package/dist/{store-presence-polling-Q1C-k2dd.js → store-presence-polling-B1ixeqIS.js} +3 -3
  93. package/dist/{store-presence-polling-Q1C-k2dd.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
  94. package/dist/store-redis-http.d.ts +1 -1
  95. package/dist/store-redis-http.js +3 -3
  96. package/dist/{store-redis-notify-tqWNnMRu.js → store-redis-notify-CM0AfLY0.js} +271 -101
  97. package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
  98. package/dist/store-redis.d.ts +1 -1
  99. package/dist/store-redis.js +1 -1
  100. package/dist/store-sqlite.d.ts +1 -1
  101. package/dist/store-sqlite.js +66 -21
  102. package/dist/store-sqlite.js.map +1 -1
  103. package/dist/{telemetry-cZH-cibj.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
  104. package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
  105. package/dist/{wire-DjfHOvdW.js → wire-BKxH1vbP.js} +2 -2
  106. package/dist/{wire-DjfHOvdW.js.map → wire-BKxH1vbP.js.map} +1 -1
  107. package/docs/01-quickstart.mdx +49 -83
  108. package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
  109. package/docs/actors/01-introduction.mdx +48 -86
  110. package/docs/actors/02-concurrency.mdx +43 -70
  111. package/docs/actors/03-timers.mdx +28 -42
  112. package/docs/actors/04-routes.mdx +110 -150
  113. package/docs/actors/meta.ts +1 -1
  114. package/docs/agents/01-introduction.mdx +257 -0
  115. package/docs/agents/02-tools.mdx +247 -0
  116. package/docs/agents/03-conversations.mdx +538 -0
  117. package/docs/agents/04-harnesses.mdx +136 -0
  118. package/docs/agents/meta.ts +1 -0
  119. package/docs/client/01-react.mdx +294 -0
  120. package/docs/client/02-transports.mdx +86 -0
  121. package/docs/client/03-presence.mdx +224 -0
  122. package/docs/client/meta.ts +1 -0
  123. package/docs/contract/01-events.mdx +57 -0
  124. package/docs/contract/02-state.mdx +142 -0
  125. package/docs/contract/03-sessions.mdx +175 -0
  126. package/docs/index.mdx +109 -145
  127. package/docs/reference/01-core.mdx +139 -0
  128. package/docs/reference/02-server.mdx +860 -0
  129. package/docs/reference/03-client.mdx +301 -0
  130. package/docs/reference/04-ai.mdx +731 -0
  131. package/docs/reference/05-adapters.mdx +351 -0
  132. package/docs/reference/06-errors.mdx +138 -0
  133. package/docs/reference/meta.ts +1 -1
  134. package/docs/server/01-handlers.mdx +200 -0
  135. package/docs/server/02-timers.mdx +130 -0
  136. package/docs/server/03-cancellation.mdx +142 -0
  137. package/docs/server/04-routes.mdx +243 -0
  138. package/docs/server/05-production.mdx +323 -0
  139. package/docs/server/06-guarantees.mdx +132 -0
  140. package/examples/playground/DEPLOY.md +3 -5
  141. package/examples/playground/app/a0/[appId]/page.tsx +12 -13
  142. package/examples/playground/app/a0/app-list.tsx +9 -2
  143. package/examples/playground/app/a0/app-view.tsx +9 -1
  144. package/examples/playground/app/a0/apps/[appId]/route.ts +10 -5
  145. package/examples/playground/app/a0/apps.test.ts +12 -0
  146. package/examples/playground/app/a0/apps.ts +22 -7
  147. package/examples/playground/app/a0/chat.tsx +47 -1
  148. package/examples/playground/app/a0/devtools.tsx +2 -8
  149. package/examples/playground/app/a0/fx/events/route.ts +9 -0
  150. package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
  151. package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
  152. package/examples/playground/app/a0/model.test.ts +18 -1
  153. package/examples/playground/app/a0/model.ts +47 -10
  154. package/examples/playground/app/a0/no-photon.cjs +4 -0
  155. package/examples/playground/app/a0/no-quickjs.cjs +3 -0
  156. package/examples/playground/app/a0/pi/events/route.ts +9 -0
  157. package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
  158. package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
  159. package/examples/playground/app/a0/sandbox-log.ts +10 -4
  160. package/examples/playground/app/a0/sandbox-session.ts +152 -0
  161. package/examples/playground/app/a0/scheduler/route.ts +2 -2
  162. package/examples/playground/app/a0/server.ts +98 -54
  163. package/examples/playground/app/a0/session.ts +17 -5
  164. package/examples/playground/app/a0/shell.tsx +11 -3
  165. package/examples/playground/app/agent/ingress.test.ts +6 -3
  166. package/examples/playground/app/agent/server.ts +9 -6
  167. package/examples/playground/app/agent/telemetry.test.ts +71 -50
  168. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +1 -1
  169. package/examples/playground/app/chat/server.test.ts +30 -26
  170. package/examples/playground/app/chat/server.ts +46 -46
  171. package/examples/playground/next.config.ts +17 -5
  172. package/examples/playground/package.json +4 -1
  173. package/examples/playground/vercel.json +18 -0
  174. package/package.json +27 -3
  175. package/src/ai-agent.ts +271 -90
  176. package/src/ai-fx.browser.ts +5 -0
  177. package/src/ai-fx.ts +912 -0
  178. package/src/ai-harness.ts +518 -0
  179. package/src/ai-model-metadata.ts +11 -6
  180. package/src/ai-pi.browser.ts +5 -0
  181. package/src/ai-pi.ts +1322 -0
  182. package/src/ai-sdk-step.ts +2 -2
  183. package/src/ai-server.ts +3 -1
  184. package/src/ai-tool-input.ts +45 -0
  185. package/src/internal.ts +13 -0
  186. package/src/libfx.d.ts +34 -0
  187. package/src/reducer.ts +1 -1
  188. package/src/scheduler-qstash.ts +5 -5
  189. package/src/scheduler-vercel.ts +14 -15
  190. package/src/server.ts +233 -29
  191. package/src/store-memory.ts +92 -16
  192. package/src/store-postgres.ts +156 -25
  193. package/src/store-redis-core.ts +322 -110
  194. package/src/store-redis-notify.ts +2 -0
  195. package/src/store-sqlite.ts +121 -28
  196. package/src/store.ts +55 -3
  197. package/src/telemetry.ts +1 -0
  198. package/dist/internal-CbVvEwad.js.map +0 -1
  199. package/dist/server-CGM8WzRG.d.ts.map +0 -1
  200. package/dist/server-Rj64fNvX.js.map +0 -1
  201. package/dist/session-clear-Dshpuhff.d.ts.map +0 -1
  202. package/dist/store-Gpkq7WBo.d.ts.map +0 -1
  203. package/dist/store-redis-notify-tqWNnMRu.js.map +0 -1
  204. package/dist/telemetry-cZH-cibj.d.ts.map +0 -1
  205. package/docs/concepts/01-contracts.mdx +0 -237
  206. package/docs/concepts/02-handlers.mdx +0 -284
  207. package/docs/concepts/03-durability.mdx +0 -314
  208. package/docs/concepts/04-state.mdx +0 -209
  209. package/docs/guides/01-timers.mdx +0 -193
  210. package/docs/guides/02-cancellation.mdx +0 -161
  211. package/docs/guides/03-react.mdx +0 -324
  212. package/docs/guides/04-local-first.mdx +0 -47
  213. package/docs/guides/05-production.mdx +0 -534
  214. package/docs/guides/06-ai-agents.mdx +0 -1408
  215. package/docs/guides/08-application-data.mdx +0 -113
  216. package/docs/guides/09-presence.mdx +0 -262
  217. package/docs/guides/10-transports.mdx +0 -221
  218. package/docs/reference/01-api.mdx +0 -2358
  219. package/docs/reference/02-errors.mdx +0 -150
  220. /package/docs/{concepts → contract}/meta.ts +0 -0
  221. /package/docs/{guides → server}/meta.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-fx.js","names":[],"sources":["../src/ai-fx.ts"],"sourcesContent":["/**\n * experimental-a2/ai/fx — `fx()`: the FX harness for `agent({ harness })`.\n * Server-only; FX's kernel comes from the optional `libfx` peer dependency.\n */\n\n// oxlint-disable no-await-in-loop -- turns replay in order, each on the kernel the last one left.\n\nimport {\n asSchema,\n type FinishReason,\n type LanguageModelUsage,\n type ToolSet,\n type UIMessageChunk,\n} from 'ai'\nimport type { FxAgent, FxHostTool, FxTurn } from 'libfx'\nimport {\n type Deferred,\n defineHarness,\n deferred,\n Divergence,\n gatewayCredential,\n type GatewayCredential,\n type Harness,\n type HarnessGeneration,\n type HarnessRead,\n type HarnessStep,\n type HarnessTurn,\n pending,\n readHarness,\n saveHarness,\n} from './ai-harness.ts'\nimport type { CompactionPartData, GenerationCompletedPayload } from './ai.ts'\nimport { schemaInput } from './ai-tool-input.ts'\nimport { boundedCache } from './bounded-cache.ts'\n\nexport type { Harness } from './ai-harness.ts'\n\n/**\n * The FX harness. Every model call FX makes is one durable step; A2 rebuilds\n * the kernel for each step from its latest checkpoint and the log since.\n */\nexport function fx(): Harness<'fx', never> {\n return defineHarness('fx', {\n tools: {},\n step: runStep,\n })\n}\n\nconst SNAPSHOT_VERSION = 1\nconst CATALOG_TTL_MS = 60 * 60 * 1000\n\ntype StreamPart = { type: string } & Record<string, unknown>\n/** A recorded tool call, with the input the kernel reads from its text. */\ntype ToolCall = { toolCallId: string; toolName: string; input: unknown }\n\n/** A model response A2 recorded, in the Gateway's stream format. */\ntype RecordedCall = {\n kind: 'step' | 'compaction'\n sse: string\n toolCalls: ToolCall[]\n}\n\n/** One FX turn to replay: its prompt, recorded calls, and how it ended. */\ntype TurnPlan = {\n prompt: string\n calls: RecordedCall[]\n /** Steering to queue while serving the call at that index. */\n steers: Map<number, string[]>\n end: 'stop' | 'interrupted' | 'live'\n}\n\ntype Completion = { finishReason?: FinishReason; usage?: LanguageModelUsage }\n\n/** The turn being replayed or run live, as the fetch and tool hooks see it. */\ntype TurnState = {\n plan: TurnPlan\n fxTurn: FxTurn\n next: number\n /** Tool calls of the last served step and the ones already answered. */\n served: ToolCall[]\n answered: Set<string>\n live: boolean\n liveStep: boolean\n failure?: Error\n /** Resolves when the live step is over: FX asked for its tools. */\n toolsRequested: Deferred\n parsed?: Promise<void>\n}\n\nfunction fail(state: TurnState, error: Error): never {\n state.failure ??= error\n state.fxTurn.cancel()\n throw state.failure\n}\n\nconst diverged = (message: string): Divergence => new Divergence('FX', message)\n\n// ---------------------------------------------------------------- step\n\nasync function runStep(step: HarnessStep): Promise<HarnessGeneration> {\n const { createFxAgent } = await loadLibfx()\n const credential = gatewayCredential('fx')\n const name = `${step.agentName}.a2.harness.fx`\n const { replayAll, ...first } = await readHarness({\n step,\n name,\n parse: savedCheckpoint,\n })\n let read: HarnessRead<Uint8Array> = first\n\n let completion: Completion = {}\n let stopped = false\n // Live responses belong to the step: the kernel aborts its fetch once it\n // has read a response's finish, while A2 may still be reading its copy.\n const released = new AbortController()\n const network = AbortSignal.any([step.signal, released.signal])\n let agent: FxAgent | undefined\n let turn: TurnState | undefined\n\n const run = async (\n controller: ReadableStreamDefaultController<UIMessageChunk>,\n turns: TurnPlan[],\n ): Promise<void> => {\n controller.enqueue({ type: 'start', messageId: step.responseMessageId })\n for (const plan of turns) {\n if (stopped) return\n const fxTurn = agent!.prompt(plan.prompt, { signal: step.signal })\n const state: TurnState = {\n plan,\n fxTurn,\n next: 0,\n served: [],\n answered: new Set(),\n live: false,\n liveStep: false,\n toolsRequested: deferred(),\n }\n turn = state\n const drained = (async () => {\n for await (const _ of fxTurn) {\n // Live output reaches A2 from the Gateway response itself.\n }\n })()\n // A failed turn surfaces through its result.\n drained.catch(() => {})\n if (plan.end !== 'live') {\n const result = await fxTurn.result.catch((error: unknown) => {\n throw state.failure ?? error\n })\n await drained\n if (state.failure) throw state.failure\n const expected = plan.end === 'stop' ? 'end_turn' : 'cancelled'\n if (result.stopReason !== expected)\n throw diverged(\n `a recorded turn ended with ${result.stopReason}, not ${expected}`,\n )\n continue\n }\n const outcome = await Promise.race([\n fxTurn.result.then((result) => ({ ended: true, result })),\n state.toolsRequested.promise.then(() => ({ ended: false as const })),\n ]).catch((error: unknown) => {\n throw state.failure ?? error\n })\n if (state.failure) throw state.failure\n await state.parsed\n if (outcome.ended) {\n await drained\n // Only a turn this attempt finished describes the log.\n if (outcome.result.stopReason === 'end_turn' && !step.signal.aborted)\n await saveCheckpoint()\n } else {\n // FX now waits on tools that A2's tool handlers run.\n fxTurn.cancel()\n }\n controller.enqueue({ type: 'finish-step' })\n controller.enqueue({\n type: 'finish',\n ...(completion.finishReason === undefined\n ? {}\n : { finishReason: completion.finishReason }),\n })\n }\n }\n\n const saveCheckpoint = async (): Promise<void> => {\n let checkpoint: Uint8Array\n try {\n checkpoint = await agent!.checkpoint()\n } catch {\n // Over libfx's bound: later steps replay from the previous snapshot.\n return\n }\n await saveHarness({\n step,\n name,\n state: {\n version: SNAPSHOT_VERSION,\n checkpoint: Buffer.from(checkpoint).toString('base64'),\n },\n })\n }\n\n const hostFetch = async (\n input: string | URL | Request,\n init: RequestInit = {},\n ): Promise<Response> => {\n const url = input instanceof Request ? input.url : String(input)\n if ((init.method ?? 'GET').toUpperCase() === 'GET')\n return catalog(url, credential, withAuth(init.headers, credential))\n const state = turn!\n if (state.failure) throw state.failure\n const body = decodeBody(init.body)\n const compaction = isCompaction(body)\n const recorded = state.plan.calls[state.next]\n if (recorded !== undefined) {\n if ((recorded.kind === 'compaction') !== compaction)\n fail(state, diverged(`request ${state.next} is not a ${recorded.kind}`))\n const index = state.next++\n if (recorded.kind === 'step') {\n state.served = recorded.toolCalls\n state.answered = new Set()\n }\n const steers = state.plan.steers.get(index) ?? []\n return relay(recorded.sse, async () => {\n for (const text of steers) await state.fxTurn.steer(text)\n })\n }\n if (state.plan.end === 'stop')\n fail(state, diverged('FX continued a turn the log ended'))\n if (state.plan.end === 'interrupted') {\n state.fxTurn.cancel()\n throw new DOMException('The recorded turn was interrupted', 'AbortError')\n }\n if (state.liveStep && !compaction) {\n // One generation is one step; the next step is A2's next generation.\n state.toolsRequested.resolve()\n return pending(init.signal)\n }\n state.live = true\n return live(state, url, init, compaction)\n }\n\n let compactions = 0\n const live = async (\n state: TurnState,\n url: string,\n init: RequestInit,\n compaction: boolean,\n ): Promise<Response> => {\n const response = await fetch(url, {\n ...init,\n headers: withAuth(init.headers, credential),\n signal: network,\n })\n // Abandoned before its headers came: the kernel has moved on without it.\n if (init.signal?.aborted) {\n void response.body?.cancel()\n throw init.signal.reason\n }\n if (!response.ok || response.body === null) return response\n const [fromNetwork, forLog] = response.body.tee()\n const forKernel = init.signal\n ? fromNetwork.pipeThrough(new TransformStream(), { signal: init.signal })\n : fromNetwork\n // Live responses reach the log in request order: a compaction's part\n // precedes the step that follows it.\n const previous = state.parsed\n if (compaction) {\n // Unique across the response's generations: the transcript keys data parts by ID.\n const id = `fx-compaction:${step.requestIndex}:${compactions++}`\n state.parsed = (async () => {\n const all = await readParts(forLog)\n await previous\n emit({\n type: 'data-a2-compaction',\n id,\n data: compactionData(all),\n })\n })()\n } else {\n state.liveStep = true\n state.parsed = (async () => {\n await previous\n emit({ type: 'start-step' })\n await streamStep({\n body: forLog,\n tools: step.tools,\n emit,\n finished: (finished) => {\n completion = finished\n },\n })\n })()\n }\n // A stopped step abandons its parse; its failure surfaces through the turn.\n state.parsed.catch(() => {})\n return new Response(forKernel, {\n status: response.status,\n headers: response.headers,\n })\n }\n\n const hostTools = await kernelTools(step.tools, (toolName, toolInput) => {\n const state = turn!\n if (state.failure) throw state.failure\n const call = state.served.find(\n (candidate) =>\n candidate.toolName === toolName &&\n !state.answered.has(candidate.toolCallId) &&\n sameJson(candidate.input, toolInput),\n )\n const result = call === undefined ? undefined : results.get(call.toolCallId)\n if (call !== undefined && result !== undefined) {\n state.answered.add(call.toolCallId)\n if (result.error !== undefined) throw new Error(result.error)\n if (result.denied === true) throw new Error('The tool call was denied.')\n return result.output ?? null\n }\n if (state.live) {\n state.toolsRequested.resolve()\n return pending(undefined)\n }\n if (state.plan.end === 'interrupted') {\n state.fxTurn.cancel()\n return pending(undefined)\n }\n return fail(state, diverged(`no recorded result for ${toolName}`))\n })\n\n let turns = read.turns.map(turnPlan)\n let results = read.results\n let controller: ReadableStreamDefaultController<UIMessageChunk> | undefined\n let closed = false\n const emit = (chunk: UIMessageChunk): void => {\n if (!closed) controller!.enqueue(chunk)\n }\n\n const create = (checkpoint: Uint8Array | undefined) =>\n createFxAgent({\n apiKey: credential.token,\n model: kernelModel(step),\n ...(step.instructions.length === 0\n ? {}\n : { instructions: step.instructions }),\n tools: hostTools,\n ...(checkpoint === undefined ? {} : { checkpoint }),\n fetch: hostFetch,\n })\n\n const stream = new ReadableStream<UIMessageChunk>({\n start(streamController) {\n controller = streamController\n const abort = () => {\n stopped = true\n turn?.fxTurn.cancel()\n }\n step.signal.addEventListener('abort', abort, { once: true })\n void (async () => {\n try {\n try {\n agent = await create(read.saved)\n } catch (error) {\n if (read.saved === undefined) throw error\n // An unusable checkpoint: replay the whole log instead.\n read = await replayAll()\n turns = read.turns.map(turnPlan)\n results = read.results\n agent = await create(undefined)\n }\n await run(streamController, turns)\n closed = true\n streamController.close()\n } catch (error) {\n closed = true\n streamController.error(\n step.signal.aborted ? step.signal.reason : error,\n )\n } finally {\n released.abort()\n step.signal.removeEventListener('abort', abort)\n await agent?.close().catch(() => {})\n }\n })()\n },\n cancel() {\n closed = true\n stopped = true\n released.abort()\n turn?.fxTurn.cancel()\n },\n })\n\n return { stream, completion: () => completion }\n}\n\n// ------------------------------------------------------------ the plan\n\nfunction turnPlan(turn: HarnessTurn): TurnPlan {\n const calls: RecordedCall[] = []\n const steers = new Map<number, string[]>()\n const steer = (at: number, texts: string[] | undefined) => {\n if (texts !== undefined) steers.set(Math.max(0, at), texts)\n }\n steer(0, turn.generations.length === 0 ? turn.steers.get(0) : undefined)\n turn.generations.forEach((generation, index) => {\n calls.push(...recordedCalls(generation.chunks, generation.completed))\n // A generation's step is its last call.\n steer(calls.length - 1, turn.steers.get(index))\n })\n return { prompt: turn.prompt, calls, steers, end: turn.end }\n}\n\n/** A completed generation's model calls: its compactions, then its step. */\nfunction recordedCalls(\n chunks: readonly UIMessageChunk[],\n completed: GenerationCompletedPayload,\n): RecordedCall[] {\n const calls: RecordedCall[] = []\n const parts: StreamPart[] = []\n const toolCalls: ToolCall[] = []\n // A streamed call's input is the provider's exact text; the kernel copies it.\n const inputText = new Map<string, string>()\n for (const chunk of chunks) {\n const metadata =\n 'providerMetadata' in chunk && chunk.providerMetadata !== undefined\n ? { providerMetadata: chunk.providerMetadata }\n : {}\n switch (chunk.type) {\n case 'data-a2-compaction':\n calls.push({\n kind: 'compaction',\n sse: compactionSse(chunk.data as CompactionPartData),\n toolCalls: [],\n })\n break\n case 'text-start':\n case 'text-end':\n case 'reasoning-start':\n case 'reasoning-end':\n parts.push({ type: chunk.type, id: chunk.id, ...metadata })\n break\n case 'text-delta':\n case 'reasoning-delta':\n parts.push({\n type: chunk.type,\n id: chunk.id,\n delta: chunk.delta,\n ...metadata,\n })\n break\n case 'tool-input-start':\n inputText.set(chunk.toolCallId, '')\n parts.push({\n type: 'tool-input-start',\n id: chunk.toolCallId,\n toolName: chunk.toolName,\n ...metadata,\n })\n break\n case 'tool-input-delta':\n inputText.set(\n chunk.toolCallId,\n (inputText.get(chunk.toolCallId) ?? '') + chunk.inputTextDelta,\n )\n parts.push({\n type: 'tool-input-delta',\n id: chunk.toolCallId,\n delta: chunk.inputTextDelta,\n })\n break\n case 'tool-input-error':\n case 'tool-input-available': {\n // A call recorded without its text: input that failed to parse is\n // that text.\n const text =\n inputText.get(chunk.toolCallId) ||\n (chunk.type === 'tool-input-error' && typeof chunk.input === 'string'\n ? chunk.input\n : JSON.stringify(chunk.input))\n if (inputText.has(chunk.toolCallId))\n parts.push({ type: 'tool-input-end', id: chunk.toolCallId })\n // The kernel calls back with this text's JSON, not the input the\n // tool's schema made of it. A call it answers itself, such as one\n // whose text is not JSON, is never asked for.\n const input = parseJson(text)\n if (input !== undefined)\n toolCalls.push({\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n input,\n })\n parts.push({\n type: 'tool-call',\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n input: text,\n ...metadata,\n })\n break\n }\n }\n }\n parts.push({\n type: 'finish',\n finishReason: { unified: completed.finishReason ?? 'other' },\n usage: streamUsage(completed.usage),\n })\n calls.push({ kind: 'step', sse: sse(parts), toolCalls })\n return calls\n}\n\nfunction compactionSse(data: CompactionPartData): string {\n return sse([\n { type: 'text-start', id: '0' },\n { type: 'text-delta', id: '0', delta: data.summary ?? '' },\n { type: 'text-end', id: '0' },\n {\n type: 'finish',\n finishReason: { unified: 'stop' },\n usage: streamUsage(data.usage),\n },\n ])\n}\n\n// ------------------------------------------------------- live responses\n\n/** Streams one live step response as UI chunks and reports its finish. */\nasync function streamStep({\n body,\n tools,\n emit,\n finished,\n}: {\n body: ReadableStream<Uint8Array>\n tools: ToolSet\n emit: (chunk: UIMessageChunk) => void\n finished: (completion: Completion) => void\n}): Promise<void> {\n // The tool calls whose input started streaming, and whether text arrived.\n const streamed = new Map<string, boolean>()\n for await (const part of sseParts(body)) {\n const metadata =\n part['providerMetadata'] === undefined\n ? {}\n : { providerMetadata: part['providerMetadata'] as never }\n switch (part.type) {\n case 'text-start':\n case 'text-end':\n case 'reasoning-start':\n case 'reasoning-end':\n emit({ type: part.type, id: part['id'] as string, ...metadata })\n break\n case 'text-delta':\n case 'reasoning-delta':\n emit({\n type: part.type,\n id: part['id'] as string,\n delta: part['delta'] as string,\n ...metadata,\n })\n break\n case 'tool-input-start':\n streamed.set(part['id'] as string, false)\n emit({\n type: 'tool-input-start',\n toolCallId: part['id'] as string,\n toolName: part['toolName'] as string,\n ...metadata,\n })\n break\n case 'tool-input-delta':\n if (part['delta'] !== '') streamed.set(part['id'] as string, true)\n emit({\n type: 'tool-input-delta',\n toolCallId: part['id'] as string,\n inputTextDelta: part['delta'] as string,\n })\n break\n case 'tool-call': {\n const toolCallId = part['toolCallId'] as string\n const toolName = part['toolName'] as string\n const text = part['input'] as string\n // Replay hands the kernel the text the log holds, so the log keeps\n // the provider's text when it streamed none.\n if (streamed.get(toolCallId) !== true && text !== '') {\n if (!streamed.has(toolCallId))\n emit({ type: 'tool-input-start', toolCallId, toolName })\n emit({ type: 'tool-input-delta', toolCallId, inputTextDelta: text })\n }\n const input = await parseToolInput({\n tools,\n toolName,\n text,\n })\n emit(\n input.success\n ? {\n type: 'tool-input-available',\n toolCallId,\n toolName,\n input: input.value,\n ...metadata,\n }\n : {\n type: 'tool-input-error',\n toolCallId,\n toolName,\n input: input.input,\n errorText: input.errorText,\n ...metadata,\n },\n )\n break\n }\n case 'finish': {\n const reason = part['finishReason'] as { unified?: FinishReason }\n finished({\n ...(reason?.unified === undefined\n ? {}\n : { finishReason: reason.unified }),\n usage: modelUsage(part['usage']),\n })\n break\n }\n case 'error':\n emit({ type: 'error', errorText: errorText(part['error']) })\n break\n }\n }\n}\n\ntype ToolInput =\n | { success: true; value: unknown }\n | { success: false; input: unknown; errorText: string }\n\n/**\n * A live call's input as the AI SDK step reads it: JSON, then the tool's\n * schema with its defaults. Input that fails either is an input error, which\n * A2 answers without running the tool.\n */\nasync function parseToolInput({\n tools,\n toolName,\n text,\n}: {\n tools: ToolSet\n toolName: string\n text: string\n}): Promise<ToolInput> {\n let value: unknown\n try {\n value = JSON.parse(text)\n } catch (error) {\n return { success: false, input: text, errorText: errorText(error) }\n }\n const input = await schemaInput({ tools, toolName, value })\n return input.success ? input : { ...input, input: value }\n}\n\nasync function readParts(\n body: ReadableStream<Uint8Array>,\n): Promise<StreamPart[]> {\n const all: StreamPart[] = []\n for await (const part of sseParts(body)) all.push(part)\n return all\n}\n\nfunction compactionData(all: readonly StreamPart[]): CompactionPartData {\n const finish = all.find((part) => part.type === 'finish')\n return {\n status: 'completed',\n summary: all\n .filter((part) => part.type === 'text-delta')\n .map((part) => part['delta'] as string)\n .join(''),\n ...(finish === undefined ? {} : { usage: modelUsage(finish['usage']) }),\n }\n}\n\nasync function* sseParts(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamPart> {\n const decoder = new TextDecoder()\n let pendingText = ''\n for await (const chunk of body) {\n pendingText += decoder.decode(chunk, { stream: true })\n let end: number\n while ((end = pendingText.indexOf('\\n\\n')) !== -1) {\n const frame = pendingText.slice(0, end)\n pendingText = pendingText.slice(end + 2)\n if (frame.startsWith('data: {')) yield JSON.parse(frame.slice(6))\n }\n }\n}\n\n/**\n * Hands a recorded response to the kernel frame by frame. Steering due after\n * it is queued before its finish part, while the kernel still waits on it.\n */\nfunction relay(text: string, beforeFinish: () => Promise<void>): Response {\n const encoder = new TextEncoder()\n const frames = text.split(/(?<=\\n\\n)/)\n let index = 0\n let steered = false\n return new Response(\n new ReadableStream({\n async pull(controller) {\n const frame = frames[index++]\n if (frame === undefined) {\n controller.close()\n return\n }\n if (!steered && frame.includes('\"type\":\"finish\"')) {\n steered = true\n await beforeFinish()\n }\n controller.enqueue(encoder.encode(frame))\n },\n }),\n { headers: { 'content-type': 'text/event-stream' } },\n )\n}\n\n// ----------------------------------------------------------- the kernel\n\nasync function loadLibfx(): Promise<typeof import('libfx')> {\n try {\n return await import('libfx')\n } catch (error) {\n throw new Error('fx() needs the libfx package: install libfx', {\n cause: error,\n })\n }\n}\n\nfunction withAuth(\n headers: HeadersInit | undefined,\n credential: GatewayCredential,\n): Headers {\n const result = new Headers(headers)\n result.set('ai-gateway-auth-method', credential.method)\n return result\n}\n\nfunction kernelModel(\n step: HarnessStep,\n): string | { id: string; effort?: string; fast?: boolean } {\n const effort =\n step.reasoning === undefined || step.reasoning === 'provider-default'\n ? undefined\n : step.reasoning\n const fast = step.speed === 'fast'\n if (effort === undefined && !fast) return step.model\n return {\n id: step.model,\n ...(effort === undefined ? {} : { effort }),\n ...(fast ? { fast } : {}),\n }\n}\n\nasync function kernelTools(\n tools: ToolSet,\n execute: (toolName: string, input: unknown) => unknown,\n): Promise<FxHostTool[]> {\n return Promise.all(\n Object.entries(tools)\n .filter(([, tool]) => tool.type !== 'provider')\n .map(async ([toolName, tool]) => ({\n name: toolName,\n description:\n typeof tool.description === 'string' ? tool.description : toolName,\n inputSchema: (await asSchema(tool.inputSchema).jsonSchema) as object,\n execute: (input: unknown) => execute(toolName, input),\n })),\n )\n}\n\n// Keyed by credential, and Vercel's OIDC tokens rotate, so it is bounded.\nconst catalogCache = boundedCache<\n string,\n { expires: number; body: Promise<string> }\n>({ maxEntries: 16, maxBytes: 16 })\n\n/**\n * Model catalog reads, shared for an hour by every step in the process that\n * uses the same credential; credentials can see different catalogs.\n */\nasync function catalog(\n url: string,\n credential: GatewayCredential,\n headers: Headers,\n): Promise<Response> {\n const key = `${url}\\n${credential.token}`\n const now = Date.now()\n let entry = catalogCache.get(key)\n if (entry === undefined || entry.expires <= now) {\n const body = fetch(url, { headers }).then(async (response) => {\n if (!response.ok)\n throw new Error(`catalog request failed: ${response.status}`)\n return response.text()\n })\n entry = { expires: now + CATALOG_TTL_MS, body }\n catalogCache.set(key, entry, 1)\n body.catch(() => catalogCache.delete(key))\n }\n return new Response(await entry.body, {\n headers: { 'content-type': 'application/json' },\n })\n}\n\n// ------------------------------------------------------------- helpers\n\nfunction savedCheckpoint(state: unknown): Uint8Array | undefined {\n if (typeof state !== 'object' || state === null) return undefined\n const { version, checkpoint } = state as Record<string, unknown>\n if (version !== SNAPSHOT_VERSION || typeof checkpoint !== 'string')\n return undefined\n return new Uint8Array(Buffer.from(checkpoint, 'base64'))\n}\n\nfunction isCompaction(body: string): boolean {\n const request = JSON.parse(body) as { toolChoice?: { type?: string } }\n return request.toolChoice?.type === 'none'\n}\n\nfunction decodeBody(body: BodyInit | null | undefined): string {\n if (typeof body === 'string') return body\n if (body instanceof Uint8Array || body instanceof ArrayBuffer)\n return new TextDecoder().decode(body)\n throw new TypeError('FX sent an unexpected request body')\n}\n\nfunction parseJson(text: string): unknown {\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n\nfunction sameJson(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b)\n}\n\nfunction sse(all: readonly object[]): string {\n return (\n all.map((part) => `data: ${JSON.stringify(part)}\\n\\n`).join('') +\n 'data: [DONE]\\n\\n'\n )\n}\n\nfunction errorText(error: unknown): string {\n if (typeof error === 'string') return error\n if (error instanceof Error) return error.message\n return JSON.stringify(error)\n}\n\ntype StreamUsage = {\n inputTokens?: {\n total?: number | undefined\n noCache?: number | undefined\n cacheRead?: number | undefined\n cacheWrite?: number | undefined\n }\n outputTokens?: {\n total?: number | undefined\n text?: number | undefined\n reasoning?: number | undefined\n }\n}\n\n/** A Gateway stream usage, as AI SDK normalizes it. */\nfunction modelUsage(value: unknown): LanguageModelUsage {\n const usage = (value ?? {}) as StreamUsage\n const input = usage.inputTokens ?? {}\n const output = usage.outputTokens ?? {}\n return {\n inputTokens: input.total,\n inputTokenDetails: {\n noCacheTokens: input.noCache,\n cacheReadTokens: input.cacheRead,\n cacheWriteTokens: input.cacheWrite,\n },\n outputTokens: output.total,\n outputTokenDetails: {\n textTokens: output.text,\n reasoningTokens: output.reasoning,\n },\n totalTokens:\n input.total === undefined && output.total === undefined\n ? undefined\n : (input.total ?? 0) + (output.total ?? 0),\n }\n}\n\n/** The inverse of `modelUsage`, for replay. */\nfunction streamUsage(usage: LanguageModelUsage | undefined): StreamUsage {\n return {\n inputTokens: {\n total: usage?.inputTokens,\n noCache: usage?.inputTokenDetails?.noCacheTokens,\n cacheRead: usage?.inputTokenDetails?.cacheReadTokens,\n cacheWrite: usage?.inputTokenDetails?.cacheWriteTokens,\n },\n outputTokens: {\n total: usage?.outputTokens,\n text: usage?.outputTokenDetails?.textTokens,\n reasoning: usage?.outputTokenDetails?.reasoningTokens,\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import "./ai-BMLlI2Ff.js";
2
+ import { Experimental_SandboxSession, ToolSet, UIMessage, UIMessageChunk } from "ai";
3
+ //#region src/ai-harness.d.ts
4
+ declare const harnessBrand: unique symbol;
5
+ /**
6
+ * A coding agent's own loop for `agent({ harness })`, from `fx()` or `pi()`.
7
+ * `Tools` names the tools the harness brings, which `toolRecovery` may name.
8
+ */
9
+ type Harness<Type extends "fx" | "pi" = "fx" | "pi", Tools extends string = string> = {
10
+ readonly type: Type;
11
+ readonly [harnessBrand]: {
12
+ readonly tools: Tools;
13
+ };
14
+ };
15
+ /** What a harness's sandbox resolver receives for one step or tool execution. */
16
+ type HarnessSandboxContext = {
17
+ session: {
18
+ readonly id: string;
19
+ };
20
+ signal: AbortSignal;
21
+ };
22
+ /** Resolves the AI SDK sandbox session for an agent session, the same one every time. */
23
+ type HarnessSandbox = (context: HarnessSandboxContext) => Experimental_SandboxSession | Promise<Experimental_SandboxSession>;
24
+ //#endregion
25
+ export { HarnessSandbox as n, HarnessSandboxContext as r, Harness as t };
26
+ //# sourceMappingURL=ai-harness-B2suP2Qh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-harness-B2suP2Qh.d.ts","names":[],"sources":["../src/ai-harness.ts"],"mappings":";;;cAgBc;;;;;KAMF,QACV,wCACA;WAES,MAAM;YACL;aAA0B,OAAO;;;;KAIjC;EACV;aAAoB;;EACpB,QAAQ;;;KAIE,kBACV,SAAS,0BACN,8BAA8B,QAAQ"}
@@ -0,0 +1,273 @@
1
+ import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
2
+ //#region src/ai-harness.ts
3
+ const DRIVER = Symbol.for("experimental-a2.ai.harness");
4
+ function defineHarness(type, driver) {
5
+ const harness = { type };
6
+ Object.defineProperty(harness, DRIVER, { value: driver });
7
+ return Object.freeze(harness);
8
+ }
9
+ function harnessDriver(harness) {
10
+ const driver = typeof harness === "object" && harness !== null ? harness[DRIVER] : void 0;
11
+ if (driver === void 0) throw new TypeError("harness must be { type: 'ai-sdk' }, or come from fx() or pi()");
12
+ return driver;
13
+ }
14
+ const harnessStates = () => boundedCache({
15
+ maxEntries: 1e3,
16
+ maxBytes: 67108864
17
+ });
18
+ const savedKey = (sessionId, name) => `${sessionId}\u0000${name}`;
19
+ const sizeOf = (value) => {
20
+ let binary = 0;
21
+ const text = JSON.stringify(value, (_key, item) => {
22
+ if (!(item instanceof Uint8Array)) return item;
23
+ binary += item.byteLength;
24
+ return null;
25
+ });
26
+ return binary + (text?.length ?? 0);
27
+ };
28
+ /**
29
+ * The session log as a harness step reads it: the state this process saved
30
+ * at the end of the last response, when it has one, and the log after it.
31
+ * Saved states are copied in and out, so a step cannot change one in place.
32
+ */
33
+ function harnessLog(options) {
34
+ const { states, session } = options;
35
+ return {
36
+ read: async ({ name, throughIndex, fresh }) => {
37
+ const entry = fresh ? void 0 : states.get(savedKey(session.id, name));
38
+ const snapshot = entry === void 0 || entry.index > throughIndex ? null : {
39
+ index: entry.index,
40
+ state: structuredClone(entry.state)
41
+ };
42
+ return {
43
+ snapshot,
44
+ events: await session.history(snapshot === null ? { lte: throughIndex } : {
45
+ gte: snapshot.index + 1,
46
+ lte: throughIndex
47
+ })
48
+ };
49
+ },
50
+ write: async ({ name, index, state }) => {
51
+ const copy = structuredClone(state);
52
+ states.set(savedKey(session.id, name), {
53
+ index,
54
+ state: copy
55
+ }, sizeOf(copy));
56
+ }
57
+ };
58
+ }
59
+ const agentStates = /* @__PURE__ */ new WeakMap();
60
+ /** Registers an agent server's saved harness states, for `savedHarnessState`. */
61
+ function registerHarnessStates(server, states) {
62
+ agentStates.set(server, states);
63
+ }
64
+ /**
65
+ * Reads a harness's saved state and the log since, as turns to replay. A
66
+ * snapshot counts only when the attempt that wrote it committed: a stopped,
67
+ * superseded, or still-running attempt can write one the log never kept.
68
+ * `replayAll` reads the whole log instead, for a state that fails to restore.
69
+ */
70
+ async function readHarness({ step, name, parse }) {
71
+ const replayAll = async () => {
72
+ return {
73
+ saved: void 0,
74
+ ...harnessTurns(step, (await step.log.read({
75
+ name,
76
+ throughIndex: step.throughIndex,
77
+ fresh: true
78
+ })).events, void 0)
79
+ };
80
+ };
81
+ const read = await step.log.read({
82
+ name,
83
+ throughIndex: step.throughIndex
84
+ });
85
+ if (read.snapshot === null) return {
86
+ saved: void 0,
87
+ ...harnessTurns(step, read.events, void 0),
88
+ replayAll
89
+ };
90
+ const envelope = savedEnvelope(read.snapshot.state);
91
+ const saved = envelope === void 0 ? void 0 : parse(envelope.state);
92
+ const committed = envelope !== void 0 && read.events.some((event) => event.type === "ai.generation.completed" && event.payload.generationId === envelope.generationId);
93
+ if (saved === void 0 || !committed || envelope.responseMessageId === step.responseMessageId) return {
94
+ ...await replayAll(),
95
+ replayAll
96
+ };
97
+ return {
98
+ saved,
99
+ ...harnessTurns(step, read.events, envelope.responseMessageId),
100
+ replayAll
101
+ };
102
+ }
103
+ /** Saves a harness's state at the end of a response; losing it costs a longer replay. */
104
+ async function saveHarness({ step, name, state }) {
105
+ const envelope = {
106
+ generationId: step.generationId,
107
+ responseMessageId: step.responseMessageId,
108
+ state
109
+ };
110
+ try {
111
+ await step.log.write({
112
+ name,
113
+ index: step.requestIndex,
114
+ state: envelope
115
+ });
116
+ } catch {}
117
+ }
118
+ function savedEnvelope(value) {
119
+ if (typeof value !== "object" || value === null) return void 0;
120
+ const { generationId, responseMessageId, state } = value;
121
+ return typeof generationId === "string" && typeof responseMessageId === "string" ? {
122
+ generationId,
123
+ responseMessageId,
124
+ state
125
+ } : void 0;
126
+ }
127
+ const STEERED = "steered after step";
128
+ /**
129
+ * Groups the log since a harness snapshot into harness turns. A response
130
+ * steered after a step continues its turn, with the next response's prompt as
131
+ * steering. `covered` is the response the snapshot already holds.
132
+ */
133
+ function harnessTurns(step, events, covered) {
134
+ const userText = new Map(step.messages.filter((message) => message.role === "user").map((message) => [message.id, textOf(message)]));
135
+ let passive = [];
136
+ const responses = /* @__PURE__ */ new Map();
137
+ const byStart = /* @__PURE__ */ new Map();
138
+ const byId = /* @__PURE__ */ new Map();
139
+ const results = /* @__PURE__ */ new Map();
140
+ for (const event of events) {
141
+ const payload = event.payload;
142
+ switch (event.type) {
143
+ case "ai.message.created": {
144
+ const message = payload["message"];
145
+ if (message.role !== "user") break;
146
+ userText.set(message.id, textOf(message));
147
+ if (payload["generate"] === false) passive.push(message.id);
148
+ break;
149
+ }
150
+ case "ai.generation.requested": {
151
+ const id = payload["responseMessageId"];
152
+ if (id === covered || responses.has(id)) break;
153
+ const messageId = payload["messageId"];
154
+ const ids = [...passive.filter((p) => p !== messageId), messageId];
155
+ passive = [];
156
+ responses.set(id, {
157
+ id,
158
+ prompt: ids.flatMap((p) => userText.get(p) ?? []),
159
+ generations: []
160
+ });
161
+ break;
162
+ }
163
+ case "ai.generation.started": {
164
+ const response = responses.get(payload["responseMessageId"]);
165
+ if (response === void 0) break;
166
+ const generation = {
167
+ id: payload["generationId"],
168
+ chunks: []
169
+ };
170
+ response.generations.push(generation);
171
+ byStart.set(event.index, generation);
172
+ byId.set(generation.id, generation);
173
+ break;
174
+ }
175
+ case "ai.generation.progress":
176
+ byStart.get(payload["startIndex"])?.chunks.push(...payload["chunks"]);
177
+ break;
178
+ case "ai.generation.completed": {
179
+ const generation = byId.get(payload["generationId"]);
180
+ if (generation) generation.completed = event.payload;
181
+ break;
182
+ }
183
+ case "ai.tool.result":
184
+ if (payload["preliminary"] !== true) results.set(payload["toolCallId"], event.payload);
185
+ break;
186
+ case "ai.message.completed": {
187
+ const response = responses.get(payload["messageId"]);
188
+ if (response) response.end = "stop";
189
+ break;
190
+ }
191
+ case "ai.message.interrupted": {
192
+ const response = responses.get(payload["messageId"]);
193
+ if (response) response.end = payload["reason"] === STEERED ? "steered" : "interrupted";
194
+ break;
195
+ }
196
+ }
197
+ }
198
+ const turns = [];
199
+ let steered = false;
200
+ for (const response of responses.values()) {
201
+ const text = response.prompt.join("\n\n");
202
+ let turn = turns.at(-1);
203
+ if (steered && turn !== void 0) {
204
+ const at = Math.max(0, turn.generations.length - 1);
205
+ turn.steers.set(at, [...turn.steers.get(at) ?? [], text]);
206
+ } else {
207
+ turn = {
208
+ prompt: text,
209
+ generations: [],
210
+ steers: /* @__PURE__ */ new Map(),
211
+ end: "live"
212
+ };
213
+ turns.push(turn);
214
+ }
215
+ for (const generation of response.generations) if (generation.completed !== void 0) turn.generations.push({
216
+ chunks: generation.chunks,
217
+ completed: generation.completed
218
+ });
219
+ turn.end = response.id === step.responseMessageId ? "live" : response.end === "stop" ? "stop" : "interrupted";
220
+ steered = response.end === "steered";
221
+ }
222
+ return {
223
+ turns,
224
+ results
225
+ };
226
+ }
227
+ function textOf(message) {
228
+ return message.parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n");
229
+ }
230
+ /** Read per step: on Vercel the OIDC token rides on each function request. */
231
+ function gatewayCredential(harness) {
232
+ const key = process.env["AI_GATEWAY_API_KEY"];
233
+ if (key) return {
234
+ token: key,
235
+ method: "api-key"
236
+ };
237
+ const oidc = requestOidcToken() ?? process.env["VERCEL_OIDC_TOKEN"];
238
+ if (oidc) return {
239
+ token: oidc,
240
+ method: "oidc"
241
+ };
242
+ throw new Error(`${harness}() needs AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN`);
243
+ }
244
+ const REQUEST_CONTEXT = Symbol.for("@vercel/request-context");
245
+ function requestOidcToken() {
246
+ const token = globalThis[REQUEST_CONTEXT]?.get?.()?.headers?.["x-vercel-oidc-token"];
247
+ return typeof token === "string" && token !== "" ? token : void 0;
248
+ }
249
+ var Divergence = class extends Error {
250
+ constructor(harness, message) {
251
+ super(`${harness} replay diverged from the log: ${message}`);
252
+ }
253
+ };
254
+ function deferred() {
255
+ let resolve;
256
+ return {
257
+ promise: new Promise((done) => {
258
+ resolve = done;
259
+ }),
260
+ resolve
261
+ };
262
+ }
263
+ /** A result that never settles; the harness is stopped instead. */
264
+ function pending(signal) {
265
+ return new Promise((_, reject) => {
266
+ if (signal?.aborted) reject(signal.reason);
267
+ signal?.addEventListener("abort", () => reject(signal.reason), { once: true });
268
+ });
269
+ }
270
+ //#endregion
271
+ export { harnessDriver as a, pending as c, saveHarness as d, gatewayCredential as i, readHarness as l, deferred as n, harnessLog as o, defineHarness as r, harnessStates as s, Divergence as t, registerHarnessStates as u };
272
+
273
+ //# sourceMappingURL=ai-harness-BuLh_EYi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-harness-BuLh_EYi.js","names":[],"sources":["../src/ai-harness.ts"],"sourcesContent":["import type {\n Experimental_SandboxSession,\n FinishReason,\n LanguageModelUsage,\n ToolSet,\n UIMessage,\n UIMessageChunk,\n} from 'ai'\nimport type {\n GenerationCompletedPayload,\n ReasoningLevel,\n ToolResultPayload,\n} from './ai.ts'\nimport { boundedCache, type BoundedCache } from './bounded-cache.ts'\nimport type { ContractEvent, EventDefs } from './contract.ts'\n\ndeclare const harnessBrand: unique symbol\n\n/**\n * A coding agent's own loop for `agent({ harness })`, from `fx()` or `pi()`.\n * `Tools` names the tools the harness brings, which `toolRecovery` may name.\n */\nexport type Harness<\n Type extends 'fx' | 'pi' = 'fx' | 'pi',\n Tools extends string = string,\n> = {\n readonly type: Type\n readonly [harnessBrand]: { readonly tools: Tools }\n}\n\n/** What a harness's sandbox resolver receives for one step or tool execution. */\nexport type HarnessSandboxContext = {\n session: { readonly id: string }\n signal: AbortSignal\n}\n\n/** Resolves the AI SDK sandbox session for an agent session, the same one every time. */\nexport type HarnessSandbox = (\n context: HarnessSandboxContext,\n) => Experimental_SandboxSession | Promise<Experimental_SandboxSession>\n\n/** What a harness step streams, as the default generator does. */\nexport type HarnessGeneration = {\n stream: ReadableStream<UIMessageChunk>\n completion: () => { finishReason?: FinishReason; usage?: LanguageModelUsage }\n}\n\n/** One stored snapshot and the log after it, read in one store operation. */\nexport type HarnessLogRead = {\n snapshot: { index: number; state: unknown } | null\n events: ContractEvent<EventDefs>[]\n}\n\n/** The session log as a harness step reads it, plus the state saved in it. */\nexport type HarnessLog = {\n /** The latest saved state under `name` and the log after it; `fresh` reads it all. */\n read(options: {\n name: string\n throughIndex: number\n fresh?: boolean\n }): Promise<HarnessLogRead>\n write(options: { name: string; index: number; state: unknown }): Promise<void>\n}\n\n/** Everything one durable generation hands its harness. */\nexport type HarnessStep = {\n agentName: string\n sessionId: string\n requestIndex: number\n /** This attempt at the generation. */\n generationId: string\n responseMessageId: string\n /** The log index this step's context was read through. */\n throughIndex: number\n /** The transcript through that index. */\n messages: readonly UIMessage[]\n model: string\n reasoning?: ReasoningLevel\n speed?: 'fast' | 'standard'\n instructions: string[]\n tools: ToolSet\n log: HarnessLog\n signal: AbortSignal\n}\n\n/** The internal side of a harness value. */\nexport type HarnessDriver = {\n /** The session's sandbox; every local tool execution receives it. */\n readonly sandbox?: HarnessSandbox\n /** Tools the harness brings; A2 executes them like the agent's own. */\n readonly tools: ToolSet\n step(step: HarnessStep): Promise<HarnessGeneration>\n}\n\n// A global symbol, so harness values work across separately bundled copies.\nconst DRIVER = Symbol.for('experimental-a2.ai.harness')\n\nexport function defineHarness<\n Type extends 'fx' | 'pi',\n Tools extends string = never,\n>(type: Type, driver: HarnessDriver): Harness<Type, Tools> {\n const harness = { type }\n Object.defineProperty(harness, DRIVER, { value: driver })\n return Object.freeze(harness) as unknown as Harness<Type, Tools>\n}\n\nexport function harnessDriver(harness: unknown): HarnessDriver {\n const driver =\n typeof harness === 'object' && harness !== null\n ? (harness as { [DRIVER]?: HarnessDriver })[DRIVER]\n : undefined\n if (driver === undefined)\n throw new TypeError(\n \"harness must be { type: 'ai-sdk' }, or come from fx() or pi()\",\n )\n return driver\n}\n\n// ------------------------------------------------------- saved state\n\n/**\n * What an agent's steps saved in this process at the end of a response, per\n * session and harness. A cache: a cold process rebuilds from the whole log.\n */\nexport type HarnessStates = BoundedCache<\n string,\n { index: number; state: unknown }\n>\n\nexport const harnessStates = (): HarnessStates =>\n boundedCache({ maxEntries: 1_000, maxBytes: 64 * 1024 * 1024 })\n\nconst savedKey = (sessionId: string, name: string): string =>\n `${sessionId}\\u0000${name}`\n\n// Binary state counts its bytes; everything else its JSON text.\nconst sizeOf = (value: unknown): number => {\n let binary = 0\n const text = JSON.stringify(value, (_key, item: unknown) => {\n if (!(item instanceof Uint8Array)) return item\n binary += item.byteLength\n return null\n })\n return binary + (text?.length ?? 0)\n}\n\n/**\n * The session log as a harness step reads it: the state this process saved\n * at the end of the last response, when it has one, and the log after it.\n * Saved states are copied in and out, so a step cannot change one in place.\n */\nexport function harnessLog(options: {\n states: HarnessStates\n session: {\n readonly id: string\n history(bounds: {\n gte?: number\n lte?: number\n }): Promise<ContractEvent<EventDefs>[]>\n }\n}): HarnessLog {\n const { states, session } = options\n return {\n read: async ({ name, throughIndex, fresh }) => {\n const entry = fresh ? undefined : states.get(savedKey(session.id, name))\n const snapshot =\n entry === undefined || entry.index > throughIndex\n ? null\n : { index: entry.index, state: structuredClone(entry.state) }\n const events = await session.history(\n snapshot === null\n ? { lte: throughIndex }\n : { gte: snapshot.index + 1, lte: throughIndex },\n )\n return { snapshot, events }\n },\n write: async ({ name, index, state }) => {\n const copy = structuredClone(state)\n states.set(\n savedKey(session.id, name),\n { index, state: copy },\n sizeOf(copy),\n )\n },\n }\n}\n\nconst agentStates = new WeakMap<object, HarnessStates>()\n\n/** Registers an agent server's saved harness states, for `savedHarnessState`. */\nexport function registerHarnessStates(\n server: object,\n states: HarnessStates,\n): void {\n agentStates.set(server, states)\n}\n\n/** What an agent's process saved for one session's harness; tests read it. */\nexport function savedHarnessState(\n server: object,\n options: { sessionId: string; name: string },\n): { index: number; state: unknown } | undefined {\n return agentStates.get(server)?.get(savedKey(options.sessionId, options.name))\n}\n\n/** A harness's state at the end of a response, from the attempt that ran it. */\ntype SavedEnvelope = {\n generationId: string\n responseMessageId: string\n state: unknown\n}\n\nexport type HarnessRead<S> = {\n /** The state saved at the end of the last response, when it is usable. */\n saved: S | undefined\n turns: HarnessTurn[]\n results: Map<string, ToolResultPayload>\n}\n\n/**\n * Reads a harness's saved state and the log since, as turns to replay. A\n * snapshot counts only when the attempt that wrote it committed: a stopped,\n * superseded, or still-running attempt can write one the log never kept.\n * `replayAll` reads the whole log instead, for a state that fails to restore.\n */\nexport async function readHarness<S>({\n step,\n name,\n parse,\n}: {\n step: HarnessStep\n name: string\n parse: (state: unknown) => S | undefined\n}): Promise<HarnessRead<S> & { replayAll: () => Promise<HarnessRead<S>> }> {\n const replayAll = async (): Promise<HarnessRead<S>> => {\n const read = await step.log.read({\n name,\n throughIndex: step.throughIndex,\n fresh: true,\n })\n return { saved: undefined, ...harnessTurns(step, read.events, undefined) }\n }\n const read = await step.log.read({ name, throughIndex: step.throughIndex })\n if (read.snapshot === null)\n return {\n saved: undefined,\n ...harnessTurns(step, read.events, undefined),\n replayAll,\n }\n const envelope = savedEnvelope(read.snapshot.state)\n const saved = envelope === undefined ? undefined : parse(envelope.state)\n const committed =\n envelope !== undefined &&\n read.events.some(\n (event) =>\n event.type === 'ai.generation.completed' &&\n (event.payload as { generationId?: unknown }).generationId ===\n envelope.generationId,\n )\n // A snapshot of this very response belongs to an earlier attempt at it.\n if (\n saved === undefined ||\n !committed ||\n envelope.responseMessageId === step.responseMessageId\n )\n return { ...(await replayAll()), replayAll }\n return {\n saved,\n ...harnessTurns(step, read.events, envelope.responseMessageId),\n replayAll,\n }\n}\n\n/** Saves a harness's state at the end of a response; losing it costs a longer replay. */\nexport async function saveHarness({\n step,\n name,\n state,\n}: {\n step: HarnessStep\n name: string\n state: unknown\n}): Promise<void> {\n const envelope: SavedEnvelope = {\n generationId: step.generationId,\n responseMessageId: step.responseMessageId,\n state,\n }\n try {\n await step.log.write({ name, index: step.requestIndex, state: envelope })\n } catch {\n // The snapshot is a cache.\n }\n}\n\nfunction savedEnvelope(value: unknown): SavedEnvelope | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const { generationId, responseMessageId, state } = value as Record<\n string,\n unknown\n >\n return typeof generationId === 'string' &&\n typeof responseMessageId === 'string'\n ? { generationId, responseMessageId, state }\n : undefined\n}\n\n// ------------------------------------------------- the log as harness turns\n\n// A2's reason on `ai.message.interrupted` when a steer ends a response.\nconst STEERED = 'steered after step'\n\n/** A completed generation as the log recorded it. */\nexport type RecordedGeneration = {\n chunks: UIMessageChunk[]\n completed: GenerationCompletedPayload\n}\n\n/** One harness turn to rebuild: its prompt, completed generations, and end. */\nexport type HarnessTurn = {\n prompt: string\n generations: RecordedGeneration[]\n /** Steering that entered after the generation at that index. */\n steers: Map<number, string[]>\n end: 'stop' | 'interrupted' | 'live'\n}\n\n/**\n * Groups the log since a harness snapshot into harness turns. A response\n * steered after a step continues its turn, with the next response's prompt as\n * steering. `covered` is the response the snapshot already holds.\n */\nexport function harnessTurns(\n step: HarnessStep,\n events: readonly ContractEvent<EventDefs>[],\n covered: string | undefined,\n): { turns: HarnessTurn[]; results: Map<string, ToolResultPayload> } {\n type Generation = {\n id: string\n chunks: UIMessageChunk[]\n completed?: GenerationCompletedPayload\n }\n type Response = {\n id: string\n prompt: string[]\n generations: Generation[]\n end?: 'stop' | 'steered' | 'interrupted'\n }\n // Queued messages are admitted together, possibly before the snapshot.\n const userText = new Map<string, string>(\n step.messages\n .filter((message) => message.role === 'user')\n .map((message) => [message.id, textOf(message)]),\n )\n let passive: string[] = []\n const responses = new Map<string, Response>()\n const byStart = new Map<number, Generation>()\n const byId = new Map<string, Generation>()\n const results = new Map<string, ToolResultPayload>()\n\n for (const event of events) {\n const payload = event.payload as Record<string, unknown>\n switch (event.type) {\n case 'ai.message.created': {\n const message = payload['message'] as UIMessage\n if (message.role !== 'user') break\n userText.set(message.id, textOf(message))\n if (payload['generate'] === false) passive.push(message.id)\n break\n }\n case 'ai.generation.requested': {\n const id = payload['responseMessageId'] as string\n if (id === covered || responses.has(id)) break\n const messageId = payload['messageId'] as string\n const ids = [...passive.filter((p) => p !== messageId), messageId]\n passive = []\n responses.set(id, {\n id,\n prompt: ids.flatMap((p) => userText.get(p) ?? []),\n generations: [],\n })\n break\n }\n case 'ai.generation.started': {\n const response = responses.get(payload['responseMessageId'] as string)\n if (response === undefined) break\n const generation: Generation = {\n id: payload['generationId'] as string,\n chunks: [],\n }\n response.generations.push(generation)\n byStart.set(event.index, generation)\n byId.set(generation.id, generation)\n break\n }\n case 'ai.generation.progress':\n byStart\n .get(payload['startIndex'] as number)\n ?.chunks.push(...(payload['chunks'] as UIMessageChunk[]))\n break\n case 'ai.generation.completed': {\n const generation = byId.get(payload['generationId'] as string)\n if (generation)\n generation.completed = event.payload as GenerationCompletedPayload\n break\n }\n case 'ai.tool.result':\n if (payload['preliminary'] !== true)\n results.set(\n payload['toolCallId'] as string,\n event.payload as ToolResultPayload,\n )\n break\n case 'ai.message.completed': {\n const response = responses.get(payload['messageId'] as string)\n if (response) response.end = 'stop'\n break\n }\n case 'ai.message.interrupted': {\n const response = responses.get(payload['messageId'] as string)\n if (response)\n response.end =\n payload['reason'] === STEERED ? 'steered' : 'interrupted'\n break\n }\n }\n }\n\n const turns: HarnessTurn[] = []\n let steered = false\n for (const response of responses.values()) {\n const text = response.prompt.join('\\n\\n')\n let turn = turns.at(-1)\n if (steered && turn !== undefined) {\n const at = Math.max(0, turn.generations.length - 1)\n turn.steers.set(at, [...(turn.steers.get(at) ?? []), text])\n } else {\n turn = { prompt: text, generations: [], steers: new Map(), end: 'live' }\n turns.push(turn)\n }\n for (const generation of response.generations)\n if (generation.completed !== undefined)\n turn.generations.push({\n chunks: generation.chunks,\n completed: generation.completed,\n })\n turn.end =\n response.id === step.responseMessageId\n ? 'live'\n : response.end === 'stop'\n ? 'stop'\n : 'interrupted'\n steered = response.end === 'steered'\n }\n return { turns, results }\n}\n\nfunction textOf(message: UIMessage): string {\n return message.parts\n .flatMap((part) => (part.type === 'text' ? [part.text] : []))\n .join('\\n')\n}\n\n// ------------------------------------------------------------- Gateway\n\nexport type GatewayCredential = { token: string; method: 'api-key' | 'oidc' }\n\n/** Read per step: on Vercel the OIDC token rides on each function request. */\nexport function gatewayCredential(harness: string): GatewayCredential {\n const key = process.env['AI_GATEWAY_API_KEY']\n if (key) return { token: key, method: 'api-key' }\n const oidc = requestOidcToken() ?? process.env['VERCEL_OIDC_TOKEN']\n if (oidc) return { token: oidc, method: 'oidc' }\n throw new Error(`${harness}() needs AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN`)\n}\n\n// Where Vercel Functions keep the current request, as @vercel/oidc reads it.\nconst REQUEST_CONTEXT = Symbol.for('@vercel/request-context')\n\nfunction requestOidcToken(): string | undefined {\n const context = (\n globalThis as {\n [REQUEST_CONTEXT]?: { get?: () => { headers?: Record<string, unknown> } }\n }\n )[REQUEST_CONTEXT]\n const token = context?.get?.()?.headers?.['x-vercel-oidc-token']\n return typeof token === 'string' && token !== '' ? token : undefined\n}\n\n// ------------------------------------------------------------- helpers\n\nexport class Divergence extends Error {\n constructor(harness: string, message: string) {\n super(`${harness} replay diverged from the log: ${message}`)\n }\n}\n\nexport type Deferred = { promise: Promise<void>; resolve: () => void }\n\nexport function deferred(): Deferred {\n let resolve!: () => void\n const promise = new Promise<void>((done) => {\n resolve = done\n })\n return { promise, resolve }\n}\n\n/** A result that never settles; the harness is stopped instead. */\nexport function pending(\n signal: AbortSignal | null | undefined,\n): Promise<never> {\n return new Promise((_, reject) => {\n if (signal?.aborted) reject(signal.reason)\n signal?.addEventListener('abort', () => reject(signal.reason), {\n once: true,\n })\n })\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,6 @@
1
+ //#region src/ai-pi.browser.ts
2
+ /** experimental-a2/ai/pi is server-only; browsers reach an agent through its route. */
3
+ throw new Error("experimental-a2/ai/pi is server-only — a client bundle imported it. Keep agent({ harness: pi() }) in server code.");
4
+ //#endregion
5
+
6
+ //# sourceMappingURL=ai-pi.browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-pi.browser.js","names":[],"sources":["../src/ai-pi.browser.ts"],"sourcesContent":["/** experimental-a2/ai/pi is server-only; browsers reach an agent through its route. */\nthrow new Error(\n 'experimental-a2/ai/pi is server-only — a client bundle imported it. Keep agent({ harness: pi() }) in server code.',\n)\nexport {}\n"],"mappings":";;AACA,MAAM,IAAI,MACR,mHACF"}
@@ -0,0 +1,17 @@
1
+ import { n as HarnessSandbox, r as HarnessSandboxContext, t as Harness } from "./ai-harness-B2suP2Qh.js";
2
+ //#region src/ai-pi.d.ts
3
+ /** What `pi()` takes. */
4
+ type PiOptions = {
5
+ /** The session's sandbox: Pi's tools, and the agent's, work in it. */
6
+ sandbox: HarnessSandbox;
7
+ };
8
+ /**
9
+ * The Pi harness. Every model call Pi makes is one durable step; A2 rebuilds
10
+ * Pi's session for each step from its latest snapshot and the log since.
11
+ */
12
+ declare function pi(options: PiOptions): Harness<"pi", Builtin>;
13
+ declare const BUILTINS: readonly ["read", "write", "edit", "bash"];
14
+ type Builtin = (typeof BUILTINS)[number];
15
+ //#endregion
16
+ export { type Harness, type HarnessSandbox, type HarnessSandboxContext, PiOptions, pi };
17
+ //# sourceMappingURL=ai-pi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-pi.d.ts","names":[],"sources":["../src/ai-pi.ts"],"mappings":";;;KAyEY;;EAEV,SAAS;;;;;;iBAOK,GAAG,SAAS,YAAY,cAAc;cAuBhD;KACD,kBAAkB"}