experimental-a2 0.18.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 (114) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/{actor-Bjce9_5U.d.ts → actor-C7b-1arn.d.ts} +3 -3
  3. package/dist/{actor-Bjce9_5U.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
  4. package/dist/actor-client.d.ts +1 -1
  5. package/dist/actor-react.d.ts +1 -1
  6. package/dist/actor-react.js +1 -1
  7. package/dist/actor.d.ts +1 -1
  8. package/dist/actor.js +2 -2
  9. package/dist/{ai-DrUaMyRt.d.ts → ai-BMLlI2Ff.d.ts} +2 -2
  10. package/dist/{ai-DrUaMyRt.d.ts.map → ai-BMLlI2Ff.d.ts.map} +1 -1
  11. package/dist/{ai-BpOGm-zB.js → ai-D6mGlO8j.js} +2 -2
  12. package/dist/{ai-BpOGm-zB.js.map → ai-D6mGlO8j.js.map} +1 -1
  13. package/dist/ai-client.d.ts +1 -1
  14. package/dist/ai-client.js +2 -2
  15. package/dist/ai-fx.d.ts +1 -1
  16. package/dist/ai-fx.d.ts.map +1 -1
  17. package/dist/ai-fx.js +92 -34
  18. package/dist/ai-fx.js.map +1 -1
  19. package/dist/{ai-harness-DvsPeJeB.d.ts → ai-harness-B2suP2Qh.d.ts} +2 -2
  20. package/dist/{ai-harness-DvsPeJeB.d.ts.map → ai-harness-B2suP2Qh.d.ts.map} +1 -1
  21. package/dist/ai-pi.d.ts +1 -1
  22. package/dist/ai-pi.d.ts.map +1 -1
  23. package/dist/ai-pi.js +59 -13
  24. package/dist/ai-pi.js.map +1 -1
  25. package/dist/ai-react.d.ts +1 -1
  26. package/dist/ai-react.js +2 -2
  27. package/dist/ai-server.d.ts +3 -3
  28. package/dist/ai-server.d.ts.map +1 -1
  29. package/dist/ai-server.js +10 -6
  30. package/dist/ai-server.js.map +1 -1
  31. package/dist/ai-tool-input-DmSqMUQi.js +40 -0
  32. package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
  33. package/dist/ai.d.ts +1 -1
  34. package/dist/ai.js +1 -1
  35. package/dist/{client-BReKqwZC.js → client-BhHLoNKF.js} +3 -3
  36. package/dist/{client-BReKqwZC.js.map → client-BhHLoNKF.js.map} +1 -1
  37. package/dist/client.js +1 -1
  38. package/dist/index.d.ts +2 -2
  39. package/dist/{internal-B2T3U4Rq.js → internal-CscSY7K_.js} +4 -2
  40. package/dist/{internal-B2T3U4Rq.js.map → internal-CscSY7K_.js.map} +1 -1
  41. package/dist/react.js +1 -1
  42. package/dist/scheduler-qstash.d.ts +2 -2
  43. package/dist/scheduler-qstash.js +3 -3
  44. package/dist/scheduler-qstash.js.map +1 -1
  45. package/dist/scheduler-vercel.d.ts +7 -7
  46. package/dist/scheduler-vercel.d.ts.map +1 -1
  47. package/dist/scheduler-vercel.js +9 -10
  48. package/dist/scheduler-vercel.js.map +1 -1
  49. package/dist/{server-Dw_k_7kO.js → server-D-Y4pqwu.js} +37 -11
  50. package/dist/server-D-Y4pqwu.js.map +1 -0
  51. package/dist/{server-En7cbi3v.d.ts → server-DYAATFuT.d.ts} +11 -5
  52. package/dist/server-DYAATFuT.d.ts.map +1 -0
  53. package/dist/server.d.ts +2 -2
  54. package/dist/server.js +1 -1
  55. package/dist/{session-clear-Bo-XTFEy.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
  56. package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
  57. package/dist/{store-Djdv0bnZ.d.ts → store-CyLUy86v.d.ts} +23 -4
  58. package/dist/store-CyLUy86v.d.ts.map +1 -0
  59. package/dist/store-N8PXxDAS.js.map +1 -1
  60. package/dist/store-memory.d.ts +1 -1
  61. package/dist/store-memory.js +25 -6
  62. package/dist/store-memory.js.map +1 -1
  63. package/dist/{store-polling-B5FcwJfo.js → store-polling-7WJV0YWP.js} +2 -2
  64. package/dist/{store-polling-B5FcwJfo.js.map → store-polling-7WJV0YWP.js.map} +1 -1
  65. package/dist/store-postgres.d.ts +1 -1
  66. package/dist/store-postgres.d.ts.map +1 -1
  67. package/dist/store-postgres.js +55 -25
  68. package/dist/store-postgres.js.map +1 -1
  69. package/dist/{store-presence-polling-BAwS8RWn.js → store-presence-polling-B1ixeqIS.js} +3 -3
  70. package/dist/{store-presence-polling-BAwS8RWn.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
  71. package/dist/store-redis-http.d.ts +1 -1
  72. package/dist/store-redis-http.js +3 -3
  73. package/dist/{store-redis-notify-BRITti_o.js → store-redis-notify-CM0AfLY0.js} +88 -37
  74. package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
  75. package/dist/store-redis.d.ts +1 -1
  76. package/dist/store-redis.js +1 -1
  77. package/dist/store-sqlite.d.ts +1 -1
  78. package/dist/store-sqlite.js +35 -20
  79. package/dist/store-sqlite.js.map +1 -1
  80. package/dist/{wire-rSUglYo8.js → wire-BKxH1vbP.js} +2 -2
  81. package/dist/{wire-rSUglYo8.js.map → wire-BKxH1vbP.js.map} +1 -1
  82. package/docs/agents/03-conversations.mdx +2 -2
  83. package/docs/index.mdx +3 -3
  84. package/docs/reference/02-server.mdx +12 -7
  85. package/docs/reference/04-ai.mdx +16 -7
  86. package/docs/reference/05-adapters.mdx +4 -4
  87. package/docs/server/01-handlers.mdx +1 -1
  88. package/docs/server/03-cancellation.mdx +3 -2
  89. package/docs/server/05-production.mdx +2 -1
  90. package/docs/server/06-guarantees.mdx +20 -11
  91. package/examples/playground/DEPLOY.md +2 -4
  92. package/examples/playground/app/a0/[appId]/page.tsx +2 -8
  93. package/examples/playground/app/a0/devtools.tsx +2 -8
  94. package/examples/playground/app/a0/server.ts +8 -19
  95. package/examples/playground/package.json +1 -1
  96. package/package.json +1 -1
  97. package/src/ai-agent.ts +10 -3
  98. package/src/ai-fx.ts +126 -47
  99. package/src/ai-pi.ts +74 -15
  100. package/src/ai-tool-input.ts +45 -0
  101. package/src/internal.ts +6 -0
  102. package/src/scheduler-qstash.ts +5 -5
  103. package/src/scheduler-vercel.ts +14 -15
  104. package/src/server.ts +58 -12
  105. package/src/store-memory.ts +50 -9
  106. package/src/store-postgres.ts +79 -28
  107. package/src/store-redis-core.ts +112 -31
  108. package/src/store-sqlite.ts +61 -28
  109. package/src/store.ts +22 -3
  110. package/dist/server-Dw_k_7kO.js.map +0 -1
  111. package/dist/server-En7cbi3v.d.ts.map +0 -1
  112. package/dist/session-clear-Bo-XTFEy.d.ts.map +0 -1
  113. package/dist/store-Djdv0bnZ.d.ts.map +0 -1
  114. package/dist/store-redis-notify-BRITti_o.js.map +0 -1
@@ -1,5 +1,5 @@
1
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-DrUaMyRt.js";
2
+ import { a as AI_STATE_REDUCER, i as AIState, r as AIMessageOf, t as AIEventDefs } from "./ai-BMLlI2Ff.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-BReKqwZC.js";
2
- import { n as agentContract } from "./ai-BpOGm-zB.js";
1
+ import { t as createClient } from "./client-BhHLoNKF.js";
2
+ import { n as agentContract } from "./ai-D6mGlO8j.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,4 +1,4 @@
1
- import { t as Harness } from "./ai-harness-DvsPeJeB.js";
1
+ import { t as Harness } from "./ai-harness-B2suP2Qh.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
@@ -1 +1 @@
1
- {"version":3,"file":"ai-fx.d.ts","names":[],"sources":["../src/ai-fx.ts"],"mappings":";;;;;;iBAwCgB,MAAM"}
1
+ {"version":3,"file":"ai-fx.d.ts","names":[],"sources":["../src/ai-fx.ts"],"mappings":";;;;;;iBAyCgB,MAAM"}
package/dist/ai-fx.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
2
2
  import { c as pending, d as saveHarness, i as gatewayCredential, l as readHarness, n as deferred, r as defineHarness, t as Divergence } from "./ai-harness-BuLh_EYi.js";
3
+ import { t as schemaInput } from "./ai-tool-input-DmSqMUQi.js";
3
4
  import { asSchema } from "ai";
4
5
  //#region src/ai-fx.ts
5
6
  /**
@@ -36,6 +37,8 @@ async function runStep(step) {
36
37
  let read = first;
37
38
  let completion = {};
38
39
  let stopped = false;
40
+ const released = new AbortController();
41
+ const network = AbortSignal.any([step.signal, released.signal]);
39
42
  let agent;
40
43
  let turn;
41
44
  const run = async (controller, turns) => {
@@ -141,10 +144,16 @@ async function runStep(step) {
141
144
  const live = async (state, url, init, compaction) => {
142
145
  const response = await fetch(url, {
143
146
  ...init,
144
- headers: withAuth(init.headers, credential)
147
+ headers: withAuth(init.headers, credential),
148
+ signal: network
145
149
  });
150
+ if (init.signal?.aborted) {
151
+ response.body?.cancel();
152
+ throw init.signal.reason;
153
+ }
146
154
  if (!response.ok || response.body === null) return response;
147
- const [forKernel, forLog] = response.body.tee();
155
+ const [fromNetwork, forLog] = response.body.tee();
156
+ const forKernel = init.signal ? fromNetwork.pipeThrough(new TransformStream(), { signal: init.signal }) : fromNetwork;
148
157
  const previous = state.parsed;
149
158
  if (compaction) {
150
159
  const id = `fx-compaction:${step.requestIndex}:${compactions++}`;
@@ -162,8 +171,13 @@ async function runStep(step) {
162
171
  state.parsed = (async () => {
163
172
  await previous;
164
173
  emit({ type: "start-step" });
165
- await streamStep(forLog, emit, (finished) => {
166
- completion = finished;
174
+ await streamStep({
175
+ body: forLog,
176
+ tools: step.tools,
177
+ emit,
178
+ finished: (finished) => {
179
+ completion = finished;
180
+ }
167
181
  });
168
182
  })();
169
183
  }
@@ -236,6 +250,7 @@ async function runStep(step) {
236
250
  closed = true;
237
251
  streamController.error(step.signal.aborted ? step.signal.reason : error);
238
252
  } finally {
253
+ released.abort();
239
254
  step.signal.removeEventListener("abort", abort);
240
255
  await agent?.close().catch(() => {});
241
256
  }
@@ -244,6 +259,7 @@ async function runStep(step) {
244
259
  cancel() {
245
260
  closed = true;
246
261
  stopped = true;
262
+ released.abort();
247
263
  turn?.fxTurn.cancel();
248
264
  }
249
265
  }),
@@ -321,34 +337,27 @@ function recordedCalls(chunks, completed) {
321
337
  });
322
338
  break;
323
339
  case "tool-input-error":
340
+ case "tool-input-available": {
341
+ const text = inputText.get(chunk.toolCallId) || (chunk.type === "tool-input-error" && typeof chunk.input === "string" ? chunk.input : JSON.stringify(chunk.input));
324
342
  if (inputText.has(chunk.toolCallId)) parts.push({
325
343
  type: "tool-input-end",
326
344
  id: chunk.toolCallId
327
345
  });
328
- parts.push({
329
- type: "tool-call",
330
- toolCallId: chunk.toolCallId,
331
- toolName: chunk.toolName,
332
- input: inputText.get(chunk.toolCallId) || (typeof chunk.input === "string" ? chunk.input : JSON.stringify(chunk.input))
333
- });
334
- break;
335
- case "tool-input-available":
336
- if (inputText.has(chunk.toolCallId)) parts.push({
337
- type: "tool-input-end",
338
- id: chunk.toolCallId
339
- });
340
- toolCalls.push({
346
+ const input = parseJson(text);
347
+ if (input !== void 0) toolCalls.push({
341
348
  toolCallId: chunk.toolCallId,
342
349
  toolName: chunk.toolName,
343
- input: chunk.input
350
+ input
344
351
  });
345
352
  parts.push({
346
353
  type: "tool-call",
347
354
  toolCallId: chunk.toolCallId,
348
355
  toolName: chunk.toolName,
349
- input: inputText.get(chunk.toolCallId) || JSON.stringify(chunk.input),
356
+ input: text,
350
357
  ...metadata
351
358
  });
359
+ break;
360
+ }
352
361
  }
353
362
  }
354
363
  parts.push({
@@ -386,7 +395,8 @@ function compactionSse(data) {
386
395
  ]);
387
396
  }
388
397
  /** Streams one live step response as UI chunks and reports its finish. */
389
- async function streamStep(body, emit, finished) {
398
+ async function streamStep({ body, tools, emit, finished }) {
399
+ const streamed = /* @__PURE__ */ new Map();
390
400
  for await (const part of sseParts(body)) {
391
401
  const metadata = part["providerMetadata"] === void 0 ? {} : { providerMetadata: part["providerMetadata"] };
392
402
  switch (part.type) {
@@ -410,6 +420,7 @@ async function streamStep(body, emit, finished) {
410
420
  });
411
421
  break;
412
422
  case "tool-input-start":
423
+ streamed.set(part["id"], false);
413
424
  emit({
414
425
  type: "tool-input-start",
415
426
  toolCallId: part["id"],
@@ -418,6 +429,7 @@ async function streamStep(body, emit, finished) {
418
429
  });
419
430
  break;
420
431
  case "tool-input-delta":
432
+ if (part["delta"] !== "") streamed.set(part["id"], true);
421
433
  emit({
422
434
  type: "tool-input-delta",
423
435
  toolCallId: part["id"],
@@ -425,25 +437,38 @@ async function streamStep(body, emit, finished) {
425
437
  });
426
438
  break;
427
439
  case "tool-call": {
440
+ const toolCallId = part["toolCallId"];
441
+ const toolName = part["toolName"];
428
442
  const text = part["input"];
429
- let input;
430
- try {
431
- input = JSON.parse(text);
432
- } catch (error) {
443
+ if (streamed.get(toolCallId) !== true && text !== "") {
444
+ if (!streamed.has(toolCallId)) emit({
445
+ type: "tool-input-start",
446
+ toolCallId,
447
+ toolName
448
+ });
433
449
  emit({
434
- type: "tool-input-error",
435
- toolCallId: part["toolCallId"],
436
- toolName: part["toolName"],
437
- input: text,
438
- errorText: error instanceof Error ? error.message : String(error)
450
+ type: "tool-input-delta",
451
+ toolCallId,
452
+ inputTextDelta: text
439
453
  });
440
- break;
441
454
  }
442
- emit({
455
+ const input = await parseToolInput({
456
+ tools,
457
+ toolName,
458
+ text
459
+ });
460
+ emit(input.success ? {
443
461
  type: "tool-input-available",
444
- toolCallId: part["toolCallId"],
445
- toolName: part["toolName"],
446
- input,
462
+ toolCallId,
463
+ toolName,
464
+ input: input.value,
465
+ ...metadata
466
+ } : {
467
+ type: "tool-input-error",
468
+ toolCallId,
469
+ toolName,
470
+ input: input.input,
471
+ errorText: input.errorText,
447
472
  ...metadata
448
473
  });
449
474
  break;
@@ -463,6 +488,32 @@ async function streamStep(body, emit, finished) {
463
488
  }
464
489
  }
465
490
  }
491
+ /**
492
+ * A live call's input as the AI SDK step reads it: JSON, then the tool's
493
+ * schema with its defaults. Input that fails either is an input error, which
494
+ * A2 answers without running the tool.
495
+ */
496
+ async function parseToolInput({ tools, toolName, text }) {
497
+ let value;
498
+ try {
499
+ value = JSON.parse(text);
500
+ } catch (error) {
501
+ return {
502
+ success: false,
503
+ input: text,
504
+ errorText: errorText(error)
505
+ };
506
+ }
507
+ const input = await schemaInput({
508
+ tools,
509
+ toolName,
510
+ value
511
+ });
512
+ return input.success ? input : {
513
+ ...input,
514
+ input: value
515
+ };
516
+ }
466
517
  async function readParts(body) {
467
518
  const all = [];
468
519
  for await (const part of sseParts(body)) all.push(part);
@@ -581,6 +632,13 @@ function decodeBody(body) {
581
632
  if (body instanceof Uint8Array || body instanceof ArrayBuffer) return new TextDecoder().decode(body);
582
633
  throw new TypeError("FX sent an unexpected request body");
583
634
  }
635
+ function parseJson(text) {
636
+ try {
637
+ return JSON.parse(text);
638
+ } catch {
639
+ return;
640
+ }
641
+ }
584
642
  function sameJson(a, b) {
585
643
  return JSON.stringify(a) === JSON.stringify(b);
586
644
  }
package/dist/ai-fx.js.map CHANGED
@@ -1 +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 { 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>\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 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 })\n if (!response.ok || response.body === null) return response\n const [forKernel, forLog] = response.body.tee()\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(forLog, emit, (finished) => {\n completion = finished\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 step.signal.removeEventListener('abort', abort)\n await agent?.close().catch(() => {})\n }\n })()\n },\n cancel() {\n closed = true\n stopped = true\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 // A call whose input did not parse: FX answered it itself.\n if (inputText.has(chunk.toolCallId))\n parts.push({ type: 'tool-input-end', id: chunk.toolCallId })\n parts.push({\n type: 'tool-call',\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n input:\n inputText.get(chunk.toolCallId) ||\n (typeof chunk.input === 'string'\n ? chunk.input\n : JSON.stringify(chunk.input)),\n })\n break\n case 'tool-input-available':\n if (inputText.has(chunk.toolCallId))\n parts.push({ type: 'tool-input-end', id: chunk.toolCallId })\n toolCalls.push({\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n input: chunk.input,\n })\n parts.push({\n type: 'tool-call',\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n input: inputText.get(chunk.toolCallId) || JSON.stringify(chunk.input),\n ...metadata,\n })\n break\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: ReadableStream<Uint8Array>,\n emit: (chunk: UIMessageChunk) => void,\n finished: (completion: Completion) => void,\n): Promise<void> {\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 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 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 text = part['input'] as string\n let input: unknown\n try {\n input = JSON.parse(text)\n } catch (error) {\n emit({\n type: 'tool-input-error',\n toolCallId: part['toolCallId'] as string,\n toolName: part['toolName'] as string,\n input: text,\n errorText: error instanceof Error ? error.message : String(error),\n })\n break\n }\n emit({\n type: 'tool-input-available',\n toolCallId: part['toolCallId'] as string,\n toolName: part['toolName'] as string,\n input,\n ...metadata,\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\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 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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"}
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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"}
@@ -1,4 +1,4 @@
1
- import "./ai-DrUaMyRt.js";
1
+ import "./ai-BMLlI2Ff.js";
2
2
  import { Experimental_SandboxSession, ToolSet, UIMessage, UIMessageChunk } from "ai";
3
3
  //#region src/ai-harness.d.ts
4
4
  declare const harnessBrand: unique symbol;
@@ -23,4 +23,4 @@ type HarnessSandboxContext = {
23
23
  type HarnessSandbox = (context: HarnessSandboxContext) => Experimental_SandboxSession | Promise<Experimental_SandboxSession>;
24
24
  //#endregion
25
25
  export { HarnessSandbox as n, HarnessSandboxContext as r, Harness as t };
26
- //# sourceMappingURL=ai-harness-DvsPeJeB.d.ts.map
26
+ //# sourceMappingURL=ai-harness-B2suP2Qh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-harness-DvsPeJeB.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"}
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"}
package/dist/ai-pi.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as HarnessSandbox, r as HarnessSandboxContext, t as Harness } from "./ai-harness-DvsPeJeB.js";
1
+ import { n as HarnessSandbox, r as HarnessSandboxContext, t as Harness } from "./ai-harness-B2suP2Qh.js";
2
2
  //#region src/ai-pi.d.ts
3
3
  /** What `pi()` takes. */
4
4
  type PiOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-pi.d.ts","names":[],"sources":["../src/ai-pi.ts"],"mappings":";;;KAwEY;;EAEV,SAAS;;;;;;iBAOK,GAAG,SAAS,YAAY,cAAc;cAuBhD;KACD,kBAAkB"}
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"}
package/dist/ai-pi.js CHANGED
@@ -1,6 +1,7 @@
1
- import { u as ambientToolScopeStorage } from "./internal-B2T3U4Rq.js";
1
+ import { u as ambientToolScopeStorage } from "./internal-CscSY7K_.js";
2
2
  import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
3
3
  import { c as pending, d as saveHarness, i as gatewayCredential, l as readHarness, n as deferred, r as defineHarness, t as Divergence } from "./ai-harness-BuLh_EYi.js";
4
+ import { t as schemaInput } from "./ai-tool-input-DmSqMUQi.js";
4
5
  import { createHash } from "node:crypto";
5
6
  import { asSchema, jsonSchema } from "ai";
6
7
  import { readFile, unlink } from "node:fs/promises";
@@ -113,7 +114,7 @@ async function runStep(step, sandbox) {
113
114
  });
114
115
  const live = kind === "step" ? liveStep() : void 0;
115
116
  for await (const event of upstream) {
116
- live?.(event);
117
+ await live?.(event);
117
118
  if (event.type === "done" || event.type === "error") {
118
119
  const response = event.type === "done" ? event.message : event.error;
119
120
  if (kind === "compaction") state.compactions.push(response);
@@ -125,11 +126,47 @@ async function runStep(step, sandbox) {
125
126
  out.push(event);
126
127
  }
127
128
  };
129
+ /**
130
+ * A live call's input as Pi's loop, then the AI SDK step, read it. Pi
131
+ * answers a call to no tool, or whose arguments it cannot prepare or
132
+ * validate, itself. The agent's tool reads the arguments Pi accepts through
133
+ * its own schema; A2 runs Pi's own tools from the model's arguments, as
134
+ * Pi's loop does.
135
+ */
136
+ const callInput = async (block) => {
137
+ const definition = tools.find((tool) => tool.name === block.name);
138
+ if (definition === void 0) return {
139
+ success: false,
140
+ errorText: `Tool ${block.name} not found`
141
+ };
142
+ let args;
143
+ try {
144
+ const prepared = definition.prepareArguments?.(block.arguments);
145
+ args = modules.ai.validateToolArguments(definition, prepared === void 0 ? block : {
146
+ ...block,
147
+ arguments: prepared
148
+ });
149
+ } catch (error) {
150
+ return {
151
+ success: false,
152
+ errorText: asError(error).message
153
+ };
154
+ }
155
+ if (builtinOf(step.tools, block.name) !== void 0) return {
156
+ success: true,
157
+ value: block.arguments
158
+ };
159
+ return schemaInput({
160
+ tools: step.tools,
161
+ toolName: block.name,
162
+ value: args
163
+ });
164
+ };
128
165
  /** Streams one live step response as UI chunks and records it. */
129
166
  const liveStep = () => {
130
167
  const ref = (index) => `pi:${step.requestIndex}:${index}`;
131
168
  const started = /* @__PURE__ */ new Set();
132
- return (event) => {
169
+ return async (event) => {
133
170
  switch (event.type) {
134
171
  case "start":
135
172
  emit({ type: "start-step" });
@@ -194,6 +231,7 @@ async function runStep(step, sandbox) {
194
231
  case "done":
195
232
  case "error": {
196
233
  const response = event.type === "done" ? event.message : event.error;
234
+ const changed = /* @__PURE__ */ new Set();
197
235
  if (event.type === "done") for (const block of response.content) {
198
236
  if (block.type !== "toolCall") continue;
199
237
  if (!started.has(block.id)) emit({
@@ -201,22 +239,27 @@ async function runStep(step, sandbox) {
201
239
  toolCallId: block.id,
202
240
  toolName: block.name
203
241
  });
204
- emit(response.stopReason === "length" ? {
205
- type: "tool-input-error",
242
+ const input = response.stopReason === "length" ? {
243
+ success: false,
244
+ errorText: "The response hit the output token limit before this call was complete."
245
+ } : await callInput(block);
246
+ if (input.success && JSON.stringify(input.value) !== JSON.stringify(block.arguments)) changed.add(block.id);
247
+ emit(input.success ? {
248
+ type: "tool-input-available",
206
249
  toolCallId: block.id,
207
250
  toolName: block.name,
208
- input: block.arguments,
209
- errorText: "The response hit the output token limit before this call was complete."
251
+ input: input.value
210
252
  } : {
211
- type: "tool-input-available",
253
+ type: "tool-input-error",
212
254
  toolCallId: block.id,
213
255
  toolName: block.name,
214
- input: block.arguments
256
+ input: block.arguments,
257
+ errorText: input.errorText
215
258
  });
216
259
  }
217
260
  record({
218
261
  call: "step",
219
- response: storedResponse(response, ref)
262
+ response: storedResponse(response, ref, changed)
220
263
  });
221
264
  completion = {
222
265
  finishReason: finishReason(response.stopReason),
@@ -437,7 +480,7 @@ function recordedCalls(generation) {
437
480
  if (!calls.some((call) => call.kind === "step")) throw diverged("a completed generation has no recorded response");
438
481
  return calls;
439
482
  }
440
- function storedResponse(response, ref) {
483
+ function storedResponse(response, ref, changed) {
441
484
  return {
442
485
  ...response,
443
486
  content: response.content.map((block, index) => {
@@ -457,6 +500,7 @@ function storedResponse(response, ref) {
457
500
  };
458
501
  }
459
502
  case "toolCall": {
503
+ if (changed.has(block.id)) return block;
460
504
  const { arguments: _, ...rest } = block;
461
505
  return rest;
462
506
  }
@@ -470,7 +514,7 @@ function restoredResponse(stored, texts, inputs) {
470
514
  content: stored.content.map((block) => {
471
515
  if (block.type === "toolCall") return {
472
516
  ...block,
473
- arguments: inputs.get(block.id) ?? {}
517
+ arguments: block.arguments ?? inputs.get(block.id) ?? {}
474
518
  };
475
519
  const { ref, ...rest } = block;
476
520
  const text = texts.get(ref) ?? "";
@@ -606,6 +650,8 @@ async function recordedResult(result, sandbox) {
606
650
  }
607
651
  };
608
652
  }
653
+ /** The Pi tool a name in the agent's tool set runs, unless the agent replaced it. */
654
+ const builtinOf = (tools, name) => BUILTINS.find((candidate) => candidate === name && Object.hasOwn(tools, name) && tools[name] === builtinTools[name]);
609
655
  const untyped = (definition) => definition;
610
656
  function builtinDefinition(modules, name, cwd, call) {
611
657
  const sandbox = call?.sandbox;
@@ -626,7 +672,7 @@ function builtinDefinition(modules, name, cwd, call) {
626
672
  */
627
673
  async function sessionTools(modules, tools, cwd, result) {
628
674
  return Promise.all(Object.entries(tools).filter(([, tool]) => tool.type !== "provider").map(async ([name, tool]) => {
629
- const builtin = BUILTINS.find((candidate) => candidate === name && builtinTools[name] === tool);
675
+ const builtin = builtinOf(tools, name);
630
676
  if (builtin !== void 0) return Object.assign(builtinDefinition(modules, builtin, cwd), { execute: (toolCallId, _params, signal) => result(toolCallId, signal, "pi") });
631
677
  return {
632
678
  name,