@copilotkit/aimock 1.38.0 → 1.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/README.md +23 -2
  4. package/dist/agui-handler.cjs +20 -18
  5. package/dist/agui-handler.cjs.map +1 -1
  6. package/dist/agui-handler.d.cts +8 -1
  7. package/dist/agui-handler.d.cts.map +1 -1
  8. package/dist/agui-handler.d.ts +8 -1
  9. package/dist/agui-handler.d.ts.map +1 -1
  10. package/dist/agui-handler.js +20 -18
  11. package/dist/agui-handler.js.map +1 -1
  12. package/dist/agui-stub.d.cts +2 -2
  13. package/dist/agui-stub.d.ts +2 -2
  14. package/dist/agui-types.d.cts +19 -1
  15. package/dist/agui-types.d.cts.map +1 -1
  16. package/dist/agui-types.d.ts +19 -1
  17. package/dist/agui-types.d.ts.map +1 -1
  18. package/dist/aimock-cli.cjs +1 -1
  19. package/dist/aimock-cli.cjs.map +1 -1
  20. package/dist/aimock-cli.js +1 -1
  21. package/dist/aimock-cli.js.map +1 -1
  22. package/dist/cli.cjs +10 -10
  23. package/dist/cli.cjs.map +1 -1
  24. package/dist/cli.js +10 -10
  25. package/dist/cli.js.map +1 -1
  26. package/dist/config-loader.d.ts.map +1 -1
  27. package/dist/index.d.cts +2 -2
  28. package/dist/index.d.ts +2 -2
  29. package/dist/llmock.cjs +23 -9
  30. package/dist/llmock.cjs.map +1 -1
  31. package/dist/llmock.d.cts +22 -0
  32. package/dist/llmock.d.cts.map +1 -1
  33. package/dist/llmock.d.ts +22 -0
  34. package/dist/llmock.d.ts.map +1 -1
  35. package/dist/llmock.js +25 -11
  36. package/dist/llmock.js.map +1 -1
  37. package/dist/openrouter-video.cjs.map +1 -1
  38. package/dist/openrouter-video.js.map +1 -1
  39. package/dist/server.cjs +34 -17
  40. package/dist/server.cjs.map +1 -1
  41. package/dist/server.d.cts +6 -1
  42. package/dist/server.d.cts.map +1 -1
  43. package/dist/server.d.ts +6 -1
  44. package/dist/server.d.ts.map +1 -1
  45. package/dist/server.js +34 -18
  46. package/dist/server.js.map +1 -1
  47. package/dist/stream-collapse.cjs +77 -0
  48. package/dist/stream-collapse.cjs.map +1 -1
  49. package/dist/stream-collapse.d.cts.map +1 -1
  50. package/dist/stream-collapse.d.ts.map +1 -1
  51. package/dist/stream-collapse.js +77 -0
  52. package/dist/stream-collapse.js.map +1 -1
  53. package/dist/vector-types.d.ts.map +1 -1
  54. package/dist/ws-gemini-live.cjs +41 -6
  55. package/dist/ws-gemini-live.cjs.map +1 -1
  56. package/dist/ws-gemini-live.js +41 -6
  57. package/dist/ws-gemini-live.js.map +1 -1
  58. package/package.json +3 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aimock",
3
- "version": "1.38.0",
3
+ "version": "1.39.0",
4
4
  "description": "Fixture authoring guidance for @copilotkit/aimock — LLM, multimedia, MCP, A2A, AG-UI, vector, and service mocking",
5
5
  "author": {
6
6
  "name": "CopilotKit"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.39.0] - 2026-08-18
6
+
7
+ ### Added
8
+
9
+ - **AG-UI `RUN_FINISHED` and `RUN_ERROR` events now carry an optional `usage` field.** AG-UI's canonical `events.ts` declares an optional `usage: TokenUsage[]` on both terminal event schemas, but aimock's event interfaces carried neither. A new exported `AGUITokenUsage` type — numeric-only, mirroring `@ag-ui/core`'s `TokenUsageSchema` field for field (`provider` / `model` labels plus non-negative-integer `inputTokens`, `outputTokens`, `totalTokens`, `reasoningTokens`, `cachedInputTokens`, and no content-bearing or identifying fields) — is added as `usage?: AGUITokenUsage[]` on `AGUIRunFinishedEvent` and `AGUIRunErrorEvent`, and exported from both the package root and the `agui-stub` entrypoint. The field is reachable, not merely declarative: `AGUIBuildOpts` gains a `usage` option that is threaded to the terminal `RUN_FINISHED` of every builder and to `RUN_ERROR` in `buildErrorResponse`. Following the repo's existing usage policy (Bedrock / Cohere / Gemini), token counts are never synthesized from fixture content — `usage` is emitted only when a caller supplies it explicitly, so existing callers see byte-identical events. It is an array so a run that invokes multiple models keeps their counts separate (#378)
10
+
11
+ ### Changed
12
+
13
+ - `POST /__aimock/reset` is now the canonical full reset and returns a plain `{ "reset": true }` with no deprecation header or body fields. `POST /__aimock/reset/journal` is unaffected.
14
+ - **`LLMock.reset()` and the control-API full reset are now one implementation.** Both call a shared `performFullReset`, which clears the fixtures array, the journal (entries _and_ per-test fixture match-counts, across every testId), video and fal.ai job/queue state, and the Gemini interaction/event-id counters. The in-process `reset()` previously left `veoVideoJobs`, `grokVideoJobs` and both Gemini counters populated, so an in-process test suite could see a stale Veo/Grok poll resolve after a reset and interaction ids that never restarted at `aimock-int-0`. `reset()` additionally clears the search / rerank / moderation fixtures, which are registrable only through `LLMock` and that the control API cannot reach.
15
+ - **Behavior change for multi-instance in-process users:** `reset()` now also clears state that is MODULE-GLOBAL, not per-instance — the Gemini interaction and event-id counters, and the fal.ai job/queue maps. With two `LLMock` instances live in one process, `a.reset()` rewinds the Gemini id sequence that instance `b` is mid-way through, so `b` re-emits `aimock-int-0` / `evt_1` — ids it has already handed out — and drops `b`'s in-flight fal jobs. The fal maps were already global before this change; the counters are newly reached. Give each instance its own process (or its own vitest worker) if that matters.
16
+ - `aimock-pytest`: `AIMockServer.reset()` and `.reset_fixtures()` now call `POST /__aimock/reset`. Both already performed a full reset, so the observable behavior is unchanged.
17
+ - **This does not yet avoid the deprecation warning.** `_version.py` pins `AIMOCK_VERSION = "1.38.0"`, and on that published server `/reset` is still the deprecated alias — so the client trips a deprecation on every reset until the pin moves. **Release follow-up (required):** bump `AIMOCK_VERSION` to the first npm release containing this change before publishing the next `aimock-pytest`. Until then the client is deprecation-clean only against a server built from this branch.
18
+
19
+ ### Deprecated
20
+
21
+ - `POST /__aimock/reset/fixtures` — now a deprecated alias for `POST /__aimock/reset`. The name promised a fixtures-only reset while it always performed the full reset, so `/reset` is the honest route and the deprecation moves onto the alias: it still performs the same full reset but emits a `Deprecation: true` response header, `deprecated` / `deprecation` fields in the body, and a log warning. Use `POST /__aimock/reset` for a full reset, `POST /__aimock/reset/journal` for a journal-only one, or `DELETE /__aimock/fixtures` to clear fixtures and nothing else.
22
+ - The alias's **reset semantics are unchanged** — it clears exactly what it always did, so existing callers keep working. Its **response body is additively extended**: it now carries `deprecated` and `deprecation` alongside `reset`, plus the `Deprecation: true` header. A caller asserting strict equality on the old `{ "reset": true }` body will need to relax that assertion; a caller reading `body.reset` is unaffected.
23
+
24
+ ### Fixed
25
+
26
+ - **Recording a tool-call turn over the OpenAI Responses API now collapses to `toolCalls` instead of an empty assistant turn.** `collapseOpenAISSE` handled Responses-API text, reasoning and web-search output items but let a catch-all (`if (parsed.type?.startsWith("response.")) continue;`) silently skip the entire function-call sequence — `response.output_item.added` for a `function_call` item, `response.function_call_arguments.delta` / `.done`, and `response.output_item.done` for a `function_call`. A tool-call-only turn therefore collapsed to empty `content` with no `toolCalls` (logged `Stream collapse produced empty content — fixture may be incomplete`), and replaying that fixture yielded an empty assistant turn with no tool invocation. Only fresh Responses-API recordings broke, because the older Chat-Completions path already accumulated `choices[0].delta.tool_calls`. aimock now accumulates the function-call events into the existing tool-call map keyed by `output_index`, capturing the Responses `call_id` (the id a tool result references — **not** the internal `fc_…` item id) as the tool-call `id`, and emits `{ id, name, arguments }` with arguments normalized to valid JSON — identical to the Chat-Completions shape and the checked-in fixtures. Scope: this fixes the stream collapser only; it does not address the fixture-capture race in which a post-tool-result turn can still be draining when the capture probe exits (#380)
27
+ - **A tool-first OpenAI Responses turn now replays its assistant text and tool calls in the recorded order.** Follow-up to #380. `collapseOpenAISSE`'s Responses-API `response.output_text.delta` handler accumulated `content += parsed.delta` but never pushed a text order-atom, so `buildOrderedBlocks` returned `undefined` for any Responses stream. A Responses turn whose `function_call` arrives **before** its `output_text` therefore collapsed to a fixture with no `blocks`, and because the Responses replay path consumes `blocks`, replay silently lost the tool-before-text ordering. The handler now pushes `{ kind: "text", text: parsed.delta }` for each non-empty delta — mirroring the Chat-Completions path — so a mixed text-and-tool Responses turn carries an ordered `blocks` array and replays in the sequence it was recorded (#382)
28
+ - **A Gemini Live turn that both speaks and calls a function is now expressible over the Live protocol, and an audio turn keeps its companions.** The Live handler's audio branch emitted a single `serverContent` frame (audio `inlineData` + `turnComplete: true`) and returned, silently dropping the `toolCalls` and text `content` that `AudioResponse` documents as preserved. Because `serverContent` and `toolCall` are alternatives of one `LiveServerMessage` union (not sibling parts of a single list as on HTTP `generateContent`), a speak-and-call turn is now emitted as separate messages in the order the live provider was observed to use: a `serverContent` (`modelTurn.parts` = audio first, then the text companion) strictly **before** the `toolCall` (`functionCalls`), then a final `serverContent{ turnComplete: true }`. The assistant entry pushed to conversation history now records the recorded text `content` (instead of the literal `"[audio]"`) and the tool calls, with tool-call ids resolved once so the wire message and history agree. An audio-only turn (no `toolCalls`) is unchanged except that it now includes its text companion part when the fixture carries one. Not handled: `AudioResponse.reasoning` — this handler emits no thought channel in any branch, so replaying reasoning from the audio branch alone is deliberately left out as a separate gap (#378)
29
+ - **The CLI installs its `SIGINT` / `SIGTERM` handlers before announcing readiness, so a supervisor that shuts the server down the instant it starts no longer kills it ungracefully.** Previously the CLI logged `aimock server listening on <url>` and only then registered the signal handlers. Pipe writes are synchronous on Linux, so a supervisor reacting to that readiness line could deliver `SIGTERM` while the process was still mid-statement, in the window before the handler existed; the signal reached Node's default disposition, which re-raises it, and the process died with a null exit code without running its own shutdown (closing the file watcher and the server) — most visible under container / process supervisors. Both entrypoints (`cli.ts` and `aimock-cli.ts`) now register the handlers first and log readiness last, closing that race (observed on linux/node20 by freezing the child at the announcement: 55/60 iterations died with `code=null signal=SIGTERM` before the change, 0/60 after). The handlers are installed once the server is already listening, so a signal delivered during earlier startup — strictly before readiness — remains outside their scope (#374)
30
+
5
31
  ## [1.38.0] - 2026-08-03
6
32
 
7
33
  ### Added
package/README.md CHANGED
@@ -1,7 +1,28 @@
1
- # aimock [![Unit Tests](https://github.com/CopilotKit/aimock/actions/workflows/test-unit.yml/badge.svg)](https://github.com/CopilotKit/aimock/actions/workflows/test-unit.yml) [![Drift Tests](https://github.com/CopilotKit/aimock/actions/workflows/test-drift.yml/badge.svg)](https://github.com/CopilotKit/aimock/actions/workflows/test-drift.yml) [![npm version](https://img.shields.io/npm/v/@copilotkit/aimock)](https://www.npmjs.com/package/@copilotkit/aimock)
1
+ <div align="center">
2
2
 
3
+ # aimock
3
4
 
4
- Mock infrastructure for AI application testing — LLM APIs, image generation, image editing, text-to-speech, transcription, audio translation, audio generation, video generation, embeddings, MCP tools, A2A agents, AG-UI event streams, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.
5
+ **Mock infrastructure for AI application testing — point your SDK at one local port and every provider, protocol, and service answers deterministically.**
6
+
7
+ [**Quick start**](#quick-start) · [**The suite**](#the-aimock-suite) · [**Record & replay**](https://aimock.copilotkit.dev/record-replay) · [**Docs**](https://aimock.copilotkit.dev/docs)
8
+
9
+ [![npm](https://img.shields.io/npm/v/@copilotkit/aimock.svg?label=%40copilotkit%2Faimock)](https://www.npmjs.com/package/@copilotkit/aimock)
10
+ [![Unit Tests](https://github.com/CopilotKit/aimock/actions/workflows/test-unit.yml/badge.svg)](https://github.com/CopilotKit/aimock/actions/workflows/test-unit.yml)
11
+ [![Drift Tests](https://github.com/CopilotKit/aimock/actions/workflows/test-drift.yml/badge.svg)](https://github.com/CopilotKit/aimock/actions/workflows/test-drift.yml)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
13
+
14
+ </div>
15
+
16
+
17
+ <div align="center">
18
+
19
+ One package, one port, zero dependencies. LLM APIs, image generation and
20
+ editing, text-to-speech, transcription, audio translation and generation, video
21
+ generation, embeddings, MCP tools, A2A agents, AG-UI event streams, vector
22
+ databases, search, rerank, and moderation — no keys, no network, no surprise
23
+ bills.
24
+
25
+ </div>
5
26
 
6
27
  ## Quick Start
7
28
 
@@ -82,7 +82,8 @@ function makeRunFinished(started, finishOpts) {
82
82
  threadId: started.threadId,
83
83
  runId: started.runId,
84
84
  ...finishOpts?.result !== void 0 ? { result: finishOpts.result } : {},
85
- ...finishOpts?.outcome !== void 0 ? { outcome: finishOpts.outcome } : {}
85
+ ...finishOpts?.outcome !== void 0 ? { outcome: finishOpts.outcome } : {},
86
+ ...finishOpts?.usage !== void 0 ? { usage: finishOpts.usage } : {}
86
87
  };
87
88
  }
88
89
  /**
@@ -108,7 +109,7 @@ function buildTextResponse(text, opts) {
108
109
  type: "TEXT_MESSAGE_END",
109
110
  messageId
110
111
  },
111
- makeRunFinished(started)
112
+ makeRunFinished(started, { usage: opts?.usage })
112
113
  ];
113
114
  }
114
115
  /**
@@ -125,7 +126,7 @@ function buildTextChunkResponse(text, opts) {
125
126
  role: "assistant",
126
127
  delta: text
127
128
  },
128
- makeRunFinished(started)
129
+ makeRunFinished(started, { usage: opts?.usage })
129
130
  ];
130
131
  }
131
132
  /**
@@ -159,7 +160,7 @@ function buildToolCallResponse(toolName, args, opts) {
159
160
  content: opts.result,
160
161
  role: "tool"
161
162
  });
162
- events.push(makeRunFinished(started));
163
+ events.push(makeRunFinished(started, { usage: opts?.usage }));
163
164
  return events;
164
165
  }
165
166
  /**
@@ -174,7 +175,7 @@ function buildStateUpdate(snapshot, opts) {
174
175
  type: "STATE_SNAPSHOT",
175
176
  snapshot
176
177
  },
177
- makeRunFinished(started)
178
+ makeRunFinished(started, { usage: opts?.usage })
178
179
  ];
179
180
  }
180
181
  /**
@@ -189,7 +190,7 @@ function buildStateDelta(patches, opts) {
189
190
  type: "STATE_DELTA",
190
191
  delta: patches
191
192
  },
192
- makeRunFinished(started)
193
+ makeRunFinished(started, { usage: opts?.usage })
193
194
  ];
194
195
  }
195
196
  /**
@@ -204,7 +205,7 @@ function buildMessagesSnapshot(messages, opts) {
204
205
  type: "MESSAGES_SNAPSHOT",
205
206
  messages
206
207
  },
207
- makeRunFinished(started)
208
+ makeRunFinished(started, { usage: opts?.usage })
208
209
  ];
209
210
  }
210
211
  /**
@@ -239,7 +240,7 @@ function buildReasoningResponse(text, opts) {
239
240
  type: "REASONING_END",
240
241
  messageId
241
242
  },
242
- makeRunFinished(started)
243
+ makeRunFinished(started, { usage: opts?.usage })
243
244
  ];
244
245
  }
245
246
  /**
@@ -257,7 +258,7 @@ function buildActivityResponse(messageId, activityType, content, opts) {
257
258
  content,
258
259
  replace: true
259
260
  },
260
- makeRunFinished(started)
261
+ makeRunFinished(started, { usage: opts?.usage })
261
262
  ];
262
263
  }
263
264
  /**
@@ -268,7 +269,8 @@ function buildErrorResponse(message, code, opts) {
268
269
  return [makeRunStarted(opts), {
269
270
  type: "RUN_ERROR",
270
271
  message,
271
- ...code !== void 0 ? { code } : {}
272
+ ...code !== void 0 ? { code } : {},
273
+ ...opts?.usage !== void 0 ? { usage: opts.usage } : {}
272
274
  }];
273
275
  }
274
276
  /**
@@ -303,7 +305,7 @@ function buildStepWithText(stepName, text, opts) {
303
305
  type: "STEP_FINISHED",
304
306
  stepName
305
307
  },
306
- makeRunFinished(started)
308
+ makeRunFinished(started, { usage: opts?.usage })
307
309
  ];
308
310
  }
309
311
  /**
@@ -319,7 +321,7 @@ function buildCompositeResponse(builderOutputs, opts) {
319
321
  return [
320
322
  started,
321
323
  ...inner,
322
- ...hasError ? [] : [makeRunFinished(started)]
324
+ ...hasError ? [] : [makeRunFinished(started, { usage: opts?.usage })]
323
325
  ];
324
326
  }
325
327
  /**
@@ -336,7 +338,7 @@ function buildActivityDelta(messageId, activityType, patch, opts) {
336
338
  activityType,
337
339
  patch
338
340
  },
339
- makeRunFinished(started)
341
+ makeRunFinished(started, { usage: opts?.usage })
340
342
  ];
341
343
  }
342
344
  /**
@@ -354,7 +356,7 @@ function buildToolCallChunk(delta, opts) {
354
356
  ...opts?.parentMessageId !== void 0 ? { parentMessageId: opts.parentMessageId } : {},
355
357
  delta
356
358
  },
357
- makeRunFinished(started)
359
+ makeRunFinished(started, { usage: opts?.usage })
358
360
  ];
359
361
  }
360
362
  /**
@@ -370,7 +372,7 @@ function buildRawEvent(event, source, opts) {
370
372
  event,
371
373
  ...source !== void 0 ? { source } : {}
372
374
  },
373
- makeRunFinished(started)
375
+ makeRunFinished(started, { usage: opts?.usage })
374
376
  ];
375
377
  }
376
378
  /**
@@ -386,7 +388,7 @@ function buildCustomEvent(name, value, opts) {
386
388
  name,
387
389
  value
388
390
  },
389
- makeRunFinished(started)
391
+ makeRunFinished(started, { usage: opts?.usage })
390
392
  ];
391
393
  }
392
394
  /**
@@ -402,7 +404,7 @@ function buildReasoningChunk(delta, opts) {
402
404
  ...opts?.messageId !== void 0 ? { messageId: opts.messageId } : {},
403
405
  delta
404
406
  },
405
- makeRunFinished(started)
407
+ makeRunFinished(started, { usage: opts?.usage })
406
408
  ];
407
409
  }
408
410
  /**
@@ -419,7 +421,7 @@ function buildReasoningEncryptedValue(subtype, entityId, encryptedValue, opts) {
419
421
  entityId,
420
422
  encryptedValue
421
423
  },
422
- makeRunFinished(started)
424
+ makeRunFinished(started, { usage: opts?.usage })
423
425
  ];
424
426
  }
425
427
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"agui-handler.cjs","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type { Logger } from \"./logger.js\";\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n * Walks structured content arrays (e.g. `[{type:\"text\", text:\"...\"}, {type:\"document\", ...}]`)\n * and joins their text parts. Returns `\"\"` when no user message is present or has no text.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role !== \"user\") continue;\n const text = extractTextFromContent(msg.content);\n if (text) return text;\n }\n return \"\";\n}\n\nfunction extractTextFromContent(content: AGUIMessage[\"content\"]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const part of content) {\n if (\n part &&\n typeof part === \"object\" &&\n part.type === \"text\" &&\n typeof part.text === \"string\" &&\n part.text\n ) {\n parts.push(part.text);\n }\n }\n return parts.join(\" \").trim();\n}\n\n/**\n * Return the absolute last message if it has role \"tool\", otherwise null.\n */\nexport function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null {\n if (!input.messages || input.messages.length === 0) return null;\n const last = input.messages[input.messages.length - 1];\n return last.role === \"tool\" ? last : null;\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolCallId !== undefined) {\n const lastMsg = input.messages?.[input.messages.length - 1];\n if (!lastMsg || lastMsg.role !== \"tool\" || lastMsg.toolCallId !== match.toolCallId) {\n return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [started, ...inner, ...(hasError ? [] : [makeRunFinished(started)])];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal; logger?: Logger },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n const msg = (err as Error).message;\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed (serialization):\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed (serialization):\", msg);\n }\n } else if (err instanceof Error) {\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", err.message);\n } else {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n } else {\n const msg = String(err);\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed:\", msg);\n }\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agui-handler.cjs","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type { Logger } from \"./logger.js\";\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUITokenUsage,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n * Walks structured content arrays (e.g. `[{type:\"text\", text:\"...\"}, {type:\"document\", ...}]`)\n * and joins their text parts. Returns `\"\"` when no user message is present or has no text.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role !== \"user\") continue;\n const text = extractTextFromContent(msg.content);\n if (text) return text;\n }\n return \"\";\n}\n\nfunction extractTextFromContent(content: AGUIMessage[\"content\"]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const part of content) {\n if (\n part &&\n typeof part === \"object\" &&\n part.type === \"text\" &&\n typeof part.text === \"string\" &&\n part.text\n ) {\n parts.push(part.text);\n }\n }\n return parts.join(\" \").trim();\n}\n\n/**\n * Return the absolute last message if it has role \"tool\", otherwise null.\n */\nexport function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null {\n if (!input.messages || input.messages.length === 0) return null;\n const last = input.messages[input.messages.length - 1];\n return last.role === \"tool\" ? last : null;\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolCallId !== undefined) {\n const lastMsg = input.messages?.[input.messages.length - 1];\n if (!lastMsg || lastMsg.role !== \"tool\" || lastMsg.toolCallId !== match.toolCallId) {\n return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n /**\n * Token usage to attach to the terminal RUN_FINISHED / RUN_ERROR event.\n * Optional and never synthesized: aimock does not estimate token counts\n * from fixture content, so `usage` is emitted only when a caller supplies\n * it explicitly (same policy as the Bedrock/Cohere/Gemini usage overrides).\n */\n usage?: AGUITokenUsage[];\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown; usage?: AGUITokenUsage[] },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n ...(finishOpts?.usage !== undefined ? { usage: finishOpts.usage } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started, { usage: opts?.usage }));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n ...(opts?.usage !== undefined ? { usage: opts.usage } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [\n started,\n ...inner,\n ...(hasError ? [] : [makeRunFinished(started, { usage: opts?.usage })]),\n ];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started, { usage: opts?.usage }),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal; logger?: Logger },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n const msg = (err as Error).message;\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed (serialization):\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed (serialization):\", msg);\n }\n } else if (err instanceof Error) {\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", err.message);\n } else {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n } else {\n const msg = String(err);\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed:\", msg);\n }\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.cjs";
2
- import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput } from "./agui-types.cjs";
2
+ import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput, AGUITokenUsage } from "./agui-types.cjs";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/agui-handler.d.ts
@@ -29,6 +29,13 @@ interface AGUIBuildOpts {
29
29
  parentRunId?: string;
30
30
  /** For tool call builder: include a result event */
31
31
  result?: string;
32
+ /**
33
+ * Token usage to attach to the terminal RUN_FINISHED / RUN_ERROR event.
34
+ * Optional and never synthesized: aimock does not estimate token counts
35
+ * from fixture content, so `usage` is emitted only when a caller supplies
36
+ * it explicitly (same policy as the Bedrock/Cohere/Gemini usage overrides).
37
+ */
38
+ usage?: AGUITokenUsage[];
32
39
  }
33
40
  /**
34
41
  * Build a complete text message response sequence.
@@ -1 +1 @@
1
- {"version":3,"file":"agui-handler.d.cts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"agui-handler.d.cts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.js";
2
- import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput } from "./agui-types.js";
2
+ import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput, AGUITokenUsage } from "./agui-types.js";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/agui-handler.d.ts
@@ -29,6 +29,13 @@ interface AGUIBuildOpts {
29
29
  parentRunId?: string;
30
30
  /** For tool call builder: include a result event */
31
31
  result?: string;
32
+ /**
33
+ * Token usage to attach to the terminal RUN_FINISHED / RUN_ERROR event.
34
+ * Optional and never synthesized: aimock does not estimate token counts
35
+ * from fixture content, so `usage` is emitted only when a caller supplies
36
+ * it explicitly (same policy as the Bedrock/Cohere/Gemini usage overrides).
37
+ */
38
+ usage?: AGUITokenUsage[];
32
39
  }
33
40
  /**
34
41
  * Build a complete text message response sequence.
@@ -1 +1 @@
1
- {"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
@@ -81,7 +81,8 @@ function makeRunFinished(started, finishOpts) {
81
81
  threadId: started.threadId,
82
82
  runId: started.runId,
83
83
  ...finishOpts?.result !== void 0 ? { result: finishOpts.result } : {},
84
- ...finishOpts?.outcome !== void 0 ? { outcome: finishOpts.outcome } : {}
84
+ ...finishOpts?.outcome !== void 0 ? { outcome: finishOpts.outcome } : {},
85
+ ...finishOpts?.usage !== void 0 ? { usage: finishOpts.usage } : {}
85
86
  };
86
87
  }
87
88
  /**
@@ -107,7 +108,7 @@ function buildTextResponse(text, opts) {
107
108
  type: "TEXT_MESSAGE_END",
108
109
  messageId
109
110
  },
110
- makeRunFinished(started)
111
+ makeRunFinished(started, { usage: opts?.usage })
111
112
  ];
112
113
  }
113
114
  /**
@@ -124,7 +125,7 @@ function buildTextChunkResponse(text, opts) {
124
125
  role: "assistant",
125
126
  delta: text
126
127
  },
127
- makeRunFinished(started)
128
+ makeRunFinished(started, { usage: opts?.usage })
128
129
  ];
129
130
  }
130
131
  /**
@@ -158,7 +159,7 @@ function buildToolCallResponse(toolName, args, opts) {
158
159
  content: opts.result,
159
160
  role: "tool"
160
161
  });
161
- events.push(makeRunFinished(started));
162
+ events.push(makeRunFinished(started, { usage: opts?.usage }));
162
163
  return events;
163
164
  }
164
165
  /**
@@ -173,7 +174,7 @@ function buildStateUpdate(snapshot, opts) {
173
174
  type: "STATE_SNAPSHOT",
174
175
  snapshot
175
176
  },
176
- makeRunFinished(started)
177
+ makeRunFinished(started, { usage: opts?.usage })
177
178
  ];
178
179
  }
179
180
  /**
@@ -188,7 +189,7 @@ function buildStateDelta(patches, opts) {
188
189
  type: "STATE_DELTA",
189
190
  delta: patches
190
191
  },
191
- makeRunFinished(started)
192
+ makeRunFinished(started, { usage: opts?.usage })
192
193
  ];
193
194
  }
194
195
  /**
@@ -203,7 +204,7 @@ function buildMessagesSnapshot(messages, opts) {
203
204
  type: "MESSAGES_SNAPSHOT",
204
205
  messages
205
206
  },
206
- makeRunFinished(started)
207
+ makeRunFinished(started, { usage: opts?.usage })
207
208
  ];
208
209
  }
209
210
  /**
@@ -238,7 +239,7 @@ function buildReasoningResponse(text, opts) {
238
239
  type: "REASONING_END",
239
240
  messageId
240
241
  },
241
- makeRunFinished(started)
242
+ makeRunFinished(started, { usage: opts?.usage })
242
243
  ];
243
244
  }
244
245
  /**
@@ -256,7 +257,7 @@ function buildActivityResponse(messageId, activityType, content, opts) {
256
257
  content,
257
258
  replace: true
258
259
  },
259
- makeRunFinished(started)
260
+ makeRunFinished(started, { usage: opts?.usage })
260
261
  ];
261
262
  }
262
263
  /**
@@ -267,7 +268,8 @@ function buildErrorResponse(message, code, opts) {
267
268
  return [makeRunStarted(opts), {
268
269
  type: "RUN_ERROR",
269
270
  message,
270
- ...code !== void 0 ? { code } : {}
271
+ ...code !== void 0 ? { code } : {},
272
+ ...opts?.usage !== void 0 ? { usage: opts.usage } : {}
271
273
  }];
272
274
  }
273
275
  /**
@@ -302,7 +304,7 @@ function buildStepWithText(stepName, text, opts) {
302
304
  type: "STEP_FINISHED",
303
305
  stepName
304
306
  },
305
- makeRunFinished(started)
307
+ makeRunFinished(started, { usage: opts?.usage })
306
308
  ];
307
309
  }
308
310
  /**
@@ -318,7 +320,7 @@ function buildCompositeResponse(builderOutputs, opts) {
318
320
  return [
319
321
  started,
320
322
  ...inner,
321
- ...hasError ? [] : [makeRunFinished(started)]
323
+ ...hasError ? [] : [makeRunFinished(started, { usage: opts?.usage })]
322
324
  ];
323
325
  }
324
326
  /**
@@ -335,7 +337,7 @@ function buildActivityDelta(messageId, activityType, patch, opts) {
335
337
  activityType,
336
338
  patch
337
339
  },
338
- makeRunFinished(started)
340
+ makeRunFinished(started, { usage: opts?.usage })
339
341
  ];
340
342
  }
341
343
  /**
@@ -353,7 +355,7 @@ function buildToolCallChunk(delta, opts) {
353
355
  ...opts?.parentMessageId !== void 0 ? { parentMessageId: opts.parentMessageId } : {},
354
356
  delta
355
357
  },
356
- makeRunFinished(started)
358
+ makeRunFinished(started, { usage: opts?.usage })
357
359
  ];
358
360
  }
359
361
  /**
@@ -369,7 +371,7 @@ function buildRawEvent(event, source, opts) {
369
371
  event,
370
372
  ...source !== void 0 ? { source } : {}
371
373
  },
372
- makeRunFinished(started)
374
+ makeRunFinished(started, { usage: opts?.usage })
373
375
  ];
374
376
  }
375
377
  /**
@@ -385,7 +387,7 @@ function buildCustomEvent(name, value, opts) {
385
387
  name,
386
388
  value
387
389
  },
388
- makeRunFinished(started)
390
+ makeRunFinished(started, { usage: opts?.usage })
389
391
  ];
390
392
  }
391
393
  /**
@@ -401,7 +403,7 @@ function buildReasoningChunk(delta, opts) {
401
403
  ...opts?.messageId !== void 0 ? { messageId: opts.messageId } : {},
402
404
  delta
403
405
  },
404
- makeRunFinished(started)
406
+ makeRunFinished(started, { usage: opts?.usage })
405
407
  ];
406
408
  }
407
409
  /**
@@ -418,7 +420,7 @@ function buildReasoningEncryptedValue(subtype, entityId, encryptedValue, opts) {
418
420
  entityId,
419
421
  encryptedValue
420
422
  },
421
- makeRunFinished(started)
423
+ makeRunFinished(started, { usage: opts?.usage })
422
424
  ];
423
425
  }
424
426
  /**