diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a2b7f0d2cc..c868ffc82367 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(cli):** persist `STORAGE_ENCRYPTION_KEY` into `DATA_DIR` (not only `~/.omniroute`) and refuse to auto-generate a fresh key when a `storage.sqlite` already exists — a new key cannot decrypt previously-encrypted credentials, so silently regenerating it locked users out of their database. The CLI now mirrors the server `bootstrapEnv` guard. (reported by Daniel Nach; original key persistence by @Chewji9875 — follow-up to [#1622](https://github.com/diegosouzapw/OmniRoute/issues/1622)) - **fix(gemini):** preserve and re-attach the `thoughtSignature` on Gemini thinking-model tool calls — thread the signature namespace through the `FORMATS.GEMINI` and `FORMATS.GEMINI_CLI` request translators so the cached signature (keyed by connection + tool-call id) is found on the follow-up turn. Fixes `[400]: Function call is missing a thought_signature in functionCall parts` on agentic Gemini tool use. ([#2504](https://github.com/diegosouzapw/OmniRoute/issues/2504)) - **fix(translator):** accept PDFs sent in the Responses-API `input_file` shape on the Gemini path, and the Gemini-style `document` shape on the Responses/Codex path — content parts are now normalized across `input_file` / `file` / `document` so a PDF reaches the model regardless of which field name the client used. ([#2515](https://github.com/diegosouzapw/OmniRoute/issues/2515)) diff --git a/bin/omniroute.mjs b/bin/omniroute.mjs old mode 100644 new mode 100755 diff --git a/docs/i18n/ar/CHANGELOG.md b/docs/i18n/ar/CHANGELOG.md index 2691087a8d66..edcfd084b16f 100644 --- a/docs/i18n/ar/CHANGELOG.md +++ b/docs/i18n/ar/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/az/CHANGELOG.md b/docs/i18n/az/CHANGELOG.md index d675192199a7..4fbe8b92082b 100644 --- a/docs/i18n/az/CHANGELOG.md +++ b/docs/i18n/az/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/bg/CHANGELOG.md b/docs/i18n/bg/CHANGELOG.md index aa5d60aff532..2092a4510402 100644 --- a/docs/i18n/bg/CHANGELOG.md +++ b/docs/i18n/bg/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/bn/CHANGELOG.md b/docs/i18n/bn/CHANGELOG.md index 696d06adac4c..ed6d3f5ff00e 100644 --- a/docs/i18n/bn/CHANGELOG.md +++ b/docs/i18n/bn/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/cs/CHANGELOG.md b/docs/i18n/cs/CHANGELOG.md index eff1d588d907..952189364059 100644 --- a/docs/i18n/cs/CHANGELOG.md +++ b/docs/i18n/cs/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/da/CHANGELOG.md b/docs/i18n/da/CHANGELOG.md index 3589234f5448..3a8f9c5e9ffd 100644 --- a/docs/i18n/da/CHANGELOG.md +++ b/docs/i18n/da/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/de/CHANGELOG.md b/docs/i18n/de/CHANGELOG.md index 7200ee59ce22..495f0c7e66fd 100644 --- a/docs/i18n/de/CHANGELOG.md +++ b/docs/i18n/de/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/es/CHANGELOG.md b/docs/i18n/es/CHANGELOG.md index 47ca4e1ff013..f0e0c5291eba 100644 --- a/docs/i18n/es/CHANGELOG.md +++ b/docs/i18n/es/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/fa/CHANGELOG.md b/docs/i18n/fa/CHANGELOG.md index d0205f31cbcb..ded22fa16956 100644 --- a/docs/i18n/fa/CHANGELOG.md +++ b/docs/i18n/fa/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/fi/CHANGELOG.md b/docs/i18n/fi/CHANGELOG.md index 1f474eb87fa8..e560b40e54c6 100644 --- a/docs/i18n/fi/CHANGELOG.md +++ b/docs/i18n/fi/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/fr/CHANGELOG.md b/docs/i18n/fr/CHANGELOG.md index 20f4b501d440..8434a36e0cb8 100644 --- a/docs/i18n/fr/CHANGELOG.md +++ b/docs/i18n/fr/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/gu/CHANGELOG.md b/docs/i18n/gu/CHANGELOG.md index 12aaf61d0985..93e2663d6ab8 100644 --- a/docs/i18n/gu/CHANGELOG.md +++ b/docs/i18n/gu/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/he/CHANGELOG.md b/docs/i18n/he/CHANGELOG.md index 835d585308db..047a0eba8ed1 100644 --- a/docs/i18n/he/CHANGELOG.md +++ b/docs/i18n/he/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/hi/CHANGELOG.md b/docs/i18n/hi/CHANGELOG.md index 357dfc1cf298..3b450a2c2447 100644 --- a/docs/i18n/hi/CHANGELOG.md +++ b/docs/i18n/hi/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/hu/CHANGELOG.md b/docs/i18n/hu/CHANGELOG.md index 66f23441f589..ca71986ec2ff 100644 --- a/docs/i18n/hu/CHANGELOG.md +++ b/docs/i18n/hu/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/id/CHANGELOG.md b/docs/i18n/id/CHANGELOG.md index 7df773bff061..20b8a3300d77 100644 --- a/docs/i18n/id/CHANGELOG.md +++ b/docs/i18n/id/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/in/CHANGELOG.md b/docs/i18n/in/CHANGELOG.md index a723011bb5d2..17832cef7eaa 100644 --- a/docs/i18n/in/CHANGELOG.md +++ b/docs/i18n/in/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/it/CHANGELOG.md b/docs/i18n/it/CHANGELOG.md index 04d55d95e5b6..debd388f6a36 100644 --- a/docs/i18n/it/CHANGELOG.md +++ b/docs/i18n/it/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ja/CHANGELOG.md b/docs/i18n/ja/CHANGELOG.md index 264d1be302db..76045b35f41f 100644 --- a/docs/i18n/ja/CHANGELOG.md +++ b/docs/i18n/ja/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ko/CHANGELOG.md b/docs/i18n/ko/CHANGELOG.md index e0cd02984bfd..356209b4e4c5 100644 --- a/docs/i18n/ko/CHANGELOG.md +++ b/docs/i18n/ko/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/mr/CHANGELOG.md b/docs/i18n/mr/CHANGELOG.md index 352f553582d0..544db3683962 100644 --- a/docs/i18n/mr/CHANGELOG.md +++ b/docs/i18n/mr/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ms/CHANGELOG.md b/docs/i18n/ms/CHANGELOG.md index ecfeef4d18b6..ba13ca9d11b0 100644 --- a/docs/i18n/ms/CHANGELOG.md +++ b/docs/i18n/ms/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/nl/CHANGELOG.md b/docs/i18n/nl/CHANGELOG.md index 21ad0d84a569..51b9f8235566 100644 --- a/docs/i18n/nl/CHANGELOG.md +++ b/docs/i18n/nl/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/no/CHANGELOG.md b/docs/i18n/no/CHANGELOG.md index a659bb69be22..46c9762b9895 100644 --- a/docs/i18n/no/CHANGELOG.md +++ b/docs/i18n/no/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/phi/CHANGELOG.md b/docs/i18n/phi/CHANGELOG.md index a0c3682db439..b5a98d0200a6 100644 --- a/docs/i18n/phi/CHANGELOG.md +++ b/docs/i18n/phi/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/pl/CHANGELOG.md b/docs/i18n/pl/CHANGELOG.md index 692d4abe8fd3..84c0d236ff54 100644 --- a/docs/i18n/pl/CHANGELOG.md +++ b/docs/i18n/pl/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/pt-BR/CHANGELOG.md b/docs/i18n/pt-BR/CHANGELOG.md index cc0e6f29a599..d2d0fed88ead 100644 --- a/docs/i18n/pt-BR/CHANGELOG.md +++ b/docs/i18n/pt-BR/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/pt/CHANGELOG.md b/docs/i18n/pt/CHANGELOG.md index cf629684e2c0..45ff7e59904e 100644 --- a/docs/i18n/pt/CHANGELOG.md +++ b/docs/i18n/pt/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ro/CHANGELOG.md b/docs/i18n/ro/CHANGELOG.md index a4999f52d70c..6074520abe2a 100644 --- a/docs/i18n/ro/CHANGELOG.md +++ b/docs/i18n/ro/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ru/CHANGELOG.md b/docs/i18n/ru/CHANGELOG.md index 6b061e082754..4718135d324a 100644 --- a/docs/i18n/ru/CHANGELOG.md +++ b/docs/i18n/ru/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/sk/CHANGELOG.md b/docs/i18n/sk/CHANGELOG.md index 6b459ed21f05..323144506ead 100644 --- a/docs/i18n/sk/CHANGELOG.md +++ b/docs/i18n/sk/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/sv/CHANGELOG.md b/docs/i18n/sv/CHANGELOG.md index e545fecd3460..1462132e7e96 100644 --- a/docs/i18n/sv/CHANGELOG.md +++ b/docs/i18n/sv/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/sw/CHANGELOG.md b/docs/i18n/sw/CHANGELOG.md index efffb2e9d794..2194ddc2ba5c 100644 --- a/docs/i18n/sw/CHANGELOG.md +++ b/docs/i18n/sw/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ta/CHANGELOG.md b/docs/i18n/ta/CHANGELOG.md index 523fdd437aa7..06b2e3f45f3b 100644 --- a/docs/i18n/ta/CHANGELOG.md +++ b/docs/i18n/ta/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/te/CHANGELOG.md b/docs/i18n/te/CHANGELOG.md index 069f09b75106..5ffdcf6bf306 100644 --- a/docs/i18n/te/CHANGELOG.md +++ b/docs/i18n/te/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/th/CHANGELOG.md b/docs/i18n/th/CHANGELOG.md index 4bb63c6f6717..b15a68114926 100644 --- a/docs/i18n/th/CHANGELOG.md +++ b/docs/i18n/th/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/tr/CHANGELOG.md b/docs/i18n/tr/CHANGELOG.md index 2c65191509cf..69e019511f25 100644 --- a/docs/i18n/tr/CHANGELOG.md +++ b/docs/i18n/tr/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/uk-UA/CHANGELOG.md b/docs/i18n/uk-UA/CHANGELOG.md index caf73bdb83ed..c223b29b4d70 100644 --- a/docs/i18n/uk-UA/CHANGELOG.md +++ b/docs/i18n/uk-UA/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/ur/CHANGELOG.md b/docs/i18n/ur/CHANGELOG.md index d51a3969cc2b..7e213d8488c4 100644 --- a/docs/i18n/ur/CHANGELOG.md +++ b/docs/i18n/ur/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/vi/CHANGELOG.md b/docs/i18n/vi/CHANGELOG.md index 179eac4f4d14..02a5c814fc2a 100644 --- a/docs/i18n/vi/CHANGELOG.md +++ b/docs/i18n/vi/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/docs/i18n/zh-CN/CHANGELOG.md b/docs/i18n/zh-CN/CHANGELOG.md index 9e58186ed8bf..d79505d67259 100644 --- a/docs/i18n/zh-CN/CHANGELOG.md +++ b/docs/i18n/zh-CN/CHANGELOG.md @@ -8,6 +8,13 @@ ### 🔧 Bug Fixes +- **fix(cli):** mark `bin/omniroute.mjs` as executable (mode 755) so the globally-installed CLI runs directly without a manual `chmod +x`. ([#2469](https://github.com/diegosouzapw/OmniRoute/issues/2469) — thanks @disonjer) +- **fix(settings):** restore the Global System Prompt into the in-memory config on server startup and after JSON/SQLite import — it was only loaded by the PUT endpoint, so the toggle/prompt silently reverted to defaults after any restart or import. ([#2470](https://github.com/diegosouzapw/OmniRoute/issues/2470) — thanks @disonjer) +- **fix(settings):** append the Global System Prompt **after** existing system content instead of prepending it, so provider/agent instructions (Kiro, OpenCode, Hermes, …) injected into the system message no longer override the user's global prompt via recency bias. ([#2468](https://github.com/diegosouzapw/OmniRoute/issues/2468) — thanks @disonjer) +- **fix(kiro):** refresh imported social tokens (`authMethod === "imported"`) via the Kiro social-auth endpoint instead of AWS SSO OIDC — imported tokens carry a registered `clientId`/`clientSecret` but a social-issued refresh token the OIDC client cannot refresh, so auto-refresh was failing with "provider returned no new token". ([#2467](https://github.com/diegosouzapw/OmniRoute/issues/2467) — thanks @disonjer) +- **fix(antigravity):** resolve the Cloud Code `projectId` from `providerSpecificData` as a fallback (and preserve it across token refresh) so the Gemini `/v1beta` streaming path stops returning a spurious `422 Missing Google projectId` for connections that store the project there. ([#2480](https://github.com/diegosouzapw/OmniRoute/issues/2480)) +- **fix(api):** `GET /v1beta/models` now lists only models whose provider has an active/validated connection, matching the OpenAI-format `/v1/models` behavior, instead of returning the entire catalog. ([#2483](https://github.com/diegosouzapw/OmniRoute/issues/2483)) + - **fix(translator):** inject `omniroute_web_search` in the Responses-API flat tool shape (`{ type, name }`) when the target provider speaks the Responses API — previously it was always emitted in the Chat Completions nested shape (`{ type, function: { name } }`), and on the Responses→Responses passthrough path nothing flattened it, so Codex/relay upstreams rejected the request with `[400]: Missing required parameter: 'tools[0].name'.` ([#2390](https://github.com/diegosouzapw/OmniRoute/issues/2390)) - **fix(kiro):** serialize non-string `role:"tool"` message content before sending to CodeWhisperer — structured/array tool output was collapsing to `content:[{ text: "" }]`, which Kiro rejects with `400 Improperly formed request`. Now reuses the shared `serializeToolResultContent`. ([#2446](https://github.com/diegosouzapw/OmniRoute/issues/2446)) - **fix(claude):** gate heavy-agent beta headers (`context-1m-2025-08-07`, `effort-2025-11-24`, `advanced-tool-use-2025-11-20`) on Opus/Sonnet only and stop deleting Haiku's `thinking` config — Haiku with OAuth was rejecting `context-1m` with `[400]: This authentication style is incompatible with the long context beta header`. Also sanitizes historical `thinking` block signatures in Claude OAuth passthrough, fixing `[400]: Invalid signature in thinking block` on mid-session model switches. ([#2454](https://github.com/diegosouzapw/OmniRoute/issues/2454) — thanks @havockdev) diff --git a/open-sse/executors/antigravity.ts b/open-sse/executors/antigravity.ts index f08ce7e576eb..28cba9ec38ba 100644 --- a/open-sse/executors/antigravity.ts +++ b/open-sse/executors/antigravity.ts @@ -583,6 +583,9 @@ export class AntigravityExecutor extends BaseExecutor { : credentials.refreshToken, expiresIn: typeof tokens.expires_in === "number" ? tokens.expires_in : undefined, projectId: credentials.projectId, + // Preserve providerSpecificData so a projectId stored there survives the refresh + // (the onCredentialsRefreshed DB write) instead of being dropped → 422 (#2480). + providerSpecificData: credentials.providerSpecificData, }; } catch (error) { const message = error instanceof Error ? error.message : String(error); diff --git a/open-sse/services/systemPrompt.ts b/open-sse/services/systemPrompt.ts index f584a011aa59..95dce9100ad3 100644 --- a/open-sse/services/systemPrompt.ts +++ b/open-sse/services/systemPrompt.ts @@ -44,21 +44,24 @@ export function injectSystemPrompt(body, promptText = null) { const sysIdx = result.messages.findIndex((m) => m.role === "system" || m.role === "developer"); result.messages = [...result.messages]; if (sysIdx >= 0) { - // Prepend to existing system message + // Append after existing system content so the global prompt is the FINAL + // instruction — provider/agent system blocks (Kiro, OpenCode, Hermes, etc.) + // are injected into the system message later, and recency bias means the + // user's global prompt must come after them to take priority (#2468). const msg = { ...result.messages[sysIdx] }; - msg.content = text + "\n\n" + (msg.content || ""); + msg.content = (msg.content || "") + "\n\n" + text; result.messages[sysIdx] = msg; } else { result.messages = [{ role: "system", content: text }, ...result.messages]; } } - // Claude format (system field) + // Claude format (system field) — append for the same reason as above (#2468). if (result.system !== undefined) { if (typeof result.system === "string") { - result.system = text + "\n\n" + result.system; + result.system = result.system + "\n\n" + text; } else if (Array.isArray(result.system)) { - result.system = [{ type: "text", text }, ...result.system]; + result.system = [...result.system, { type: "text", text }]; } } diff --git a/open-sse/services/tokenRefresh.ts b/open-sse/services/tokenRefresh.ts index d22173ec5dae..94001479ce5b 100755 --- a/open-sse/services/tokenRefresh.ts +++ b/open-sse/services/tokenRefresh.ts @@ -611,8 +611,11 @@ export async function refreshKiroToken( const region = providerSpecificData?.region; // AWS SSO OIDC (Builder ID or IDC) - // If clientId and clientSecret exist, assume AWS SSO OIDC (default to builder-id if authMethod not specified) - if (clientId && clientSecret) { + // If clientId and clientSecret exist, assume AWS SSO OIDC (default to builder-id if authMethod not specified). + // Exception: imported social tokens (authMethod === "imported") carry a freshly-registered + // clientId/clientSecret but their refresh token is Kiro-social-issued — the isolated OIDC client + // cannot refresh it, so they must fall through to the social auth path (#2467). + if (clientId && clientSecret && authMethod !== "imported") { const endpoint = `https://oidc.${region || "us-east-1"}.amazonaws.com/token`; const response = await runWithProxyContext(proxyConfig, () => diff --git a/open-sse/translator/request/openai-to-gemini.ts b/open-sse/translator/request/openai-to-gemini.ts index 6370a787dbd4..66a226bf9514 100644 --- a/open-sse/translator/request/openai-to-gemini.ts +++ b/open-sse/translator/request/openai-to-gemini.ts @@ -518,7 +518,15 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra // Both Antigravity and Gemini CLI need the project field for the Cloud Code API. // For Gemini CLI, the stored projectId may be stale; the executor's transformRequest // refreshes it via loadCodeAssist before the request is sent to the API. - let projectId = credentials?.projectId; + // Fall back to providerSpecificData.projectId — some connections (and post-refresh + // credentials) store it there rather than at the top level, which otherwise produced a + // spurious 422 "Missing Google projectId" on the Antigravity /v1beta path (#2480). + const providerSpecificProjectId = ( + credentials?.providerSpecificData as { projectId?: unknown } | undefined + )?.projectId; + let projectId = + credentials?.projectId || + (typeof providerSpecificProjectId === "string" ? providerSpecificProjectId : ""); if (!projectId) { console.warn( diff --git a/src/app/api/db-backups/import/route.ts b/src/app/api/db-backups/import/route.ts index 645a5b90b938..2afcfccce65e 100644 --- a/src/app/api/db-backups/import/route.ts +++ b/src/app/api/db-backups/import/route.ts @@ -6,6 +6,8 @@ import os from "os"; import { getDbInstance, resetDbInstance, SQLITE_FILE } from "@/lib/db/core"; import { backupDbFile } from "@/lib/db/backup"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; +import { getSettings } from "@/lib/db/settings"; +import { setSystemPromptConfig } from "@omniroute/open-sse/services/systemPrompt.ts"; const MAX_UPLOAD_SIZE = 100 * 1024 * 1024; // 100 MB @@ -154,6 +156,17 @@ export async function POST(request: Request) { `[DB] Imported database from upload: ${connCount} connections, ${nodeCount} nodes, ${comboCount} combos, ${keyCount} API keys` ); + // The DB was replaced wholesale — re-hydrate the in-memory Global System Prompt so it + // reflects the imported settings without requiring a restart (#2470). + try { + const importedSettings = getSettings(); + if (importedSettings.systemPrompt) { + setSystemPromptConfig(importedSettings.systemPrompt); + } + } catch { + // non-fatal: import succeeded; system prompt will hydrate on next restart + } + return NextResponse.json({ imported: true, filename: fileName, diff --git a/src/app/api/oauth/kiro/social-authorize/route.ts b/src/app/api/oauth/kiro/social-authorize/route.ts index 6a557abb43f1..77003fdedebc 100755 --- a/src/app/api/oauth/kiro/social-authorize/route.ts +++ b/src/app/api/oauth/kiro/social-authorize/route.ts @@ -1,12 +1,12 @@ import { NextResponse } from "next/server"; -import { generatePKCE } from "@/lib/oauth/utils/pkce"; -import { KiroService } from "@/lib/oauth/services/kiro"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; +const KIRO_AUTH_SERVICE = "https://prod.us-east-1.auth.desktop.kiro.dev"; + /** * GET /api/oauth/kiro/social-authorize - * Generate Google/GitHub social login URL for manual callback flow - * Uses kiro:// custom protocol as required by AWS Cognito + * Initiate Google/GitHub social login via device flow. + * Returns a verification URL for the user to open in their browser. */ export async function GET(request) { if ((await isAuthRequired(request)) && !(await isAuthenticated(request))) { @@ -15,7 +15,7 @@ export async function GET(request) { try { const { searchParams } = new URL(request.url); - const provider = searchParams.get("provider"); // "google" or "github" + const provider = searchParams.get("provider"); if (!provider || !["google", "github"].includes(provider)) { return NextResponse.json( @@ -24,17 +24,30 @@ export async function GET(request) { ); } - // Generate PKCE for social auth - const { codeVerifier, codeChallenge, state } = generatePKCE(); + const loginProvider = provider === "google" ? "Google" : "Github"; + + const response = await fetch(`${KIRO_AUTH_SERVICE}/oauth/device/authorization`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + clientId: "kiro-cli", + loginProvider, + }), + }); + + if (!response.ok) { + const error = await response.text(); + return NextResponse.json({ error: `Device authorization failed: ${error}` }, { status: 502 }); + } - const kiroService = new KiroService(); - const authUrl = kiroService.buildSocialLoginUrl(provider, codeChallenge, state); + const data = await response.json(); return NextResponse.json({ - authUrl, - state, - codeVerifier, - codeChallenge, + authUrl: data.verificationUriComplete, + deviceCode: data.deviceCode, + userCode: data.userCode, + expiresIn: Math.floor((data.expiresInMilliseconds || 300000) / 1000), + interval: Math.floor((data.intervalInMilliseconds || 5000) / 1000), provider, }); } catch (error) { diff --git a/src/app/api/oauth/kiro/social-exchange/route.ts b/src/app/api/oauth/kiro/social-exchange/route.ts index 888b600ad9ef..255f275d71c5 100755 --- a/src/app/api/oauth/kiro/social-exchange/route.ts +++ b/src/app/api/oauth/kiro/social-exchange/route.ts @@ -3,14 +3,14 @@ import { KiroService } from "@/lib/oauth/services/kiro"; import { createProviderConnection, isCloudEnabled } from "@/models"; import { getConsistentMachineId } from "@/shared/utils/machineId"; import { syncToCloud } from "@/lib/cloudSync"; -import { kiroSocialExchangeSchema } from "@/shared/validation/schemas"; -import { isValidationFailure, validateBody } from "@/shared/validation/helpers"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; +const KIRO_AUTH_SERVICE = "https://prod.us-east-1.auth.desktop.kiro.dev"; + /** * POST /api/oauth/kiro/social-exchange - * Exchange authorization code for tokens (Google/GitHub social login) - * Callback URL will be in format: kiro://kiro.kiroAgent/authenticate-success?code=XXX&state=YYY + * Poll device code for tokens (Google/GitHub social login device flow). + * Frontend calls this repeatedly until authorization completes. */ export async function POST(request: Request) { if ((await isAuthRequired(request)) && !(await isAuthenticated(request))) { @@ -33,61 +33,57 @@ export async function POST(request: Request) { } try { - const validation = validateBody(kiroSocialExchangeSchema, rawBody); - if (isValidationFailure(validation)) { - return NextResponse.json({ error: validation.error }, { status: 400 }); + const { deviceCode, provider } = rawBody; + + if (!deviceCode || !provider) { + return NextResponse.json({ error: "Missing deviceCode or provider" }, { status: 400 }); } - const { code, codeVerifier, provider } = validation.data; - const kiroService = new KiroService(); + const response = await fetch(`${KIRO_AUTH_SERVICE}/oauth/device/poll`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ deviceCode, clientId: "kiro-cli" }), + }); - // Exchange code for tokens (redirect_uri handled internally) - const tokenData = await kiroService.exchangeSocialCode(code, codeVerifier); - - // Register an independent OIDC client for this connection so multiple Kiro accounts - // do not share a single backend session (#2328). Failure is non-fatal; the - // connection will degrade to the shared social-auth refresh path. - let oidcRegistration: { - clientId?: string; - clientSecret?: string; - clientSecretExpiresAt?: number; - } = {}; - try { - oidcRegistration = await kiroService.registerClient(); - } catch (err) { - console.warn("[kiro social-exchange] registerClient failed, continuing without it:", err); + const data = await response.json(); + + if (!response.ok || data.error === "authorization_pending" || data.error === "slow_down") { + return NextResponse.json({ + pending: true, + error: data.error || "authorization_pending", + }); + } + + if (!data.accessToken && !data.refreshToken) { + return NextResponse.json({ + pending: true, + error: data.error || "no_tokens", + }); } - // Extract email from JWT if available - const email = kiroService.extractEmailFromJWT(tokenData.accessToken); + const kiroService = new KiroService(); + const email = kiroService.extractEmailFromJWT(data.accessToken); + + const providerSpecificData: Record = { + authMethod: "imported", + provider: provider.charAt(0).toUpperCase() + provider.slice(1), + }; + + if (data.profileArn) { + providerSpecificData.profileArn = data.profileArn; + } - // Save to database const connection: any = await createProviderConnection({ provider: "kiro", authType: "oauth", - accessToken: tokenData.accessToken, - refreshToken: tokenData.refreshToken, - expiresAt: new Date(Date.now() + tokenData.expiresIn * 1000).toISOString(), + accessToken: data.accessToken, + refreshToken: data.refreshToken, + expiresAt: new Date(Date.now() + (data.expiresIn || 3600) * 1000).toISOString(), email: email || null, - providerSpecificData: { - profileArn: tokenData.profileArn, - authMethod: provider, // "google" or "github" - provider: provider.charAt(0).toUpperCase() + provider.slice(1), - ...(oidcRegistration.clientId - ? { - clientId: oidcRegistration.clientId, - clientSecret: oidcRegistration.clientSecret, - region: "us-east-1", - ...(oidcRegistration.clientSecretExpiresAt - ? { clientSecretExpiresAt: oidcRegistration.clientSecretExpiresAt } - : {}), - } - : {}), - }, + providerSpecificData, testStatus: "active", }); - // Auto sync to Cloud if enabled await syncToCloudIfEnabled(); return NextResponse.json({ @@ -104,14 +100,10 @@ export async function POST(request: Request) { } } -/** - * Sync to Cloud if enabled - */ async function syncToCloudIfEnabled() { try { const cloudEnabled = await isCloudEnabled(); if (!cloudEnabled) return; - const machineId = await getConsistentMachineId(); await syncToCloud(machineId); } catch (error) { diff --git a/src/app/api/settings/import-json/route.ts b/src/app/api/settings/import-json/route.ts index beecf58cf365..57d07d34053c 100644 --- a/src/app/api/settings/import-json/route.ts +++ b/src/app/api/settings/import-json/route.ts @@ -3,6 +3,8 @@ import { getDbInstance } from "@/lib/db/core"; import { backupDbFile } from "@/lib/db/backup"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; import { runJsonMigration, type LegacyJsonData } from "@/lib/db/jsonMigration"; +import { getSettings } from "@/lib/db/settings"; +import { setSystemPromptConfig } from "@omniroute/open-sse/services/systemPrompt.ts"; /** * POST /api/settings/import-json @@ -65,6 +67,13 @@ export async function POST(request: Request) { // Delegate the actual migration to the shared helper (avoids duplication with core.ts) const counts = runJsonMigration(db, data); + // Re-hydrate the in-memory Global System Prompt config — the migration writes it to + // the DB but the in-memory state would stay stale until a restart otherwise (#2470). + const importedSettings = await getSettings(); + if (importedSettings.systemPrompt) { + setSystemPromptConfig(importedSettings.systemPrompt); + } + console.log( `[JSON Import] Imported ${counts.connections} connections, ${counts.nodes} nodes, ` + `${counts.combos} combos, ${counts.apiKeys} API keys, ` + diff --git a/src/app/api/v1beta/models/route.ts b/src/app/api/v1beta/models/route.ts index 8d6a50834bad..7e782d6e8ebf 100644 --- a/src/app/api/v1beta/models/route.ts +++ b/src/app/api/v1beta/models/route.ts @@ -1,13 +1,38 @@ -import { PROVIDER_MODELS } from "@/shared/constants/models"; +import { PROVIDER_MODELS, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/models"; import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error"; import { getAllCustomModels, getAllSyncedAvailableModels, getSyncedAvailableModels, } from "@/lib/db/models"; +import { getProviderConnections } from "@/lib/localDb"; import { getResolvedModelCapabilities } from "@/lib/modelCapabilities"; import { getSyncedCapabilities } from "@/lib/modelsDevSync"; +/** + * Build the set of provider keys (raw id + alias) that have at least one active/validated + * connection. Mirrors the active-provider filter used by the OpenAI-format /v1/models + * catalog so /v1beta/models only lists models the user can actually call (#2483). + */ +async function getActiveProviderKeys(): Promise> { + const keys = new Set(); + try { + const connections = await getProviderConnections(); + for (const conn of connections) { + if (conn.isActive === false) continue; + const provider = conn.provider; + if (!provider) continue; + keys.add(provider); + const alias = (PROVIDER_ID_TO_ALIAS as Record)[provider]; + if (alias) keys.add(alias); + } + } catch (e) { + // DB unavailable — return empty set (safe default: list nothing provider-gated) + console.error("[v1beta/models] Could not fetch provider connections:", e); + } + return keys; +} + /** * Handle CORS preflight */ @@ -29,8 +54,12 @@ export async function GET() { getSyncedCapabilities(); const models = []; + // Only list models whose provider has an active/validated connection (#2483). + const activeKeys = await getActiveProviderKeys(); + // Built-in models (hardcoded defaults) for (const [provider, providerModels] of Object.entries(PROVIDER_MODELS)) { + if (!activeKeys.has(provider)) continue; for (const model of providerModels) { const resolved = getResolvedModelCapabilities({ provider, model: model.id }); models.push({ @@ -56,7 +85,9 @@ export async function GET() { } } try { - const syncedGeminiModels = await getSyncedAvailableModels("gemini"); + const syncedGeminiModels = activeKeys.has("gemini") + ? await getSyncedAvailableModels("gemini") + : []; for (const m of syncedGeminiModels) { models.push({ name: `models/gemini/${m.id}`, @@ -79,6 +110,7 @@ export async function GET() { const syncedModelsMap = await getAllSyncedAvailableModels(); for (const [providerId, syncedModels] of Object.entries(syncedModelsMap)) { if (providerId === "gemini") continue; + if (!activeKeys.has(providerId)) continue; if (!Array.isArray(syncedModels)) continue; for (const m of syncedModels) { if (!m || typeof m.id !== "string") continue; @@ -119,6 +151,7 @@ export async function GET() { if (!Array.isArray(rawModels)) continue; // Skip Gemini — handled by syncedAvailableModels above if (providerId === "gemini") continue; + if (!activeKeys.has(providerId)) continue; for (const model of rawModels) { if (!model || typeof model !== "object" || typeof (model as any).id !== "string") continue; diff --git a/src/lib/oauth/services/kiro.ts b/src/lib/oauth/services/kiro.ts index a399ce7f18ad..a335d0d1cd1b 100644 --- a/src/lib/oauth/services/kiro.ts +++ b/src/lib/oauth/services/kiro.ts @@ -184,8 +184,10 @@ export class KiroService { async refreshToken(refreshToken: string, providerSpecificData: any = {}) { const { authMethod, clientId, clientSecret, region } = providerSpecificData; - // AWS SSO OIDC refresh (Builder ID or IDC) - if (clientId && clientSecret) { + // AWS SSO OIDC refresh (Builder ID or IDC). + // Imported social tokens (authMethod === "imported") have a registered clientId/clientSecret + // but a Kiro-social refresh token the OIDC client can't refresh — use the social path (#2467). + if (clientId && clientSecret && authMethod !== "imported") { const endpoint = `https://oidc.${region || "us-east-1"}.amazonaws.com/token`; const response = await fetch(endpoint, { diff --git a/src/server-init.ts b/src/server-init.ts index 9a94afaf61ec..829fd0663fcc 100644 --- a/src/server-init.ts +++ b/src/server-init.ts @@ -8,6 +8,7 @@ import { startBudgetResetJob } from "./lib/jobs/budgetResetJob"; import { startReasoningCacheCleanupJob } from "./lib/jobs/reasoningCacheCleanupJob"; import { getSettings } from "./lib/db/settings"; import { applyRuntimeSettings } from "./lib/config/runtimeSettings"; +import { setSystemPromptConfig } from "@omniroute/open-sse/services/systemPrompt.ts"; import { startRuntimeConfigHotReload } from "./lib/config/hotReload"; import { startSpendBatchWriter } from "./lib/spend/batchWriter"; import { registerDefaultGuardrails } from "./lib/guardrails"; @@ -76,6 +77,14 @@ async function startServer() { ); } + // Restore the Global System Prompt into the in-memory config. It lives in the + // `settings.systemPrompt` key but is NOT covered by applyRuntimeSettings, so without + // this the toggle/prompt revert to defaults on every restart (#2470). + if (settings.systemPrompt) { + setSystemPromptConfig(settings.systemPrompt); + startupLog.info("Global System Prompt restored from settings"); + } + // Initialize cloud sync startSpendBatchWriter(); registerDefaultGuardrails(); diff --git a/src/shared/components/KiroAuthModal.tsx b/src/shared/components/KiroAuthModal.tsx index 05d26a46e7a0..7d4b3e07ecfc 100644 --- a/src/shared/components/KiroAuthModal.tsx +++ b/src/shared/components/KiroAuthModal.tsx @@ -174,25 +174,21 @@ export default function KiroAuthModal({

Google Account

-

- Login with your Google account (manual callback). -

+

Login with your Google account.

- {/* GitHub Social Login - HIDDEN */} + {/* GitHub Social Login */} diff --git a/src/shared/components/KiroSocialOAuthModal.tsx b/src/shared/components/KiroSocialOAuthModal.tsx index 64c56d19cc89..3af87e72e603 100644 --- a/src/shared/components/KiroSocialOAuthModal.tsx +++ b/src/shared/components/KiroSocialOAuthModal.tsx @@ -1,10 +1,8 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import Modal from "./Modal"; import Button from "./Button"; -import Input from "./Input"; -import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard"; type KiroSocialOAuthModalProps = { isOpen: boolean; @@ -14,10 +12,6 @@ type KiroSocialOAuthModalProps = { onClose: () => void; }; -/** - * Kiro Social OAuth Modal (Google/GitHub) - * Handles manual callback URL flow for social login - */ export default function KiroSocialOAuthModal({ isOpen, provider, @@ -25,14 +19,12 @@ export default function KiroSocialOAuthModal({ onSuccess, onClose, }: KiroSocialOAuthModalProps) { - const [step, setStep] = useState("loading"); // loading | input | success | error + const [step, setStep] = useState<"loading" | "polling" | "success" | "error">("loading"); + const [error, setError] = useState(null); + const [userCode, setUserCode] = useState(""); const [authUrl, setAuthUrl] = useState(""); - const [authData, setAuthData] = useState(null); - const [callbackUrl, setCallbackUrl] = useState(""); - const [error, setError] = useState(null); - const { copied, copy } = useCopyToClipboard(); + const pollRef = useRef | null>(null); - // Initialize auth flow useEffect(() => { if (!isOpen || !provider) return; @@ -45,69 +37,55 @@ export default function KiroSocialOAuthModal({ const data = await res.json(); if (!res.ok) { - throw new Error(data.error); + throw new Error(data.error || "Failed to start authorization"); } - setAuthData(data); - setAuthUrl(data.authUrl); - setStep("input"); - - // Auto-open browser - window.open(data.authUrl, "kiro_social_auth"); - } catch (err) { + setUserCode(data.userCode || ""); + setAuthUrl(data.authUrl || ""); + setStep("polling"); + + const interval = (data.interval || 5) * 1000; + pollRef.current = setInterval(async () => { + try { + const pollRes = await fetch("/api/oauth/kiro/social-exchange", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ deviceCode: data.deviceCode, provider }), + }); + const pollData = await pollRes.json(); + + if (pollData.success) { + if (pollRef.current) clearInterval(pollRef.current); + pollRef.current = null; + setStep("success"); + onSuccess?.(); + } + } catch { + // Network error, keep polling + } + }, interval); + } catch (err: any) { setError(err.message); setStep("error"); } }; initAuth(); - }, [isOpen, provider]); - - const handleManualSubmit = async () => { - try { - setError(null); - - // Parse callback URL - can be either kiro:// or http://localhost format - let url; - try { - url = new URL(callbackUrl); - } catch (e) { - // If URL parsing fails, might be malformed - throw new Error("Invalid callback URL format"); - } - - const code = url.searchParams.get("code"); - const state = url.searchParams.get("state"); - const errorParam = url.searchParams.get("error"); - if (errorParam) { - throw new Error(url.searchParams.get("error_description") || errorParam); - } - - if (!code) { - throw new Error("No authorization code found in URL"); + return () => { + if (pollRef.current) { + clearInterval(pollRef.current); + pollRef.current = null; } + }; + }, [isOpen, provider]); - // Exchange code for tokens - const res = await fetch("/api/oauth/kiro/social-exchange", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - code, - codeVerifier: authData.codeVerifier, - provider, - }), - }); - - const data = await res.json(); - if (!res.ok) throw new Error(data.error); - - setStep("success"); - onSuccess?.(); - } catch (err) { - setError(err.message); - setStep("error"); + const handleClose = () => { + if (pollRef.current) { + clearInterval(pollRef.current); + pollRef.current = null; } + onClose(); }; const providerName = provider === "google" ? "Google" : "GitHub"; @@ -116,11 +94,10 @@ export default function KiroSocialOAuthModal({
- {/* Loading */} {step === "loading" && (
@@ -133,50 +110,58 @@ export default function KiroSocialOAuthModal({
)} - {/* Manual Input Step */} - {step === "input" && ( - <> -
-
-

Step 1: Open this URL in your browser

-
- - + content_copy +
- -
-

Step 2: Paste the callback URL here

-

- After authorization, copy the full URL from your browser address bar. -

- setCallbackUrl(e.target.value)} - placeholder="kiro://kiro.kiroAgent/authenticate-success?code=..." - className="font-mono text-xs" - /> + )} + {userCode && ( +
+

Verification code

+

{userCode}

+ )} +
+ + progress_activity + + Waiting for authorization...
- -
- -
- +
)} - {/* Success */} {step === "success" && (
@@ -188,13 +173,12 @@ export default function KiroSocialOAuthModal({

Your {providerLabel} account via {providerName} has been connected.

-
)} - {/* Error */} {step === "error" && (
@@ -203,11 +187,8 @@ export default function KiroSocialOAuthModal({

Connection Failed

{error}

- -
diff --git a/tests/unit/system-prompt.test.ts b/tests/unit/system-prompt.test.ts index a90ff52bdd67..fa5347098824 100644 --- a/tests/unit/system-prompt.test.ts +++ b/tests/unit/system-prompt.test.ts @@ -30,7 +30,7 @@ test("injectSystemPrompt: adds system message when none exists", () => { assert.equal(result.messages.length, 2); }); -test("injectSystemPrompt: prepends to existing system message", () => { +test("injectSystemPrompt: appends after existing system message (#2468)", () => { setSystemPromptConfig({ enabled: true, prompt: "GLOBAL:" }); const body = { messages: [ @@ -39,23 +39,24 @@ test("injectSystemPrompt: prepends to existing system message", () => { ], }; const result = injectSystemPrompt(body); - assert.ok(result.messages[0].content.startsWith("GLOBAL:")); - assert.ok(result.messages[0].content.includes("Original prompt")); + // Global prompt must be the FINAL instruction so it wins over provider/agent blocks. + assert.ok(result.messages[0].content.startsWith("Original prompt")); + assert.ok(result.messages[0].content.trimEnd().endsWith("GLOBAL:")); assert.equal(result.messages.length, 2); }); -test("injectSystemPrompt: Claude body.system field", () => { +test("injectSystemPrompt: Claude body.system field appends global last (#2468)", () => { setSystemPromptConfig({ enabled: true, prompt: "GLOBAL:" }); const body = { system: "Claude prompt", messages: [{ role: "user", content: "hi" }], }; const result = injectSystemPrompt(body); - assert.ok(result.system.startsWith("GLOBAL:")); - assert.ok(result.system.includes("Claude prompt")); + assert.ok(result.system.startsWith("Claude prompt")); + assert.ok(result.system.trimEnd().endsWith("GLOBAL:")); }); -test("injectSystemPrompt: Claude array system field", () => { +test("injectSystemPrompt: Claude array system field appends global last (#2468)", () => { setSystemPromptConfig({ enabled: true, prompt: "GLOBAL:" }); const body = { system: [{ type: "text", text: "Claude prompt" }], @@ -63,7 +64,8 @@ test("injectSystemPrompt: Claude array system field", () => { }; const result = injectSystemPrompt(body); assert.ok(Array.isArray(result.system)); - assert.equal(result.system[0].text, "GLOBAL:"); + assert.equal(result.system[0].text, "Claude prompt"); + assert.equal(result.system[result.system.length - 1].text, "GLOBAL:"); assert.equal(result.system.length, 2); }); diff --git a/tests/unit/token-refresh-service.test.ts b/tests/unit/token-refresh-service.test.ts index 4727684bdb4b..143ef92a8ab4 100644 --- a/tests/unit/token-refresh-service.test.ts +++ b/tests/unit/token-refresh-service.test.ts @@ -589,6 +589,47 @@ test("refreshKiroToken uses AWS OIDC path for social-auth token when clientId is }); }); +// Issue #2467 — an IMPORTED social token (authMethod === "imported") carries a +// freshly-registered clientId/clientSecret, but its refresh token is Kiro-social-issued +// and the isolated OIDC client cannot refresh it. It must use the social-auth endpoint, +// NOT AWS OIDC (which is what #2328 enabled for authMethod "google"). +test("refreshKiroToken uses social-auth path for imported token even with clientId (#2467)", async () => { + const log = createLog(); + const calls: any[] = []; + + await withMockedFetch( + async (url, options = {}) => { + calls.push({ url, options }); + return jsonResponse({ + accessToken: "kiro-imported-access", + refreshToken: "kiro-imported-refresh-next", + expiresIn: 1100, + }); + }, + async () => { + const result = await refreshKiroToken( + "kiro-imported-refresh", + { + authMethod: "imported", + clientId: "isolated-client-id", + clientSecret: "isolated-client-secret", + region: "us-east-1", + }, + log + ); + assert.equal(result.accessToken, "kiro-imported-access"); + } + ); + + // Must call the shared social-auth tokenUrl — NOT the AWS OIDC endpoint. + assert.equal( + calls[0].url, + PROVIDERS.kiro.tokenUrl, + `expected social-auth endpoint but got ${calls[0].url}` + ); + assert.ok(!calls[0].url.includes("oidc."), "imported token must not use AWS OIDC"); +}); + test("refreshQoderToken uses basic auth once qoder oauth settings are configured", async () => { const log = createLog(); const calls: any[] = []; diff --git a/tests/unit/translator-openai-to-gemini.test.ts b/tests/unit/translator-openai-to-gemini.test.ts index e75651f1afa9..579eca181151 100644 --- a/tests/unit/translator-openai-to-gemini.test.ts +++ b/tests/unit/translator-openai-to-gemini.test.ts @@ -892,6 +892,29 @@ test("OpenAI -> Antigravity Gemini path preserves thinkingConfig (only Claude is assert.equal((result as any).request?.generationConfig.thinkingConfig.includeThoughts, true); }); +// Regression for #2480: when projectId is stored in providerSpecificData rather than at +// the top level of the credential record, the Antigravity Cloud Code envelope must still +// pick it up — otherwise the /v1beta path 422s with "Missing Google projectId". +test("openaiToAntigravityRequest falls back to providerSpecificData.projectId (#2480)", () => { + const result = openaiToAntigravityRequest( + "gemini-3.1-flash-lite", + { messages: [{ role: "user", content: "Hello" }] }, + false, + { providerSpecificData: { projectId: "proj-from-psd" } } as any + ); + assert.equal(result.project, "proj-from-psd"); +}); + +test("openaiToAntigravityRequest prefers top-level projectId over providerSpecificData (#2480)", () => { + const result = openaiToAntigravityRequest( + "gemini-3.1-flash-lite", + { messages: [{ role: "user", content: "Hello" }] }, + false, + { projectId: "proj-top", providerSpecificData: { projectId: "proj-psd" } } as any + ); + assert.equal(result.project, "proj-top"); +}); + // Regression for #2515: a PDF sent in the Responses-API `input_file` shape must reach // Gemini as inlineData instead of being silently dropped. test("convertOpenAIContentToParts handles input_file file_data (#2515)", () => { diff --git a/tests/unit/v1beta-models-route.test.ts b/tests/unit/v1beta-models-route.test.ts index 21f6b210b4a9..1f66e7ae24a3 100644 --- a/tests/unit/v1beta-models-route.test.ts +++ b/tests/unit/v1beta-models-route.test.ts @@ -10,8 +10,18 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "v1beta-models-test-s const core = await import("../../src/lib/db/core.ts"); const modelsDb = await import("../../src/lib/db/models.ts"); +const providersDb = await import("../../src/lib/db/providers.ts"); const v1betaModelsRoute = await import("../../src/app/api/v1beta/models/route.ts"); +async function addActiveConnection(provider: string) { + await providersDb.createProviderConnection({ + provider, + authType: "apikey", + apiKey: `test-key-${provider}`, + testStatus: "active", + }); +} + async function resetStorage() { core.resetDbInstance(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); @@ -28,6 +38,8 @@ test.after(async () => { }); test("v1beta models route deduplicates custom models against built-in and synced entries", async () => { + // #2483: the route now lists only models whose provider has an active connection. + await addActiveConnection("openai"); await modelsDb.replaceSyncedAvailableModelsForConnection("openai", "conn-main", [ { id: "gpt-4o", @@ -53,3 +65,24 @@ test("v1beta models route deduplicates custom models against built-in and synced assert.equal(names.filter((name) => name === "models/openai/review-sync-only").length, 1); assert.equal(names.filter((name) => name === "models/openai/review-manual-only").length, 1); }); + +test("v1beta models route excludes providers without an active connection (#2483)", async () => { + // No connections configured at all → no built-in catalog models should leak. + const emptyResp = await v1betaModelsRoute.GET(); + const emptyBody = (await emptyResp.json()) as { models: Array<{ name: string }> }; + assert.equal(emptyResp.status, 200); + assert.equal(emptyBody.models.length, 0, "no active connections → empty model list"); + + // Configure ONLY an anthropic connection; custom models for an unconfigured provider + // (kie) must NOT appear, while anthropic catalog models do. + await addActiveConnection("anthropic"); + await modelsDb.addCustomModel("kie", "claude-opus-4-7", "Kie Claude Opus"); + const resp = await v1betaModelsRoute.GET(); + const body = (await resp.json()) as { models: Array<{ name: string }> }; + const names = body.models.map((m) => m.name); + assert.ok(!names.some((n) => n.startsWith("models/kie/")), "unconfigured kie must be excluded"); + assert.ok( + names.some((n) => n.startsWith("models/anthropic/")), + "configured anthropic must be present" + ); +});