- Add contextLength field to RegistryModel interface for per-model overrides
- Add defaultContextLength to RegistryEntry for provider-level defaults
- Set context lengths for major providers:
- Claude: 200k
- Codex: 400k (fixes combo context display)
- Gemini: 1M
- OpenAI: 128k
- GitHub Copilot: 128k
- Kiro/Cursor: 200k
- OpenCode: 200k
- Include context_length in /v1/models API response
- Add context_length field to combo schema for custom combo context
- Update contextManager to use registry defaults and support env overrides
- CONTEXT_LENGTH_<PROVIDER> for per-provider override
- CONTEXT_LENGTH_DEFAULT for global override
This allows clients like OpenClaw to display accurate context windows
for combo models instead of guessing based on model name patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add model-pattern → combo mapping feature that automatically routes requests
to specific combos based on model name patterns (glob matching).
Implementation:
- New migration 010: model_combo_mappings table with pattern, combo_id, priority
- DB module with CRUD + resolveComboForModel() using glob-to-regex matching
- getComboForModel() in model.ts: augments getCombo() with pattern fallback
- chat.ts: replaced getCombo() → getComboForModel() at routing decision point
- API endpoints: GET/POST /api/model-combo-mappings, GET/PUT/DELETE by [id]
- ModelRoutingSection.tsx: dashboard UI with inline add/edit/toggle/delete
- Integrated into Combos page
- 15 new unit tests (glob matching, priority ordering, disabled filtering)
- Full test suite: 923/923 pass
Examples:
claude-sonnet* → code-combo
claude-*-opus* → frontier-combo
gpt-4o* → openai-combo
gemini-* → google-combo
Resolves: #563
Cherry-pick from codex/omniroute-fixes-20260324:
- Replace MCP singleton transport with per-session architecture for Streamable HTTP
- Fix Claude passthrough via OpenAI round-trip normalization
- Add detectFormatFromEndpoint() for endpoint-aware format detection
- Support raw code#state in OAuth modal for Claude Code remote auth
- Expose cloudConfigured/cloudUrl/machineId in settings API
- Switch docker-compose.prod.yml target to runner-cli
- Add 3 new tests for round-trip and detectFormat
PR: #562
CLI settings routes (codex-settings, droid-settings, kilo-settings) were
writing the masked API key string directly to config files when the
dashboard sent a keyId. Now resolves the real key from the database via
getApiKeyById() before writing, matching the pattern already implemented
in claude-settings, openclaw-settings, and cline-settings.
Closes#549
feat(ui): ProviderIcon component with @lobehub/icons + PNG fallback (#529)
- 130+ providers covered by Lobehub SVG components via LobehubErrorBoundary
- Falls back to existing /providers/{id}.png, then generic icon
- Replaces manual img state machine in ProviderCard + ApiKeyProviderCard
feat(scheduler): modelSyncScheduler — 24h model list auto-update (#488)
- Syncs 16 major providers every 24h (MODEL_SYNC_INTERVAL_HOURS configurable)
- Wired into POST /api/sync/initialize startup hook
fix(oauth): Gemini CLI — clear error when client_secret missing in Docker (#537)
fix(cli-tools): save real API key to CLI config files instead of masked string (#523, #526)
- claude-settings/route.ts: accept keyId, look up real key from DB (getApiKeyById)
- cline-settings/route.ts: same keyId resolution pattern
- openclaw-settings/route.ts: same keyId resolution pattern
- ClaudeToolCard.tsx: store key.id as selected value, send keyId in POST body
The /api/keys endpoint returns masked strings (first8+****+last4) which were being
written verbatim to ~/.claude/settings.json and similar config files, causing auth
failures on CLI tool launch.
fix(combo): update CACHE_TAG_PATTERN to strip surrounding \\n sequences (#531)
- comboAgentMiddleware.ts: non-global regex now matches literal \\n (backslash-n)
and actual newline U+000A that combo.ts injects around the <omniModel> tag.
- fix(translator): preserve prompt_cache_key in Responses API translation (#517)
- fix(combo): escape \n in tagContent for valid JSON injection (#515)
- fix(usage): sync expired token status back to DB on live auth failure (#491)
- chore: bump version to 2.9.4 in package.json + docs/openapi.yaml
- docs: update CHANGELOG.md with v2.9.4 release notes
- Add preserveDeveloperRole option and model compat override
- Normalize developer→system in roleNormalizer when not preserving
- Translator runs normalizeRoles for Responses API with option
- UI: ModelCompatPopover with do not preserve developer toggle
- Add ZWS_README_V2 documenting cause and fix
Made-with: Cursor
- New API: /api/logs/export?hours=24&type=call-logs
- UI: Export button with dropdown on /dashboard/logs page
- Supports export of request-logs, proxy-logs, and call-logs
- Downloads as JSON file with Content-Disposition header
* feat: add api-key Kimi Coding provider support
* fix(kimi-coding): honor apikey auth header in executor
Ensure DefaultExecutor sends x-api-key for kimi-coding-apikey at runtime
and deduplicate shared kimi coding config blocks in registry and models
config to reduce drift between oauth and apikey variants.
---------
Co-authored-by: OmniRoute Agent <agent@omniroute.local>
- fix(docker): copy pino-abstract-transport and pino-pretty explicitly in
runner-base stage — Next.js standalone trace omits them, causing
'Cannot find module pino-abstract-transport' crash on startup (#449)
- fix(responses): remove initTranslators() call from /v1/responses route —
bootstrapping translator registry from a Next.js Route Handler worker
caused 'the worker has exited' uncaughtException on Codex CLI requests.
Translators are already bootstrapped server-side via open-sse (#450)
- chore: include package-lock.json in commit (was being left behind on
version bumps, causing npm ci to install inconsistent deps in Docker)
Search Playground (Phase 1):
- Web Search as 10th endpoint in Playground with isolated SearchPlayground component
- Endpoint selector moved first; Provider/Model/Send hidden when search selected
- Provider dropdown via GET /api/search/providers, formatted results with cache indicator
Search Tools page (Phase 2) at /dashboard/search-tools:
- Split panel: SearchForm (left) with query, provider, filters + ResultsPanel (right)
- Compare Providers: parallel queries with latency, cost, response size, URL overlap
- Rerank Pipeline: model selector from /v1/models, results with position delta
- Search History: last 10 searches from call_logs with replay
- Sidebar entry under Debug section
Backend:
- GET /api/search/providers — list providers with auth guard + SEARCH_CREDENTIAL_FALLBACKS
- GET /api/search/stats — cache stats, provider aggregates, recent searches (auth guard)
- Add local provider_nodes routing for /v1/rerank (oMLX, vLLM support)
Bug fixes (from F-27 PR #432):
- Fix Brave news normalizer: data.results directly, not data.news.results
- Enforce max_results truncation after normalization for all providers
- Fix EndpointPageClient: use /api/search/providers instead of /api/v1/search
- Add isAuthenticated() guards on /api/search/providers and /api/search/stats
Response size metric in results meta bar and compare table.
i18n: 30+ keys in search namespace (en.json)
DB Migrations (zero-breaking, ADD COLUMN DEFAULT NULL + new table):
- 005_combo_agent_fields.sql: system_message, tool_filter_regex, context_cache_protection on combos
- 006_detailed_request_logs.sql: ring-buffer table (500 entries) for full pipeline body capture
Features:
- #399 System Message Override + Tool Filter Regex per Combo
- applyComboAgentMiddleware() injected into handleComboChat/handleRoundRobinCombo
- Supports both OpenAI and Anthropic tool name formats
- #401 Context Caching Protection (Stateless)
- injectModelTag() appends <omniModel>provider/model</omniModel> to responses
- extractPinnedModel() reads tag from history and pins model for session
- #320 Auto-Update via Settings
- GET /api/system/version — current vs latest npm
- POST /api/system/update — fire-and-forget npm install + pm2 restart
- #378 Detailed Request Logs
- saveRequestDetailLog() captures bodies at 4 pipeline stages (opt-in toggle)
- GET/POST /api/logs/detail — list logs + enable/disable toggle
- #336 MITM Kiro IDE
- src/mitm/targets/kiro.ts: MitmTarget profile for api.anthropic.com interception