@copilotkit/aimock 1.38.0 → 1.40.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +56 -0
- package/README.md +24 -2
- package/dist/agui-handler.cjs +20 -18
- package/dist/agui-handler.cjs.map +1 -1
- package/dist/agui-handler.d.cts +8 -1
- package/dist/agui-handler.d.cts.map +1 -1
- package/dist/agui-handler.d.ts +8 -1
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/agui-handler.js +20 -18
- package/dist/agui-handler.js.map +1 -1
- package/dist/agui-stub.d.cts +2 -2
- package/dist/agui-stub.d.ts +2 -2
- package/dist/agui-types.d.cts +84 -3
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +84 -3
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +1 -1
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.js +1 -1
- package/dist/aimock-cli.js.map +1 -1
- package/dist/cli.cjs +10 -10
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +10 -10
- package/dist/cli.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/helpers.cjs +8 -4
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +8 -4
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/llmock.cjs +23 -9
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +22 -0
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +22 -0
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +25 -11
- package/dist/llmock.js.map +1 -1
- package/dist/openrouter-chat.cjs +41 -0
- package/dist/openrouter-chat.cjs.map +1 -1
- package/dist/openrouter-chat.js +41 -0
- package/dist/openrouter-chat.js.map +1 -1
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +77 -8
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +77 -8
- package/dist/recorder.js.map +1 -1
- package/dist/server.cjs +80 -17
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +6 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +6 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +80 -18
- package/dist/server.js.map +1 -1
- package/dist/stream-collapse.cjs +97 -6
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +16 -0
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +16 -0
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +97 -6
- package/dist/stream-collapse.js.map +1 -1
- package/dist/types.d.cts +22 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +22 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/ws-gemini-live.cjs +41 -6
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.js +41 -6
- package/dist/ws-gemini-live.js.map +1 -1
- package/package.json +5 -3
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"source": {
|
|
10
10
|
"source": "npm",
|
|
11
11
|
"package": "@copilotkit/aimock",
|
|
12
|
-
"version": "^1.
|
|
12
|
+
"version": "^1.40.0"
|
|
13
13
|
},
|
|
14
14
|
"description": "Fixture authoring skill for @copilotkit/aimock — LLM, multimedia (image/TTS/transcription/video), MCP, A2A, AG-UI, vector, embeddings, structured output, sequential responses, streaming physics, record/replay, agent loop patterns, and debugging"
|
|
15
15
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.40.0] - 2026-09-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`GET /__aimock/fixtures` — read-only fixture-count introspection.** The control API could already add fixtures (`POST`) and clear them (`DELETE`), but offered no way to ASK what was loaded, so a CI job or test harness wanting to confirm its tape was registered had to send a probe chat request and infer the answer from the reply. `GET /__aimock/fixtures` returns `{ count }`. It sits behind the same `AIMOCK_API_KEYS` boundary and CORS headers as every other `/__aimock/*` route, and serializes the count ONLY — fixtures carry predicate closures, so none of their contents cross the wire (#407)
|
|
10
|
+
|
|
11
|
+
- **AG-UI subagent lifecycle events, and `subagentRunId` attribution mirrored where canonical declares it.** Upstream `@ag-ui/core` added `SUBAGENT_STARTED` / `SUBAGENT_FINISHED` / `SUBAGENT_ERROR` and threaded an optional `subagentRunId` through the events a subagent can emit; aimock's AG-UI types carried none of it. The three literals now join `AGUIEventType` and the `AGUIEvent` union, backed by `AGUISubagentStartedEvent` (required `subagentRunId` and `name`, optional `description` / `parentSubagentRunId`, plus `parentToolCallId` / `parentMessageId` so an agents-as-tools subagent can be correlated to the call that spawned it without inspecting `rawEvent.metadata`), `AGUISubagentFinishedEvent` (optional `result`, plus an `AGUISubagentFinishedOutcome` of `{ type: "success" }` or `{ type: "suspended"; interruptIds?: string[] }` — `AGUIRunFinishedOutcome` one level down, where absent still means success, `interruptIds` names only the run-level interrupts that subagent directly owns, and unlike `RUN_FINISHED.outcome` the field postdates the valueless-field cleanup so it never tolerates `null`), and `AGUISubagentErrorEvent` (`message`, optional `code`). `subagentRunId` itself is declared **per event, not on a shared base type**, because that is how canonical declares it: optional on 24 event interfaces, required on the three subagent events, and deliberately absent from `RUN_STARTED` / `RUN_FINISHED` / `RUN_ERROR`, `MESSAGES_SNAPSHOT` and the deprecated `THINKING_*` family. Putting it once on `AGUIBaseEvent` would have cleared the drift report while granting the field to events canonical does not give it. The same optional field is mirrored onto `AGUIMessage` and `AGUIInterrupt`. Canonical `types.ts` declares it INDEPENDENTLY on `BaseMessageSchema`, `ToolMessageSchema`, `ActivityMessageSchema` and `ReasoningMessageSchema` — the latter three are standalone `z.object`s that do NOT extend the base, so there is no inheritance carrying the field to them — and on `InterruptSchema`; aimock deliberately flattens the canonical message union into one `role`-discriminated `AGUIMessage`, which is why two edits cover all four message declarations. So a replayed message or approval request keeps the attribution that lets a client group it under the subagent that produced it instead of reading as root-raised. All four new names — the three event interfaces and `AGUISubagentFinishedOutcome` — are exported from both the package root and the `agui-stub` entrypoint, guarded by a public-surface test that fails whenever any `agui-types.ts` type is missing from either barrel. The `AGUIMessage` / `AGUIInterrupt` mirroring is NOT guarded: the existing drift suite walks `*EventSchema` declarations only and cannot see the non-event schemas, so nothing fails if that field is later dropped — closing that gap is deferred to the drift-harness rewrite rather than bolted on here. **Scope: this is a type surface only.** Unlike 1.39.0's `AGUITokenUsage`, which was reachable through `AGUIBuildOpts`, no RUNTIME code CONSUMES these types — they are exported and guarded, but `agui-handler.ts` gained no builder and no build option, so aimock can TYPE a subagent event but cannot yet EMIT one. Every added field is optional or sits on a new type, so existing fixtures and callers are byte-identical (#391)
|
|
12
|
+
|
|
13
|
+
- **Recorded OpenAI/OpenRouter token usage — including OpenRouter `usage.cost` (#368).** Collapsing a streaming OpenAI-compatible chat completion previously dropped the final usage frame (the `chat.completion.chunk` with an empty `choices` array and a populated `usage`), because the collapser skipped every chunk without choices. A recorded fixture therefore kept content / reasoning / tool calls / timings but no token counts at all, and replay could only ever serve the `ceil(length / 4)` estimate or a hand-authored `response.usage` override. OpenRouter's provider-reported `cost` was never captured, so an app that bills from real provider cost could not e2e-test its wallet/ledger path from a tape (the same gap #269 closed for fal's `x-fal-billable-units`).
|
|
14
|
+
- **Record:** `collapseOpenAISSE` now captures the last non-null `usage` object on the stream (`CollapseResult.usage`), and the non-streaming recorder captures the completion envelope's `usage`.
|
|
15
|
+
- **Persist:** the recorder writes it to the fixture's `response.usage` via `sanitizeRecordedUsage`, which keeps each field by its documented shape: the numeric token scalars (`cost` among them) and any unmodelled scalar extra such as OpenRouter's `native_tokens_*`, but only when finite; the `cost_details` / `prompt_tokens_details` / `completion_tokens_details` objects, keeping their finite-numeric inner scalars; and the `is_byok` boolean. What it drops is anything that fits none of those shapes — an unmodelled extra that is not a finite number, or a modelled field of the wrong type — so a recorded fixture always passes the load-time validator (a separate stage in `fixture-loader.ts` that type-checks each documented field per its type and independently rejects, for example, a non-numeric `usage` scalar in a hand-authored fixture). **Back-compatible:** a stream that reported no usage records no `usage` key and the fixture stays byte-identical to before.
|
|
16
|
+
- **Replay:** recorded counts win over estimation (existing `resolveUsage` precedence), and OpenRouter-shaped responses emit the recorded `cost` / breakdowns on both the final streaming usage chunk and the non-streaming envelope. `ResponseOverrides.usage` accepts forward-compat extra keys, and OpenRouter shaping now passes any such key through verbatim rather than dropping it.
|
|
17
|
+
- **Note:** capturing cost requires the recorded request to actually elicit a usage frame — `stream_options: { include_usage: true }` on OpenAI-compatible streams (OpenRouter sends it regardless), or a non-streaming response. Plain OpenAI (`/v1/...`) replays continue to emit token counts only; `cost` is OpenRouter-shaped output.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **The AG-UI drift CI lane runs every `agui-*.drift.ts` guard, not one hardcoded file.** The `agui-schema-drift` job in `.github/workflows/test-drift.yml` and `runAgUiDriftTests` in `scripts/drift-report-collector.ts` both invoked `npx vitest run src/__tests__/drift/agui-schema.drift.ts`. That positional argument is a vitest FILENAME FILTER (substring match on the test file path), not a single file, so both now pass the path prefix `src/__tests__/drift/agui-` and every AG-UI drift file runs — one today, and any future guard automatically — under a documented naming contract: an AG-UI drift guard MUST be named `src/__tests__/drift/agui-<something>.drift.ts` to land in this lane. The workflow's `paths:` trigger widens to `src/__tests__/drift/agui-*.drift.ts` to match. `vitest.config.drift.ts` already scopes `include` to `src/__tests__/drift/**/*.drift.ts`, so the prefix cannot pull in `*.test.ts` helpers from the same directory, and the lane still needs no provider API keys — these files read `src/agui-types.ts` and the cloned canonical `../ag-ui` checkout only, unlike the credit-burning `drift` leg. The collector retains the single filename as report metadata (the file a human opens when drift is reported), no longer as a run target.
|
|
22
|
+
- `aimock-pytest` 0.5.3 now defaults to `@copilotkit/aimock` 1.39.0.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **`X-AIMock-Strict` is parsed case-insensitively and tolerates surrounding whitespace.** `resolveStrictMode` compared the raw header value against `"true"` / `"false"` / `"1"` / `"0"` literally, so the variants clients, proxies and shell snippets actually emit — `True`, `TRUE`, `" true "` — matched nothing and fell through to the server default. A caller on a `--strict false` server asking for `X-AIMock-Strict: True` kept getting `404` instead of `503`, and on a `--strict true` server `X-AIMock-Strict: False` stayed strict; the same header gates reasoning suppression, so the mismatch could also surface as a flaky reasoning assertion. The value is now trimmed and lower-cased before comparison. Unrecognised values still fall back to the server default, and trimming is end-only — `"tr ue"` is still not a match (#408)
|
|
27
|
+
|
|
28
|
+
- **A non-WebSocket upgrade probe no longer 404s, and its request body survives on every supported Node.** Node fires `"upgrade"` rather than `"request"` for ANY `Connection: Upgrade` header, whatever protocol is named, so langchain4j's OkHttp client — which speculatively sends `Upgrade: h2c` on plain requests to probe for HTTP/2 cleartext — had `GET /api/tags` and `POST /api/chat` land in the WebSocket-only handler and take an unconditional `404`. Such a request is now replayed onto the socket with `Upgrade`/`Connection` stripped and re-parsed as an ordinary request. **Where the body lives depends on the Node version, and both are replayed:** Node <= 24 detaches the parser at `"upgrade"` and leaves body bytes in `head`, while Node >= 26 parses them onto `req` and leaves `head` empty — with the bytes on neither the socket nor `head`, so a `head`-only replay left the re-parsed request waiting on a `Content-Length` worth of bytes that never arrived and the connection hung open instead of answering. Real WebSocket upgrades are untouched (the guard matches the `Upgrade` token case-insensitively, so `websocket` and `WebSocket` both still get `101`), the replayed request still passes the `AIMOCK_API_KEYS` boundary rather than bypassing it, and keep-alive reuse of the same socket afterwards still works. The unit and pytest CI matrices gain Node 26, which is inside the declared `engines` range (`>=20.15.0`) and was previously untested — the gap that let the body-loss case pass CI (#410)
|
|
29
|
+
- **The AG-UI drift collector no longer reports "clean" for a failure it could not read.** `collectAgUiDriftEntries` recognizes three failure-message shapes; any FAILED assertion matching none of them was dropped outright — no entry, no counter, no warning — and a FAILED assertion carrying no message at all was skipped before it was even looked at. Both paths produced zero entries, exit 0 and `conclusion: "clean"`, so a genuinely failing `agui-schema.drift.ts` assertion (`should parse aimock event types` fails with a bare `expect` message that matches no shape) certified AG-UI as drift-free. Every such failure now takes the collector's EXISTING quarantine lane — held for review at exit 5, the same "never silently swallowed" contract the HTTP leg already used — per-assertion and unconditional, so an unreadable failure survives a mixed run in which other failures DID parse. Separately, a ZERO-exit AG-UI run whose stdout is not vitest JSON now THROWS instead of returning an empty (`"no failures"`) result, matching what the HTTP twin `runDriftTests()` has always done on the same condition: the two legs no longer disagree about whether garbage output is clean. Drift-harness tooling, not runtime behavior — no published surface changes (#391)
|
|
30
|
+
|
|
31
|
+
- **The AG-UI drift suite's canonical-schema parser no longer drops the field declared after a trailing comment.** `extractExtendFields` stripped whole-line comments only (`/^\s*\/\/.*$/gm`). Upstream's `STATE_DELTA` declares `delta: z.array(z.any()), // JSON Patch (RFC 6902)`, and after the top-level comma split that trailing comment heads the NEXT entry, so the field-name match failed and the entry was discarded silently — which is why the drift report read canonical as declaring `subagentRunId` on 23 events rather than 24, and flagged `STATE_DELTA.subagentRunId` as aimock-only. Comments are now stripped wherever they appear; no canonical schema literal contains `//`, so the unconditional strip is safe. This is drift-harness tooling, not runtime behavior — no published surface changes (#391)
|
|
32
|
+
|
|
33
|
+
- **`openrouter` is no longer treated as an unknown SSE provider when recording.** `collapseStreamingResponse`'s provider switch had cases for `openai` / `azure` / `anthropic` / `gemini` / `cohere` / `bedrock` but none for `openrouter`, even though it is a first-class `RecordProviderKey` that the server sets on every `/api/v1/chat/completions` request. Recording a streaming OpenRouter completion therefore hit the `default` arm and logged `[stream-collapse] unknown SSE provider "openrouter", falling back to OpenAI SSE format` on **every** recorded stream. The collapse itself was already correct (the fallback is the OpenAI collapser, and OpenRouter speaks the OpenAI SSE wire format), so this is a log-noise/diagnostics fix with no behavior change — but the warning claimed aimock did not recognize a provider it ships first-class support for, which is actively misleading while debugging a recording.
|
|
34
|
+
|
|
35
|
+
## [1.39.0] - 2026-08-18
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **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)
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- `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.
|
|
44
|
+
- **`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.
|
|
45
|
+
- **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.
|
|
46
|
+
- `aimock-pytest`: `AIMockServer.reset()` and `.reset_fixtures()` now call `POST /__aimock/reset`. Both already performed a full reset, so the observable behavior is unchanged.
|
|
47
|
+
- **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.
|
|
48
|
+
|
|
49
|
+
### Deprecated
|
|
50
|
+
|
|
51
|
+
- `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.
|
|
52
|
+
- 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.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- **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)
|
|
57
|
+
- **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)
|
|
58
|
+
- **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)
|
|
59
|
+
- **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)
|
|
60
|
+
|
|
5
61
|
## [1.38.0] - 2026-08-03
|
|
6
62
|
|
|
7
63
|
### Added
|
package/README.md
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
+
# aimock
|
|
3
4
|
|
|
4
|
-
Mock infrastructure for AI application testing —
|
|
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
|
+
[](https://www.npmjs.com/package/@copilotkit/aimock)
|
|
10
|
+
[](https://github.com/CopilotKit/aimock/actions/workflows/test-unit.yml)
|
|
11
|
+
[](https://github.com/CopilotKit/aimock/actions/workflows/test-drift.yml)
|
|
12
|
+
[](./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
|
|
|
@@ -49,6 +70,7 @@ Run them all on one port with `npx @copilotkit/aimock --config aimock.json`, or
|
|
|
49
70
|
|
|
50
71
|
- **[Record & Replay](https://aimock.copilotkit.dev/record-replay)** — Proxy real APIs, save as fixtures, replay deterministically forever
|
|
51
72
|
- **Timing-aware recording and replay** — Recorded fixtures capture per-frame arrival timestamps; replay uses recorded timings for approximate timing reproduction based on recorded TTFT and inter-frame cadence (replay chunk count may differ from recording — TTFT and average pace are preserved, not per-token fidelity) with configurable `--replay-speed` multiplier
|
|
73
|
+
- **[Recorded token usage and cost](https://aimock.copilotkit.dev/record-replay)** — Recording captures the final usage frame of a streaming completion, so replayed fixtures serve real `prompt_tokens` / `completion_tokens` instead of a length estimate; OpenRouter's provider-reported `usage.cost` and its `cost_details` / `*_tokens_details` breakdowns are captured too, so an app that bills from real provider cost can e2e-test its wallet path from a tape
|
|
52
74
|
- **[Multi-turn Conversations](https://aimock.copilotkit.dev/multi-turn)** — Record and replay multi-turn traces with tool rounds; match distinct turns via `turnIndex`, `hasToolResult`, `toolCallId`, `toolResultContains` (gate on the tool-result payload), `sequenceIndex`, `systemMessage` (gate on host-supplied agent context), or custom predicates
|
|
53
75
|
- **[13 providers across 15 API surfaces](https://aimock.copilotkit.dev/docs)** — OpenAI Chat, OpenAI Responses, OpenAI Realtime (GA + Beta shim), Claude, Gemini REST, Gemini embedContent, Gemini Live, Gemini Interactions, Azure, Bedrock, Vertex AI, Ollama (chat + embeddings), Cohere (chat + embed), OpenRouter (chat + router failover), ElevenLabs TTS — full streaming support
|
|
54
76
|
- **Multimedia APIs** — [image generation](https://aimock.copilotkit.dev/images) (DALL-E, Imagen), [image editing](https://aimock.copilotkit.dev/images) (/v1/images/edits), [text-to-speech](https://aimock.copilotkit.dev/speech) (OpenAI + ElevenLabs), [audio transcription](https://aimock.copilotkit.dev/transcription), [audio translation](https://aimock.copilotkit.dev/transcription) (/v1/audio/translations), [video generation](https://aimock.copilotkit.dev/video), [OpenRouter video generation](https://aimock.copilotkit.dev/openrouter-video) (/api/v1/videos with async job lifecycle), [Google Veo video generation](https://aimock.copilotkit.dev/veo-video) (:predictLongRunning + /v1beta/operations async lifecycle), [Grok Imagine video generation](https://aimock.copilotkit.dev/grok-video) (/v1/videos/generations with async job lifecycle), [fal.ai](https://aimock.copilotkit.dev/fal-ai) (image / video / audio with queue lifecycle)
|
package/dist/agui-handler.cjs
CHANGED
|
@@ -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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"}
|
package/dist/agui-handler.d.cts
CHANGED
|
@@ -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":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"agui-handler.d.cts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/agui-handler.d.ts
CHANGED
|
@@ -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":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
|