Example Fixtures
Ready-to-use fixture examples for every mock type. Copy any example to get started
quickly, or use fixtures/examples/full-suite.json as a complete config
template.
LLM Fixtures
Embeddings
Matching on inputText and returning a vector.
{
"fixtures": [
{
"match": { "inputText": "hello world" },
"response": {
"embedding": [0.0023064255, -0.009327292, 0.015797347]
}
}
]
}
Streaming Physics
Realistic streaming timing with ttft, tps, and
jitter.
{
"fixtures": [
{
"match": { "userMessage": "explain gravity" },
"response": {
"content": "Gravity is a fundamental force of nature that attracts objects with mass toward one another. It keeps planets in orbit around the sun and holds galaxies together."
},
"streamingProfile": {
"ttft": 200,
"tps": 40,
"jitter": 0.1
}
}
]
}
Error Injection
Rate limit error response for any message.
{
"fixtures": [
{
"match": { "userMessage": ".*" },
"response": {
"error": {
"message": "Rate limit exceeded. Please retry after 30 seconds.",
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
},
"status": 429
}
}
]
}
Sequential Responses
Stateful multi-turn responses using sequenceIndex.
{
"fixtures": [
{
"match": { "userMessage": "tell me a joke", "sequenceIndex": 0 },
"response": {
"content": "Why did the programmer quit his job? Because he didn't get arrays!"
}
},
{
"match": { "userMessage": "tell me a joke", "sequenceIndex": 1 },
"response": { "content": "Why do Java developers wear glasses? Because they can't C#!" }
},
{
"match": { "userMessage": "tell me a joke", "sequenceIndex": 2 },
"response": {
"content": "A SQL query walks into a bar, sees two tables, and asks: 'Can I join you?'"
}
}
]
}
Protocol Configs
MCP
Tools and resources for the Model Context Protocol mock.
{
"mcp": {
"tools": [
{
"name": "search",
"description": "Search the web",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
},
"result": "No results found for the given query."
}
],
"resources": [
{
"uri": "file:///readme",
"name": "README",
"mimeType": "text/plain",
"text": "# My Project\n\nThis is the project README."
}
]
}
}
A2A
Agent registration and streaming tasks for the Agent-to-Agent protocol mock.
{
"a2a": {
"agents": [
{
"name": "research-agent",
"description": "An agent that researches topics and returns summaries",
"version": "1.0.0",
"skills": [
{
"id": "web-research",
"name": "Web Research",
"description": "Search the web and summarize findings",
"tags": ["research", "search"]
}
],
"capabilities": { "streaming": true },
"messages": [
{
"pattern": "research",
"parts": [{ "text": "Here is a summary of my research findings on the topic." }]
}
],
"streamingTasks": [
{
"pattern": "deep-research",
"events": [
{ "type": "status", "state": "TASK_STATE_WORKING" },
{
"type": "artifact",
"name": "research-report",
"parts": [{ "text": "## Research Report\n\nFindings from deep research..." }],
"lastChunk": true
},
{ "type": "status", "state": "TASK_STATE_COMPLETED" }
],
"delayMs": 100
}
]
}
]
}
}
AG-UI
Text response and tool call event stream for the AG-UI protocol mock.
{
"agui": {
"fixtures": [
{
"match": { "message": "hello" },
"text": "Hi! How can I help you today?"
},
{
"match": { "message": "search" },
"events": [
{ "type": "RUN_STARTED", "threadId": "t1", "runId": "r1" },
{ "type": "TOOL_CALL_START", "toolCallId": "tc1", "toolCallName": "web_search" },
{
"type": "TOOL_CALL_ARGS",
"toolCallId": "tc1",
"delta": "{\"query\": \"latest news\"}"
},
{ "type": "TOOL_CALL_END", "toolCallId": "tc1" },
{
"type": "TEXT_MESSAGE_START",
"messageId": "m1",
"role": "assistant"
},
{
"type": "TEXT_MESSAGE_CONTENT",
"messageId": "m1",
"delta": "Here are the latest results..."
},
{ "type": "TEXT_MESSAGE_END", "messageId": "m1" },
{ "type": "RUN_FINISHED", "threadId": "t1", "runId": "r1" }
]
}
]
}
}
Vector
Collection with vectors and query results for the vector database mock.
{
"vector": {
"collections": [
{
"name": "documents",
"dimension": 3,
"vectors": [
{
"id": "doc-1",
"values": [0.1, 0.2, 0.3],
"metadata": { "title": "Getting Started", "category": "tutorial" }
},
{
"id": "doc-2",
"values": [0.4, 0.5, 0.6],
"metadata": { "title": "API Reference", "category": "reference" }
}
],
"queryResults": [
{
"id": "doc-1",
"score": 0.95,
"metadata": { "title": "Getting Started", "category": "tutorial" }
},
{
"id": "doc-2",
"score": 0.82,
"metadata": { "title": "API Reference", "category": "reference" }
}
]
}
]
}
}
Testing & Operations
Chaos Testing
Configure drop, malformed, and disconnect rates for chaos testing.
{
"llm": {
"fixtures": "fixtures/example-greeting.json",
"chaos": {
"dropRate": 0.1,
"malformedRate": 0.05,
"disconnectRate": 0.02
}
}
}
Record & Replay
Provider URLs for proxy mode to record live API traffic.
{
"llm": {
"record": {
"providers": {
"openai": "https://api.openai.com/v1",
"anthropic": "https://api.anthropic.com"
},
"fixturePath": "./recorded-fixtures"
}
}
}
Snapshot Recording (per-test fixtures)
Send X-Test-Id from your test runner to organize recorded fixtures into
per-test directories. Here is a Playwright example:
import { test } from "@playwright/test";
test.beforeEach(async ({ page }, testInfo) => {
// Route all LLM traffic through aimock with a test ID header
await page.setExtraHTTPHeaders({
"X-Test-Id": testInfo.title,
});
});
The resulting fixture directory layout groups each test’s recordings by provider:
fixtures/recorded/
should-greet-the-user/
openai.json
anthropic.json
should-handle-tool-calls/
openai.json
See Snapshot-Style Recording for the full workflow, including replay and drift detection.
Full Suite
Complete Config
A complete configuration running all mocks on one port.
{
"port": 4000,
"host": "127.0.0.1",
"metrics": true,
"strict": true,
"llm": {
"fixtures": "fixtures/example-greeting.json",
"chaos": {
"dropRate": 0.01,
"malformedRate": 0.005,
"disconnectRate": 0.002
}
},
"mcp": {
"serverInfo": { "name": "full-suite-mcp", "version": "1.0.0" },
"tools": [
{
"name": "search",
"description": "Search the knowledge base",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" },
"limit": { "type": "number" }
},
"required": ["query"]
},
"result": "Found 3 results for your query."
}
],
"resources": [
{
"uri": "file:///config",
"name": "Configuration",
"mimeType": "application/json",
"text": "{\"version\": \"1.0\", \"environment\": \"test\"}"
}
],
"prompts": [
{
"name": "summarize",
"description": "Summarize a document",
"arguments": [{ "name": "text", "description": "The text to summarize", "required": true }],
"result": {
"messages": [
{
"role": "assistant",
"content": { "type": "text", "text": "Here is a summary of the provided text." }
}
]
}
}
]
},
"a2a": {
"agents": [
{
"name": "assistant",
"description": "A general-purpose assistant agent",
"version": "1.0.0",
"skills": [{ "id": "qa", "name": "Q&A", "description": "Answer questions" }],
"capabilities": { "streaming": true },
"messages": [
{
"pattern": ".*",
"parts": [{ "text": "I can help you with that." }]
}
]
}
]
},
"agui": {
"fixtures": [
{
"match": { "message": "hello" },
"text": "Hello from the full-suite mock!"
},
{
"match": { "toolName": "get_data" },
"events": [
{ "type": "RUN_STARTED", "threadId": "t1", "runId": "r1" },
{ "type": "TOOL_CALL_START", "toolCallId": "tc1", "toolCallName": "get_data" },
{ "type": "TOOL_CALL_ARGS", "toolCallId": "tc1", "delta": "{}" },
{ "type": "TOOL_CALL_END", "toolCallId": "tc1" },
{ "type": "RUN_FINISHED", "threadId": "t1", "runId": "r1" }
]
}
]
},
"vector": {
"collections": [
{
"name": "knowledge-base",
"dimension": 384,
"queryResults": [
{
"id": "kb-001",
"score": 0.97,
"metadata": { "source": "docs", "title": "Quick Start Guide" }
}
]
}
]
},
"services": {
"search": true,
"rerank": true,
"moderate": true
}
}
Multi-Turn Conversations
Choosing a multi-turn matcher
aimock provides four match fields for multi-turn fixtures, each suited to a different
scenario. turnIndex matches by conversation depth (how many
assistant replies precede this request) and is stateless, so it works with concurrent
clients. hasToolResult is a boolean that distinguishes the
initial request from the follow-up after a tool executes — ideal for simple two-step
tool rounds. toolCallId matches a specific tool call by its
ID, useful when the agent calls multiple tools and you need to respond to exactly one.
sequenceIndex is a stateful counter (“first request
gets A, second gets B”) but is not safe for concurrent requests to the same fixture.
See the Multi-Turn Conversations reference for the full details.
Multi-turn conversation with turnIndex
Use turnIndex to give different responses at each conversational turn.
Combine with hasToolResult to handle the post-tool-execution follow-up.
{
"fixtures": [
{
"match": { "userMessage": "plan a trip", "turnIndex": 0 },
"response": { "content": "I'd love to help plan your trip! Where would you like to go?" }
},
{
"match": { "userMessage": "plan a trip", "turnIndex": 1 },
"response": {
"content": "Great choice! Let me search for flights.",
"toolCalls": [{ "name": "search_flights", "arguments": "{\"destination\": \"Tokyo\"}" }]
}
},
{
"match": { "userMessage": "plan a trip", "turnIndex": 2, "hasToolResult": true },
"response": { "content": "I found several flights to Tokyo. The best option is..." }
}
]
}
Tool-call cycle with hasToolResult
For a simple tool round-trip, hasToolResult is the most concise matcher:
false on the initial request, true after the tool result comes
back.
{
"fixtures": [
{
"match": { "userMessage": "what's the weather?", "hasToolResult": false },
"response": {
"content": null,
"toolCalls": [{ "name": "get_weather", "arguments": "{\"city\": \"San Francisco\"}" }]
}
},
{
"match": { "userMessage": "what's the weather?", "hasToolResult": true },
"response": { "content": "It's 72°F and sunny in San Francisco!" }
}
]
}
Dynamic / Async Responses
Fixture responses can be functions — sync or async — that receive the request and return the response dynamically. Use this when you need to await side effects, compute responses based on request content, or inject runtime data into fixtures.
Async response with side-effect
Wait for an external operation to complete before constructing the fixture response. Eliminates race conditions in multi-turn E2E tests where entity creation happens out-of-band.
mock.on(
{ toolCallId: "call_create_entity" },
async (req) => {
const entity = await createEntityPromise;
return {
content: `Entity "${entity.name}" created!`,
toolCalls: [{
name: "next_step",
arguments: JSON.stringify({ entityId: entity.id }),
}],
};
},
);
Request-aware response
Compute the response from the incoming request content. Useful for echo-style fixtures, transformations, or conditional logic that goes beyond what match fields can express.
mock.onMessage("translate", (req) => {
const text = req.messages.at(-1)?.content ?? "";
return { content: `Translated: ${text.toUpperCase()}` };
});