Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# @copilotkit/aimock

## 1.14.0

### Minor Changes

- Response template merging — override `id`, `created`, `model`, `usage`, `finishReason`, `role`, `systemFingerprint` on fixture responses across all 4 provider formats (OpenAI, Claude, Gemini, Responses API) (#111)
- JSON auto-stringify — fixture `arguments` and `content` fields accept objects that are auto-stringified by the loader, eliminating escaped JSON pain (#111)
- Migration guide from openai-responses-python (#111)
- All fixture examples and docs converted to object syntax (#111)

### Patch Changes

- Fix `onTranscription` docs to show correct 1-argument signature
- Fix `validateFixtures` to recognize ContentWithToolCalls and multimedia response types
- Add `ResponseOverrides` field validation in `validateFixtures` — catches invalid types for `id`, `created`, `model`, `usage`, `finishReason`, `role`, `systemFingerprint`

## 1.13.0

### Minor Changes
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Run them all on one port with `npx aimock --config aimock.json`, or use the prog
- **[Prometheus Metrics](https://aimock.copilotkit.dev/metrics)** — Request counts, latencies, fixture match rates
- **[Docker + Helm](https://aimock.copilotkit.dev/docker)** — Container image and Helm chart for CI/CD
- **[Vitest & Jest Plugins](https://aimock.copilotkit.dev/test-plugins)** — Zero-config `useAimock()` with auto lifecycle and env patching
- **[Response Overrides](https://aimock.copilotkit.dev/fixtures)** — Control `id`, `model`, `usage`, `finishReason` in fixture responses
- **Zero dependencies** — Everything from Node.js builtins

## GitHub Action
Expand Down Expand Up @@ -94,7 +95,7 @@ Test your AI agents with aimock — no API keys, no network calls: [LangChain](h

## Switching from other tools?

Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm) · [piyook/llm-mock](https://aimock.copilotkit.dev/migrate-from-piyook) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy)
Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm) · [piyook/llm-mock](https://aimock.copilotkit.dev/migrate-from-piyook) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks) · [openai-responses](https://aimock.copilotkit.dev/migrate-from-openai-responses) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy)

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion docs/aws-bedrock/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ <h2>Fixture Examples</h2>
<span class="prop">"response"</span>: {
<span class="prop">"toolCalls"</span>: [{
<span class="prop">"name"</span>: <span class="str">"get_weather"</span>,
<span class="prop">"arguments"</span>: <span class="str">"{\"city\":\"SF\"}"</span>
<span class="prop">"arguments"</span>: { <span class="prop">"city"</span>: <span class="str">"SF"</span> }
}]
}
}
Expand Down
7 changes: 4 additions & 3 deletions docs/chat-completions/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ <h2>Unit Test: Tool Calls</h2>
<div class="code-block">
<div class="code-block-header">tool-calls.test.ts <span class="lang-tag">ts</span></div>
<pre><code><span class="fn">it</span>(<span class="str">"returns tool call in streaming mode"</span>, <span class="kw">async</span> () <span class="kw">=&gt;</span> {
<span class="cm">// arguments accepts objects (auto-stringified) or JSON strings</span>
<span class="op">mock</span>.<span class="fn">on</span>(
{ <span class="prop">userMessage</span>: <span class="str">"weather"</span> },
{ <span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: <span class="str">'{"city":"SF"}'</span> }] }
{ <span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: { <span class="prop">city</span>: <span class="str">"SF"</span> } }] }
);

<span class="kw">const</span> <span class="op">res</span> = <span class="kw">await</span> <span class="fn">fetch</span>(<span class="str">`${mock.url}/v1/chat/completions`</span>, {
Expand All @@ -147,7 +148,7 @@ <h2>Integration Test: Streaming SSE</h2>
<div class="code-block-header">
streaming-integration.test.ts <span class="lang-tag">ts</span>
</div>
<pre><code><span class="kw">import</span> { <span class="fn">createServer</span>, <span class="kw">type</span> <span class="type">ServerInstance</span> } <span class="kw">from</span> <span class="str">"@copilotkit/aimock/server"</span>;
<pre><code><span class="kw">import</span> { <span class="fn">createServer</span>, <span class="kw">type</span> <span class="type">ServerInstance</span> } <span class="kw">from</span> <span class="str">"@copilotkit/aimock"</span>;

<span class="kw">const</span> <span class="op">instance</span> = <span class="kw">await</span> <span class="fn">createServer</span>(
[{ <span class="prop">match</span>: { <span class="prop">userMessage</span>: <span class="str">"hello"</span> }, <span class="prop">response</span>: { <span class="prop">content</span>: <span class="str">"Hello! How can I help?"</span> } }],
Expand Down Expand Up @@ -192,7 +193,7 @@ <h2>JSON Fixture</h2>
<span class="key">"response"</span>: {
<span class="key">"toolCalls"</span>: [{
<span class="key">"name"</span>: <span class="str">"get_weather"</span>,
<span class="key">"arguments"</span>: <span class="str">"{\"city\":\"SF\"}"</span>
<span class="key">"arguments"</span>: { <span class="key">"city"</span>: <span class="str">"SF"</span> }
}]
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/claude-messages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ <h2>Unit Test: Tool Use</h2>
<pre><code><span class="kw">const</span> <span class="op">toolFixture</span> = {
<span class="prop">match</span>: { <span class="prop">userMessage</span>: <span class="str">"weather"</span> },
<span class="prop">response</span>: {
<span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: <span class="str">'{"city":"NYC"}'</span> }]
<span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: { <span class="prop">city</span>: <span class="str">"NYC"</span> } }]
},
};

Expand Down
2 changes: 1 addition & 1 deletion docs/cohere/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ <h2>Fixture Examples</h2>
"toolCalls": [
{
"name": "web_search",
"arguments": "{\"query\":\"latest news\"}"
"arguments": { "query": "latest news" }
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ <h2>Switching from other tools?</h2>
<a href="/migrate-from-mock-llm">mock-llm</a> <span class="sep">&middot;</span>
<a href="/migrate-from-piyook">piyook/llm-mock</a> <span class="sep">&middot;</span>
<a href="/migrate-from-python-mocks">Python mocks</a> <span class="sep">&middot;</span>
<a href="/migrate-from-openai-responses">openai-responses</a>
<span class="sep">&middot;</span>
<a href="/migrate-from-mokksy">Mokksy</a>
</div>
</main>
Expand Down
208 changes: 202 additions & 6 deletions docs/fixtures/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ <h2>Match Fields</h2>
<td>number</td>
<td>Match on the Nth occurrence of this pattern</td>
</tr>
<tr>
<td>endpoint</td>
<td>string</td>
<td>
Restrict to endpoint type: chat, image, speech, transcription, video, embedding
</td>
</tr>
<tr>
<td>predicate</td>
<td>function</td>
Expand Down Expand Up @@ -152,6 +159,11 @@ <h2>Response Types</h2>
<td>toolCalls[], finishReason?</td>
<td>Function call(s) with name + arguments</td>
</tr>
<tr>
<td>Content + Tool Calls</td>
<td>content, toolCalls[], reasoning?, finishReason?</td>
<td>Text and tool calls in a single response</td>
</tr>
<tr>
<td>Error</td>
<td>error.message, error.type?, status?</td>
Expand Down Expand Up @@ -179,12 +191,99 @@ <h2>Response Types</h2>
</tr>
<tr>
<td>Video</td>
<td>video.url, video.duration?</td>
<td>video.id, video.status, video.url?</td>
<td>Generated video URL with async polling</td>
</tr>
</tbody>
</table>

<div class="info-box">
<p>
<strong>Override fields:</strong> Text, Tool Call, and Content + Tool Calls responses
also accept the override fields listed below (<code>id</code>, <code>model</code>,
<code>usage</code>, <code>finishReason</code>, <code>role</code>,
<code>systemFingerprint</code>, <code>created</code>).
</p>
</div>

<div class="info-box">
<p>
<strong>JSON auto-stringify:</strong> In fixture files and programmatic API,
<code>arguments</code> and <code>content</code> fields accept both objects and strings.
Objects are automatically stringified via <code>JSON.stringify()</code>. Use the object
form for readability &mdash; no more escaped JSON strings.
</p>
</div>

<h2>Response Override Fields</h2>
<p>
Fixture responses can include optional fields to override auto-generated envelope values.
These map correctly across all provider formats (OpenAI, Claude, Gemini, Responses API).
</p>
<table class="endpoint-table">
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>string</td>
<td>Override auto-generated response ID</td>
</tr>
<tr>
<td>created</td>
<td>number</td>
<td>Override Unix timestamp</td>
</tr>
<tr>
<td>model</td>
<td>string</td>
<td>Override model name in response</td>
</tr>
<tr>
<td>usage</td>
<td>object</td>
<td>
Override token counts:
<code>{ prompt_tokens, completion_tokens, total_tokens }</code>. Also accepts
Anthropic field names (<code>input_tokens</code>, <code>output_tokens</code>) and
Gemini field names (<code>promptTokenCount</code>,
<code>candidatesTokenCount</code>, <code>totalTokenCount</code>). OpenAI Chat
Completions includes usage in the response body; the Responses API uses a separate
<code>response.usage</code> object. When omitted, token counts are auto-computed
from content length
</td>
</tr>
<tr>
<td>finishReason</td>
<td>string</td>
<td>
Override finish reason (default: "stop" or "tool_calls"). Provider mappings:
<code>stop</code> &rarr; <code>end_turn</code> (Claude), <code>STOP</code> (Gemini);
<code>tool_calls</code> &rarr; <code>tool_use</code> (Claude),
<code>FUNCTION_CALL</code> (Gemini); <code>length</code> &rarr;
<code>max_tokens</code> (Claude), <code>MAX_TOKENS</code> (Gemini);
<code>content_filter</code> &rarr; <code>SAFETY</code> (Gemini),
<code>failed</code> (Responses API)
</td>
</tr>
<tr>
<td>role</td>
<td>string</td>
<td>Override message role (default: "assistant")</td>
</tr>
<tr>
<td>systemFingerprint</td>
<td>string</td>
<td>Add system_fingerprint to response</td>
</tr>
</tbody>
</table>

<h2>Fixture Options</h2>

<table class="endpoint-table">
Expand All @@ -199,7 +298,7 @@ <h2>Fixture Options</h2>
<tr>
<td>latency</td>
<td>number</td>
<td>Milliseconds delay before first chunk</td>
<td>Milliseconds delay between SSE chunks (streaming)</td>
</tr>
<tr>
<td>chunkSize</td>
Expand All @@ -220,15 +319,16 @@ <h2>Fixture Options</h2>
<td>streamingProfile</td>
<td>object</td>
<td>
Streaming physics profile: <code>{ ttftMs, tps, jitter }</code>. See
Streaming physics profile: <code>{ ttft, tps, jitter }</code>. See
<a href="/streaming-physics">Streaming Physics</a>
</td>
</tr>
<tr>
<td>chaos</td>
<td>object</td>
<td>
Per-fixture chaos config: <code>{ errorRate, latencyMs, ... }</code>. See
Per-fixture chaos config: <code>{ dropRate, malformedRate, disconnectRate }</code>.
See
<a href="/chaos-testing">Chaos Testing</a>
</td>
</tr>
Expand Down Expand Up @@ -261,8 +361,8 @@ <h3>Programmatically</h3>
<span class="op">mock</span>.<span class="fn">onEmbedding</span>(<span class="str">"my text"</span>, { <span class="prop">embedding</span>: [<span class="num">0.1</span>, <span class="num">0.2</span>] });
<span class="op">mock</span>.<span class="fn">onImage</span>(<span class="str">"sunset"</span>, { <span class="prop">image</span>: { <span class="prop">url</span>: <span class="str">"https://example.com/sunset.png"</span> } });
<span class="op">mock</span>.<span class="fn">onSpeech</span>(<span class="str">"hello"</span>, { <span class="prop">audio</span>: <span class="str">"SGVsbG8="</span> });
<span class="op">mock</span>.<span class="fn">onTranscription</span>(<span class="str">"audio.mp3"</span>, { <span class="prop">transcription</span>: { <span class="prop">text</span>: <span class="str">"Hello"</span> } });
<span class="op">mock</span>.<span class="fn">onVideo</span>(<span class="str">"cats"</span>, { <span class="prop">video</span>: { <span class="prop">url</span>: <span class="str">"https://example.com/cats.mp4"</span> } });
<span class="op">mock</span>.<span class="fn">onTranscription</span>({ <span class="prop">transcription</span>: { <span class="prop">text</span>: <span class="str">"Hello"</span> } });
<span class="op">mock</span>.<span class="fn">onVideo</span>(<span class="str">"cats"</span>, { <span class="prop">video</span>: { <span class="prop">id</span>: <span class="str">"vid-1"</span>, <span class="prop">status</span>: <span class="str">"completed"</span>, <span class="prop">url</span>: <span class="str">"https://example.com/cats.mp4"</span> } });
<span class="op">mock</span>.<span class="fn">onJsonOutput</span>(<span class="str">"data"</span>, { <span class="prop">key</span>: <span class="str">"value"</span> });
<span class="op">mock</span>.<span class="fn">onToolResult</span>(<span class="str">"call_123"</span>, { <span class="prop">content</span>: <span class="str">"Done"</span> });

Expand Down Expand Up @@ -305,6 +405,102 @@ <h2>Routing Rules</h2>
programmatic registration for predicate-based routing.
</p>
</div>

<h2>Provider Support Matrix</h2>
<table class="endpoint-table">
<thead>
<tr>
<th>Feature</th>
<th>OpenAI Chat</th>
<th>OpenAI Responses</th>
<th>Claude</th>
<th>Gemini</th>
<th>Bedrock</th>
<th>Azure</th>
<th>Ollama</th>
<th>Cohere</th>
</tr>
</thead>
<tbody>
<tr>
<td>Text</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Tool Calls</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Content + Tool Calls</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Streaming</td>
<td>SSE</td>
<td>SSE</td>
<td>SSE</td>
<td>SSE</td>
<td>Binary EventStream</td>
<td>SSE</td>
<td>NDJSON</td>
<td>SSE</td>
</tr>
<tr>
<td>Reasoning</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>&mdash;</td>
<td>&mdash;</td>
</tr>
<tr>
<td>Web Searches</td>
<td>&mdash;</td>
<td>Yes</td>
<td>&mdash;</td>
<td>&mdash;</td>
<td>&mdash;</td>
<td>&mdash;</td>
<td>&mdash;</td>
<td>&mdash;</td>
</tr>
<tr>
<td>Response Overrides</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>&mdash;</td>
<td>Yes</td>
<td>&mdash;</td>
<td>&mdash;</td>
</tr>
</tbody>
</table>
</main>
<aside class="page-toc" id="page-toc"></aside>
</div>
Expand Down
2 changes: 1 addition & 1 deletion docs/gemini/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ <h2>Unit Test: Tool Call</h2>
<pre><code><span class="kw">const</span> <span class="op">toolFixture</span> = {
<span class="prop">match</span>: { <span class="prop">userMessage</span>: <span class="str">"weather"</span> },
<span class="prop">response</span>: {
<span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: <span class="str">'{"city":"NYC"}'</span> }]
<span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: { <span class="prop">city</span>: <span class="str">"NYC"</span> } }]
},
};

Expand Down
2 changes: 1 addition & 1 deletion docs/integrate-adk/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ <h2>Function Calling</h2>
<span class="prop">"toolCalls"</span>: [
{
<span class="prop">"name"</span>: <span class="str">"get_weather"</span>,
<span class="prop">"arguments"</span>: <span class="str">"{\"city\":\"San Francisco\",\"unit\":\"fahrenheit\"}"</span>
<span class="prop">"arguments"</span>: { <span class="prop">"city"</span>: <span class="str">"San Francisco"</span>, <span class="prop">"unit"</span>: <span class="str">"fahrenheit"</span> }
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion docs/integrate-crewai/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ <h2>Tool Calls</h2>
<span class="prop">"toolCalls"</span>: [
{
<span class="prop">"name"</span>: <span class="str">"web_search"</span>,
<span class="prop">"arguments"</span>: <span class="str">"{\"query\": \"LLM testing frameworks 2025\"}"</span>
<span class="prop">"arguments"</span>: { <span class="prop">"query"</span>: <span class="str">"LLM testing frameworks 2025"</span> }
}
]
}
Expand Down
Loading
Loading