diff --git a/docs/chaos-testing/index.html b/docs/chaos-testing/index.html index cdbbbde7..3a51a323 100644 --- a/docs/chaos-testing/index.html +++ b/docs/chaos-testing/index.html @@ -217,7 +217,7 @@
$ npx @copilotkit/aimock --fixtures ./fixtures \
+ $ npx -p @copilotkit/aimock llmock --fixtures ./fixtures \
--chaos-drop 0.1 \
--chaos-malformed 0.05 \
--chaos-disconnect 0.02
@@ -254,7 +254,7 @@ Journal Tracking
"path": "/v1/chat/completions",
"response": {
"status": 500,
- "fixture": { "..." },
+ "fixture": { "...": "elided for brevity" },
"chaosAction": "drop"
}
}
diff --git a/docs/migrate-from-mock-llm/index.html b/docs/migrate-from-mock-llm/index.html
index bac7c2d4..a83c210f 100644
--- a/docs/migrate-from-mock-llm/index.html
+++ b/docs/migrate-from-mock-llm/index.html
@@ -242,7 +242,7 @@ Mock Pinecone, Qdrant, Weaviate, and ChromaDB endpoints for RAG pipeline testing.
+Mock Pinecone, Qdrant, and ChromaDB endpoints for RAG pipeline testing.
# Run the mock server
-npx @copilotkit/aimock -p 4010 -f ./fixtures
+ # Run the mock server (flag-driven llmock bin)
+npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
# With a full config file
npx @copilotkit/aimock --config aimock.json --port 4010
diff --git a/docs/migrate-from-mokksy/index.html b/docs/migrate-from-mokksy/index.html
index 3f044759..c22fd96b 100644
--- a/docs/migrate-from-mokksy/index.html
+++ b/docs/migrate-from-mokksy/index.html
@@ -153,16 +153,19 @@ The quick switch
"-p", "4010:4010", "-v", "./fixtures:/fixtures",
"ghcr.io/copilotkit/aimock", "-f", "/fixtures", "-h", "0.0.0.0")
.start().waitFor()
- // Wait for server to be ready
+ // Wait for server to be ready — fail loudly if it never comes up
+ var lastError: Exception? = null
repeat(30) {
try {
- java.net.URL("http://localhost:4010/__aimock/health")
+ java.net.URL("http://localhost:4010/health")
.readText()
return
- } catch (_: Exception) {
+ } catch (e: Exception) {
+ lastError = e
Thread.sleep(200)
}
}
+ throw IllegalStateException("aimock did not become healthy after 30 attempts", lastError)
}
@AfterAll
@@ -403,7 +406,7 @@ CLI / Docker quick start
CLI sh
- npx @copilotkit/aimock -p 4010 -f ./fixtures
+ npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
diff --git a/docs/migrate-from-msw/index.html b/docs/migrate-from-msw/index.html
index e04cf47e..886d2e54 100644
--- a/docs/migrate-from-msw/index.html
+++ b/docs/migrate-from-msw/index.html
@@ -250,14 +250,21 @@ Built-in SSE for 8 providers
WebSocket APIs
- OpenAI Realtime, Responses WS, Gemini Live. MSW cannot intercept WebSocket.
+
+ OpenAI Realtime, Responses WS, Gemini Live — all built in. MSW v2 added
+ WebSocket interception via ws.link(), but you still handwrite every
+ frame; aimock ships the full provider handshakes.
+
Record & Replay
Proxy real APIs, save as fixtures, replay forever.
- npx @copilotkit/aimock --record --provider-openai https://api.openai.com
+ npx -p @copilotkit/aimock llmock --record --provider-openai
+ https://api.openai.com
@@ -311,9 +318,9 @@ What you keep (or lose)
WebSocket
- ✗
- ✓
- 3 protocols
+ Manual (ws.link, v2+)
+ Built-in
+ 3 AI protocols
Record & replay
@@ -347,6 +354,7 @@ Using aimock alongside MSW
test-setup.ts ts
// test setup
import { setupServer } from 'msw/node'
+import { http, HttpResponse } from 'msw'
import { LLMock } from '@copilotkit/aimock'
// MSW for REST APIs
@@ -372,7 +380,7 @@ CLI / Docker quick start
CLI sh
- npx @copilotkit/aimock -p 4010 -f ./fixtures
+ npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
diff --git a/docs/migrate-from-openai-responses/index.html b/docs/migrate-from-openai-responses/index.html
index 1e54d1b8..c9abebe5 100644
--- a/docs/migrate-from-openai-responses/index.html
+++ b/docs/migrate-from-openai-responses/index.html
@@ -183,7 +183,7 @@ Before / After
from openai import OpenAI
def test_chat(aimock):
- aimock.on_message("hi", content="Hello!")
+ aimock.on_message("hi", {"content": "Hello!"})
client = OpenAI(base_url=aimock.url + "/v1", api_key="test")
result = client.chat.completions.create(
model="gpt-4o", messages=[{"role": "user", "content": "hi"}]
@@ -266,7 +266,7 @@ Feature mapping
openai_mock.chat.completions.create.response = {...}
- aimock.on_message("pattern", content="...")
+ aimock.on_message("pattern", {"content": "..."})
Partial envelope (choices required, other fields auto-filled)
diff --git a/docs/migrate-from-piyook/index.html b/docs/migrate-from-piyook/index.html
index 00fc6aea..67e31b1c 100644
--- a/docs/migrate-from-piyook/index.html
+++ b/docs/migrate-from-piyook/index.html
@@ -191,14 +191,14 @@ Fixture format comparison
{
"match": { "userMessage": "hello" },
"response": { "content": "Hello there" }
-}
-
-// aimock auto-generates:
-// - id, object, created, model
-// - choices[].index, finish_reason
-// - usage (prompt_tokens, completion_tokens)
-// - SSE streaming chunks (when stream: true)
+}
+
+ aimock auto-generates id, object, created,
+ model, choices[].index, finish_reason,
+ usage (prompt / completion tokens), and SSE streaming chunks when
+ stream: true.
+
@@ -391,8 +391,8 @@
CLI / Docker quick start
Install & run sh
- # Run the mock server
-npx @copilotkit/aimock -p 4010 -f ./fixtures
+ # Run the mock server (flag-driven llmock bin)
+npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
# With a full config file
npx @copilotkit/aimock --config aimock.json --port 4010
diff --git a/docs/migrate-from-python-mocks/index.html b/docs/migrate-from-python-mocks/index.html
index 3ee71a42..42b68b57 100644
--- a/docs/migrate-from-python-mocks/index.html
+++ b/docs/migrate-from-python-mocks/index.html
@@ -255,21 +255,41 @@ aimock (after)
"ghcr.io/copilotkit/aimock:latest",
"-f", "/fixtures", "-h", "0.0.0.0"
])
- # Wait for health endpoint
+ # Wait for health endpoint — fail loudly if aimock never comes up
import requests
for _ in range(30):
+ if proc.poll() is not None:
+ raise RuntimeError(f"aimock exited early with code {proc.returncode}")
try:
- if requests.get("http://localhost:4010/__aimock/health").ok:
+ if requests.get("http://localhost:4010/health").ok:
break
except requests.ConnectionError:
- time.sleep(0.2)
-
+ pass
+ time.sleep(0.2)
+ else:
+ raise RuntimeError("aimock did not become healthy after 30 attempts")
+
+ # Save originals so we don't clobber real credentials in the test process
+ prev_base = os.environ.get("OPENAI_BASE_URL")
+ prev_key = os.environ.get("OPENAI_API_KEY")
os.environ["OPENAI_BASE_URL"] = "http://localhost:4010/v1"
os.environ["OPENAI_API_KEY"] = "mock-key"
- yield "http://localhost:4010"
- proc.terminate()
- proc.wait()
+ try:
+ yield "http://localhost:4010"
+ finally:
+ proc.terminate()
+ try:
+ proc.wait(timeout=10)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ proc.wait(timeout=5)
+ # Restore originals (or remove if there were none)
+ for name, val in (("OPENAI_BASE_URL", prev_base), ("OPENAI_API_KEY", prev_key)):
+ if val is None:
+ os.environ.pop(name, None)
+ else:
+ os.environ[name] = val
@@ -435,8 +455,8 @@ CLI / Docker quick start
Install & run sh
- # Run the mock server (requires Node.js)
-npx @copilotkit/aimock -p 4010 -f ./fixtures
+ # Run the mock server (requires Node.js, flag-driven llmock bin)
+npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
# Point your Python app at the mock
export OPENAI_BASE_URL=http://localhost:4010/v1
@@ -490,24 +510,44 @@ Alternative: npx fixture (no Docker)
@pytest.fixture(scope="session")
def aimock_server():
proc = subprocess.Popen(
- ["npx", "aimock", "-p", "4010", "-f", "./fixtures"],
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT
+ ["npx", "-p", "@copilotkit/aimock", "llmock", "-p", "4010", "-f", "./fixtures"],
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
- # Wait for health endpoint
+ # Wait for health endpoint — fail loudly if aimock never comes up
import requests
for _ in range(30):
+ if proc.poll() is not None:
+ raise RuntimeError(f"aimock exited early with code {proc.returncode}")
try:
- if requests.get("http://localhost:4010/__aimock/health").ok:
+ if requests.get("http://localhost:4010/health").ok:
break
except requests.ConnectionError:
- time.sleep(0.2)
-
+ pass
+ time.sleep(0.2)
+ else:
+ raise RuntimeError("aimock did not become healthy after 30 attempts")
+
+ # Save originals so we don't clobber real credentials in the test process
+ prev_base = os.environ.get("OPENAI_BASE_URL")
+ prev_key = os.environ.get("OPENAI_API_KEY")
os.environ["OPENAI_BASE_URL"] = "http://localhost:4010/v1"
os.environ["OPENAI_API_KEY"] = "mock-key"
- yield "http://localhost:4010"
- proc.terminate()
- proc.wait()
+ try:
+ yield "http://localhost:4010"
+ finally:
+ proc.terminate()
+ try:
+ proc.wait(timeout=10)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ proc.wait(timeout=5)
+ # Restore originals (or remove if there were none)
+ for name, val in (("OPENAI_BASE_URL", prev_base), ("OPENAI_API_KEY", prev_key)):
+ if val is None:
+ os.environ.pop(name, None)
+ else:
+ os.environ[name] = val
diff --git a/docs/migrate-from-vidaimock/index.html b/docs/migrate-from-vidaimock/index.html
index 1ea3debb..acdd2a2f 100644
--- a/docs/migrate-from-vidaimock/index.html
+++ b/docs/migrate-from-vidaimock/index.html
@@ -78,7 +78,7 @@ The quick switch
aimock (equivalent)
shell
- npx @copilotkit/aimock -p 4010 -f ./fixtures
+ npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
@@ -286,8 +286,8 @@ CLI / Docker quick start
Install & run
shell
- # Run the mock server
-npx @copilotkit/aimock -p 4010 -f ./fixtures
+ # Run the mock server (flag-driven llmock bin)
+npx -p @copilotkit/aimock llmock -p 4010 -f ./fixtures
# Point your app at it
export OPENAI_BASE_URL=http://localhost:4010/v1
diff --git a/docs/record-replay/index.html b/docs/record-replay/index.html
index 4d4a21ce..a3166d29 100644
--- a/docs/record-replay/index.html
+++ b/docs/record-replay/index.html
@@ -89,7 +89,7 @@ Proxy-Only Mode
Proxy-only mode shell
- $ npx @copilotkit/aimock -f ./fixtures \
+ $ npx -p @copilotkit/aimock llmock -f ./fixtures \
--proxy-only \
--provider-openai https://api.openai.com
@@ -140,7 +140,7 @@ Quick Start
CLI usage shell
- $ npx @copilotkit/aimock -f ./fixtures \
+ $ npx -p @copilotkit/aimock llmock -f ./fixtures \
--record \
--provider-openai https://api.openai.com \
--provider-anthropic https://api.anthropic.com
@@ -302,20 +302,25 @@ Programmatic API
const mock = new LLMock();
await mock.start();
-// Enable recording — unmatched requests are proxied AND saved as fixtures
-mock.enableRecording({
- providers: {
- openai: "https://api.openai.com",
- anthropic: "https://api.anthropic.com",
- },
- fixturePath: "./fixtures/recorded",
-});
-
-// Make requests — unmatched ones are proxied and recorded
-// ...
-
-// Disable recording — recorded fixtures persist on disk
-mock.disableRecording();
+try {
+ // Enable recording — unmatched requests are proxied AND saved as fixtures
+ mock.enableRecording({
+ providers: {
+ openai: "https://api.openai.com",
+ anthropic: "https://api.anthropic.com",
+ },
+ fixturePath: "./fixtures/recorded",
+ });
+
+ // Make requests — unmatched ones are proxied and recorded
+ // ...
+
+ // Disable recording — recorded fixtures persist on disk
+ mock.disableRecording();
+} finally {
+ // Always release the port, even if a test above threw
+ await mock.stop();
+}
@@ -478,10 +483,10 @@
Local Development Workflow
Record then replay shell
# First run: record real API responses
-$ npx @copilotkit/aimock --record --provider-openai https://api.openai.com -f ./fixtures
+$ npx -p @copilotkit/aimock llmock --record --provider-openai https://api.openai.com -f ./fixtures
# Subsequent runs: replay from recorded fixtures
-$ npx @copilotkit/aimock -f ./fixtures
+$ npx -p @copilotkit/aimock llmock -f ./fixtures
@@ -516,7 +521,7 @@ CI Pipeline Workflow
- name: Start aimock
run: |
- docker run -d --name aimock \
+ docker run -d --rm --name aimock \
-v ./fixtures:/fixtures \
-p 4010:4010 \
ghcr.io/copilotkit/aimock \
@@ -528,7 +533,8 @@ CI Pipeline Workflow
run: pnpm test
- name: Stop aimock
- run: docker stop aimock
+ if: always()
+ run: docker rm -f aimock
Request Transform
@@ -686,11 +692,16 @@ Cross-Language Testing
import openai
client = openai.OpenAI(base_url="http://localhost:4010/v1", api_key="mock")
-# Go
-client := openai.NewClient(option.WithBaseURL("http://localhost:4010/v1"))
+# Go — github.com/sashabaranov/go-openai
+config := openai.DefaultConfig("mock")
+config.BaseURL = "http://localhost:4010/v1"
+client := openai.NewClientWithConfig(config)
-# Rust
-let client = Client::new().with_base_url("http://localhost:4010/v1");
+# Rust — async-openai
+let config = OpenAIConfig::new()
+ .with_api_base("http://localhost:4010/v1")
+ .with_api_key("mock");
+let client = Client::with_config(config);