docs: mention WebSocket support in README intro and request journal#1
Open
NathanTarbert wants to merge 106 commits into
Open
docs: mention WebSocket support in README intro and request journal#1NathanTarbert wants to merge 106 commits into
NathanTarbert wants to merge 106 commits into
Conversation
Comprehensive /write-fixtures skill covering match fields, response types, agent loop patterns (tool call → tool result → final response), predicate routing, catch-alls, error injection, stream interruption, and debugging fixture mismatches. Distributed as a Claude Code plugin via marketplace: /plugin marketplace add CopilotKit/llmock /plugin install llmock@copilotkit-tools Also available via --plugin-dir, --add-dir, or manual copy.
Four install methods documented: plugin marketplace (recommended), local plugin from node_modules, --add-dir, and manual copy. Nav link and feature cards added to docs site. Changelog updated for 1.3.1.
Adds .claude-plugin, .claude, and skills directories to the package files array so downstream consumers get the fixture authoring skill when they npm install.
## Summary - Adds `.claude/commands/write-fixtures.md` — a comprehensive fixture authoring guide available as `/write-fixtures` slash command in Claude Code - Covers match fields, response types, common patterns (tool call loops, catch-alls, predicate routing), critical gotchas, debugging mismatches, and E2E test setup - Verified against current API surface (v1.3.0) including interruption options (`truncateAfterChunks`/`disconnectAfterMs`) ## Test plan - [ ] Invoke `/write-fixtures` in Claude Code while working in the llmock repo — confirm skill loads and renders correctly - [ ] Verify code examples are syntactically correct TypeScript - [ ] Confirm all documented API methods exist on the `LLMock` class
Track gif, jpg, jpeg, png, pdf, mp4, webm, and svg files via Git LFS. Matches CopilotKit/CopilotKit convention (PR #3418). Needed before any binary assets (screenshots, demo videos) land.
## Summary - Adds `.gitattributes` tracking gif, jpg, jpeg, png, pdf, mp4, webm, and svg via Git LFS - Matches CopilotKit/CopilotKit convention (PR #3418) - Needed before any binary assets (screenshots, demo videos) are added to the repo ## Test plan - [ ] `git lfs env` confirms LFS is active - [ ] Adding a binary file shows it tracked via `git lfs status`
skills/write-fixtures/SKILL.md is now a symlink to .claude/commands/write-fixtures.md. Single source of truth, both --plugin-dir and --add-dir discovery paths still work.
## Summary - Replaces `skills/write-fixtures/SKILL.md` (full copy) with a symlink to `.claude/commands/write-fixtures.md` - Single source of truth, both `--plugin-dir` and `--add-dir` discovery paths still work ## Test plan - [ ] `claude --plugin-dir ./node_modules/@copilotkit/llmock` discovers `/llmock:write-fixtures` - [ ] `claude --add-dir ./node_modules/@copilotkit/llmock` discovers `/write-fixtures` - [ ] Symlink resolves correctly after `npm install`
NathanTarbert
force-pushed
the
docs/update-readme-websocket
branch
from
March 12, 2026 01:49
8116137 to
c1593fd
Compare
OpenAI now returns a `refusal` field (null for non-refusal responses) on all Chat Completions messages. Both the SDK types and real API include it, but llmock was omitting it — causing shape mismatches for consumers that validate response structure.
Three-layer triangulation between SDK types, real API responses, and llmock output to detect response shape drift across OpenAI (Chat + Responses), Anthropic Claude, and Google Gemini. - schema.ts: shape extraction, three-way comparison, severity classification - sdk-shapes.ts: expected shapes from SDK types - providers.ts: raw fetch clients, SSE parsing, model listing - helpers.ts: shared test fixtures and server lifecycle - 4 provider drift test files (16 tests) + model deprecation checks (3 tests) - vitest.config.drift.ts: separate config with 30s timeout - Weekly CI workflow (.github/workflows/test-drift.yml) - DRIFT.md: full documentation
## Summary - **Bug fix**: OpenAI Chat Completions responses now include `refusal: null` — a field both the SDK and real API return that llmock was omitting. Conformance and unit tests updated to assert the field. - **New feature**: Three-layer drift detection test suite that triangulates between SDK types, real API responses, and llmock output to catch response shape drift across all 4 providers (OpenAI Chat, OpenAI Responses, Anthropic Claude, Google Gemini) - **CI**: Weekly GitHub Actions workflow for automated drift checks + manual trigger ## Details 19 drift tests across 5 files: - 16 shape comparison tests (4 per provider × 4 scenarios: non-streaming text/tool, streaming text/tool) - 3 model deprecation checks (one per provider) Key robustness features: - All provider functions fail fast on non-2xx responses with status code + body in the error message - All streaming tests assert events were actually received (no silent pass on zero events) - SSE parsers handle `\r\n` line endings and continuation lines (Gemini sends wrapped JSON) - Retry with exponential backoff on 429/500/502/503 - `ping` and other transport-level SSE events classified as `info`, not `critical` - Known intentional differences (usage fields, system_fingerprint, etc.) allowlisted The refusal bug was discovered by running the drift tests against real APIs — exactly the value prop. See [DRIFT.md](DRIFT.md) for full documentation. ## Test plan - [x] `pnpm test` — 540/540 existing tests pass (including new refusal assertions) - [x] `pnpm test:drift` with all 3 API keys — 19/19 pass - [x] `pnpm test:drift` without keys — 19 tests skip gracefully - [x] Prettier + ESLint clean - [x] 4 rounds of code review (code-reviewer, silent-failure-hunter, code-simplifier, comment-analyzer, pr-test-analyzer, type-design-analyzer) — all clean 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Add Gemini base URL setup instructions to README (both SDK versions) - Add missing ANTHROPIC_API_KEY=mock-key to README env block - Center orphan WebSocket APIs card in features grid - Move Real-World Usage section to bottom of docs site - Tighten section padding (6rem → 3rem) - Remove inconsistent border-top on comparison section - Match Real-World Usage heading and description style to other sections
The real OpenAI Responses WS API expects a flat message format:
{ type: "response.create", model: "...", input: [...] }
The handler previously required fields nested under a "response"
object, which doesn't match the real API. Updated the handler and
all existing WS tests to use the flat format.
…emini Live TLS WebSocket client (ws-providers.ts) connects to real provider WS endpoints using node:tls with RFC 6455 framing, ping/pong, and connection-scoped message cursors for multi-step protocols. 4 verified drift tests: - OpenAI Responses WS: text + tool call - OpenAI Realtime: text + tool call (gpt-4o-mini-realtime-preview) Canaries: - Realtime: checks gpt-4o-mini-realtime-preview still exists in model listing API, with hints for the GA replacement - Gemini Live: checks model listing API for text-capable bidiGenerateContent models; full drift tests skipped until Google ships a non-audio Live model Supporting changes: - sdk-shapes.ts: Realtime + Gemini Live event shapes - helpers.ts: collectMockWSMessages(), classifyGeminiMessage, GEMINI_WS_PATH - models.drift.ts: filter markdown anchor fragments from model scraper
DRIFT.md: WS coverage table with verified/unverified status, Gemini Live explanation, cost estimate (25 API calls), "Adding a New Provider" WS step. README.md: fix Gemini Live response shape example, update model name, add unverified warning, fix Responses WS example to use flat format. docs/index.html: add unverified note to Gemini Live in feature list and comparison table. CHANGELOG.md: 1.3.3 patch notes. vitest.config.drift.ts: increase testTimeout to 60s for WS protocols.
## Summary
- **Fix Responses WS input format**: handler now accepts the flat
`response.create` format matching the real OpenAI API (previously
required a non-standard nested `response: { ... }` envelope)
- **4 verified WS drift tests**: OpenAI Responses WS (text + tool call)
and OpenAI Realtime (text + tool call), triangulated against real APIs
- **Model canaries**: Realtime preview model availability check (detects
deprecation, suggests GA replacement); Gemini Live text-capable model
availability check (enables drift tests when Google ships one)
- **Gemini Live**: protocol implemented per docs, documented as
unverified — no text-capable `bidiGenerateContent` model exists yet
- TLS WebSocket client (`ws-providers.ts`) with RFC 6455 framing,
ping/pong, connection-scoped cursors
- SDK shapes for Realtime and Gemini Live event sequences
- Fix README Gemini Live response shape example and Responses WS example
## Test plan
- [x] `pnpm test` — 540 unit tests pass
- [x] `pnpm test:drift` without keys — all 27 tests skip gracefully
- [x] `pnpm test:drift` with keys — 25 pass, 2 skip (Gemini Live
text/tool)
- [x] `pnpm run format:check` — clean
- [x] `pnpm run lint` — clean
- [x] 5 rounds of CR→fix loop with full pr-review-toolkit suite
🤖 Generated with [Claude Code](https://claude.com/claude-code)
New section between "Fixture-driven" and "llmock vs MSW" with: - SVG triangle diagram showing three-way drift detection (SDK types × Real API × llmock) - Three diagnosis cards (mock drift, provider ahead of SDK, all clear) - Real drift report output showing mixed severity results - Daily CI badge footer Also: drift cron weekly → daily, nav link added, DRIFT.md cost updated for daily cadence, README "weekly" → "daily".
…otKit#38) ## Summary - New "Reliability" section on the docs site between code examples and MSW comparison - SVG triangle diagram showing three-way drift detection (SDK types × Real API × llmock) - Three diagnosis cards: mock drift (red), provider ahead of SDK (amber), all clear (green) - Real drift report output showing mixed severity results - Daily CI badge footer - Drift cron changed from weekly to daily - Nav link added for new section - DRIFT.md cost updated for daily cadence - README "weekly" → "daily" ## Test plan - [x] `pnpm test` — 540/540 pass - [x] All CSS uses site custom properties (no hardcoded hex) - [x] Mobile breakpoints for diagnosis grid and CI footer - [x] 2 rounds of CR — all 6 toolkit agents, clean on final round 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds the Drift Tests CI badge next to the existing Unit Tests badge.
New src/logger.ts with silent/info/debug levels. Warnings and errors always print regardless of level. Logger threaded through createServer via the widened defaults object. WebSocket upgrade console.error calls migrated to logger.
validateFixtures() checks: response type recognition, empty content, tool call name/JSON validity, empty toolCalls arrays, error message presence, HTTP status range, numeric field bounds. Warns on duplicate userMessage shadowing and catch-all positioning. Load functions accept optional logger with backward-compatible console.warn fallback.
--watch (-w): 500ms debounced fs.watch with in-place fixture reload. Error handler on FSWatcher surfaces dead-watcher conditions. Actionable error messages on reload failure. Keeps previous fixtures when validation fails. --log-level: silent/info/debug (default: info). Startup, reload, and shutdown messages at info. Warnings/errors always print. --validate-on-load: exits 1 on errors at startup. In watch mode, errors prevent reload without killing the server. CLI options table updated. Future Direction CLI section removed.
…tKit#40) ## Summary Three CLI features from the Future Direction section: - **--watch** (`-w`): 500ms debounced `fs.watch` with in-place fixture reload. Keeps previous fixtures on validation failure. Error handler on FSWatcher surfaces dead-watcher conditions. - **--log-level**: `silent` / `info` (default) / `debug`. Startup messages and per-request access logs at info. Match traces at debug. Warnings/errors always print. - **--validate-on-load**: Runs `validateFixtures()` at startup, exits 1 on errors. In watch mode, errors prevent reload but don't exit. ### Validation checks **Errors** (exit 1): unrecognized response type, empty content, empty tool call name, unparseable tool call arguments, empty error message, invalid HTTP status, negative latency, chunkSize < 1, truncateAfterChunks < 1, negative disconnectAfterMs. **Warnings** (logged): duplicate userMessage shadowing, catch-all not in last position. ### New files - `src/logger.ts` — Logger class with silent/info/debug levels - `src/watcher.ts` — File watcher for fixture hot-reload ### Documentation - CLI options table updated with new flags - Future Direction CLI section removed (all items implemented) ## Test plan - [x] 564/564 tests pass (24 new: 15 validation + 9 CLI integration) - [x] Prettier + ESLint clean - [x] 2 rounds of CR (code-reviewer, silent-failure-hunter, code-simplifier, pr-test-analyzer) — clean on final round 🤖 Generated with [Claude Code](https://claude.com/claude-code)
) ## Summary Post-merge follow-up to PR CopilotKit#40. Addresses 3 findings from code review: - Watcher error handler now clears debounce timer and closes FSWatcher to avoid indeterminate state after fs.watch errors - Reload guards against replacing fixtures with empty array on parse failure, preserving previous working fixtures - Update README Future Direction to reflect that `--validate-on-load` and `validateFixtures()` now exist ## Test plan - [x] All 565 existing tests pass - [ ] Manually verify watcher error recovery (kill the watched file's filesystem) - [ ] Verify reload with invalid JSON preserves previous fixtures
…d time Add error-severity validation checks in validateFixtures for streamingProfile (ttft >= 0, tps > 0, jitter in [0,1]) and chaos (all rates in [0,1]). Catches nonsensical streaming physics and out-of-range chaos rates early with clear error messages rather than silently producing broken behavior at request time.
…G chaos flags - docker.html: fix health probes (TCP socket → httpGet on /health and /ready) - docker.html: remove "CLI Configuration (v1.7.0)" section (references non-existent --config flag and aimock binary name) - docker.html: fix --chaos-error-rate → --chaos-drop/--chaos-malformed/--chaos-disconnect - docker.html: fix mountPath /fixtures → /app/fixtures (matches actual values.yaml) - docs.html: add POST /v2/chat (Cohere) and POST /api/generate (Ollama) to endpoint table - CHANGELOG.md: fix "via --chaos CLI flag" → list all three chaos flags - README.md: fix chaos-testing link (chaos.html → chaos-testing.html)
… bedrock SSE; body timeout
- chaos.ts: add optional logger param to resolveChaosConfig/evaluateChaos/applyChaos;
replace all console.warn calls with logger?.warn
- stream-collapse.ts: logger param on collapseStreamingResponse; replace console.warn;
add explicit case "bedrock" routing to collapseAnthropicSSE; add bounds check in
decodeEventStreamFrames — return {frames, truncated:true} when totalLength extends
past buffer, preventing out-of-bounds reads on malformed/truncated EventStream frames
- recorder.ts: pass defaults.logger to collapseStreamingResponse; add res.setTimeout
body accumulation timeout (30s) to prevent unbounded memory growth on slow responses
- bedrock.ts: update module docstring to describe all four endpoint families
- all handlers: pass defaults.logger as final arg to all applyChaos call sites
…edrock SSE, and body timeout
- chaos.test.ts: verify evaluateChaos without logger does not call console.warn;
verify invalid chaos header with logLevel:silent is silently ignored end-to-end
- stream-collapse.test.ts: verify bounds check returns {truncated:true} for
oversized totalLength; verify provider="bedrock" routes to collapseAnthropicSSE
- recorder.test.ts: verify proxyAndRecord calls res.setTimeout(30_000) on
upstream IncomingMessage
…ation, type unions - recorder.ts: fix misleading 'saving raw response' log → 'saving as error fixture' - recorder.ts: warn when stream collapse produces empty content - recorder.ts: preserve both empty-match and truncation warnings in fixture JSON - cli.ts: exit(1) on zero fixtures in strict/validate mode - server.ts: warn on out-of-range chaos config values at startup - bedrock.ts/messages.ts: narrow content block type from string to union - aws-event-stream.ts: fix writeEventStream docstring return semantics
…Kit#53) ## Summary Major feature release adding 8 capabilities to llmock, plus 29 bugs found and fixed in code review. ### Provider Endpoints - **Bedrock Streaming** — invoke-with-response-stream (AWS Event Stream binary) + Converse API - **Vertex AI** — Routes to existing Gemini handler - **Ollama** — /api/chat, /api/generate, /api/tags (NDJSON streaming) - **Cohere** — /v2/chat (typed SSE events) ### Infrastructure - **Chaos Testing** — Probabilistic drop/malformed/disconnect, three precedence levels (header > fixture > server), rate clamping to [0,1] - **Prometheus Metrics** — Opt-in /metrics, counters, cumulative histograms, gauges ### Record-and-Replay - **Proxy-on-miss** — Real API responses saved as fixtures with 30s upstream timeout - **Stream collapsing** — 6 functions (SSE, NDJSON, EventStream) supporting both Converse and Messages formats - **Strict mode (503)** — Catch missing fixtures in CI - **Auth safety** — Forwarded but redacted in journal, never in fixtures ### Quality - **1250 tests** across 37 files - 7 rounds of 7-agent code review, 29 bugs found and fixed - Build/format/lint clean, zero external dependencies, zero as-any in source ## Review Fixes (29 total across 7 rounds) ### Round 1: Original review (20 findings) - HandlerDefaults type extracted, fixing silent undefined access in 5 handlers - Provider-specific error formats (Anthropic, Gemini, Bedrock) - Recorder binary relay corruption (UTF-8 round-trip on EventStream) - collapseOllamaNDJSON tool_calls + buildFixtureResponse priority - ChaosAction dedup, RecordProviderKey union, OllamaMessage.role union - collapseCohereSSE naming, chaos rate clamping, recorder auth comment - SKILL.md 503 status, warn log level, README provider list, types.ts header ### Round 2 (2 findings) - applyChaos registry argument missing in 5 handlers (chaos metrics incomplete) - Bedrock Converse response format missing in buildFixtureResponse ### Round 5 — fresh context (2 findings) - Global recordCounter → crypto.randomUUID() (concurrent test determinism) - rawBody pass-through in OpenAI completions proxy path ### Round 6 — fresh context (2 findings) - 30s upstream timeout in makeUpstreamRequest (prevents indefinite hangs) - collapseBedrockEventStream: handle both Converse (camelCase) and Messages (flat type) formats ### Round 7 — fresh context (3 findings) - new URL() validation with specific 502 error for malformed provider URLs - writtenToDisk flag to prevent misleading "Response recorded" log on write failure - res.on("error") handler for upstream response stream mid-transfer drops All fixes have corresponding regression tests.
Automated weekly update based on competitor README analysis.
Writes a markdown file with a change table and mermaid flowchart grouped by competitor. Mermaid node labels are quoted and subgraph IDs sanitized to handle special characters in competitor/capability names.
Covers markdown table generation, mermaid flowchart structure, special character escaping (parentheses, quotes, slashes), competitor grouping, node ID uniqueness, and file I/O.
Pass --summary to the script and use gh pr create --body-file to inject the markdown directly, avoiding shell interpolation of backticks from the mermaid code fences.
## Summary - The `update-competitive-matrix.ts` script now accepts `--summary <path>` to write a markdown summary with a change table and mermaid flowchart grouped by competitor - The workflow uses `--body-file` to inject the summary directly into the PR body, avoiding shell interpolation of mermaid backtick fences - Mermaid node labels are quoted and subgraph IDs sanitized to handle special characters (parentheses, slashes, quotes) - Unit tests cover formatting, mermaid structure, escaping, and edge cases ## Test plan - [x] `pnpm test` — 1318 tests pass (13 new) - [x] `pnpm run format:check` — clean - [x] `pnpm run lint` — clean - [x] `pnpm run build` — clean - [ ] Trigger workflow via `workflow_dispatch` and confirm PR body renders correctly
The URL constructor drops the base path when the pathname is absolute:
new URL("/v1/chat/completions", "https://openrouter.ai/api") resolves to
https://openrouter.ai/v1/chat/completions — losing /api.
Extract resolveUpstreamUrl() that normalizes inputs for RFC 3986 relative
resolution (trailing slash on base, strip leading slash from pathname).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The record proxy only forwarded a hardcoded list of headers (authorization, x-api-key, api-key, content-type, accept), silently dropping provider-specific headers like anthropic-version. This made --record mode unusable with the Anthropic API. Forward all request headers by default, excluding only hop-by-hop headers that should not be proxied (host, connection, content-length, transfer-encoding, keep-alive, upgrade).
## Problem
The record proxy loses the base URL path prefix when constructing
upstream URLs.
`new URL("/v1/chat/completions", "https://openrouter.ai/api")` resolves
to
`https://openrouter.ai/v1/chat/completions` — the `/api` prefix is
dropped.
This is standard `URL` constructor behavior (absolute pathname replaces
the
base path), but breaks providers like OpenRouter whose API lives at a
non-root path (`/api/v1/...`).
Providers with root-path APIs (OpenAI, Anthropic) are unaffected.
## Fix
Extract URL joining into a `resolveUpstreamUrl()` helper that normalizes
inputs for RFC 3986 relative resolution:
- Ensure base URL has a trailing slash (marks it as a "directory")
- Strip leading slash from pathname (makes it relative, not absolute)
This preserves any path prefix while keeping existing behavior for
root-path providers unchanged. Unit tests cover all combinations.
## Examples
| Base URL | Pathname | Before | After |
|---|---|---|---|
| `https://openrouter.ai/api` | `/v1/chat/completions` |
`https://openrouter.ai/v1/chat/completions` |
`https://openrouter.ai/api/v1/chat/completions` |
| `https://api.openai.com` | `/v1/chat/completions` |
`https://api.openai.com/v1/chat/completions` |
`https://api.openai.com/v1/chat/completions` |
| `https://api.anthropic.com` | `/v1/messages` |
`https://api.anthropic.com/v1/messages` |
`https://api.anthropic.com/v1/messages` |
## Problem
The record proxy only forwards 5 hardcoded request headers to the
upstream provider:
`authorization`, `x-api-key`, `api-key`, `content-type`, `accept`.
Provider-specific headers are silently dropped. For example, the
Anthropic API
requires the `anthropic-version` header on every request — without it,
the API
returns 400:
```
{'type': 'error', 'error': {'type': 'invalid_request_error',
'message': 'anthropic-version: header is required'}}
```
This makes `--record` mode unusable with the Anthropic provider.
## Fix
Forward all request headers by default, stripping only headers that
should
not be proxied. The strip list is a module-level constant:
**Hop-by-hop headers** ([RFC 2616
§13.5.1](https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1)):
`connection`, `keep-alive`, `transfer-encoding`, `te`, `trailer`,
`upgrade`,
`proxy-authorization`, `proxy-authenticate`
**Set by the HTTP client** (from target URL / body):
`host`, `content-length`
**LLM proxy specific** (avoid leaking or encoding mismatch):
`cookie`, `accept-encoding`
Auth headers (`authorization`, `x-api-key`) are still forwarded —
they're
no longer special-cased since all non-stripped headers pass through.
They
continue to be excluded from saved fixture files (that logic is separate
and unchanged).
`Via` / `X-Forwarded-*` are **not** set or stripped — consistent with
how
other LLM proxy tools (LiteLLM, Portkey, Helicone) handle upstream
forwarding, and LLM APIs (OpenAI, Anthropic) do not use them.
Guard the Float32Array decode with try/catch so corrupted base64 data falls through to the error path instead of crashing. Add 4 tests covering the encoding_format × embedding-type matrix: - base64 string + encoding_format:base64 → decodes to float array - base64 string + no encoding_format → proxy_error (original bug path) - array embedding + encoding_format:base64 → array passthrough - truncated base64 (odd byte count) → empty embedding, no crash
## Problem
When recording fixtures, the recorder fails to save OpenAI embedding
responses that use base64 encoding. The OpenAI API returns
base64-encoded embeddings when `encoding_format: "base64"` is set (the
default in many SDKs, including Python's `openai` package).
`buildFixtureResponse` checks `Array.isArray(first.embedding)` but the
embedding is a base64 string, not an array. The fixture is saved with a
`proxy_error`:
```json
{
"response": {
"error": { "message": "Could not detect response format from upstream", "type": "proxy_error" },
"status": 200
}
}
```
## Fix
Extract `encoding_format` from the raw request body and pass it to
`buildFixtureResponse`. When `encoding_format === "base64"` and the
embedding is a string, decode it via `Buffer.from(embedding, "base64")`
→ `Float32Array` → `Array.from(floats)`.
This is forward-safe — only decodes when `encoding_format` explicitly
says `"base64"`, so future encoding formats (e.g. `"int8"`) won't be
misinterpreted.
## Changes
- `recorder.ts`: Extract `encoding_format` from raw request, pass to
`buildFixtureResponse`, decode base64 when detected
Patch release with recorder fixes: - Preserve upstream URL path prefixes in record proxy (CopilotKit#57) - Forward all request headers in record proxy (CopilotKit#58) - Decode base64-encoded embeddings in recorder (CopilotKit#64) - Guard base64 decode against corrupted data - Update CHANGELOG, skill docs
## Summary Patch release capturing recorder fixes that landed since v1.6.0. ### Patch Changes - Fix record proxy to preserve upstream URL path prefixes (CopilotKit#57) - Fix record proxy to forward all request headers to upstream (CopilotKit#58) - Fix recorder to decode base64-encoded embeddings with `encoding_format: "base64"` (CopilotKit#64) - Guard base64 decode against corrupted data - Update CHANGELOG, skill docs, competitive matrix script ### Files changed - `package.json` — version 1.6.0 → 1.6.1 - `CHANGELOG.md` — new 1.6.1 section - `skills/write-fixtures/SKILL.md` — recorder docs updated All 1,327 tests pass. Build clean.
Warns when source commits accumulate on main without a version bump, preventing fixes from sitting unreleased like the v1.6.0 → v1.6.1 gap.
Adds explicit git tag creation step before gh release create, so tags exist even if the release step fails partway. Also passes --verify-tag to gh release create for safety.
…tKit#66) ## Summary Two CI improvements to prevent the v1.6.0 → v1.6.1 gap from happening again. ### 1. Unreleased changes check (`unreleased-check.yml`) Runs on every push to main. Compares HEAD against the latest version tag and emits a `::warning` annotation when source commits exist without a version bump. Skips gracefully when the tag doesn't exist yet (i.e., the push IS the release). ### 2. Tag safety in release workflow (`publish-release.yml`) - Explicit `git tag` + `git push origin <tag>` step before `gh release create` - `--verify-tag` flag on `gh release create` for belt-and-suspenders safety - Outputs version for reuse across steps ### Also going forward Release commits must use `chore: release vX.Y.Z` format to pass commitlint. Always create a branch first, never commit directly to main.
The detailed MSW comparison table is better suited for the docs site competitive matrix than the package landing page. Keeps the README focused on what llmock does, not what competitors don't.
Removes the MSW vs llmock comparison section and table from the README/npm landing page. This content lives on the [docs site competitive matrix](https://llmock.copilotkit.dev/) instead.
Add video demo, document WebSocket endpoints (OpenAI Responses, Realtime, Gemini Live), expand fixture matching/response reference, and add error injection and request journal sections.
NathanTarbert
force-pushed
the
docs/update-readme-websocket
branch
from
April 1, 2026 01:12
be2c131 to
5f04ca5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan