Skip to content

davidreko/anthropic-mock

Repository files navigation

anthropic-mock

CI codecov

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.

Install

pnpm add anthropic-mock

Requires @anthropic-ai/sdk as a peer dependency (>=0.80.0).

Usage

Basic (non-streaming)

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.' }

Streaming

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);
}

Tool use

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.

Extended thinking

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);
});

Configuration

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();

Config options

// 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 });

Agent loop helper

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}`,
});

Batch API

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[]

Examples

Basic - text, streaming, tools, thinking, and agent loop: examples/basic.ts

pnpm run example

Advanced - config, overrides, errors, latency, batches, abort, async iteration: examples/advanced.ts

pnpm run example:advanced

API

createMockClient(config?)

Returns a MockAnthropicClient with a messages property supporting .create() and .stream(). Optional config scopes mock behavior to this client instance.

client.setConfig(config) / client.resetConfig()

Update or reset mock behavior for a specific client instance. setConfig merges with existing config.

generateFromSchema(schema)

Generates a deterministic value from a JSON Schema object. Handles string, number, integer, boolean, null, array, object, enum, anyOf, oneOf, and allOf.

MockMessageStream

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

mockAgentLoop(options)

Runs a multi-turn tool-use loop. Returns an array of all Message responses produced during the loop.

client.messages.batches

Mock implementation of the Batch API. Supports create, retrieve, list, cancel, delete, and results. Batches are processed synchronously and resolve immediately.

_resetIdCounter() (test utility)

Resets the internal ID counter used for deterministic message/tool IDs. Import from the /test subpath:

import { _resetIdCounter } from 'anthropic-mock/test';

beforeEach(() => {
  _resetIdCounter();
});

License

MIT

About

Drop-in mock for the Anthropic SDK. Test agent loops, tool use, and streaming without API calls.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors