- Add usage_history table creation in test setup
- Simplify byStrategy query to avoid non-existent combo_strategy column
- Update test assertions to work with existing test data
Adds intelligent cache control preservation for Claude Code clients:
- New cacheControlPolicy.ts module with detection logic:
- isClaudeCodeClient(): Detects Claude Code via User-Agent
- providerSupportsCaching(): Checks provider (claude, anthropic, zai, qwen)
- isDeterministicStrategy(): Identifies priority/cost-optimized strategies
- shouldPreserveCacheControl(): Main policy decision
- Cache control is preserved when:
1. Client is Claude Code (detected via User-Agent)
2. Provider supports prompt caching
3. Request routing is deterministic:
- Single model requests (always)
- Combo with priority or cost-optimized strategy only
- Updated translator to accept preserveCacheControl option
- Updated chatCore and chat handler to propagate combo strategy
- Added comprehensive unit tests (24 tests)
Non-deterministic combo strategies (weighted, round-robin, random, etc.)
continue to use OmniRoute's managed caching strategy.
Refs: #cache-control-preservation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OpenCode Go mixes request protocols by model family:
- `glm-5` and `kimi-k2.5` use OpenAI-style `/chat/completions`
- `minimax-m2.5` and `minimax-m2.7` use Anthropic-style `/messages`
OmniRoute already routed MiniMax Go models to `/messages`, but the
executor still sent `Authorization: Bearer ...`, which caused upstream
`401 Missing API key` errors.
This changes `OpencodeExecutor` to send:
- `x-api-key` + `anthropic-version` for Claude-targeted OpenCode Go requests
- `Authorization: Bearer ...` for the remaining OpenCode Go request formats
Also updates unit coverage to assert the correct header behavior for
MiniMax Go models.
Validated with:
- direct curl repro against OpenCode Go endpoints
- `node --import tsx/esm --test tests/unit/opencode-executor.test.mjs`
- `npm run typecheck:core`
- `npm run build`
HTTP 400 "invalid argument" was triggered when OmniRoute translated OpenAI
tool_calls to Gemini format, because thoughtSignature was injected onto every
functionCall part unconditionally.
thoughtSignature is only valid on thinking/reasoning parts (those with
thought: true). The Gemini API rejects any request where a functionCall
part carries a thoughtSignature field, returning HTTP 400.
Fix: remove the thoughtSignature field from functionCall parts. The thinking
parts that legitimately require thoughtSignature (emitted when a message has
reasoning_content) are unchanged.
Adds regression test (T43) with three cases:
- single tool call: no thoughtSignature on functionCall part
- multiple tool calls: none carry thoughtSignature
- thinking part regression guard: thoughtSignature still present on thought parts
Fixes#725
Non-streaming: Fixed json.messages check to use json.choices[0].message
(OpenAI format). Streaming: inject pin tag before finish_reason chunk for
tool-call-only streams. injectModelTag now appends synthetic assistant
message when content is null/array (tool_calls).
- add unit tests for API auth, display/error utilities, login bootstrap,
model combo mappings, provider validation branches, and usage analytics
- add COVERAGE_PLAN.md and extend CONTRIBUTING.md with coverage notes and
workflow guidance
- update package.json to adjust test:coverage thresholds and add coverage:report;
include c8 as a devDependency
- introduce test scaffolding and ensure compatibility with existing test runners
- align tests with open-sse changes and improve overall test coverage planning
- introduce open-sse/translator/helpers/schemaCoercion.ts to coerce
numeric JSON Schema fields encoded as strings
- wire coerceToolSchemas and sanitizeToolDescriptions into translator
pipeline; ensure tool descriptions are sanitized
- inject empty reasoning content for tool calls when target is OpenAI
format
- update qwen base URL to DashScope-compatible endpoint
- extend antigravity static catalog with Gemini 3.1 pro preview models and
update Gemini model specs with preview aliases
- implement call log max cap caching with TTL; expose invalidateCallLogsMaxCache
and invalidate on settings PATCH
- add tests: call-log-cap.test.mjs and tool-request-sanitization.test.mjs;
extend tests for Windsurf integration and gemini previews
- update CLI runtime and tools to include Windsurf as a guide-only tool
- add maxCallLogs to validation schemas (settings and updateSettings)
- add Czech README (README.cs.md) to repository
When Claude Code routes through OmniRoute (Claude → OmniRoute → Claude),
OmniRoute was stripping all cache_control markers and replacing them with
its own generic caching strategy. This broke Claude Code's carefully
placed cache breakpoints for plans and other features.
Changes:
- Add preserveCacheControl parameter to prepareClaudeRequest()
- Detect Claude passthrough mode (sourceFormat === targetFormat === CLAUDE)
- Skip cache_control normalization when preserveCacheControl=true
- Preserve client's cache_control markers in system, messages, and tools
This ensures Claude Code's prompt caching optimization works correctly
while maintaining OmniRoute's caching strategy for translation scenarios.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reviewed and approved via consolidated analysis. GLM-5.1 addition and pricing corrections match official Z.AI pricing page. All 5 files follow existing patterns.
Three tests covering the fixed bug where translateRequest received an
object instead of a boolean for the stream parameter:
- stream=true round-trip produces boolean true
- stream=false round-trip produces boolean false
- guard test documenting that passing an object as stream breaks typing
Co-Authored-By: Craft Agent <agents-noreply@craft.do>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add glm-5.1 model to GLM Coding provider with fitness scores
- Update glm-5 pricing to match Z.AI API page ($1/$3.2/$0.2)
- Set glm-5.1 pricing to $1.2/$5/$0.3 per Z.AI
- Remove glm-4-32b (deprecated, returns empty from upstream)
- Rename Z.AI provider display name from "Z.AI (GLM-5)" to "Z.AI"
- Update zai pricing section to match glm pricing
The hasValuableContent() function in streamHelpers.ts returned undefined
instead of explicit false when checking empty delta chunks. This caused
JavaScript type coercion issues where undefined !== '' evaluated to true,
passing empty chunks through to clients.
Fix: Replace implicit returns with explicit boolean returns using
typeof checks and length comparisons for all content fields (content,
reasoning_content, tool_calls, text, thinking, partial_json).
Test: Added unit tests covering OpenAI, Claude, and Gemini format edge cases.
Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Changes:
- fix: restore native Claude tool names in passthrough responses (PR #663 by @coobabm)
- fix: Clear All Models button now also removes aliases (PR #664 by @rdself)
- fix: completed truncated test from PR #663, added Claude-to-Claude passthrough test
- docs: update CHANGELOG and OpenAPI spec