@akshay_pachaar: Anthropic won't like this open-source repo. It is going to cost LLM providers a lot of money. Every CI run of an AI app…
Summary
The article introduces aimock, an open-source tool by CopilotKit that mocks API calls for AI applications during CI/CD, reducing costs and maintaining type correctness across multiple providers.
View Cached Full Text
Cached at: 08/17/26, 06:14 PM
Anthropic won’t like this open-source repo.
It is going to cost LLM providers a lot of money.
Every CI run of an AI app today sends real requests to providers like OpenAI or Anthropic.
Like any other LLM call, this too gets billed at actual API rates. So for teams with high commit volumes, this accumulates into a meaningful chunk of API spend.
One common hack devs use is that instead of invoking the LLM API, the test calls a fake local server that speaks the same API and returns a dummy response.
The catch is that the dummy response is a copy of what the provider returned on the day it was saved, and providers keep adding fields and changing types.
So the tests keep passing against a schema that’s no longer valid, while the real integration breaks in production.
A smart approach is now actually implemented in @CopilotKit’s recently open-sourced aimock project.
Every day, the repo’s own CI sends a handful of requests to the real API and the same requests to the fake server, then compares both against the official client library’s type definitions.
Those are the only real API calls in the whole setup, and they run on the repo’s own keys, not in anyone else’s CI.
A single team can push hundreds of commits a day, and thousands of teams are already doing that with coding agents.
All of those runs stay offline, because one repo checks against the real API on everyone’s behalf.
When a check fails, a coding agent updates aimock’s built-in response schema, the full test suite has to pass, and a patch version ships to npm.
By simply upgrading the package, the corrected schema gets reflected in every project using it.
The capability is not just limited to a single provider.
The same server works for Claude, OpenAI, Gemini, Bedrock, Azure, Ollama, plus MCP tools, A2A agents, AG-UI event streams, vector DBs like Pinecone and Qdrant, and search, speech, image, and video endpoints.
Here’s the repo: https://github.com/CopilotKit/aimock…
(don’t forget to star it )
That said, mocking your API calls is one thing. AI engineers should also know how to test agents properly in the first place, which several teams still skip.
I wrote a full walkthrough on that, covering build, testing, evals, tracing, and deployment.
Read it below.
CopilotKit/aimock
Source: https://github.com/CopilotKit/aimock
aimock
Mock infrastructure for AI application testing — point your SDK at one local port and every provider, protocol, and service answers deterministically.
https://github.com/user-attachments/assets/76815122-574a-48e1-b275-edae0a014667
One package, one port, zero dependencies. LLM APIs, image generation and editing, text-to-speech, transcription, audio translation and generation, video generation, embeddings, MCP tools, A2A agents, AG-UI event streams, vector databases, search, rerank, and moderation — no keys, no network, no surprise bills.
Quick Start
npm install @copilotkit/aimock
// The class is still named `LLMock` for back-compat after the v1.7.0 package
// rename from `@copilotkit/llmock` to `@copilotkit/aimock`.
import { LLMock } from "@copilotkit/aimock";
const mock = new LLMock({ port: 0 });
mock.onMessage("hello", { content: "Hi there!" });
await mock.start();
// Set env BEFORE importing/constructing the OpenAI (or other provider) client.
// Many SDKs cache the base URL at construction time — if the client is built
// before these are set, it will talk to the real API (surprise bills) instead
// of aimock.
process.env.OPENAI_BASE_URL = `${mock.url}/v1`;
process.env.OPENAI_API_KEY = "mock"; // SDK requires a value, even when base URL is mocked
// ... run your tests ...
await mock.stop();
The aimock Suite
aimock mocks everything your AI app talks to:
| Tool | What it mocks | Docs |
|---|---|---|
| LLMock | OpenAI (Chat/Responses/Realtime GA+Beta), Claude, Gemini (REST/Live/Interactions/Embeddings), Bedrock, Azure, Vertex AI, Ollama (chat/embeddings), Cohere (chat/embed), OpenRouter (chat/router), ElevenLabs TTS | Providers |
| MCPMock | MCP tools, resources, prompts with session management | MCP |
| A2AMock | Agent-to-agent protocol with SSE streaming | A2A |
| AGUIMock | AG-UI agent-to-UI event streams for frontend testing | AG-UI |
| VectorMock | Pinecone, Qdrant, ChromaDB compatible endpoints | Vector |
| Services | Tavily search, Cohere rerank, OpenAI moderation, ElevenLabs TTS | Services |
Run them all on one port with npx @copilotkit/aimock --config aimock.json, or use the programmatic API to compose exactly what you need.
Features
- Record & Replay — Proxy real APIs, save as fixtures, replay deterministically forever
- Timing-aware recording and replay — Recorded fixtures capture per-frame arrival timestamps; replay uses recorded timings for approximate timing reproduction based on recorded TTFT and inter-frame cadence (replay chunk count may differ from recording — TTFT and average pace are preserved, not per-token fidelity) with configurable
--replay-speedmultiplier - Multi-turn Conversations — Record and replay multi-turn traces with tool rounds; match distinct turns via
turnIndex,hasToolResult,toolCallId,toolResultContains(gate on the tool-result payload),sequenceIndex,systemMessage(gate on host-supplied agent context), or custom predicates - 13 providers across 15 API surfaces — OpenAI Chat, OpenAI Responses, OpenAI Realtime (GA + Beta shim), Claude, Gemini REST, Gemini embedContent, Gemini Live, Gemini Interactions, Azure, Bedrock, Vertex AI, Ollama (chat + embeddings), Cohere (chat + embed), OpenRouter (chat + router failover), ElevenLabs TTS — full streaming support
- Multimedia APIs — image generation (DALL-E, Imagen), image editing (/v1/images/edits), text-to-speech (OpenAI + ElevenLabs), audio transcription, audio translation (/v1/audio/translations), video generation, OpenRouter video generation (/api/v1/videos with async job lifecycle), Google Veo video generation (:predictLongRunning + /v1beta/operations async lifecycle), Grok Imagine video generation (/v1/videos/generations with async job lifecycle), fal.ai (image / video / audio with queue lifecycle)
- MCP / A2A / AG-UI / Vector — Mock every protocol your AI agents use
- Chaos Testing — 500 errors, malformed JSON, mid-stream disconnects at any probability
- Per-Request Strict Mode —
X-AIMock-Strictheader overrides the server-level--strictflag per request (true/1= strict,false/0= lenient) - Context-Based Fixture Routing —
X-AIMock-Contextheader scopes fixtures per integration; fixtures withmatch.contextonly match requests carrying that context, fixtures without it remain shared - Drift Detection — Daily CI validation against real APIs
- Streaming Physics — Configurable
ttft,tps, andjitter - WebSocket APIs — OpenAI Realtime (GA protocol with models: gpt-realtime, gpt-realtime-2, gpt-realtime-1.5, gpt-realtime-mini; transcription/translation via gpt-4o-transcribe, gpt-4o-mini-transcribe, whisper-1; image input; commentary phase), Responses WS, Gemini Live
- Prometheus Metrics — Request counts, latencies, fixture match rates
- Docker + Helm — Container image and Helm chart for CI/CD
- Vitest & Jest Plugins — Zero-config
useAimock()with auto lifecycle and env patching - Response Overrides — Control
id,model,usage,finishReasonin fixture responses - Ordered Blocks — A
blocksarray streams text and tool calls in any order (tool-first or interleaved); blocks-only fixtures are first-class, and the recorder captures order from genuinely tool-first/interleaved streams - Streaming Usage Chunks —
stream_options.include_usagesupport emits a final chunk with token counts, matching OpenAI’s streaming usage protocol - Rate Limiting Headers —
x-ratelimit-*headers on every response andRetry-Afteron 429 errors for testing retry/backoff logic - Zero dependencies — Everything from Node.js builtins
GitHub Action
- uses: CopilotKit/aimock@v1
with:
fixtures: ./test/fixtures
- run: npm test
env:
OPENAI_BASE_URL: http://127.0.0.1:4010/v1
See the GitHub Action docs for all inputs and examples.
CLI
# LLM mocking only
npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
# Remote fixtures — load JSON from an HTTPS URL (repeatable)
npx -p @copilotkit/aimock llmock -p 4010 \
-f https://raw.githubusercontent.com/acme/mocks/main/openai.json \
-f ./fixtures/local-overrides.json
# Full suite from config
npx @copilotkit/aimock --config aimock.json
# Record mode: proxy to real APIs, save fixtures
npx -p @copilotkit/aimock llmock --record --provider-openai https://api.openai.com
# Record with extended timeout for reasoning models
npx -p @copilotkit/aimock llmock --record --provider-openai https://api.openai.com \
--body-timeout-ms 180000
# Replay recorded fixtures at 2× speed
npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures --replay-speed 2
# Convert fixtures from other tools
npx @copilotkit/aimock convert vidaimock ./templates/ ./fixtures/
npx @copilotkit/aimock convert mockllm ./config.yaml ./fixtures/
# Docker
docker run -d -p 4010:4010 -v "$(pwd)/fixtures:/fixtures" ghcr.io/copilotkit/aimock -f /fixtures -h 0.0.0.0
Note on
llmockvsaimockCLIs. Thellmockbin is retained as a compat alias for users of the pre-1.7.0@copilotkit/llmockpackage. It runs a narrower flag-driven CLI without--configor theconvertsubcommand. New projects should useaimock(ornpx @copilotkit/aimock) for full feature support.
Remote fixture URLs
--fixtures accepts https:// and http:// URLs pointing at JSON fixture files in addition to filesystem paths, and the flag is repeatable so you can layer remote and local sources in argv order. Fetched fixtures are cached on disk at ~/.cache/aimock/fixtures/<sha256-of-url>/ (honors $XDG_CACHE_HOME); when paired with --validate-on-load, a fetch failure with a valid cached copy logs a warning and continues — without a cache, the process exits non-zero. HTTP fetches have a 10s timeout and a 50 MB body cap; redirects are rejected fail-loud, so configure your upstream to serve the final URL directly (GitHub raw content URLs already do).
Private and link-local addresses (loopback, RFC1918, CGNAT, cloud metadata, ULA, multicast) are rejected by default to prevent SSRF. For local development or tests that need to hit 127.0.0.1, opt out with AIMOCK_ALLOW_PRIVATE_URLS=1. Tarball and zip URL support is intentionally deferred.
Replay matching & AIMOCK_STRICT_TURN_INDEX
On replay, turnIndex is a non-fatal disambiguator, not a hard reject gate: a content-matching fixture is served even when its scripted turnIndex differs from the request’s assistant-message count. This kills false “no fixture matched” misses for multi-bubble agent runs (multi-step agents emit several assistant bubbles per logical turn). When a served fixture diverges from its scripted turnIndex, the match diagnostic carries turnIndexRelaxed: true and aimock logs a one-shot warning (at the warn log level — silent by default). To restore the legacy strict behavior where a defined turnIndex must equal the assistant count exactly, set AIMOCK_STRICT_TURN_INDEX=1. The record path is always strict regardless of this flag.
API-key validation
By default aimock accepts all requests. Opt into inbound test-client validation with a programmatic option, top-level aimock.json field, or environment-only key list:
await createServer(fixtures, { auth: { apiKeys: ["test-key"] } });
{ "auth": { "apiKeys": ["test-key"] } }
AIMOCK_API_KEYS=test-key,rotated-key npx @copilotkit/aimock --config aimock.json
Use Authorization: Bearer <key>, Authorization: Key <key>, x-api-key, x-goog-api-key, api-key, or xi-api-key. Every supplied credential must resolve to one configured key; mismatches return 401 with an OpenAI-compatible authentication error. HTTP routes, control APIs, mounts, and WebSocket upgrades are protected. Genuine CORS preflights plus GET /health, GET /ready, and GET /metrics remain public. This is inbound test access control, distinct from record.providerKeys; when enabled, proxying strips test credentials and requires a configured static provider credential before egress.
aimock-owned upstream keys — AIMOCK_PROVIDER_*_KEY
In record or --proxy-only mode, aimock forwards the caller’s auth header to the real provider unchanged. If your tests can only send a dummy placeholder key (e.g. an SDK that refuses to start without a non-empty API key), aimock can inject its own configured upstream key on a fixture-miss passthrough so the proxied call actually authenticates. Each provider has an independent env var, and the key is applied with the provider-correct wire scheme:
| Env var | Provider | Injected header |
|---|---|---|
AIMOCK_PROVIDER_OPENAI_KEY | OpenAI | Authorization: Bearer <key> |
AIMOCK_PROVIDER_OPENROUTER_KEY | OpenRouter | Authorization: Bearer <key> |
AIMOCK_PROVIDER_COHERE_KEY | Cohere | Authorization: Bearer <key> |
AIMOCK_PROVIDER_GROK_KEY | Grok (xAI) | Authorization: Bearer <key> |
AIMOCK_PROVIDER_OLLAMA_KEY | Ollama (Cloud / bearer-gated) | Authorization: Bearer <key> |
AIMOCK_PROVIDER_ANTHROPIC_KEY | Anthropic | x-api-key: <key> |
AIMOCK_PROVIDER_GEMINI_KEY | Gemini (and Gemini Interactions) | x-goog-api-key: <key> |
AIMOCK_PROVIDER_VEO_KEY | Veo | x-goog-api-key: <key> |
AIMOCK_PROVIDER_AZURE_KEY | Azure OpenAI | api-key: <key> |
AIMOCK_PROVIDER_ELEVENLABS_KEY | ElevenLabs | xi-api-key: <key> |
AIMOCK_PROVIDER_FAL_KEY | fal.ai | Authorization: Key <key> |
The Gemini interactions provider mode reuses AIMOCK_PROVIDER_GEMINI_KEY (same upstream API as Gemini). An empty-string value is treated as unset.
This is opt-in and backward-compatible: with no key configured the feature is inert and the caller’s header passes through as-is. Injection fires only when the caller sent no credential or a dummy credential prefixed with sk-aimock- (overridable via AIMOCK_DUMMY_KEY_MARKER); a real caller key never starting with that marker is always forwarded verbatim, so the caller overrides aimock. Signed and exchanged credentials — AWS Bedrock (SigV4) and Vertex AI (OAuth) — are never rewritten and always forwarded unchanged. (Azure’s static api-key is injected; a real Microsoft Entra ID Authorization: Bearer token from the caller is never dummy-prefixed, so it too passes through verbatim.)
Framework Guides
Test your AI agents with aimock — no API keys, no network calls: LangChain · CrewAI · PydanticAI · LlamaIndex · Mastra · Google ADK · Microsoft Agent Framework
Switching from other tools?
Step-by-step migration guides: MSW · VidaiMock · mock-llm · piyook/llm-mock · Python mocks · openai-responses · Mokksy
Documentation
https://aimock.copilotkit.dev · Example fixtures
Real-World Usage
AG-UI uses aimock for its end-to-end test suite, verifying AI agent behavior across LLM providers with fixture-driven responses.
License
MIT
Similar Articles
@akshay_pachaar: https://x.com/akshay_pachaar/status/2053166970166772052
The article discusses a shift in AI agent tool usage from the 'MCP vs CLI' debate to 'Code Mode,' where agents write code to dynamically import tools, significantly reducing context window usage. It highlights Anthropic's approach and Cloudflare's implementation, demonstrating a 98.7% reduction in token consumption for specific tasks.
@PrajwalTomar_: If you're serious about open source AI, bookmark this entire list. Headroom alone will save you 90% on API costs withou…
A tweet recommending several open-source AI tools, including Headroom for saving 90% on API costs, /last30days search engine, agent-skills for developer skills, and open-notebook for local notebook LM.
Cheap AI could derail OpenAI and Anthropic's IPOs (7 minute read)
The article discusses how the rising availability of cheap AI models from Chinese labs and other competitors threatens the valuation and market position of OpenAI and Anthropic ahead of their planned IPOs, as enterprise customers increasingly seek cost-effective alternatives.
AI News: Anthropic Leak Shows Us The Future of AI
A leaked Claude Code repository reveals Anthropic’s autonomous “demon-mode” agents and three-tier memory system, while OpenAI closes a record $122 B round and Microsoft ships MAI-Transcribe-1.
@akshay_pachaar: Karpathy said something you'll regret ignoring: "We have to keep the AI on the leash. I'm still the bottleneck. I have …
Karpathy's point about keeping AI on a leash still holds even as models improve, because permissions and authorization are separate from correctness. The article demonstrates how AI-generated apps lack identity and audit, and how Retool's platform solves this by providing a governed runtime.