Skip to content

chore(deps): update dependency @copilotkit/aimock to v1.47.0 - #2277

Merged
edelauna merged 2 commits into
mainfrom
renovate/copilotkit-aimock-1.x
Nov 8, 2026
Merged

edelauna merged 2 commits into
mainfrom
renovate/copilotkit-aimock-1.x

Conversation

@renovate

@renovate renovate Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
@copilotkit/aimock (source) 1.35.0 → 1.47.0 age confidence

Release Notes

CopilotKit/aimock (@​copilotkit/aimock)

v1.47.0

Compare Source

Added
  • Fixture citations serve sources on Responses, Chat Completions, Claude and Gemini (#​550, #​578)
  • Fixture files serve generated images on Gemini and OpenAI Responses (#​550, #​578)
  • Raw passthrough fixtures send provider SSE events or JSON exactly as written (#​580)
  • Opt-in nonStreamingTimingAllProviders delays non-streaming replies on every provider (#​579)
Fixed
  • Client disconnects stop and journal every LLM reply; Docker image on Node 22.23.4 (#​579, #​576)

v1.46.0

Compare Source

Added
  • Gemini model list/detail, Anthropic model detail, and token-count routes (#​542, #​551)
  • Opt-in policies: requiredHeaders, native authErrors, native modelCatalog (#​542, #​566, #​568)
  • Opt-in fixture nonStreamingTiming: true delays non-streaming OpenAI chat replies (#​545, #​567)
  • Anthropic/Bedrock cache usage kept in replay and record; Responses phase override (#​531, #​542)
Fixed
  • Ollama embed batches, AG-UI thread/run IDs, empty MCP reads, Anthropic aborts (#​533, #​553, #​557)

v1.45.1

Compare Source

Changed
  • OpenRouter Video: openai/sora-2 now returns OpenRouter's 400 removal error, not a job (#​520)
Fixed
  • MCP tools/list: a tool registered without inputSchema now lists {"type":"object"} (#​529)
  • MCP tools/list: a registered inputSchema with no type now gets "type": "object" (#​529)

v1.45.0

Compare Source

Every fixture, config and request that 1.44.0 accepted behaves the same by default. New behavior that would change those inputs is opt-in.

Added
  • Record live MCP servers into mcpFakes files and replay them offline: --mcp-record <mount>=<url> and --mcp-proxy-only <mount>=<url> (llmock bin and Docker image), llm.record.mcp with the opt-in llm.enableMcpRecording: true for aimock --config (without the opt-in, llm.record.mcp is ignored with a warning, as 1.44.0 ignored it), and MCPMock.enableRecording() / disableRecording() (#​509).
  • Recordings never contain headers and redact known secrets (AIMOCK_RECORD_SECRET_VALUES, AIMOCK_MCP_UPSTREAM_AUTH); a file is not written while a secret remains (#​509).
  • Recorded MCP fakes replay list order, progress and log notifications, and call timing (scaled by --replay-speed). The recorded mcpFakes keys (list, recorded, timing, notifications, durationMs) need 1.45.0 or later (#​509).
  • Per-test MCP fake report at GET /__aimock/mcp/fakes/report (#​509).
  • Vitest and Jest: fakesFor() and fakesReport() on a new AimockFakesHandle returned by useAimock(), and opt-in useAimock({ fakesReport: "warn" | "fail" }) (default "off"); Jest option testIdRoot. New exports assertFakesReport, AimockFakesReportError and AimockTestIdCollisionError (#​509).
  • aimock-pytest 0.7.0: fakes_for, fakes_report and assert_fakes_report (#​509), and AIMockServer opt-ins enable_misbehavior and responses_tools (#​508, #​511).
  • Workflow-target examples: a Mastra Workflow and a LangGraph JS graph call MCP fakes with no LLM (examples/mcp-workflow-targets), plus record and report proofs (#​509).
  • Model misbehavior faults (invalid tool arguments, schema violations, unknown tools, duplicate IDs, length stops, empty responses, refusals, content filtering, reasoning-only) across provider wires, with seeded rates, /__aimock/misbehavior runtime controls, journal evidence and the aimock_misbehavior_total metric. Off unless enabled with enableMisbehavior: true (programmatic, including useAimock), llmock --misbehavior / aimock validate --misbehavior, or aimock --misbehavior, or the config opt-in llm.enableMisbehavior: true (an llm.misbehavior key alone never enables it, as in 1.44.0). Invalid misbehavior settings throw the new MisbehaviorConfigError (#​508).
  • Namespaced function calls and custom tool calls on the OpenAI Responses API, over HTTP, SSE and WebSocket, plus match.toolNamespace (#​511). Like the fixture fields below, match.toolNamespace applies only with responsesTools: "extended"; in the default mode it is ignored, as in 1.44.0.
  • Responses namespaced and custom tool calls: with responsesTools: "extended" (CLI --responses-tools extended, also on aimock validate; config llm.responsesTools), tools inside namespace tools, custom tools and additional_tools / tool_search_output tools are visible to toolName, toolNamespace and predicates, custom tool rounds count for hasToolResult, toolCallId and turnIndex, and fixtures can answer with namespaced calls and customToolCalls / responsesBlocks. The default "legacy" keeps 1.44.0 behavior. New types: CustomToolCallMessage, ResponsesToolsMode (#​511).
  • Record mode keeps Responses namespaces and custom tool calls (customToolCalls, responsesBlocks, CollapseResult.customToolCalls) in streamed recordings when responsesTools: "extended" is set (#​513).
  • Strict tool arguments: with strictToolArguments (CLI --strict-tool-arguments, config llm.strictToolArguments), malformed tool-call argument strings are sent unchanged on string wires and return an explicit error on object wires. The default keeps 1.44.0 behavior (#​501).
  • Vertex and Bedrock modeled-contract comparisons for the misbehavior faults in the daily drift checks (#​508).
Fixed
  • MCP recording checks its config at start, redacts credentials in errors, fails loudly when the upstream dies mid-body (502 or a terminated stream, logged and journaled), and defaults aimock --config with record mounts to logLevel: "warn" (#​517).
  • Kept 1.44.0 default behavior for strict tool arguments, model misbehavior, Responses namespaced and custom tools, llm.record.mcp, fixture identity and the exported stream helpers, and made each new behavior opt-in (#​518).
  • Kept the published types compatible with 1.44.0: AimockHandle, Mountable and McpFakeAddOrigin keep their 1.44.0 shape, and every entry point type-checks with skipLibCheck: false (#​517).
  • Align Cohere streaming length-stop faults with captured provider framing (#​508).
  • Retain drift evidence across retries and for oversized records (#​510, #​512).
  • Classify claude-haiku-5-5 in the drift model registry (#​515).
  • Docs: dark-site font smoothing, consistent homepage comparison headings, the test-suite highlight, and the copy-button fallback (#​504, #​506, #​514).
  • Invalid opt-in values never stop startup: an invalid responsesTools warns once and runs "legacy", and a non-boolean llm.strictToolArguments, llm.enableMisbehavior or llm.enableMcpRecording warns once and stays off (#​518).

v1.44.0

Compare Source

Added
  • Script MCP tool answers and errors per scenario, including aimock-pytest 0.6.0 support.
  • Mock OpenAI Vector Stores, file batches and deterministic search (#​497).
  • Discover supported HTTP routes through the OpenAPI 3.1 catalog (#​451).
Fixed
  • Reject malformed requests and fixtures with clear validation errors (#​474).
  • Correct video status, browser PUT access, model classification and comparison docs.

v1.43.0

Compare Source

BREAKING — aimock -h is --help, not --host: aimock -h 0.0.0.0 exits 1 with Error: Unexpected argument '0.0.0.0'. This command does not take positional arguments. Migration: --host <string> (long form only). The llmock bin (the Docker ENTRYPOINT) keeps -h, --host (#​453).

Added
  • OpenAI GPT-Live mock, record and offline replay on GET /v1/live/sessions, with onLive fixtures (#​468)
  • Live sessions enforce message/audio/queue/lifetime limits; recordings sanitize credentials (#​468)
  • Live drift canaries for lifecycle, audio/transcript, delegation and usage, attributed to openai-live (#​468)
  • Chaos rateLimitRate / --chaos-ratelimit: deterministic 429 with Retry-After (#​449)
  • Chaos latencyMs / --chaos-latency now actually delays responses on every path (#​449)
  • OpenAI Files API mock — byte-exact uploads, create-purpose enum, CORS on faults (#​445)
  • OpenAI fine-tuning jobs mock — deterministic lifecycle, events, cursor pages (#​447)
  • OpenAI Batches API mock — create/list/retrieve/cancel with real output files (#​446)
  • X-Request-Id echoed or minted on every response; ?requestId= filters the journal (#​450)
  • aimock validate lints fixture files or directories offline, failing on broken files (#​453)
  • ElevenLabs Voice Design record/replay — design, save-as-voice, and voice slot management (#​452)
  • ElevenLabs Voice Design provenance block and strict-mode 503 coverage (#​454)
Changed
  • BREAKING: aimock -h is --help, matching aimock convert -h and aimock validate -h; the host override is --host only. The llmock bin (the Docker entrypoint) keeps its own -h, --host — see the note above (#​453)
  • aimock --config "", --port "" and --host "" are usage errors naming the option (#​453)
  • Realtime OpenAI-Beta: realtime=v1 now returns the real sunset rejection, not a session (#​461)
  • POST /v1/images/variations now replays the real removal 404; OpenAI deleted it (#​462)
  • ChaosAction gains "rateLimit" — an exhaustive switch over it needs a case (#​449)
  • applyChaosAsync() returns false | "handled" | "unwritable" instead of a bare boolean (#​449)
  • Journal headers now ALWAYS carry x-request-id — exact toEqual asserts break (#​450)
Deprecated
  • Synchronous applyChaos() warns once per process; it skips chaos latency. Use await applyChaosAsync(...) (#​449)
Fixed
  • Reasoning-first chat streams with content and tool calls carry the assistant role in the first chunk (#​470)
  • Journals and metrics reflect delivered vs interrupted responses; one-shot errors never double-deliver (#​466)
  • Nonstreaming OpenAI chat returns block text and tools; text-only blocks finish normally on every provider (#​467)
  • AG-UI drift reads generated 1.0 schemas; AGUIRunStartedEvent gains optional protocolVersion (#​469)
  • Drift reports list unverifiedSurfaces; offline Bedrock/Vertex checks no longer skip silently (#​460)
  • Drift docs match actual coverage; ElevenLabs drift separates vendor observations from fixture checks (#​465)
  • Chaos no longer treats committed headers as a dead response; only status-writing actions are skipped (#​449)
  • Chaos skip logs name what happened; aimock_chaos_triggered_total counts only written responses (#​449)
  • A request whose chaos latency was cancelled by client hang-up is no longer served or journalled (#​449)
  • Moderations echoes the request's model; default is now omni-moderation-latest (#​459)
  • Image endpoints default to gpt-image-1 — dall-e-2/dall-e-3 were removed (#​459)
  • AG-UI record/proxy forwards the caller's headers and raw body upstream; Accept is forced to SSE (#​455)
  • The AG-UI recorder refuses to write a fixture from a non-stream or empty 2xx upstream reply (#​455)
  • A MINTED x-request-id is no longer forwarded upstream in record/proxy mode (#​450)

v1.42.1

Compare Source

Fixed
  • Identify reasoning-first tool streams as assistant messages for MCP Apps (#​470).

v1.42.0

Compare Source

Added
  • Filtering and pagination on GET /__aimock/journal, with an X-Total-Count header (#​435)
  • Runtime chaos control at /__aimock/chaos, and a ?include=fixtures fixture dump (#​435)
Fixed
  • Every wrapper path journals now — exact-length or X-Total-Count asserts see more (#​441)
  • Moderation, rerank and search honour strict mode; non-object JSON bodies now 400 (#​440, #​438)
  • POST /__aimock/error validates its payload; quoted multipart boundaries parse (#​434)

v1.41.0

Compare Source

Added
  • BytePlus Ark (Seedance) video record/replay — submit, poll, retrieve raw Ark tasks (#​424)
  • New --provider-byteplus flag to proxy BytePlus Ark to an upstream base (#​424)
Changed
  • /api/v3 chat and image requests are attributed to the byteplus provider (#​424)
  • aimock-pytest now defaults to @copilotkit/aimock 1.41.0.
Fixed
  • aimock now fails at startup if a BytePlus base already ends in /api/v3 (#​424)

v1.40.0

Compare Source

Added
  • 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)

  • 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.objects 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)

  • 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).

    • 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.
    • 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.
    • 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.
    • 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.
Changed
  • 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.
  • aimock-pytest 0.5.3 now defaults to @copilotkit/aimock 1.39.0.
Fixed
  • 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)

  • 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)

  • 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)

  • 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)

  • 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.

v1.39.0

Compare Source

Added
  • 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)

  • 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.objects 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)

  • 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).

    • 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.
    • 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.
    • 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.
    • 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.
Changed
  • 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.
  • aimock-pytest 0.5.3 now defaults to @copilotkit/aimock 1.39.0.
Fixed
  • 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)

  • 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)

  • 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)

  • 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)

  • 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.

v1.38.0

Compare Source

Added
  • OpenAI tr

[!IMPORTANT]
✂ PR body was truncated to here.


Configuration

📅 Schedule: (in timezone America/Los_Angeles)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one): 1

  • coderabbit-review-active

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Review status

This PR was opened by an automated account. A human maintainer must verify the change intent, provenance, and validation before merging.

Current step: The required review sequence passed. Remaining merge requirements apply.

Review-state labels are managed by this workflow; do not edit them manually. community-approved is managed the same way — do not add or remove it manually. It signals a fresh community code approval for the current head as an advisory priority only; maintainer review is still required.

@codecov

codecov Bot commented Oct 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added the awaiting-maintainer CodeRabbit approved; waiting for a human maintainer label Oct 31, 2026
@renovate renovate Bot changed the title Update dependency @copilotkit/aimock to v1.47.0 chore(deps): update dependency @copilotkit/aimock to v1.47.0 Oct 31, 2026
@renovate
renovate Bot force-pushed the renovate/copilotkit-aimock-1.x branch from 2d3a8a4 to 8e6a9fe Compare November 5, 2026 23:43
@github-actions github-actions Bot added awaiting-maintainer CodeRabbit approved; waiting for a human maintainer and removed awaiting-maintainer CodeRabbit approved; waiting for a human maintainer labels Nov 5, 2026
@edelauna
edelauna force-pushed the renovate/copilotkit-aimock-1.x branch from 252a905 to 3b5a3f5 Compare November 7, 2026 20:30
@github-actions github-actions Bot removed the awaiting-maintainer CodeRabbit approved; waiting for a human maintainer label Nov 7, 2026
@renovate

renovate Bot commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Edited/Blocked Notification

Renovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR.

You can manually request rebase by checking the rebase/retry box above.

⚠️ Warning: custom changes will be lost.

@github-actions github-actions Bot added the awaiting-maintainer CodeRabbit approved; waiting for a human maintainer label Nov 7, 2026
@edelauna
edelauna force-pushed the renovate/copilotkit-aimock-1.x branch from 3b5a3f5 to 5da6bd3 Compare November 8, 2026 15:31
@github-actions github-actions Bot removed the awaiting-maintainer CodeRabbit approved; waiting for a human maintainer label Nov 8, 2026
@edelauna
edelauna enabled auto-merge November 8, 2026 15:37
@edelauna
edelauna added this pull request to the merge queue Nov 8, 2026
Merged via the queue into main with commit d956405 Nov 8, 2026
23 checks passed
@edelauna
edelauna deleted the renovate/copilotkit-aimock-1.x branch November 8, 2026 15:49
easonLiangWorldedtech added a commit to easonLiangWorldedtech/Zoo-Code that referenced this pull request Nov 9, 2026
Brings in Zoo-Code-Org#2343 (apply_diff auto-approves edits outside the workspace), Zoo-Code-Org#2283 (task
abort/abortReason run-state latches), Zoo-Code-Org#2324 (Turbo cache input contracts), Zoo-Code-Org#2327
(CSS transitions for visual themes) and Zoo-Code-Org#2277 (aimock 1.47.0), so the required arms
judge this branch against the content they actually check out.

The merge is textually clean and ApplyDiffTool.ts lands as main's content with this
branch's hunks applied on top, which is the composition the arms need. The only
reconciliation needed was in main's new applyDiffTool.outsideWorkspace.spec.ts: its
diff-view double stubbed open() as a no-op and left originalContent at "", which is
the fixture shape applyDiffTool.failureReporting.spec.ts warns about. The stale-base
guard added on this branch reads open()'s re-read as the save baseline, so that
double reported a stale base that never happened and execute returned before asking
for approval - nine failures in CI's windows lane. The double now re-reads through
the same fs mock and provides the stat the tool takes around its read; main's
c assertions and expectations are untouched.
easonLiangWorldedtech added a commit to easonLiangWorldedtech/Zoo-Code that referenced this pull request Nov 9, 2026
Brings 1404 up to the content the required arms actually check out: the 20 non-merge main
commits between its merge base 3ee042d and main tip e487cd7, including Zoo-Code-Org#2283 (task
abort/abortReason run-state latches, which turn Task.abort and Task.abortReason into getter-only
accessors), the settings round-trip unit e943530, Zoo-Code-Org#2343, Zoo-Code-Org#2324, Zoo-Code-Org#2327 and Zoo-Code-Org#2277. 29 of this
branch's 43 delta files were also edited on main and every one of them auto-merged.

Nothing had to be reconciled, and that was measured rather than assumed: tsc --noEmit over the
merged tree exits 0 with zero error rows once @roo-code/types resolves to the merged packages/types
(it reported 25 perWriteCheckpoints rows while resolving to a sibling checkout's stale types, which
is a resolution artifact, not a defect in this tree). The accessor hazard that class of merge usually
produces is absent here: this branch's Task.ts never assigns this.abort or this.abortReason (its three
mentions are comparisons), and the five spec-side writes all land on object-literal doubles that
declare abort as a mutable property or on a local { abort: boolean } alias. Control: injecting
'this.abort = true' inside the getter body produces exactly one row, TS2540 Cannot assign to 'abort'
because it is a read-only property, and removing it returns the program to exit 0, so the check would
have caught the hazard if the merge had created it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant