Commit Graph

4934 Commits

Author SHA1 Message Date
diegosouzapw
5da471bf15 Merge branch 'release/v3.8.0' into upstream/executors-sanitize-reasoning-effort 2026-05-11 21:01:41 -03:00
Anton
d995713e21 fix(translator): inject thinking placeholder for all Claude-shape upstreams (#2161)
Integrated into release/v3.8.0 — removes redundant provider guard in prepareClaudeRequest, fixing thinking placeholder injection for all Claude-shape upstreams (kimi-coding, glmt, zai).
2026-05-11 21:01:23 -03:00
diegosouzapw
f188e76b8c Merge branch 'release/v3.8.0' into upstream/translator-claude-thinking-placeholder 2026-05-11 20:57:36 -03:00
Andrew Munsell
6d722ecd27 fix(providers): allow optional-key providers to pass connection test (#2169)
Integrated into release/v3.8.0 — allows optional-key providers (SearXNG, Petals, self-hosted chat, OpenAI/Anthropic-compatible) to pass connection test by centralizing the check in providerAllowsOptionalApiKey().
2026-05-11 20:57:01 -03:00
diegosouzapw
90cf685165 Merge branch 'release/v3.8.0' into fix/searxng-test-connection 2026-05-11 20:56:18 -03:00
Hernan Javier Ardila Sanchez
c52b365e1d refactor(catalog): remove .ts imports, as any casts, normalize alias resolution (#2152)
Integrated into release/v3.8.0 — removes .ts import extensions, replaces as any casts with proper types, and normalizes provider alias resolution in combo context_length calculation.
2026-05-11 20:55:20 -03:00
diegosouzapw
a14802fe2c Merge branch 'release/v3.8.0' into fix/combo-context-length-auto-calc 2026-05-11 20:40:59 -03:00
Andrew Munsell
2777c0541c feat(search): add Ollama Search as a web search provider
Integrate the Ollama hosted web search API (ollama.com/api/web_search) as a
new search provider, bringing the total to 11.

What:
- Register "ollama-search" in the search provider registry with POST to
  ollama.com/api/web_search, Bearer auth, web-only, max 10 results
- Add credential fallback from ollama-cloud (same API key)
- Add request builder (query + max_results) and response normalizer
  (maps {results: [{title, url, content}]} to SearchResult[] with
  optional chaining and full_text content mapping)
- Wire into Zod validation, provider constants, and connection test config
- Add 4 integration tests through handleSearch covering builder, normalizer,
  empty results, and missing results field edge cases
- Update registry and route listing tests (provider count 10→11)

Why:
Gives OmniRoute users another search backend option, reusing their existing
Ollama Cloud API key with no additional setup.

Testing:
- 4 new integration tests in search-handler-extended.test.ts using handleSearch
  with mocked fetch
- 2 new assertions + count update in search-registry.test.ts
- Updated provider listing test in search-route.test.ts
- All 60 tests pass, no new ESLint or TypeScript errors
2026-05-11 16:29:33 -07:00
Andrew Munsell
51c4e1cdc2 fix(providers): allow optional-key providers to pass connection test
Centralize the requiresApiKey guard into providerAllowsOptionalApiKey()
in src/shared/constants/providers.ts so testApiKeyConnection and
validateProviderApiKey share the same logic. The test route was missing
openai-compatible-* and anthropic-compatible-* checks, causing connection
test failures for those provider types when no API key was provided.

Test file now imports providerAllowsOptionalApiKey and
SELF_HOSTED_CHAT_PROVIDER_IDS directly from the source instead of
duplicating them.
2026-05-11 13:55:34 -07:00
OmniRoute Ops
f946f6e0a7 fix(cliproxyapi): conditional thinking strip to preserve valid Anthropic shape
Follow-up after testing the Capy BYOK flow. The unconditional
`delete transformed.thinking` was killing legitimate thinking configs
that applyThinkingBudget had already converted to Anthropic-valid form
({type:"enabled"|"disabled", budget_tokens:N}). Replace with a
conditional strip that:

- Preserves Anthropic-valid shapes (enabled/disabled + numeric
  budget_tokens, no extra fields)
- Strips Capy/Anthropic-SDK shapes Anthropic doesn't accept
  (type:"adaptive", or presence of the Capy-specific `display` field)

Symptom we observed: clients sending
`thinking: {type:"adaptive", display:"summarized"}` on /v1/messages
saw plain text responses with no thinking block. Their UIs (e.g. Capy)
fell back to rendering answer text inside the empty "Thought" section.

With applyThinkingBudget in adaptive mode (default for many user
configs), the body reaching this executor already has a valid
Anthropic shape — the unconditional strip was undoing that work.
Bodies that bypass applyThinkingBudget (passthrough mode) still get
stripped here because Anthropic 400s on the unconverted shape.

5 new test cases cover the preserve/strip matrix on Anthropic-shape
and OpenAI-shape bodies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 20:00:54 +00:00
Zhaba1337228
52143d2c8e feat(oauth): complete Windsurf / Devin CLI OAuth + API-token flows
## OAuth (browser PKCE)

- **`poll-callback`**: generalise from codex-only to all
  `PKCE_CALLBACK_PROVIDERS` (codex, windsurf, devin-cli); state slot
  is now dynamic (`__codexCallbackState` vs `__windsurfCallbackState`)
- **`OAuthModal`**: replace the codex-specific callback-server block
  with a shared `PKCE_CALLBACK_SERVER_PROVIDERS` branch covering all
  three providers; same start-callback-server + poll-callback polling
  loop, same 2-second interval, same 5-minute timeout
- **`OAuthModal` redirect URI fallback**: windsurf/devin-cli now use
  `http://localhost:{port}/auth/callback` (correct path) instead of
  the generic `/callback` on non-true-localhost
- **`/auth/callback` page**: new Next.js route (`src/app/auth/callback`)
  that re-exports `/callback/page`; Windsurf redirects to `/auth/callback`
  so the popup auto-completes without manual URL paste (postMessage +
  BroadcastChannel + localStorage)

## API-token (WINDSURF_API_KEY / paste-token)

- **`route.ts` — `import-token` action**: new POST action for
  `IMPORT_TOKEN_PROVIDERS` (windsurf, devin-cli); calls
  `provider.mapTokens({ accessToken: token })` skipping the HTTP
  exchange and creating the connection directly
- **`oauthImportTokenSchema`**: Zod schema `{ token, connectionId? }`
- **`OAuthModal` — "Paste API Key" tab**: tab-switcher UI for
  windsurf/devin-cli; sends `POST /import-token`; errors shown inline

## Security: remove hardcoded Firebase API key (GH secret alert)

- `AIzaSyBpLTEGSt59AUPKxBb7lIWjSE2ZXQH7mgU` removed from both
  `oauth.ts` and `tokenRefresh.ts`; code now reads only
  `process.env.WINDSURF_FIREBASE_API_KEY`
- Added `WINDSURF_FIREBASE_API_KEY` to `.env.example` with the
  public key value and an explanation that it is a client-side
  credential embedded in the Windsurf app (not a secret)
- `tokenRefresh.ts`: graceful `return null` with warn log when
  key is absent (import tokens are long-lived and skip refresh anyway)

## Docs

- Sync 40 i18n CHANGELOG mirrors to v3.8.0 root content

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-11 22:07:03 +03:00
diegosouzapw
0594b1d2ea fix(providers): correct pollinations requests and provider dashboard state
Update Pollinations request transformation to send the selected model
and stream flag so requests match the active endpoint behavior.

Align the ChatGPT TLS client with shared proxy resolution so dashboard
proxy context is honored before falling back to environment settings.
Also refresh provider display names across dashboard pages, correct the
Claude extra-usage toggle messaging and visual state, and mark
Pollinations as offering a free public endpoint.
2026-05-11 15:51:05 -03:00
Zhaba1337228
5925f313f9 feat(sse): add Devin CLI + Windsurf providers
Adds two providers for Windsurf/Devin CLI access:

**`devin-cli`** — official path via ACP JSON-RPC over stdio
- Spawns `devin acp --agent-type summarizer` as a subprocess
- Full streaming via session/update notifications
- Auth: WINDSURF_API_KEY env var or `devin auth login` stored creds
- Binary auto-discovered: %LOCALAPPDATA%\devin\cli\bin\devin.exe (Win),
  ~/.local/share/devin/bin/devin (Linux), PATH fallback
- Model IDs verified from model_configs_v2.bin in Devin CLI binary
  (swe-1.6-fast, claude-opus-4.7-max, gpt-5.5-high, gemini-3.1-pro-high, etc.)

**`windsurf`** — direct gRPC-web fallback (no binary needed)
- Calls server.self-serve.windsurf.com directly via gRPC-web+proto
- Auth: token from windsurf.com/show-auth-token
- MODEL_ALIAS_MAP dot-to-dash normalisation for all 100+ catalog models

Supporting changes:
- cliRuntime.ts: add `devin` to CLI_TOOLS with Windows/Linux binary paths
- tokenRefresh.ts: Firebase STS refresh for devin-cli + windsurf
- oauth providers: windsurf + devin-cli (token import / device-code)
- providerRegistry: full model list from CLI binary (GPT-5.5, GPT-5.4,
  GPT-5.3-Codex, Claude Opus 4.7, SWE-1.6, DeepSeek V4, Kimi K2.6, etc.)

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-11 20:21:12 +03:00
doda
78b084502a feat(api): aggregate combo model metadata in catalog 2026-05-12 01:31:50 +09:00
OmniRoute Ops
c1b004c74e address review: extra fields strip + non-mutating tool rewrite + system string
Per gemini-code-assist review on #2165:

1. Extra strip-list fields (PR description claimed but implementation
   missed):
   - client_info, prompt_cache_key, safety_identifier, metadata
   These trigger Anthropic's "Extra usage required" 400 the same way
   output_config does on CPA's /v1/messages surface.

2. applyMcpToolNameRewrite no longer mutates the nested input body. The
   shallow clone produced by transformRequest's `{...body}` left nested
   tools/messages/tool_choice as shared references with the original
   body, so direct `t.name = rewritten` assignments leaked back to the
   caller. Now returns a new array for tools (cloning the rewritten
   entries), a new messages array with cloned content blocks for each
   message containing a rewritten tool_use, and a cloned tool_choice
   object when rewrite is needed. Unchanged elements share references
   to keep memory churn minimal.

3. isAnthropicShape now treats any top-level `system` field as a strong
   signal — including the string form (Anthropic supports both `system:
   "Rules"` and `system: [{type: "text", text: "Rules"}]`). Previously
   only the array form was recognized, so plain-string Anthropic-shape
   bodies were routed to /v1/chat/completions and returned OpenAI SSE
   that Anthropic SDK clients can't decode.

On tool_result tool_use_id rewriting: tool_use_id is the opaque id
field of the corresponding tool_use block (e.g. "toolu_01abc"), not
the tool name. Anthropic's ^mcp_[^_] gate fires on `name`, not `id`,
so ids do not need rewriting. The PR description claim to rewrite
tool_use_id refs was overspecified relative to the actual constraint.
2026-05-11 16:27:52 +00:00
OmniRoute Ops
8b1da7b92c address review: emit BACKGROUND_DEGRADE log + test for background:false case
Per gemini-code-assist review on #2164:

1. Re-introduce the BACKGROUND_DEGRADE warning log (mentioned in PR
   description but missing from code). Operators can grep for this to
   identify clients still requesting background mode that should be
   reconfigured.
2. Make the log conditional on `background === true` (not on the strip
   itself). background:false / unset now passes through silently with
   no log spam.
3. Add unit test for both background unset AND background:false cases
   asserting no BACKGROUND_DEGRADE log is emitted, and update the
   existing background:true test to assert the log IS emitted.
2026-05-11 16:26:07 +00:00
OmniRoute Ops
992848431b address review: add MODEL_SPECS entries for new claude/kimi/mimo models
Per gemini-code-assist review on #2163, the registry contextLength/
maxOutputTokens values were being silently capped to 8192 by
capMaxOutputTokens() because the model IDs were absent from MODEL_SPECS,
falling back to __default__.maxOutputTokens. Adds entries with
matching limits :

- claude-opus-4-5-20251101 : 64000 max_out (overrides prefix-match to
  claude-opus-4-5 which has 32768)
- claude-opus-4-6 : 128000 max_out, 1M context tier
- claude-sonnet-4-6, claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001
  : 64000 max_out each
- kimi-k2.6 : 262144 max_out, 262144 context, with aliases for
  kimi-k2.6-thinking and kimi-for-coding
- mimo-v2.5-pro / mimo-v2.5 : 131072 max_out, 1048576 context
- mimo-v2-omni : 131072 max_out, 262144 context
- mimo-v2-flash : 65536 max_out, 262144 context

Each entry carries `aliases` where dot-notation variants exist
(e.g. claude-opus-4.6), so capMaxOutputTokens resolves them via the
explicit alias lookup before falling back to the prefix-match path.
2026-05-11 16:25:00 +00:00
OmniRoute Ops
c83792a8cd address review: exclude arrays from reasoning check + hoist regex constants
Per gemini-code-assist review on #2162:
- Add `!Array.isArray(b.reasoning)` guard so spread of array-typed
  reasoning doesn't pollute the body with numeric-keyed entries
- Hoist /devstral/i and /(claude|haiku|oswe)/i to module-level
  MISTRAL_NO_REASONING_EFFORT_PATTERN and
  GITHUB_NO_REASONING_EFFORT_PATTERN constants to avoid per-call
  RegExp construction
2026-05-11 16:24:05 +00:00
OmniRoute Ops
83f25922b0 fix(cliproxyapi): rewrite mcp_* tool names to bypass Anthropic gate
Anthropic Messages API silently gates client-declared tool names matching
^mcp_[^_].* behind their "Extra usage required" / "out of extra usage" 400
error — the prefix is reserved for their server-side MCP connector tools.
The error is misleading: it looks like a quota exhaustion, but it's body-
shape gating triggered purely by the regex match on `tools[].name`.

Bisected character-by-character against the real Anthropic API via CPA
(uTLS spoof, Claude OAuth account):

  Gate hit (HTTP 400):  mcp_call, mcp_query, mcp_x, mcp_test, mcp_anything
  Bypass (HTTP 200):    Mcp_call, MCP_call, _mcp_call, xmcp_call,
                        mcp__call, mcp-call, mcpcall, my_mcp_call

Independent of system prompt, metadata.user_id shape, thinking/output_config
presence, request size, or tool count. Capy declares mcp_call + mcp_query
for its MCP bridge, so every Capy Claude-BYOK request 400'd.

Fix: in CliproxyapiExecutor.transformRequest, for Anthropic-shape bodies,
rewrite tool names matching ^mcp_[^_] to "M" + name.slice(1) (mcp_call →
Mcp_call). Same rewrite applied to:

  - tools[].name
  - messages[].content[type=tool_use].name (for multi-turn)
  - tool_choice.name (when type=tool)

Build a reverse map {rewritten → original} and attach as body._toolNameMap.
chatCore.ts:mergeResponseToolNameMap already reads this from finalBody and
forwards it to the SSE passthrough stream
(utils/stream.ts:restoreClaudePassthroughToolUseName), which rewrites
tool_use.name back to the client's original namespace on response chunks.
End-to-end: Capy sends mcp_call → CPA/Anthropic sees Mcp_call → response
tool_use blocks emit Mcp_call → client receives mcp_call. Capy's dispatch
keyed on mcp_call works unchanged.

_toolNameMap is filtered out of the JSON.stringify body sent to CPA so the
in-memory channel doesn't leak over the wire.
2026-05-11 16:15:39 +00:00
OmniRoute Ops
05212b0a3f fix(cliproxyapi): strip Capy premium extras on Anthropic-shape bodies
When Capy (Anthropic SDK 0.90.0) BYOK Pro forwards a request via OmniRoute,
it injects:
  - thinking: { type: "adaptive", display: "summarized" }
  - output_config: { effort: "xhigh" }    ← premium tier
  - context_management: { edits: [...] }

These extras request features that bill against Anthropic "extra usage" even
on Claude Max subscriptions. Anthropic gates the request:
  400 "You're out of extra usage. Add more at claude.ai/settings/usage"

The existing strip lives in BaseExecutor's Claude OAuth cloak block, but the
CliproxyapiExecutor extends BaseExecutor without inheriting that cloak (the
block is gated on this.provider === "claude", but in CPA mode chatCore swaps
the executor to "cliproxyapi" entirely). So Capy's extras reach CPA verbatim
and CPA forwards them.

Fix: in CliproxyapiExecutor.transformRequest(), when the body is in
Anthropic shape (i.e. about to be POSTed to CPA's /v1/messages), strip the
three extras. CPA still applies its own Claude Code wire-image cloak (CCH
signing, billing header, system sentinel, uTLS) downstream. OpenAI-shape
bodies are untouched.

Mirrors the runtime "Patch I2/I4" effect previously applied via patch.mjs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:15:39 +00:00
OmniRoute Ops
4ee9ba9766 fix(cliproxyapi): route Anthropic-shape bodies to /v1/messages
When chatCore detects target=claude (source format = claude), it skips the
openai translation and passes the Anthropic-shape body straight to the
cliproxyapi executor. The executor's buildUrl() was hardcoded to
/v1/chat/completions, so CPA received an Anthropic body on the OpenAI
endpoint. CPA responded with an OpenAI-style SSE stream (choices[].message)
which Anthropic SDK clients (Capy, claude-cli, etc.) cannot parse —
server-side 200 with "request ended without sending any chunks" client-side.

Fix: detect Anthropic body shape (top-level `system` as array OR
messages[0].content as array) in execute() and route to /v1/messages.
CPA natively supports both endpoints; routing to /v1/messages preserves
the wire shape end-to-end. No translator round-trip required.

OpenAI Chat passthrough cases (Capy in OpenAI API mode, Codex CLI, etc.)
hit the false branch and keep the previous /v1/chat/completions route.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:15:39 +00:00
OmniRoute Ops
970e14725b feat(responses): degrade background mode to synchronous execution
OpenAI Responses API supports background: true for async/deferred runs
(returns 202 with response_id + GET /responses/<id> polling). Implementing
the full background contract requires queue/poll infrastructure that
OmniRoute does not have as a forward proxy.

Previously the translator rejected such requests with HTTP 400
"Unsupported Responses API feature: background mode is not supported by
omniroute". This breaks clients that opportunistically set background=true
for long-running tasks (Capy Captain Pro, Codex agents) even when the
underlying execution would complete in a normal HTTP timeout window.

Degrade silently: strip the background flag and run synchronously. The
client receives the full response in one round-trip with status=completed.
Clients that strictly require the async contract still observe a completed
response on the first poll and can adapt.

The existing test that asserted background=true throws is split into two:
- the unsupported-tool-type branch keeps the throw assertion
- the background branch now asserts the flag is stripped and translation
  completes with the expected messages

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:14:57 +00:00
OmniRoute Ops
ef1022e9c8 fix(registry): cap gpt-5.5 codex OAuth contextLength at 400K (not 1.05M)
The codex OAuth backend (chatgpt.com/backend-api/codex/responses) caps
the gpt-5.5 context window at 400 000 tokens, not the 1 050 000 advertised
by the public OpenAI API. Clients reading /v1/models for prompt-budget
math (e.g. Capy computing compression thresholds) would otherwise allow
prompts beyond the OAuth backend's actual capacity, triggering
silent truncation or upstream 400s.

Per-entry override of GPT_5_5_CODEX_CAPABILITIES (which spreads
contextLength=1050000 from the shared constant) — the constant itself
is unchanged because it's also consumed by the github provider's
gpt-5.5 entry where DB sync provides the canonical 400K/128K values.

max_output_tokens=128000 is informational only — the codex OAuth
backend strips max_output_tokens server-side (LiteLLM and Codex CLI
both confirm this). Advertising a realistic value still helps clients
that read it for token-budget heuristics.

References :
- openai/codex#19208 "1M context window gone after GPT-5.5 release"
- openai/codex#19319 — 258 400 effective context window observation
- openai/codex#19464 — Support 1M for GPT-5.5 in Codex (feature ask)
- opencode#24171 — GPT-5.5 Codex 400K vs API 1M
- BerriAI/litellm#21193 — codex backend rejects unsupported params
- openai/codex#4138 — model_max_output_tokens not wired up

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:13:51 +00:00
OmniRoute Ops
fa3b6d18ac chore(registry): per-model contextLength/maxOutputTokens for active providers
The /v1/models catalog endpoint reads `model.contextLength` directly from
the REGISTRY entries (src/app/api/v1/models/catalog.ts:823) and falls back
to REGISTRY[provider].defaultContextLength → getTokenLimit chain otherwise.
`max_output_tokens` flows through enrichCatalogModelEntry which calls
getResolvedModelCapabilities (src/lib/modelCapabilities.ts:261-265) reading
the same per-model registry fields.

Currently most non-default-spec models lack explicit contextLength /
maxOutputTokens, so /v1/models advertises stale defaults
(DEFAULT_LIMITS.default = 128000, MODEL_SPECS.__default__.maxOutputTokens
= 8192). Clients that read these values to compute compression thresholds
or prompt budgets (e.g. Capy reading context_length for its compress
trigger) over-aggressively trim long conversations.

Provider IDs in the registry (`claude`, `kimi-coding`, `xiaomi-mimo`) do
not match the canonical IDs synced from models.dev (`anthropic`, `cc`,
`xiaomi`), so the DB lookup misses for these entries. The cleanest fix
is to populate the registry directly with values consensus'd across 6+
upstream sync sources (anthropic, cc, openrouter, kilocode, vercel,
xiaomi-token-plan-*, llmgateway, kc, kilo-gateway).

Values:

- claude (id="claude", alias="cc"):
    opus-4-7, opus-4-6 → 1M ctx / 128K max_out
    opus-4-5-20251101, sonnet-4-6, sonnet-4-5-20250929, haiku-4-5-20251001
      → 200K ctx / 64K max_out
- kiro (alias="kr"): same opus/sonnet/haiku tiering
- github (alias="gh"): same claude subset tiering
- KIMI_CODING_SHARED:
    kimi-k2.6, kimi-k2.6-thinking → 262K ctx / 262K max_out
- xiaomi-mimo:
    mimo-v2.5-pro, mimo-v2.5 → 1M ctx / 131K max_out
    mimo-v2-omni → 262K ctx / 131K max_out
    mimo-v2-flash → 262K ctx / 65K max_out

The 1M context tier for claude-opus-4-6/4-7 requires the
`context-1m-2025-08-07` beta header which selectBetaFlags() already
attaches automatically for full-agent traffic (hasTools && hasSystem,
the Capy pattern) — see open-sse/executors/claudeIdentity.ts:304. No
wire-level change needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:13:51 +00:00
OmniRoute Ops
7395d71e1d fix(registry): set kimi-coding defaultContextLength to 262144 (K2.6 native)
The Kimi Code OAuth product (https://api.kimi.com/coding/v1/messages) runs
on the Kimi K2.6 backbone, which has a 262144 (256K) native context window
per Moonshot's published platform docs. The KIMI_CODING_SHARED registry
block had no defaultContextLength set, and the OAuth Coding plan is not
covered by the models.dev sync (no rows in model_capabilities), so
contextManager.ts:getTokenLimit fell through to DEFAULT_LIMITS.default
= 128000 — half the actual model capacity.

This propagates to /v1/models advertised context_length=128000 for
kimi-coding/kimi-k2.6 and kmc/kimi-k2.6, which under-reports the prompt
budget to downstream clients. Capy and similar clients that compute
prompt_cap = context_length - request.max_tokens then end up with an
artificially low cap (128K - 64K = 64K for Captain agent), causing
premature plateau in long conversations.

Reference: cross-provider model_capabilities rows in the DB confirm
the 262144 value (openrouter/moonshotai/kimi-k2.6, moonshot/kimi-k2.6,
ali/kimi-k2.6, deepinfra/moonshotai/Kimi-K2.6, hf/moonshotai/Kimi-K2.6,
and ~30 others). 128000 was a per-provider-default underbid only because
the OAuth Coding plan never gets a sync row.

The model_capabilities DB rows for synced providers override this
default, so any future syncing or per-model overrides still work as
intended.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:12:48 +00:00
OmniRoute Ops
21ca713af4 fix(executors): sanitize reasoning_effort for non-supporting providers
The claude→openai translator emits reasoning_effort=xhigh when the client
sends output_config.effort=max on a Claude-shape request. Combined with
runtime alias remapping (e.g. claude-opus-4-6 → mimo/mimo-v2.5-pro), this
routes xhigh to OpenAI-shape providers that only accept low|medium|high:

  xiaomi-mimo 400 reasoning_effort: Input should be 'low','medium' or 'high'
  mistral/devstral 400 unrecognized field reasoning_effort
  github/claude-* 400 unrecognized field reasoning_effort

Each rejection burns a combo fallback attempt before reaching a working
provider, adding latency per turn and polluting logs.

Add provider-aware sanitation in BaseExecutor.execute after transformRequest:
- xiaomi-mimo and other non-xhigh providers: downgrade xhigh → high
  (gated by the supportsXHighEffort helper from providerModels.ts, so
  models that genuinely expose xhigh pass through unchanged)
- mistral/devstral, github/claude|haiku|oswe: strip reasoning_effort entirely

The hook runs after transformRequest so per-provider transforms that
reintroduce reasoning_effort are also caught before fetch.

Includes unit tests covering: xhigh downgrade (top-level and nested),
strip-entirely for rejecting providers, no-op when effort is absent,
no-op for non-object bodies, and pass-through for unknown providers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:12:11 +00:00
OmniRoute Ops
08de5a1bbb fix(translator): inject thinking placeholder for all Claude-shape upstreams
prepareClaudeRequest already injects a synthetic thinking content block
when body.thinking is enabled, an assistant turn contains a tool_use,
and no precursor thinking block exists in content[]. The injection was
gated by `provider === "claude" || provider?.startsWith?.("anthropic-
compatible-")`, which excluded other Anthropic-shape upstreams:

  - kimi-coding (api.kimi.com/coding/v1/messages)
  - glmt (z.ai coding plan Anthropic endpoint)
  - zai, agentrouter, and any future provider registered with format: "claude"

These providers enforce the same body-shape contract for thinking mode
and reject multi-turn requests with errors like:

  kimi-coding: "thinking is enabled but reasoning_content is missing in
                assistant tool call message at index N"
  claude (cross-provider replay): "Invalid signature in thinking block"

prepareClaudeRequest is only invoked when targetFormat === FORMATS.CLAUDE
(translator/index.ts:165-168), so the outer provider gate is redundant:
any body reaching this function is destined for a Claude-shape upstream.
Drop the gate; the body of the block executes uniformly for all Claude-
shape targets.

Net effect:
- Single-turn requests unchanged (no tool_use in history yet)
- Multi-turn requests with assistant tool_use turns get a placeholder
  thinking block ("." with DEFAULT_THINKING_CLAUDE_SIGNATURE) prepended
- Existing thinking blocks get their signature replaced with the default
  (already the case for claude/anthropic-compatible-*; now applied to
  kimi-coding and similar — same defensive cross-provider posture)

The `supportsPromptCaching` gate at line 152 (for cache_control insertion)
remains unchanged — that one still wants to be conservative about which
providers support prompt caching.

Includes 5 unit test cases covering: claude native injection (regression),
kimi-coding injection (new), existing-thinking signature replacement,
thinking-off pass-through, and single-turn no-inject.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:11:22 +00:00
diegosouzapw
fea8e5a1e9 docs(workflow): strictly restrict cherry-pick to locked PRs only
Mandate direct PR fixes over cherry-picking in all cases where the maintainer has write access to the contributor's branch. Explicitly forbid using cherry-pick just to bypass conflict resolution.
2026-05-11 10:30:51 -03:00
diegosouzapw
f632da7943 docs: add contributor credits to CHANGELOG for all merged/cherry-picked PRs
Also update review-prs workflow to mandate CHANGELOG credits when cherry-picking
is used, preventing credit erasure from release notes.
2026-05-11 10:28:29 -03:00
Gioxa
2880155772 fix(openai-responses): emit reasoning summary as delta.reasoning_content (#2159)
Integrated into release/v3.8.0 — emit reasoning summary as delta.reasoning_content for Chat Completions clients
2026-05-11 10:22:07 -03:00
diegosouzapw
e4c8c14fb3 feat(resilience): add model cooldowns dashboard card with real-time list and re-enable
Cherry-picked from PR #2146: ModelCooldownsCard.tsx, model-cooldowns API route, ResilienceTab integration.

Co-authored-by: rafacpti23 <rafacpti23@users.noreply.github.com>
2026-05-11 10:21:28 -03:00
ipanghu
d3e0353203 fix: Added in debug mode, support for storing raw data in json (#2156)
Integrated into release/v3.8.0 — configurable chat log truncation, CHAT_DEBUG_FILE mode, cloudflared state file lock
2026-05-11 10:19:09 -03:00
diegosouzapw
6fc66eaba7 fix(catalog): cherry-pick type safety from PR #2152 — remove .ts imports, as any casts, add CustomModelEntry/ComboModelStep types
Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
2026-05-11 10:18:25 -03:00
backryun
6e2c5e2d4c chore(models): tidy up alibaba-coding-plan and cursor provider (#2150)
Integrated into release/v3.8.0 — tidies up Alibaba Coding Plan and Cursor provider model catalogs
2026-05-11 10:08:34 -03:00
Gioxa
fca89049c9 fix(openai-responses): propagate include so chat clients stream reasoning summaries (#2154)
Integrated into release/v3.8.0 — propagates include array so chat clients stream reasoning summaries via Responses API
2026-05-11 10:06:31 -03:00
Gioxa
1814d2bde0 fix(kiro): synthesize tools schema when history references tool_calls without body.tools (#2149)
Integrated into release/v3.8.0 — synthesizes tools schema for Kiro when body.tools is omitted but history has tool_calls
2026-05-11 10:06:05 -03:00
Gioxa
fdb4c63244 fix(kiro): avoid treating high-traffic 429s as quota exhaustion (#2153)
Integrated into release/v3.8.0 — fixes transient Kiro 429s being incorrectly classified as quota exhaustion
2026-05-11 10:05:48 -03:00
diegosouzapw
19c15a5139 chore(hooks): disable husky pre-push test enforcement
Comment out the npm availability guard and unit test execution in the
pre-push hook so pushes are no longer blocked by local hook checks. This
shifts validation away from developer machines and avoids failures in
environments where npm is unavailable or hooks are undesired.
2026-05-11 09:28:14 -03:00
diegosouzapw
bbecbccb0a fix(cli): harden setup, doctor, and backup workflows
Hide admin password entry during setup, make doctor degrade to warnings
when source-only runtime checks are unavailable, and improve stop
behavior by attempting graceful shutdown before force killing ports.

Also use SQLite's backup API for safer snapshots under WAL, align CLI
key writes with the current provider_connections schema, and include
follow-on compatibility fixes for GLM provider detection, stream error
sanitization, and auth-aware test coverage.
2026-05-11 09:13:49 -03:00
Automation
66d5808d4a refactor(catalog): replace bracket-access with CustomModelEntry interface
Addresses code review feedback from PR #2152: use a proper
CustomModelEntry interface instead of Record<string, unknown>
bracket-access for custom model fields like inputTokenLimit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 09:43:19 +02:00
Automation
360a97b654 refactor(catalog): remove .ts import extensions, as any casts, and normalize alias resolution
Addresses code review feedback from PR #2136:

- Remove .ts extensions from @omniroute/open-sse imports for better
  module resolution
- Replace all as any casts with proper types: ComboModelStep for
  combo step iteration, Record<string, unknown> bracket access for
  custom model fields, ManagedAvailableModel.contextLength type
  for fallback models, and Error instanceof check for catch blocks
- Normalize provider alias resolution in combo context_length
  calculation via resolveCanonicalProviderId for consistent
  getTokenLimit lookups

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 09:27:55 +02:00
Ramel Tecnologia
66d5d40a7d feat(resilience): expose model cooldown list with manual re-enable 2026-05-11 01:09:14 -03:00
diegosouzapw
7d8b783195 fix(types): remove extraneous config/models from AutoComboConfig returns and type seedConnection overrides 2026-05-11 00:13:20 -03:00
diegosouzapw
966e411ecb docs(changelog): add PR #2141 entry and update contributor credits 2026-05-10 23:48:38 -03:00
backryun
602f897c50 fix: remove duplicate cloud agent provider constants (#2141)
Integrated into release/v3.8.0 — Kiro model alias normalization (dash→dot), trimmed duplicate catalog entries, and new tests.
2026-05-10 23:47:20 -03:00
Diego Rodrigues de Sa e Souza
67af6c303f Add claude GitHub actions 1778466254012 (#2142)
* "Claude PR Assistant workflow"

* "Claude Code Review workflow"
2026-05-10 23:36:43 -03:00
diegosouzapw
c5967381d6 docs(changelog): add entries for PRs #2136, #2137, #2138, #2140 and update contributor credits 2026-05-10 21:27:18 -03:00
Davy Massoneto
4e53fba8b9 fix(sanitizer): preserve reasoning_content on assistant messages with tool_calls (#2140)
Integrated into release/v3.8.0 — preserves reasoning_content on assistant messages with tool_calls/function_call, fixing Kimi 400 errors.
2026-05-10 21:25:32 -03:00
diegosouzapw
0f748cb732 Merge remote-tracking branch 'origin/release/v3.8.0' into bugfix/preserve-reasoning-content-tool-calls 2026-05-10 21:25:18 -03:00
diegosouzapw
f8812b95c7 Merge remote-tracking branch 'origin/release/v3.8.0' into fix/combo-context-length-auto-calc
# Conflicts:
#	tests/unit/models-catalog-route.test.ts
2026-05-10 21:24:21 -03:00