saveCallLog only read prompt_tokens/completion_tokens (OpenAI format).
When sourceFormat=claude, the openai-to-claude translator writes
input_tokens/output_tokens instead, causing all cross-format requests
(Codex-via-Claude, Kiro-via-Claude, etc.) to show 0|0 tokens in
call_logs.
Also includes cache_read and cache_creation tokens in tokens_in total
so heavily-cached requests don't show misleadingly low input counts.
Changes:
- Read prompt_tokens || input_tokens (supports both formats)
- Read completion_tokens || output_tokens (supports both formats)
- Sum cache_read_input_tokens + cache_creation_input_tokens into total
logUsage stored only non-cached input tokens in usage_history.tokens_input.
For heavily-cached Claude requests (common with Claude Code), this shows
near-zero input when the real total is 150K+, causing the analytics
dashboard to severely underreport input token usage.
Now sums: input = prompt_tokens + cache_read + cache_creation
chatCore.ts injects translatedBody.model for all providers after
translation. Kiro API (AWS CodeWhisperer) has strict schema validation
and rejects unknown top-level fields — only conversationState, profileArn,
and inferenceConfig are valid. This causes 100% of Kiro requests to fail
with "Improperly formed request".
Strip the injected model field in KiroExecutor.transformRequest().
* 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(budget): BudgetTab sent integer percentage (80) but schema validated
fraction (0-1). Now divides by 100 on POST and multiplies by 100 on GET (#451)
- fix(combos): expose Agent Features UI in combo create/edit modal — fields for
system_message override, tool_filter_regex, and context_cache_protection were
implemented server-side (#399/#401) but missing from the dashboard UI (#454)
- fix(combos): strip <omniModel> tags from messages before forwarding to provider.
The internal cache-pinning tag was being sent to the provider, causing cache
misses as providers treated each tagged request as a new session (#454)
- fix(docker): copy pino-abstract-transport + pino-pretty in standalone (#449)
- fix(responses): remove initTranslators() from /v1/responses route (#450)
- chore(deps): commit package-lock.json with each version bump
- 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)
- fix(ux): add default password hint on login page for first-time users (#437)
The fallback password (123456) is now shown as a hint below the
password input so users don't get locked out during initial setup.
- fix(cli): add shell:true to spawn on Windows so .cmd wrappers are
resolved correctly via PATHEXT (#447). Claude, opencode, and other
npm-installed CLIs show as 'not runnable' on Windows even when
installed because spawn() cannot find .cmd files without shell:true.
- i18n: add defaultPasswordHint key to en.json auth namespace
Keep search provider validation responses consistent with other validators so Serper regression tests and CI assertions can rely on unsupported=false.
Made-with: Cursor
Normalize GitHub Copilot account tiers from the usage payload and hide misleading unlimited buckets so account type and limits render correctly in the dashboard.
Made-with: Cursor
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)
New in v2.7.0: pluggable RouterStrategy, multilingual intent detection,
request deduplication, new providers (Grok-4 Fast, GLM-5/Z.AI,
MiniMax M2.5, Kimi K2.5). Native translations for de/es/fr/it/ru/zh-CN/ja/ko/ar/pt-BR/pt.