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
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"name": "llmock",
"source": {
"source": "npm",
"package": "@copilotkit/llmock",
"version": "^1.5.0"
"package": "@copilotkit/aimock",
"version": "^1.7.0"
},
"description": "Fixture authoring skill for @copilotkit/llmock — match fields, response types, embeddings, structured output, sequential responses, streaming physics, agent loop patterns, gotchas, and debugging"
"description": "Fixture authoring skill for @copilotkit/aimock — match fields, response types, embeddings, structured output, sequential responses, streaming physics, agent loop patterns, gotchas, and debugging"
}
]
}
4 changes: 2 additions & 2 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "llmock",
"version": "1.5.0",
"description": "Fixture authoring guidance for @copilotkit/llmock",
"version": "1.7.0",
"description": "Fixture authoring guidance for @copilotkit/aimock",
"author": {
"name": "CopilotKit"
},
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/fix-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
# Step 0: Configure git identity and create fix branch
- name: Configure git
run: |
git config user.name "llmock-drift-bot"
git config user.name "aimock-drift-bot"
git config user.email "drift-bot@copilotkit.ai"
git checkout -B fix/drift-$(date +%Y-%m-%d)-${{ github.run_id }}

Expand Down
24 changes: 18 additions & 6 deletions .github/workflows/publish-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ on:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
PRIMARY_IMAGE: ghcr.io/copilotkit/aimock
COMPAT_IMAGE: ghcr.io/copilotkit/llmock

jobs:
build-and-push:
Expand All @@ -37,11 +38,20 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
- name: Extract metadata (primary — aimock)
id: meta-primary
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
images: ${{ env.PRIMARY_IMAGE }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
- name: Extract metadata (compat — llmock)
id: meta-compat
uses: docker/metadata-action@v5
with:
images: ${{ env.COMPAT_IMAGE }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
Expand All @@ -52,7 +62,9 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
tags: |
${{ steps.meta-primary.outputs.tags }}
${{ steps.meta-compat.outputs.tags }}
labels: ${{ steps.meta-primary.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
42 changes: 42 additions & 0 deletions .github/workflows/publish-pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Publish aimock-pytest
on:
push:
branches: [main]
paths:
- "packages/aimock-pytest/**"
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install build tools
run: pip install hatch

- name: Check if version is already published
id: check
run: |
VERSION=$(python -c "import tomllib; print(tomllib.load(open('packages/aimock-pytest/pyproject.toml', 'rb'))['project']['version'])")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if pip install "aimock-pytest==$VERSION" --dry-run --no-deps 2>/dev/null; then
echo "published=true" >> "$GITHUB_OUTPUT"
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi

- name: Build
if: steps.check.outputs.published == 'false'
run: cd packages/aimock-pytest && hatch build

- name: Publish to PyPI
if: steps.check.outputs.published == 'false'
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: packages/aimock-pytest/dist/
44 changes: 44 additions & 0 deletions .github/workflows/test-pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Python Tests
on:
push:
branches: [main]
paths:
- "packages/aimock-pytest/**"
- "src/**"
- "dist/**"
pull_request:
branches: [main]
paths:
- "packages/aimock-pytest/**"
- "src/**"
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

# Build the TS package first
- run: pnpm install --frozen-lockfile
- run: pnpm run build

# Set CLI path to local build
- name: Set AIMOCK_CLI_PATH
run: echo "AIMOCK_CLI_PATH=$PWD/dist/cli.js" >> $GITHUB_ENV

# Install and test Python package
- name: Install aimock-pytest
run: pip install ./packages/aimock-pytest[test]
- name: Run Python tests
run: cd packages/aimock-pytest && pytest tests/ -v
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ dist/
*.tsbuildinfo
.worktrees/
.superpowers/
coverage/
**/__pycache__/
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ dist/
node_modules/
pnpm-lock.yaml
charts/
coverage/
.remember/
30 changes: 30 additions & 0 deletions .remember/remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Handoff

## State

aimock rebrand COMPLETE on `feat/aimock` in `/Users/jpr5/proj/cpk/llmock-v1.7.0-sp1`. PR #68 on CopilotKit/llmock. Package renamed to `@copilotkit/aimock`. 1989 tests, 55 files. All docs/source/Docker/Helm/CI/skills/README rebranded. 6 migration pages, aimock-pytest, 2 converters, control API, MCP/A2A/Vector metrics. 8 blog posts on Notion.

**aimock-pytest CI + local dev path** added:

- `AIMOCK_CLI_PATH` env var support in `_node_manager.py` (ensure_installed) and `_server.py` (start) — bypasses npm tarball download, points directly at a local `cli.js`
- `tests/conftest.py` auto-detects `../../dist/cli.js` for local development
- `.github/workflows/test-pytest.yml` — Python 3.10-3.13 x Node 20/22 matrix, builds TS first, sets AIMOCK_CLI_PATH
- `.github/workflows/publish-pytest.yml` — publishes to PyPI on main push when version bumped (needs `PYPI_TOKEN` secret)
- `pyproject.toml` — added `[test]` optional dependency group (pytest, requests)
- `README.md` — added Development section with local test instructions and CI explanation

## Next

1. **Merge PR #68** → triggers npm publish + Docker push
2. **GitHub repo rename**: CopilotKit/llmock → CopilotKit/aimock (Settings → General)
3. **CNAME**: aimock.copilotkit.dev, update docs/CNAME, redirect llmock.copilotkit.dev
4. **Deprecate @copilotkit/llmock**: final version re-exporting @copilotkit/aimock
5. **Clean **pycache**** from aimock-pytest commit
6. **Add `PYPI_TOKEN` secret** to CopilotKit/llmock (or aimock) GitHub repo for publish-pytest workflow

## Context

- Branch `feat/aimock`, worktree `/Users/jpr5/proj/cpk/llmock-v1.7.0-sp1`
- Notion: Content (3353aa38-1852-81fb), Website (3353aa38-1852-811d), Conversion (3353aa38-1852-816d)
- PRs #62 (reasoning) and #63 (requestTransform) awaiting contributor fixes
- `npx aimock` always, `aimock` lowercase, `LLMock` class stays
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# @copilotkit/llmock
# @copilotkit/aimock

## 1.6.1

Expand Down
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ RUN pnpm run build
# --- Production stage ---
FROM node:22-alpine

LABEL org.opencontainers.image.title="aimock"
LABEL org.opencontainers.image.description="Mock infrastructure for AI application testing"
LABEL org.opencontainers.image.source="https://github.com/CopilotKit/llmock"

WORKDIR /app

# No runtime dependencies — all imports are node:* built-ins
Expand Down
109 changes: 46 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,98 +1,81 @@
# @copilotkit/llmock [![Unit Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml) [![Drift Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml) [![npm version](https://img.shields.io/npm/v/@copilotkit/llmock)](https://www.npmjs.com/package/@copilotkit/llmock)
# aimock [![Unit Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml) [![Drift Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml) [![npm version](https://img.shields.io/npm/v/@copilotkit/aimock)](https://www.npmjs.com/package/@copilotkit/aimock)

Deterministic mock LLM server for testing. A real HTTP server on a real port — not an in-process interceptor — so every process in your stack (Playwright, Next.js, agent workers, microservices) can point at it via `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL` and get reproducible, instant responses. Streams SSE in real OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, and Cohere API formats, driven entirely by fixtures. Zero runtime dependencies.
Mock infrastructure for AI application testing — LLM APIs, MCP tools, A2A agents, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.

## Quick Start

```bash
npm install @copilotkit/llmock
npm install @copilotkit/aimock
```

```typescript
import { LLMock } from "@copilotkit/llmock";

const mock = new LLMock({ port: 5555 });
import { LLMock } from "@copilotkit/aimock";

const mock = new LLMock({ port: 0 });
mock.onMessage("hello", { content: "Hi there!" });
await mock.start();

const url = await mock.start();
// Point your OpenAI client at `url` instead of https://api.openai.com
process.env.OPENAI_BASE_URL = `${mock.url}/v1`;

// ... run your tests ...

await mock.stop();
```

## Features
## The aimock Suite

- **[Multi-provider support](https://llmock.copilotkit.dev/compatible-providers.html)** — [OpenAI Chat Completions](https://llmock.copilotkit.dev/chat-completions.html), [OpenAI Responses](https://llmock.copilotkit.dev/responses-api.html), [Anthropic Claude](https://llmock.copilotkit.dev/claude-messages.html), [Google Gemini](https://llmock.copilotkit.dev/gemini.html), [AWS Bedrock](https://llmock.copilotkit.dev/aws-bedrock.html) (streaming + Converse), [Azure OpenAI](https://llmock.copilotkit.dev/azure-openai.html), [Vertex AI](https://llmock.copilotkit.dev/vertex-ai.html), [Ollama](https://llmock.copilotkit.dev/ollama.html), [Cohere](https://llmock.copilotkit.dev/cohere.html)
- **[Embeddings API](https://llmock.copilotkit.dev/embeddings.html)** — OpenAI-compatible embedding responses with configurable dimensions
- **[Structured output / JSON mode](https://llmock.copilotkit.dev/structured-output.html)** — `response_format`, `json_schema`, and function calling
- **[Sequential responses](https://llmock.copilotkit.dev/sequential-responses.html)** — Stateful multi-turn fixtures that return different responses on each call
- **[Streaming physics](https://llmock.copilotkit.dev/streaming-physics.html)** — Configurable `ttft`, `tps`, and `jitter` for realistic timing
- **[WebSocket APIs](https://llmock.copilotkit.dev/websocket.html)** — OpenAI Responses WS, Realtime API, and Gemini Live
- **[Error injection](https://llmock.copilotkit.dev/error-injection.html)** — One-shot errors, rate limiting, and provider-specific error formats
- **[Chaos testing](https://llmock.copilotkit.dev/chaos-testing.html)** — Probabilistic failure injection: 500 errors, malformed JSON, mid-stream disconnects
- **[Prometheus metrics](https://llmock.copilotkit.dev/metrics.html)** — Request counts, latencies, and fixture match rates at `/metrics`
- **[Request journal](https://llmock.copilotkit.dev/docs.html)** — Record, inspect, and assert on every request
- **[Fixture validation](https://llmock.copilotkit.dev/fixtures.html)** — Schema validation at load time with `--validate-on-load`
- **CLI with hot-reload** — Standalone server with `--watch` for live fixture editing
- **[Docker + Helm](https://llmock.copilotkit.dev/docker.html)** — Container image and Helm chart for CI/CD pipelines
- **Record-and-replay** — VCR-style proxy-on-miss records real API responses as fixtures for deterministic replay
- **[Drift detection](https://llmock.copilotkit.dev/drift-detection.html)** — Daily CI runs against real APIs to catch response format changes
- **Claude Code integration** — `/write-fixtures` skill teaches your AI assistant how to write fixtures correctly

## CLI Quick Reference
aimock mocks everything your AI app talks to:

```bash
llmock [options]
```
| Tool | What it mocks | Docs |
| -------------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
| **LLMock** | OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere | [Providers](https://aimock.copilotkit.dev/docs.html) |
| **MCPMock** | MCP tools, resources, prompts with session management | [MCP](https://aimock.copilotkit.dev/mcp-mock.html) |
| **A2AMock** | Agent-to-agent protocol with SSE streaming | [A2A](https://aimock.copilotkit.dev/a2a-mock.html) |
| **VectorMock** | Pinecone, Qdrant, ChromaDB compatible endpoints | [Vector](https://aimock.copilotkit.dev/vector-mock.html) |
| **Services** | Tavily search, Cohere rerank, OpenAI moderation | [Services](https://aimock.copilotkit.dev/services.html) |

| Option | Short | Default | Description |
| -------------------- | ----- | ------------ | ------------------------------------------- |
| `--port` | `-p` | `4010` | Port to listen on |
| `--host` | `-h` | `127.0.0.1` | Host to bind to |
| `--fixtures` | `-f` | `./fixtures` | Path to fixtures directory or file |
| `--latency` | `-l` | `0` | Latency between SSE chunks (ms) |
| `--chunk-size` | `-c` | `20` | Characters per SSE chunk |
| `--watch` | `-w` | | Watch fixture path for changes and reload |
| `--log-level` | | `info` | Log verbosity: `silent`, `info`, `debug` |
| `--validate-on-load` | | | Validate fixture schemas at startup |
| `--chaos-drop` | | `0` | Chaos: probability of 500 errors (0-1) |
| `--chaos-malformed` | | `0` | Chaos: probability of malformed JSON (0-1) |
| `--chaos-disconnect` | | `0` | Chaos: probability of disconnect (0-1) |
| `--metrics` | | | Enable Prometheus metrics at /metrics |
| `--record` | | | Record mode: proxy unmatched to real APIs |
| `--strict` | | | Strict mode: fail on unmatched requests |
| `--provider-*` | | | Upstream URL per provider (with `--record`) |
| `--help` | | | Show help |
Run them all on one port with `npx aimock --config aimock.json`, or use the programmatic API to compose exactly what you need.

```bash
# Start with bundled example fixtures
llmock
## Features

# Custom fixtures on a specific port
llmock -p 8080 -f ./my-fixtures
- **[Record & Replay](https://aimock.copilotkit.dev/record-replay.html)** — Proxy real APIs, save as fixtures, replay deterministically forever
- **[11 LLM Providers](https://aimock.copilotkit.dev/docs.html)** — OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere — full streaming support
- **[MCP / A2A / Vector](https://aimock.copilotkit.dev/mcp-mock.html)** — Mock every protocol your AI agents use
- **[Chaos Testing](https://aimock.copilotkit.dev/chaos-testing.html)** — 500 errors, malformed JSON, mid-stream disconnects at any probability
- **[Drift Detection](https://aimock.copilotkit.dev/drift-detection.html)** — Daily CI validation against real APIs
- **[Streaming Physics](https://aimock.copilotkit.dev/streaming-physics.html)** — Configurable `ttft`, `tps`, and `jitter`
- **[WebSocket APIs](https://aimock.copilotkit.dev/websocket.html)** — OpenAI Realtime, Responses WS, Gemini Live
- **[Prometheus Metrics](https://aimock.copilotkit.dev/metrics.html)** — Request counts, latencies, fixture match rates
- **[Docker + Helm](https://aimock.copilotkit.dev/docker.html)** — Container image and Helm chart for CI/CD
- **Zero dependencies** — Everything from Node.js builtins

# Simulate slow responses
llmock --latency 100 --chunk-size 5
## CLI

# Record mode: proxy unmatched requests to real APIs and save as fixtures
llmock --record --provider-openai https://api.openai.com --provider-anthropic https://api.anthropic.com
```bash
# LLM mocking only
npx aimock -p 4010 -f ./fixtures

# Full suite from config
npx aimock --config aimock.json

# Record mode: proxy to real APIs, save fixtures
npx aimock --record --provider-openai https://api.openai.com

# Strict mode in CI: fail if any request doesn't match a fixture
llmock --strict -f ./fixtures
# Docker
docker run -d -p 4010:4010 -v ./fixtures:/fixtures ghcr.io/copilotkit/aimock -f /fixtures
```

## Documentation
## Switching from other tools?

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

Full API reference, fixture format, E2E patterns, and provider-specific guides:
## Documentation

**[https://llmock.copilotkit.dev/docs.html](https://llmock.copilotkit.dev/docs.html)**
**[https://aimock.copilotkit.dev](https://aimock.copilotkit.dev)**

## Real-World Usage

[CopilotKit](https://github.com/CopilotKit/CopilotKit) uses llmock across its test suite to verify AI agent behavior across multiple LLM providers without hitting real APIs.
[AG-UI](https://github.com/ag-ui-protocol/ag-ui) uses aimock for its [end-to-end test suite](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e), verifying AI agent behavior across LLM providers with [fixture-driven responses](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e/fixtures/openai).

## License

Expand Down
6 changes: 6 additions & 0 deletions charts/aimock/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v2
name: aimock
description: Mock infrastructure for AI application testing (OpenAI, Anthropic, Gemini, MCP, A2A, vector)
type: application
version: 0.1.0
appVersion: "1.7.0"
Loading
Loading