Cloudflare AI rule only sets flattenContent. Treat missing match as
provider-wide and missing drop as empty list to avoid crash. Fixes#1960.
Co-authored-by: Cursor <cursoragent@cursor.com>
Retry short-lived 5xx/capacity errors (500/502/503/504 + message
patterns) with bounded backoff capped at 15s; honor Retry-After/reset
hints and skip when wait is too long. Keep 400 non-retryable. Enable the
retry hook for 500 alongside existing 429/503.
Deduplicate sanitized Antigravity tool names before emitting the single
functionDeclarations group to avoid upstream "Tool names must be unique"
rejections.
Add Headroom size diagnostics and phantom-savings warning when reported
token delta does not shrink the outbound payload.
Co-authored-by: Cursor <cursoragent@cursor.com>
Carry Claude reasoning_effort/reasoning into OpenAI Chat, map into
OpenAI Responses reasoning.effort, and keep request-level effort
(incl. xhigh) across tool-result turns instead of collapsing to high.
Co-authored-by: Cursor <cursoragent@cursor.com>
Registry exposes the dashed id claude-opus-4-7; matchPattern treats "."
as a literal, so it missed the dotted pattern and fell through to the
generic claude opus entry (200k / claude-budget). Add an exact entry so
it resolves to 1M context + adaptive thinking, plus a unit test covering
the dashed Opus ids.
Co-authored-by: Cursor <cursoragent@cursor.com>
OpenAI-compatible apikey provider (chat/embedding/image) with dynamic
model discovery via modelsFetcher + passthroughModels. No executor needed.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add 1M context capability overrides for claude-opus-4.8 and -thinking
variants, and use the resolved capability contextWindow (fallback 200k)
instead of the hardcoded 200k estimate in the Kiro executor.
Co-authored-by: Cursor <cursoragent@cursor.com>
Codex (openai-responses) body.input holds Responses items, not OpenAI
messages. Translate input -> OpenAI -> compress -> back to input so the
Responses contract is preserved. Fixes#1998
Co-authored-by: Cursor <cursoragent@cursor.com>
Forcing reasoning_effort:"medium" + reasoning_summary:"auto" on plain
requests tripped CodeBuddy's content filter and returned an error (#2071).
Make reasoning params opt-in: only set reasoning_summary when the client
sent an explicit reasoning_effort; none/off still drops it.
Fixes#2071
Co-authored-by: Cursor <cursoragent@cursor.com>
Pass Gemini AUDIO/TTS generateContent requests through to Google's native
v1beta endpoint instead of converting to chat, with per-credential fallback
(504 timeout, 502 fetch failure). Accept client keys from Bearer,
x-goog-api-key, or ?key= while forwarding only the configured Gemini
credential upstream. Expose native v1beta model names and rewrites, and add
Gemini 3.1 Flash TTS to the catalogs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Fetch the live model list from the Copilot /models endpoint and surface
it through /v1/models, replacing the hardcoded github entry so newly
shipped models appear without a code change. Catalog is cached per
credential and the Copilot token is refreshed on 401/403 before retry.
Also raise the connectivity-test budget to max_tokens:16, since Claude on
Copilot emits no choices at max_tokens:1 and produced a false negative.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add "text" to Codex Responses API allowlist so text.format.json_schema
reaches upstream for structured outputs instead of being stripped.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep provider-required streaming when client prefers JSON. The
Accept: application/json branch no longer flips stream back to false
for forceStream providers, fixing 400 errors on stream-only providers
(e.g. Command Code) for Hermes / Claude Code / other JSON clients.
Fixes#2031
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve Gemini TTS models from shared TTS catalog and provider registry
with a safe fallback, fixing requests resolving to models/undefined when
ttsConfig.models is empty. Add gemini-3.1-flash-tts-preview to catalogs.
Co-authored-by: Cursor <cursoragent@cursor.com>
logUsage now only logs to console; DB write removed. Streaming usage is
recorded once via saveUsageStats (onStreamComplete), eliminating duplicate
usageHistory rows that inflated dashboard totals.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add image generation for Antigravity provider via gemini-3.1-flash-image
and gemini-3-pro-image, exposed through Text to Image UI and
/v1/images/generations.
- registry: serviceKinds ['llm','image'] + image model entries
- executor: image model detection + image_gen request envelope
- chatCore: force stream=false for image models (generateContent)
- nonStreamingHandler: parse inlineData -> markdown image
- imageGenerationCore: useExecutor fast-path for executor delegation
- imageProviders/antigravity: image adapter with image input support
- usage/google: image models in quota whitelist
Co-authored-by: Cursor <cursoragent@cursor.com>
The pattern matcher marked *minimax-m3* as vision: false, causing
9Router to strip image attachments before forwarding upstream. This
broke Claude Code / Cursor / Cline vision flows when routing through
MiniMax-M3.
Scoped vision: true to *minimax-m3* only. M2.7 and the catch-all
*minimax* pattern remain vision: false: those models are text-only
(per MiniMax docs / NVIDIA NIM model card), so forcing vision there
would send images to a model that errors instead of degrading.
Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes#1933 — upstream returns 403 "Illegal access" on the chat endpoint
when requests lack a browser-like User-Agent. Mirror OmniRoute mimocode
executor: rotate across 3 Chrome UA strings on both bootstrap and chat.
Co-authored-by: Cursor <cursoragent@cursor.com>
Workers AI rejects OpenAI content-part array shape; flatten text parts
to a plain string per message before sending.
Co-authored-by: Cursor <cursoragent@cursor.com>
Strip `type` field and fold `function.{name,description,parameters}` into
top-level {name, description, input_schema} before forwarding to Claude-format
endpoints. MiniMax (and other Anthropic-compatible providers) reject tools
carrying a `type` field with error code 2013 ("invalid tool type").
Refs #1939
Co-authored-by: Cursor <cursoragent@cursor.com>
Two additions on top of the merged CodeBuddy CN OAuth provider:
1. API key auth — connect with a direct API key (sent as
Authorization: Bearer), not only via OAuth device-code flow.
- registry: add authModes ["oauth","apikey"] + hasOAuth; combined Bearer
auth already forwards the key, token-refresh skips key connections.
- providers POST: accept dual-auth providers (authModes includes
"apikey") that live under category "oauth" — previously rejected as
"Invalid provider". Also fixes the same latent gap for xai.
2. Quota tracker — surface CodeBuddy CN credit balance on the usage
dashboard for both OAuth and API-key connections.
- registry: add transport.usage.url (Tencent billing endpoint) +
features.usage/usageApikey so the connection is quota-eligible.
- new CN-scoped handler services/usage/codebuddy-cn.js: POST the billing
meter endpoint, unwrap data.Response.Data.Accounts[]. The payload mixes
two credit types that must not be merged:
* refill/base ("基础体验包") — recurring allowance; cycle resets well
before the resource expires (CycleEndTime << DeductionEndTime).
Reads the *Cycle* balance, resetAt = next refresh. Cadence-labelled.
* bonus ("活动赠送包") — one-shot credits that expire at CycleEndTime.
Reads the plain Capacity balance. Labelled "Bonus Pack N".
One quota row per package, soonest-expiring first.
- register handler under "codebuddy-cn" in USAGE_HANDLERS.
Frontend needs no change — USAGE_SUPPORTED_PROVIDERS/USAGE_APIKEY_PROVIDERS
and the generic parseQuotaData branch already cover this shape.
Co-authored-by: Cursor <cursoragent@cursor.com>
codebuddy-cn shipped without a short alias, making its model prefix the
longest of any provider (codebuddy-cn/glm-5.2). Add alias + uiAlias
"cbcn" so the prefix becomes cbcn/glm-5.2, consistent with qoder (qd),
kiro (kr), codex (cx). "cbcn" = CodeBuddy CN; reserves "cbai" for a
future codebuddy-ai (intl) provider.
Backward-compatible: full id codebuddy-cn/... still resolves (resolver
matches both id and alias).
Also regenerate tests/__baseline__/alias-baseline.json: idToAlias entry
codebuddy-cn now maps to cbcn, and cbcn joins the sorted modelKeys list.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove "pattern" from UNSUPPORTED_SCHEMA_CONSTRAINTS so glob/grep tool
schemas keep the required "pattern" property for the antigravity provider.
Fixesdecolua/9router#1368
Co-authored-by: Cursor <cursoragent@cursor.com>
flattenToolHistory only recognized OpenAI-style tool calls. Anthropic-compatible clients (Claude Code, /v1/messages) send tool invocations and results as tool_use/tool_result blocks inside the message content array. Since panel calls strip the tools definitions (#1859), the panel expert models received structured tool history without schemas, causing them to fail or misbehave (leading to empty responses and 503 errors).
Extend flattenToolHistory to recognize and flatten tool_use and tool_result blocks in the content array into prose text, keeping panel expert execution robust and independent of the client API format.
PR decolua/9router#1910
Co-authored-by: Cursor <cursoragent@cursor.com>
Update OpenCode Go model catalog to match the official Go docs.
Route Qwen 3.7 and MiniMax models through /v1/messages with
Anthropic-compatible headers instead of OpenAI-compatible chat.
Keep GLM, Kimi, DeepSeek, and MiMo on /chat/completions; use
kimi-k2.7-code because the live Go API rejects kimi-k2.7 for chat
while the docs config example uses the code model ID.
PR #1931 by nguyenha935
Co-authored-by: Cursor <cursoragent@cursor.com>
Build on the optional Headroom Token Saver from Carmelo Campos
(PR: feat: add optional Headroom token saver). Add managed start/stop
of the local headroom proxy from the dashboard, install detection,
status probing, and a simplified Token Saver UI.
- detect headroom CLI + python>=3.10, probe proxy /health
- spawn/stop proxy as a detached, pid-tracked process
- /api/headroom/{status,start,stop} routes, gated local-only in dashboardGuard
- one-click Start/Stop Headroom modal, no manual config needed
- claude<->openai shape conversion for /v1/compress via 9router translators
Thanks to Carmelo Campos (@carmelogunsroses) for the original Headroom integration.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Made wrapQoderSSE async to peek at first chunk before streaming
- Parse first SSE line to check for error envelope (statusCodeValue !== 200)
- If error detected, return error Response with proper HTTP status code
- This triggers chatCore's !providerResponse.ok check and failover logic
- Fixes issue where qoder 403 quota errors were wrapped as successful streams
Before: qoder errors appeared as stream content with finish_reason: 'stop'
After: qoder errors return proper HTTP error codes, triggering provider failover
- Enhanced saveUsageStats to include cache tokens (cache_read, cache_creation), reasoning tokens, and estimated flag
- Replaced logUsage calls in stream.js with saveUsageStats (2 locations)
- Removed duplicate saveUsageStats call from streamingHandler.js onStreamComplete
- Removed logUsage function and unused imports from usageTracking.js
- Each streaming request now writes exactly 1 usage record instead of 2
## Fixes
- **Kiro**: honor thinking effort budgets
- **AG/Kiro/Xiaomi**: provider fixes
- **Combo/Fusion**: flatten tool history in panel calls to prevent 503
- **LLM selector**: show custom vision models in selector and model list
- **Image**: prevent compatible nodes from shadowing provider aliases
Resolve the Kiro thinking budget from client intent (OpenAI reasoning_effort,
OpenAI Responses reasoning.effort, Claude output_config.effort, and Claude
thinking.budget_tokens) by reusing the shared thinkingUnified extractThinking
parser, then inject the resolved budget into the Kiro thinking system prefix.
Explicit none/off/disabled stops the prefix injection; synthetic -thinking
aliases keep the default budget.
Co-authored-by: Cursor <cursoragent@cursor.com>
Panel models in the fusion strategy must answer in prose. When the request
carried tools or prior tool_calls/tool messages, agentic panel models kept
emitting tool_calls instead of prose, so extractPanelText() returned empty
and the engine fell into the 503 "All fusion panel models failed" branch.
Panel fan-out now strips tools/tool_choice and flattens tool turns into
assistant prose (instead of dropping them), so panels keep the context but
cannot loop on tools. The judge still receives the unmodified history.
Co-authored-by: warelik <warelik@WARELIK-MB.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose user-added imageToText custom models as vision-capable chat
models in the default LLM selector and /v1/models, map custom service
kinds to runtime capabilities, and keep typed filtering for
/v1/models/{kind}.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add config-driven stripUnsupportedParams helper and use it in the default and github executors. Removes the deprecated temperature param for claude-opus-4 models (Anthropic 400) and consolidates github's scattered capability checks into one rule table.
Fixes#1748
Co-Authored-By: fjia <fjia@suntekcorps.com>
Co-authored-by: Cursor <cursoragent@cursor.com>