Note
This is an unofficial community project and is not affiliated with, endorsed by, or maintained by Anthropic.
Drop-in mock for the Anthropic SDK client. Generates structurally correct responses without API calls - useful for testing AI agent loops, tool-use pipelines, and streaming consumers.
pnpm add anthropic-mockRequires @anthropic-ai/sdk as a peer dependency (>=0.80.0).
import { createMockClient } from 'anthropic-mock';
const client = createMockClient();
const message = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(message.content[0]); // { type: 'text', text: 'Mock response from anthropic-mock.' }const stream = client.messages.stream({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello' }],
});
stream.on('text', (delta, snapshot) => {
console.log(delta);
});
const final = await stream.finalMessage();The stream emits the same event sequence as the real SDK: message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop.
Also supports for await...of:
for await (const event of stream) {
console.log(event.type);
}When tools are provided, the mock invokes all of them and returns a tool_use block for each, with inputs derived from each tool's input_schema:
const msg = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: 'What is the weather?' }],
tools: [
{
name: 'get_weather',
description: 'Get weather for a location',
input_schema: {
type: 'object',
properties: {
location: { type: 'string' },
units: { type: 'string', enum: ['celsius', 'fahrenheit'] },
},
required: ['location', 'units'],
},
},
],
});
// msg.content[0].input => { location: 'mock_value', units: 'celsius' }Generated values are deterministic: strings become 'mock_value', numbers use minimum or 0, enums pick the first value, and only required fields are populated.
When thinking is enabled in the request params, the mock produces a thinking block before the text/tool response:
const msg = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 16000,
thinking: { type: 'enabled', budget_tokens: 10000 },
messages: [{ role: 'user', content: 'Think about this' }],
});
// msg.content[0] => { type: 'thinking', thinking: 'Mock thinking...', signature: 'mock_signature' }
// msg.content[1] => { type: 'text', text: 'Mock response from anthropic-mock.' }Streaming emits thinking_delta and signature_delta events for the thinking block, matching the real SDK's behavior. You can also listen for the thinking convenience event:
stream.on('thinking', (delta, snapshot) => {
console.log(delta);
});Pass config to createMockClient() to control mock behavior. Use client.setConfig() to update it mid-test, and client.resetConfig() to restore defaults.
import { createMockClient } from 'anthropic-mock';
// Custom response text
const client = createMockClient({ responseText: 'Custom reply' });
// Update config mid-test (merges with existing)
client.setConfig({ toolChoice: 'none' });
// Reset to defaults
client.resetConfig();// Custom response text
createMockClient({ responseText: 'Custom reply' });
// Custom thinking text
createMockClient({ thinkingText: 'Let me think about this carefully...' });
// Invoke only a specific tool (by index) instead of all
createMockClient({ toolChoice: 1 }); // picks the second tool only
// Skip tools entirely even when provided
createMockClient({ toolChoice: 'none' });
// Override generated tool inputs per tool name
createMockClient({ toolInputOverrides: { get_weather: { location: 'San Francisco' } } });
// Simulate an API error
createMockClient({ simulateError: new Error('rate limited') });
// Simulate latency (ms delay between each stream event)
createMockClient({ latencyMs: 50 });mockAgentLoop runs a multi-turn tool-use loop, cycling between tool_use and tool_result messages until the model returns a text response (or maxTurns is reached):
import { createMockClient, mockAgentLoop } from 'anthropic-mock';
const client = createMockClient();
const responses = await mockAgentLoop({
client,
params: {
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
tools: [/* your tools */],
},
messages: [{ role: 'user', content: 'Do the thing' }],
maxTurns: 5,
onToolUse: (name, input, id) => `Result for ${name}`,
});client.messages.batches supports create, retrieve, list, cancel, delete, and results. Batches resolve immediately (no polling needed):
const batch = await client.messages.batches.create({
requests: [
{ custom_id: 'req-1', params: { model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [{ role: 'user', content: 'Hello' }] } },
],
});
const results = await client.messages.batches.results(batch.id);
// results[0].result.message => standard Message object
const all = await client.messages.batches.list();
// all => MessageBatch[]Basic - text, streaming, tools, thinking, and agent loop: examples/basic.ts
pnpm run exampleAdvanced - config, overrides, errors, latency, batches, abort, async iteration: examples/advanced.ts
pnpm run example:advancedReturns a MockAnthropicClient with a messages property supporting .create() and .stream(). Optional config scopes mock behavior to this client instance.
Update or reset mock behavior for a specific client instance. setConfig merges with existing config.
Generates a deterministic value from a JSON Schema object. Handles string, number, integer, boolean, null, array, object, enum, anyOf, oneOf, and allOf.
Implements the same interface as the SDK's MessageStream:
.on()/.off()/.once()- event listeners (text,thinking,inputJson,message,streamEvent, etc.).emitted(event)- promise for a specific event.done()- resolves when the stream ends.finalMessage()/.finalText()- convenience accessors.abort()- abort the stream[Symbol.asyncIterator]- async iteration over raw events
Runs a multi-turn tool-use loop. Returns an array of all Message responses produced during the loop.
Mock implementation of the Batch API. Supports create, retrieve, list, cancel, delete, and results. Batches are processed synchronously and resolve immediately.
Resets the internal ID counter used for deterministic message/tool IDs. Import from the /test subpath:
import { _resetIdCounter } from 'anthropic-mock/test';
beforeEach(() => {
_resetIdCounter();
});MIT