Release v3.8.10 - #3140
Release v3.8.10#3140
Conversation
Bump 3.8.9 → 3.8.10 across package.json, lockfile, electron, open-sse, and docs/reference/openapi.yaml; add the [3.8.10] CHANGELOG section (root + 41 i18n mirrors) as the integration target for the cycle. Entries land here as work merges into release/v3.8.10; finalized by the release flow.
There was a problem hiding this comment.
Code Review
This pull request bumps the project version from 3.8.9 to 3.8.10 across package.json, package-lock.json, electron/package.json, open-sse/package.json, and the OpenAPI specification. It also prepares the main and internationalized CHANGELOG files for the new release cycle by adding an 'Unreleased' section for version 3.8.10. There are no review comments, and I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 406a150f15
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "": { | ||
| "name": "omniroute", | ||
| "version": "3.8.9", | ||
| "version": "3.8.10", |
There was a problem hiding this comment.
Regenerate the lockfile for the workspace version
This lockfile version bump is incomplete: open-sse/package.json now says 3.8.10, but the packages["open-sse"].version entry near the end of package-lock.json still says 3.8.9 (running npm install --package-lock-only updates it). Any release or audit tooling that reads workspace versions from the lockfile will still report @omniroute/open-sse as 3.8.9, so please regenerate or patch the workspace entry as part of this bump.
Useful? React with 👍 / 👎.
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (14 files)
Fix Link: Fix these issues in Kilo Cloud Reviewed by step-3.7-flash · 877,293 tokens |
CI Coverage Report
Coverage artifact was not available for this run. |
Assign unique aliases to HuggingChat, Kimi Web, and Qwen Web so they no longer shadow primary providers or trigger startup warnings. Add a unit test to enforce provider alias uniqueness and prevent future collisions. Also expand local ignore and VS Code exclude rules for agent, build, and worktree artifacts.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2eb0f0500c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1,219 +0,0 @@ | |||
| { | |||
There was a problem hiding this comment.
Restore the i18n drift state file
Deleting this committed state file breaks the documented/CI i18n gate: scripts/i18n/check-translation-drift.mjs reads .i18n-state.json and exits 1 when it is missing, so npm run i18n:check now fails immediately with “.i18n-state.json not found — run npm run i18n:run to bootstrap.” This affects any release/check workflow that runs the i18n drift check after this commit, so the state file should be restored or the checker/workflow intentionally changed in the same PR.
Useful? React with 👍 / 👎.
Normalize image_url parts across all Responses input paths. Integrated into release/v3.8.10.
Preserve API key expiration local time + clear button. Integrated into release/v3.8.10.
Strip previous_response_id for stateless Responses upstreams (auto/strip/preserve). Integrated into release/v3.8.10.
| // `previous_response_id` is only safe when the upstream actually keeps | ||
| // Responses state. OmniRoute defaults to stateless upstream calls, so auto | ||
| // strips unless the connection explicitly opts into OpenAI Responses storage. | ||
| const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData); |
There was a problem hiding this comment.
WARNING: Redundant double toRecord() call
const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData);The inner toRecord(credentials) already returns a JsonRecord. The outer toRecord() is unnecessary since .providerSpecificData on a JsonRecord returns unknown, which the outer call wraps. Simplify to:
| const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData); | |
| const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData as unknown); |
Or more clearly:
| const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData); | |
| const credentialsRecord = toRecord(credentials); | |
| const providerSpecificData = toRecord(credentialsRecord.providerSpecificData); |
|
|
||
| type JsonRecord = Record<string, unknown>; | ||
|
|
||
| type ApplyResponsesPreviousResponseIdPolicyOptions = { |
There was a problem hiding this comment.
SUGGESTION: Options type uses unknown for all fields, losing type safety
type ApplyResponsesPreviousResponseIdPolicyOptions = {
mode: unknown;
sourceFormat?: unknown;
targetFormat?: unknown;
credentials?: unknown;
};Consider using proper types:
mode: ResponsesPreviousResponseIdMode | stringsourceFormat?: stringtargetFormat?: stringcredentials?: { providerSpecificData?: Record<string, unknown> }
This would catch type mismatches at compile time and improve IDE support.
| } | ||
|
|
||
| function normalizeResponsesReasoningEffort(value: unknown): string { | ||
| const effort = toString(value).toLowerCase(); |
There was a problem hiding this comment.
WARNING: Duplicate imageUrlToText function
This function is identical to the one in open-sse/services/responsesInputSanitizer.ts:58-62. Consider extracting to a shared utility (e.g., open-sse/utils/imageUtils.ts) to avoid divergence.
| const effort = toString(value).toLowerCase(); | |
| import { imageUrlToText } from "../utils/imageUtils"; |
Then remove the local definition.
| return next; | ||
| } | ||
|
|
||
| function imageUrlToText(value: unknown): string { |
There was a problem hiding this comment.
WARNING: imageUrlToText returns empty string for invalid input
function imageUrlToText(value: unknown): string {
if (typeof value === "string") return value;
const record = toRecord(value);
return typeof record?.url === "string" ? record.url : "";
}When value is malformed (e.g., { image_url: null } or { url: 123 }), this returns "", causing downstream code to produce [Image: ] (empty URL). Consider returning a placeholder like [Invalid image] or throwing for truly invalid structures to surface data issues earlier.
|
|
||
| useEffect(() => { | ||
| let cancelled = false; | ||
| fetch("/api/settings") |
There was a problem hiding this comment.
WARNING: Fetch to /api/settings without credentials/auth headers
fetch("/api/settings")This relies on same-origin cookies for authentication. If the dashboard is served from a different origin (e.g., via tunnel/proxy) or if cookie auth is disabled, this will fail with 401. Consider using the authenticated fetch wrapper used elsewhere in the codebase, or at minimum add credentials: "include".
| setStatus(""); | ||
|
|
||
| try { | ||
| const res = await fetch("/api/settings", { |
There was a problem hiding this comment.
WARNING: No response type checking before .json()
const res = await fetch("/api/settings", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ responsesPreviousResponseIdMode: nextMode }),
});
if (!res.ok) {
setMode(previousMode);
setStatus("error");
return;
}
setStatus("saved");If the server returns a non-JSON error response (HTML error page, plain text), res.json() on the next call (implicit in the success path) would throw. The code doesn't call .json() on success, but if the error path is taken and the response body is read elsewhere, it could fail. Add try { await res.json() } catch {} or check content-type header before parsing.
| } | ||
| translatedBody.model = finalModelToUpstream; | ||
|
|
||
| const previousResponseIdPolicy = applyResponsesPreviousResponseIdPolicy(translatedBody, { |
There was a problem hiding this comment.
SUGGESTION: Verify credentials structure matches policy expectations
const previousResponseIdPolicy = applyResponsesPreviousResponseIdPolicy(translatedBody, {
mode: settings.responsesPreviousResponseIdMode,
sourceFormat,
targetFormat,
credentials,
});The credentials object here should have providerSpecificData.openaiStoreEnabled for the auto mode to work correctly. Add a comment or type assertion documenting the expected shape, or validate at the call site. This prevents silent misconfiguration if the credentials structure changes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 273268c18d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // `previous_response_id` is only safe when the upstream actually keeps | ||
| // Responses state. OmniRoute defaults to stateless upstream calls, so auto | ||
| // strips unless the connection explicitly opts into OpenAI Responses storage. | ||
| const providerSpecificData = toRecord(toRecord(credentials).providerSpecificData); | ||
| return !isOpenAIResponsesStoreEnabled(providerSpecificData); |
There was a problem hiding this comment.
Honor request-level store before stripping state IDs
When a client calls /v1/responses for the OpenAI provider with store: true and a previous_response_id, auto mode still strips the ID unless the connection has providerSpecificData.openaiStoreEnabled set. Since chatCore leaves store on OpenAI requests, the upstream would actually have Responses storage enabled for this request, but the state pointer is removed and the follow-up starts without the referenced prior response. Consider treating an explicit request-level store: true as stateful for the auto policy.
Useful? React with 👍 / 👎.
…3138) Map caps.thinking to ModelV2.capabilities.interleaved for opencode-plugin. Integrated into release/v3.8.10.
Use synced models as authoritative local catalog for all providers (+regression test). Integrated into release/v3.8.10.
…I key→dashscope (#3149) Bifurcate Qoder validation by token type (PAT→Cosy, regular→dashscope) +regression test. Integrated into release/v3.8.10.
Dynamic antigravity MITM model resolution in the executor (+bug fix +regression test; DB import dropped from client-reachable config). Integrated into release/v3.8.10.
Podman deployment options + larger upload body-size limits (+CONTAINER_HOST docs). Integrated into release/v3.8.10.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f0e3a9bec9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - DATA_DIR=/app/data # Must match the volume mount below | ||
| - PORT=${PORT:-20128} | ||
| - DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}} | ||
| - DASHBOARD_PORT=${DASHBOARD_PORT:-20128} |
There was a problem hiding this comment.
Preserve PORT as the dashboard default
When a compose user sets only PORT (which .env.example documents as the canonical single-port setting), this now still exports DASHBOARD_PORT=20128 and the service port mappings below also default to 20128, so PORT=3000 docker compose --profile base up no longer starts/exposes the dashboard on 3000. The runtime helpers fall back DASHBOARD_PORT to PORT when it is unset, so the compose file should keep the same fallback instead of forcing 20128 unless DASHBOARD_PORT is explicitly provided.
Useful? React with 👍 / 👎.
) Fireworks router IDs (accounts/fireworks/routers/...) were double-prefixed with accounts/fireworks/models/ → upstream 404. Add optional acceptedModelIdPrefixes to the registry entry and skip the prepend when the model already starts with an accepted prefix. Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com>
…3136) (#3161) llama-cpp was missing from the local-provider group in buildUrl(), so it fell through to the OpenAI baseUrl and returned an OpenAI 401. Add the case to resolve the connection's providerSpecificData.baseUrl. Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com>
…ial (#3007) (#3162) The executor read credentials.cookies/convexSessionId, but the pipeline only stores the pasted string under apiKey → t3.chat always 400'd. Parse both values from apiKey (fallback accessToken), mirroring validation.ts. Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com>
… (#3163) MiniMax-M3 had no MODEL_SPECS entry and capitalized MiniMax-M2.7 missed its lowercase spec (case-sensitive lookup) → both fell to the 8192 default cap. Add the M3 spec (512K output), alias the capitalized ids, and make getModelSpec lookups case-insensitive. Co-authored-by: totaltube <totaltube@users.noreply.github.com>
…ot.com (#3120, #3121) (#3164) The github (Copilot) provider had a static hardcoded catalog with no discovery source, so Import Models never refreshed (#3120) and advertised non-entitled models that 400 on use (#3121). Add a live /models fetch with fallback to the static list. Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
| }); | ||
|
|
||
| assert.equal(url, "http://127.0.0.1:8080/v1/chat/completions"); | ||
| assert.ok(!url.includes("api.openai.com"), `expected local URL, got ${url}`); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0909b31f50
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const allSynced = await getSyncedAvailableModels(provider); | ||
| if (Array.isArray(allSynced) && allSynced.length > 0) { | ||
| providerSyncedModels = allSynced.map((m) => ({ |
There was a problem hiding this comment.
Limit synced catalog fallback to the current connection
When the provider is GitHub Copilot, the catalog is per-account and the live branch below fetches with this connection's Copilot token, but this provider-wide lookup unions synced models from every GitHub connection before building the fallback/local catalog. If account A has already synced a model that account B is not entitled to, then B's auto-fetch-disabled or live-fetch-failure path will return A's cached model list, reintroducing the non-entitled model advertisement this change is trying to avoid. Use the current connection's synced models for per-account providers instead of getSyncedAvailableModels(provider).
Useful? React with 👍 / 👎.
| Wants=network-online.target | ||
|
|
||
| [Container] | ||
| Image=docker.io/redis:7-alpine |
There was a problem hiding this comment.
Use the official Redis image namespace in Quadlet
The new Quadlet service points Podman at docker.io/redis:7-alpine, but the official Redis image lives under Docker Hub's library namespace (the compose file in this same change uses docker.io/library/redis:7-alpine). With this Quadlet file, systemctl --user start omniroute-redis will try to pull the non-official redis namespace/repository and can fail before OmniRoute starts; use docker.io/library/redis:7-alpine here as well.
Useful? React with 👍 / 👎.
) (#3165) Editing a combo did not invalidate the 10s nested-combo expansion caches (chat.ts getCombosCachedForChat + chatCore.ts getCombosCached; the exported clearCombosCache was dead code), so a removed nested target/model could be served as a phantom for up to 10s. Wire a shared monotonic combos-cache version in readCache (bumped by invalidateDbCache("combos") on every combo write); both cache layers treat a version mismatch as a miss. Also log the resolved DATA_DIR/SQLITE_FILE absolute path at DB init so the reporter's 'persists across restart + volume wipe' symptom (a multi-replica Docker volume/DATA_DIR mismatch, not a routing bug) is diagnosable from logs. Includes consolidated CHANGELOG entries for #3133/#3136/#3007/#3141/#3120/#3121. Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8fb51f44d0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const copilotToken = | ||
| toNonEmptyString(psd.copilotToken) || toNonEmptyString(accessToken) || null; |
There was a problem hiding this comment.
Refresh Copilot token before model discovery
When a GitHub Copilot connection has an expired providerSpecificData.copilotToken (the normal OAuth flow stores a short-lived token plus copilotTokenExpiresAt), this route still sends that stale token to /models and never uses the valid GitHub access/refresh token path that the chat executor uses to refresh Copilot credentials. The fetch then returns non-OK and falls back to the static/synced catalog, so “refresh/import models” after token expiry can again advertise non-entitled Copilot models instead of the per-account live list this branch is meant to enforce.
Useful? React with 👍 / 👎.
Parse bare JSON tool calls for deepseek-web (#2820) + fuzzy tool-name matching. Integrated into release/v3.8.10.
…ry manager (#3177) Misc: ProviderProfile export, DeepSeek reasoning regex, binary guard. Integrated into release/v3.8.10.
Kiro social OAuth: optional targetProvider passthrough. Integrated into release/v3.8.10.
Bump hono to 4.12.23. Integrated into release/v3.8.10.
kilocode: openai format + default executor (matches kilo-gateway) + registry test. Integrated into release/v3.8.10.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05aafa1374
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| const connection: any = await createProviderConnection({ | ||
| provider: "kiro", | ||
| provider: targetProvider || "kiro", |
There was a problem hiding this comment.
Clamp social OAuth target providers
When the social OAuth poll succeeds, this now trusts targetProvider from the request body verbatim; an authenticated caller (or a tampered dashboard request) can submit targetProvider: "openai"/"codex"/any string and persist Kiro/Amazon-Q tokens as that provider. The neighboring Kiro import and auto-import routes clamp this value to "amazon-q" or "kiro", so this route should apply the same allowlist before calling createProviderConnection.
Useful? React with 👍 / 👎.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76838f6594
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| const providers = providerStats.map((p: any) => ({ | ||
| ...p, | ||
| provider: resolveName(p.provider, p.nodeName), |
There was a problem hiding this comment.
Preserve provider ids for tool-latency lookups
When tool latency has been recorded for a provider whose display name differs from its id (for example openai → OpenAI), this rewrites provider before returning the payload while toolLatency remains keyed by the raw id from recordToolLatency. The dashboard indexes data.toolLatency[p.provider], so the new TTFT/Gap columns and sorting show no measurements for those providers; keep a separate display name or re-key the latency map consistently.
Useful? React with 👍 / 👎.
…h, actionable 401 (#3156) Sequential+spaced OAuth quota sync, reactive force-refresh on 401, actionable 401 in UI. Integrated into release/v3.8.10.
…ort-TTL OAuth) (#3159) Per-provider proactive-refresh skip list (OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) to rescue short-TTL OAuth. Integrated into release/v3.8.10.
…informative) (#3178) Show OAuth token expiry on provider cards (small, blue, informative). Integrated into release/v3.8.10.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ac40829c0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (isFinishChunk && passthroughHasToolCalls) { | ||
| toolFinishTime = Date.now(); | ||
| try { | ||
| markToolFinish(sessionId); |
There was a problem hiding this comment.
Create the session before marking tool completion
In the Next API path, open-sse/handlers/chatCore.ts creates this stream without touching sessionManager first, and markToolFinish() only updates an already-existing session. For /api/v1/chat/completions tool-call streams this call is therefore a no-op, so the follow-up request cannot consume the tool-finish timestamp and the new cross-request TTFT-after-tool metric never records. Ensure the generated session is touched/created before marking the tool finish.
Useful? React with 👍 / 👎.
| const translateHasContent = | ||
| typeof parsed.delta?.text === "string" || | ||
| typeof parsed.choices?.[0]?.delta?.content === "string" || | ||
| typeof parsed.choices?.[0]?.delta?.reasoning_content === "string"; |
There was a problem hiding this comment.
Ignore empty translated deltas for tool TTFT
When a translated stream emits an empty/role-only delta after a tool result, this predicate treats it as the first content token because it only checks typeof ... === "string". That records TTFT/gap immediately and sets contentAfterToolSeen, so the real first non-empty text delta is ignored and the dashboard reports artificially low tool latency for providers that send empty SSE prelude chunks. Require a non-empty string before recording the metric.
Useful? React with 👍 / 👎.
| /** Larger limit for file uploads: 500 MB */ | ||
| export const MAX_BODY_BYTES_FILE = 500 * 1024 * 1024; |
There was a problem hiding this comment.
Match the file upload guard to the route limit
The /api/v1/files handler accepts files up to 512 * 1024 * 1024 bytes, but this new body-size guard rejects requests above 500 * 1024 * 1024 bytes before the handler runs. Uploads between 500 MiB and 512 MiB now get a 413 even though the endpoint’s own validation and proxy config allow them, so align this limit with the file route cap.
Useful? React with 👍 / 👎.
…models (#3181) Empty refresh must not resurface just-cleared synced models (fixes the release-blocking provider-models-route test). Integrated into release/v3.8.10.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee791000a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| import { getProviderCallStats, getModelCallStats } from "@/lib/db/providerStats"; | ||
| import { AI_PROVIDERS } from "@/shared/constants/providers"; | ||
|
|
||
| export async function GET() { |
There was a problem hiding this comment.
Require management auth before returning provider stats
When the instance is reachable on a network, this new dashboard API can be called without any dashboard/API-key management check before it reads call_logs aggregates and in-memory combo metrics. That also bypasses the existing protected /api/combos/metrics route for the same combo data, so provider/model usage and latency stats are exposed to unauthenticated callers; gate this handler with the management auth guard before collecting stats.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3d3590482
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pdf: outMods.has("pdf"), | ||
| }, | ||
| interleaved: false, | ||
| interleaved: Boolean(caps.thinking), |
There was a problem hiding this comment.
Don't advertise thinking-only models as interleaved
For any /v1/models entry where OmniRoute sets capabilities.thinking from generic reasoning support, this now reports capabilities.interleaved: true to OpenCode even though interleaved reasoning is a separate capability in the rest of the repo (interleaved_field/interleavedField, not thinking). With thinking-only models such as DeepSeek/MiniMax-style reasoning models, OpenCode can select an interleaved reasoning/tool flow that the upstream model/router path does not support, causing follow-up tool turns to be formatted incorrectly; keep this false unless the raw model carries an explicit interleaved signal.
Useful? React with 👍 / 👎.
|
* chore(release): open v3.8.10 development cycle Bump 3.8.9 → 3.8.10 across package.json, lockfile, electron, open-sse, and docs/reference/openapi.yaml; add the [3.8.10] CHANGELOG section (root + 41 i18n mirrors) as the integration target for the cycle. Entries land here as work merges into release/v3.8.10; finalized by the release flow. * fix(providers): resolve web provider alias collisions Assign unique aliases to HuggingChat, Kimi Web, and Qwen Web so they no longer shadow primary providers or trigger startup warnings. Add a unit test to enforce provider alias uniqueness and prevent future collisions. Also expand local ignore and VS Code exclude rules for agent, build, and worktree artifacts. * fix(responses): normalize image_url parts across input paths (diegosouzapw#3150) Normalize image_url parts across all Responses input paths. Integrated into release/v3.8.10. * fix(api-manager): preserve API key expiration local time (diegosouzapw#3146) Preserve API key expiration local time + clear button. Integrated into release/v3.8.10. * Strip previous_response_id for stateless Responses upstreams (diegosouzapw#3143) Strip previous_response_id for stateless Responses upstreams (auto/strip/preserve). Integrated into release/v3.8.10. * fix(opencode-plugin): map thinking cap to interleaved in model+combo (diegosouzapw#3138) Map caps.thinking to ModelV2.capabilities.interleaved for opencode-plugin. Integrated into release/v3.8.10. * fix(providers): use synced models as fallback for all providers (diegosouzapw#3148) Use synced models as authoritative local catalog for all providers (+regression test). Integrated into release/v3.8.10. * fix(qoder): bifurcate validation by token type — PAT→Cosy, regular API key→dashscope (diegosouzapw#3149) Bifurcate Qoder validation by token type (PAT→Cosy, regular→dashscope) +regression test. Integrated into release/v3.8.10. * fix(antigravity): dynamic model resolution via MITM alias table (diegosouzapw#3144) Dynamic antigravity MITM model resolution in the executor (+bug fix +regression test; DB import dropped from client-reachable config). Integrated into release/v3.8.10. * Feature/batch allow big (diegosouzapw#3128) Podman deployment options + larger upload body-size limits (+CONTAINER_HOST docs). Integrated into release/v3.8.10. * fix(fireworks): preserve fully-qualified router/model IDs (diegosouzapw#3133) (diegosouzapw#3160) Fireworks router IDs (accounts/fireworks/routers/...) were double-prefixed with accounts/fireworks/models/ → upstream 404. Add optional acceptedModelIdPrefixes to the registry entry and skip the prepend when the model already starts with an accepted prefix. Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> * fix(llama-cpp): route to configured local baseUrl instead of OpenAI (diegosouzapw#3136) (diegosouzapw#3161) llama-cpp was missing from the local-provider group in buildUrl(), so it fell through to the OpenAI baseUrl and returned an OpenAI 401. Add the case to resolve the connection's providerSpecificData.baseUrl. Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> * fix(t3-chat-web): parse cookies + convexSessionId from stored credential (diegosouzapw#3007) (diegosouzapw#3162) The executor read credentials.cookies/convexSessionId, but the pipeline only stores the pasted string under apiKey → t3.chat always 400'd. Parse both values from apiKey (fallback accessToken), mirroring validation.ts. Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> * fix(minimax): stop capping MiniMax-M3 / M2.7 max_tokens at 8192 (diegosouzapw#3141) (diegosouzapw#3163) MiniMax-M3 had no MODEL_SPECS entry and capitalized MiniMax-M2.7 missed its lowercase spec (case-sensitive lookup) → both fell to the 8192 default cap. Add the M3 spec (512K output), alias the capitalized ids, and make getModelSpec lookups case-insensitive. Co-authored-by: totaltube <totaltube@users.noreply.github.com> * fix(github-copilot): discover model catalog live from api.githubcopilot.com (diegosouzapw#3120, diegosouzapw#3121) (diegosouzapw#3164) The github (Copilot) provider had a static hardcoded catalog with no discovery source, so Import Models never refreshed (diegosouzapw#3120) and advertised non-entitled models that 400 on use (diegosouzapw#3121). Add a live /models fetch with fallback to the static list. Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> * fix(combo): invalidate nested-combo cache on edits + log DATA_DIR (diegosouzapw#3147) (diegosouzapw#3165) Editing a combo did not invalidate the 10s nested-combo expansion caches (chat.ts getCombosCachedForChat + chatCore.ts getCombosCached; the exported clearCombosCache was dead code), so a removed nested target/model could be served as a phantom for up to 10s. Wire a shared monotonic combos-cache version in readCache (bumped by invalidateDbCache("combos") on every combo write); both cache layers treat a version mismatch as a miss. Also log the resolved DATA_DIR/SQLITE_FILE absolute path at DB init so the reporter's 'persists across restart + volume wipe' symptom (a multi-replica Docker volume/DATA_DIR mismatch, not a routing bug) is diagnosable from logs. Includes consolidated CHANGELOG entries for diegosouzapw#3133/diegosouzapw#3136/diegosouzapw#3007/diegosouzapw#3141/diegosouzapw#3120/diegosouzapw#3121. Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> * fix(web-tools): parse bare JSON tool calls (diegosouzapw#3157) Parse bare JSON tool calls for deepseek-web (diegosouzapw#2820) + fuzzy tool-name matching. Integrated into release/v3.8.10. * fix(misc): minor fixes across reasoning cache, account fallback, binary manager (diegosouzapw#3177) Misc: ProviderProfile export, DeepSeek reasoning regex, binary guard. Integrated into release/v3.8.10. * fix(kiro): minor OAuth social exchange tweaks (diegosouzapw#3176) Kiro social OAuth: optional targetProvider passthrough. Integrated into release/v3.8.10. * deps: bump hono from 4.12.18 to 4.12.23 (diegosouzapw#3179) Bump hono to 4.12.23. Integrated into release/v3.8.10. * fix(providerRegistry): update kilocode format and executor (diegosouzapw#3166) kilocode: openai format + default executor (matches kilo-gateway) + registry test. Integrated into release/v3.8.10. * feat(metrics): cross-request TTFT and gap latency after tool calls (diegosouzapw#3173) Cross-request TTFT + gap-after-tool latency metrics (+test). Integrated into release/v3.8.10. * feat(dashboard): provider stats API endpoint and dashboard page (diegosouzapw#3175) Provider stats dashboard + API (SQL moved to db module per Hard Rule diegosouzapw#5, +test). Integrated into release/v3.8.10. * fix(usage): sequential+spaced OAuth quota sync, reactive force-refresh, actionable 401 (diegosouzapw#3156) Sequential+spaced OAuth quota sync, reactive force-refresh on 401, actionable 401 in UI. Integrated into release/v3.8.10. * fix(healthcheck): per-provider proactive-refresh skip list (rescue short-TTL OAuth) (diegosouzapw#3159) Per-provider proactive-refresh skip list (OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) to rescue short-TTL OAuth. Integrated into release/v3.8.10. * feat(quota): show OAuth token expiry on provider cards (small, blue, informative) (diegosouzapw#3178) Show OAuth token expiry on provider cards (small, blue, informative). Integrated into release/v3.8.10. * fix(providers): empty refresh must not resurface just-cleared synced models (diegosouzapw#3181) Empty refresh must not resurface just-cleared synced models (fixes the release-blocking provider-models-route test). Integrated into release/v3.8.10. * chore(release): v3.8.10 — 2026-06-04 (finalize CHANGELOG) --------- Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Xiangzhe <32761048+xz-dev@users.noreply.github.com> Co-authored-by: Jan Leon <Jan.gaschler@gmail.com> Co-authored-by: M.M <mr.maatoug@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> Co-authored-by: totaltube <totaltube@users.noreply.github.com> Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
* chore(release): open v3.8.10 development cycle Bump 3.8.9 → 3.8.10 across package.json, lockfile, electron, open-sse, and docs/reference/openapi.yaml; add the [3.8.10] CHANGELOG section (root + 41 i18n mirrors) as the integration target for the cycle. Entries land here as work merges into release/v3.8.10; finalized by the release flow. * fix(providers): resolve web provider alias collisions Assign unique aliases to HuggingChat, Kimi Web, and Qwen Web so they no longer shadow primary providers or trigger startup warnings. Add a unit test to enforce provider alias uniqueness and prevent future collisions. Also expand local ignore and VS Code exclude rules for agent, build, and worktree artifacts. * fix(responses): normalize image_url parts across input paths (diegosouzapw#3150) Normalize image_url parts across all Responses input paths. Integrated into release/v3.8.10. * fix(api-manager): preserve API key expiration local time (diegosouzapw#3146) Preserve API key expiration local time + clear button. Integrated into release/v3.8.10. * Strip previous_response_id for stateless Responses upstreams (diegosouzapw#3143) Strip previous_response_id for stateless Responses upstreams (auto/strip/preserve). Integrated into release/v3.8.10. * fix(opencode-plugin): map thinking cap to interleaved in model+combo (diegosouzapw#3138) Map caps.thinking to ModelV2.capabilities.interleaved for opencode-plugin. Integrated into release/v3.8.10. * fix(providers): use synced models as fallback for all providers (diegosouzapw#3148) Use synced models as authoritative local catalog for all providers (+regression test). Integrated into release/v3.8.10. * fix(qoder): bifurcate validation by token type — PAT→Cosy, regular API key→dashscope (diegosouzapw#3149) Bifurcate Qoder validation by token type (PAT→Cosy, regular→dashscope) +regression test. Integrated into release/v3.8.10. * fix(antigravity): dynamic model resolution via MITM alias table (diegosouzapw#3144) Dynamic antigravity MITM model resolution in the executor (+bug fix +regression test; DB import dropped from client-reachable config). Integrated into release/v3.8.10. * Feature/batch allow big (diegosouzapw#3128) Podman deployment options + larger upload body-size limits (+CONTAINER_HOST docs). Integrated into release/v3.8.10. * fix(fireworks): preserve fully-qualified router/model IDs (diegosouzapw#3133) (diegosouzapw#3160) Fireworks router IDs (accounts/fireworks/routers/...) were double-prefixed with accounts/fireworks/models/ → upstream 404. Add optional acceptedModelIdPrefixes to the registry entry and skip the prepend when the model already starts with an accepted prefix. Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> * fix(llama-cpp): route to configured local baseUrl instead of OpenAI (diegosouzapw#3136) (diegosouzapw#3161) llama-cpp was missing from the local-provider group in buildUrl(), so it fell through to the OpenAI baseUrl and returned an OpenAI 401. Add the case to resolve the connection's providerSpecificData.baseUrl. Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> * fix(t3-chat-web): parse cookies + convexSessionId from stored credential (diegosouzapw#3007) (diegosouzapw#3162) The executor read credentials.cookies/convexSessionId, but the pipeline only stores the pasted string under apiKey → t3.chat always 400'd. Parse both values from apiKey (fallback accessToken), mirroring validation.ts. Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> * fix(minimax): stop capping MiniMax-M3 / M2.7 max_tokens at 8192 (diegosouzapw#3141) (diegosouzapw#3163) MiniMax-M3 had no MODEL_SPECS entry and capitalized MiniMax-M2.7 missed its lowercase spec (case-sensitive lookup) → both fell to the 8192 default cap. Add the M3 spec (512K output), alias the capitalized ids, and make getModelSpec lookups case-insensitive. Co-authored-by: totaltube <totaltube@users.noreply.github.com> * fix(github-copilot): discover model catalog live from api.githubcopilot.com (diegosouzapw#3120, diegosouzapw#3121) (diegosouzapw#3164) The github (Copilot) provider had a static hardcoded catalog with no discovery source, so Import Models never refreshed (diegosouzapw#3120) and advertised non-entitled models that 400 on use (diegosouzapw#3121). Add a live /models fetch with fallback to the static list. Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> * fix(combo): invalidate nested-combo cache on edits + log DATA_DIR (diegosouzapw#3147) (diegosouzapw#3165) Editing a combo did not invalidate the 10s nested-combo expansion caches (chat.ts getCombosCachedForChat + chatCore.ts getCombosCached; the exported clearCombosCache was dead code), so a removed nested target/model could be served as a phantom for up to 10s. Wire a shared monotonic combos-cache version in readCache (bumped by invalidateDbCache("combos") on every combo write); both cache layers treat a version mismatch as a miss. Also log the resolved DATA_DIR/SQLITE_FILE absolute path at DB init so the reporter's 'persists across restart + volume wipe' symptom (a multi-replica Docker volume/DATA_DIR mismatch, not a routing bug) is diagnosable from logs. Includes consolidated CHANGELOG entries for diegosouzapw#3133/diegosouzapw#3136/diegosouzapw#3007/diegosouzapw#3141/diegosouzapw#3120/diegosouzapw#3121. Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> * fix(web-tools): parse bare JSON tool calls (diegosouzapw#3157) Parse bare JSON tool calls for deepseek-web (diegosouzapw#2820) + fuzzy tool-name matching. Integrated into release/v3.8.10. * fix(misc): minor fixes across reasoning cache, account fallback, binary manager (diegosouzapw#3177) Misc: ProviderProfile export, DeepSeek reasoning regex, binary guard. Integrated into release/v3.8.10. * fix(kiro): minor OAuth social exchange tweaks (diegosouzapw#3176) Kiro social OAuth: optional targetProvider passthrough. Integrated into release/v3.8.10. * deps: bump hono from 4.12.18 to 4.12.23 (diegosouzapw#3179) Bump hono to 4.12.23. Integrated into release/v3.8.10. * fix(providerRegistry): update kilocode format and executor (diegosouzapw#3166) kilocode: openai format + default executor (matches kilo-gateway) + registry test. Integrated into release/v3.8.10. * feat(metrics): cross-request TTFT and gap latency after tool calls (diegosouzapw#3173) Cross-request TTFT + gap-after-tool latency metrics (+test). Integrated into release/v3.8.10. * feat(dashboard): provider stats API endpoint and dashboard page (diegosouzapw#3175) Provider stats dashboard + API (SQL moved to db module per Hard Rule diegosouzapw#5, +test). Integrated into release/v3.8.10. * fix(usage): sequential+spaced OAuth quota sync, reactive force-refresh, actionable 401 (diegosouzapw#3156) Sequential+spaced OAuth quota sync, reactive force-refresh on 401, actionable 401 in UI. Integrated into release/v3.8.10. * fix(healthcheck): per-provider proactive-refresh skip list (rescue short-TTL OAuth) (diegosouzapw#3159) Per-provider proactive-refresh skip list (OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) to rescue short-TTL OAuth. Integrated into release/v3.8.10. * feat(quota): show OAuth token expiry on provider cards (small, blue, informative) (diegosouzapw#3178) Show OAuth token expiry on provider cards (small, blue, informative). Integrated into release/v3.8.10. * fix(providers): empty refresh must not resurface just-cleared synced models (diegosouzapw#3181) Empty refresh must not resurface just-cleared synced models (fixes the release-blocking provider-models-route test). Integrated into release/v3.8.10. * chore(release): v3.8.10 — 2026-06-04 (finalize CHANGELOG) --------- Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Xiangzhe <32761048+xz-dev@users.noreply.github.com> Co-authored-by: Jan Leon <Jan.gaschler@gmail.com> Co-authored-by: M.M <mr.maatoug@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> Co-authored-by: totaltube <totaltube@users.noreply.github.com> Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
* chore(release): open v3.8.10 development cycle Bump 3.8.9 → 3.8.10 across package.json, lockfile, electron, open-sse, and docs/reference/openapi.yaml; add the [3.8.10] CHANGELOG section (root + 41 i18n mirrors) as the integration target for the cycle. Entries land here as work merges into release/v3.8.10; finalized by the release flow. * fix(providers): resolve web provider alias collisions Assign unique aliases to HuggingChat, Kimi Web, and Qwen Web so they no longer shadow primary providers or trigger startup warnings. Add a unit test to enforce provider alias uniqueness and prevent future collisions. Also expand local ignore and VS Code exclude rules for agent, build, and worktree artifacts. * fix(responses): normalize image_url parts across input paths (diegosouzapw#3150) Normalize image_url parts across all Responses input paths. Integrated into release/v3.8.10. * fix(api-manager): preserve API key expiration local time (diegosouzapw#3146) Preserve API key expiration local time + clear button. Integrated into release/v3.8.10. * Strip previous_response_id for stateless Responses upstreams (diegosouzapw#3143) Strip previous_response_id for stateless Responses upstreams (auto/strip/preserve). Integrated into release/v3.8.10. * fix(opencode-plugin): map thinking cap to interleaved in model+combo (diegosouzapw#3138) Map caps.thinking to ModelV2.capabilities.interleaved for opencode-plugin. Integrated into release/v3.8.10. * fix(providers): use synced models as fallback for all providers (diegosouzapw#3148) Use synced models as authoritative local catalog for all providers (+regression test). Integrated into release/v3.8.10. * fix(qoder): bifurcate validation by token type — PAT→Cosy, regular API key→dashscope (diegosouzapw#3149) Bifurcate Qoder validation by token type (PAT→Cosy, regular→dashscope) +regression test. Integrated into release/v3.8.10. * fix(antigravity): dynamic model resolution via MITM alias table (diegosouzapw#3144) Dynamic antigravity MITM model resolution in the executor (+bug fix +regression test; DB import dropped from client-reachable config). Integrated into release/v3.8.10. * Feature/batch allow big (diegosouzapw#3128) Podman deployment options + larger upload body-size limits (+CONTAINER_HOST docs). Integrated into release/v3.8.10. * fix(fireworks): preserve fully-qualified router/model IDs (diegosouzapw#3133) (diegosouzapw#3160) Fireworks router IDs (accounts/fireworks/routers/...) were double-prefixed with accounts/fireworks/models/ → upstream 404. Add optional acceptedModelIdPrefixes to the registry entry and skip the prepend when the model already starts with an accepted prefix. Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> * fix(llama-cpp): route to configured local baseUrl instead of OpenAI (diegosouzapw#3136) (diegosouzapw#3161) llama-cpp was missing from the local-provider group in buildUrl(), so it fell through to the OpenAI baseUrl and returned an OpenAI 401. Add the case to resolve the connection's providerSpecificData.baseUrl. Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> * fix(t3-chat-web): parse cookies + convexSessionId from stored credential (diegosouzapw#3007) (diegosouzapw#3162) The executor read credentials.cookies/convexSessionId, but the pipeline only stores the pasted string under apiKey → t3.chat always 400'd. Parse both values from apiKey (fallback accessToken), mirroring validation.ts. Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> * fix(minimax): stop capping MiniMax-M3 / M2.7 max_tokens at 8192 (diegosouzapw#3141) (diegosouzapw#3163) MiniMax-M3 had no MODEL_SPECS entry and capitalized MiniMax-M2.7 missed its lowercase spec (case-sensitive lookup) → both fell to the 8192 default cap. Add the M3 spec (512K output), alias the capitalized ids, and make getModelSpec lookups case-insensitive. Co-authored-by: totaltube <totaltube@users.noreply.github.com> * fix(github-copilot): discover model catalog live from api.githubcopilot.com (diegosouzapw#3120, diegosouzapw#3121) (diegosouzapw#3164) The github (Copilot) provider had a static hardcoded catalog with no discovery source, so Import Models never refreshed (diegosouzapw#3120) and advertised non-entitled models that 400 on use (diegosouzapw#3121). Add a live /models fetch with fallback to the static list. Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> * fix(combo): invalidate nested-combo cache on edits + log DATA_DIR (diegosouzapw#3147) (diegosouzapw#3165) Editing a combo did not invalidate the 10s nested-combo expansion caches (chat.ts getCombosCachedForChat + chatCore.ts getCombosCached; the exported clearCombosCache was dead code), so a removed nested target/model could be served as a phantom for up to 10s. Wire a shared monotonic combos-cache version in readCache (bumped by invalidateDbCache("combos") on every combo write); both cache layers treat a version mismatch as a miss. Also log the resolved DATA_DIR/SQLITE_FILE absolute path at DB init so the reporter's 'persists across restart + volume wipe' symptom (a multi-replica Docker volume/DATA_DIR mismatch, not a routing bug) is diagnosable from logs. Includes consolidated CHANGELOG entries for diegosouzapw#3133/diegosouzapw#3136/diegosouzapw#3007/diegosouzapw#3141/diegosouzapw#3120/diegosouzapw#3121. Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> * fix(web-tools): parse bare JSON tool calls (diegosouzapw#3157) Parse bare JSON tool calls for deepseek-web (diegosouzapw#2820) + fuzzy tool-name matching. Integrated into release/v3.8.10. * fix(misc): minor fixes across reasoning cache, account fallback, binary manager (diegosouzapw#3177) Misc: ProviderProfile export, DeepSeek reasoning regex, binary guard. Integrated into release/v3.8.10. * fix(kiro): minor OAuth social exchange tweaks (diegosouzapw#3176) Kiro social OAuth: optional targetProvider passthrough. Integrated into release/v3.8.10. * deps: bump hono from 4.12.18 to 4.12.23 (diegosouzapw#3179) Bump hono to 4.12.23. Integrated into release/v3.8.10. * fix(providerRegistry): update kilocode format and executor (diegosouzapw#3166) kilocode: openai format + default executor (matches kilo-gateway) + registry test. Integrated into release/v3.8.10. * feat(metrics): cross-request TTFT and gap latency after tool calls (diegosouzapw#3173) Cross-request TTFT + gap-after-tool latency metrics (+test). Integrated into release/v3.8.10. * feat(dashboard): provider stats API endpoint and dashboard page (diegosouzapw#3175) Provider stats dashboard + API (SQL moved to db module per Hard Rule diegosouzapw#5, +test). Integrated into release/v3.8.10. * fix(usage): sequential+spaced OAuth quota sync, reactive force-refresh, actionable 401 (diegosouzapw#3156) Sequential+spaced OAuth quota sync, reactive force-refresh on 401, actionable 401 in UI. Integrated into release/v3.8.10. * fix(healthcheck): per-provider proactive-refresh skip list (rescue short-TTL OAuth) (diegosouzapw#3159) Per-provider proactive-refresh skip list (OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) to rescue short-TTL OAuth. Integrated into release/v3.8.10. * feat(quota): show OAuth token expiry on provider cards (small, blue, informative) (diegosouzapw#3178) Show OAuth token expiry on provider cards (small, blue, informative). Integrated into release/v3.8.10. * fix(providers): empty refresh must not resurface just-cleared synced models (diegosouzapw#3181) Empty refresh must not resurface just-cleared synced models (fixes the release-blocking provider-models-route test). Integrated into release/v3.8.10. * chore(release): v3.8.10 — 2026-06-04 (finalize CHANGELOG) --------- Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Xiangzhe <32761048+xz-dev@users.noreply.github.com> Co-authored-by: Jan Leon <Jan.gaschler@gmail.com> Co-authored-by: M.M <mr.maatoug@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com> Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com> Co-authored-by: totaltube <totaltube@users.noreply.github.com> Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com> Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nicolas Lorin <androw95220@gmail.com>




[3.8.10] — 2026-06-04
OAuth resilience & observability release: spaced/sequential quota sync for OAuth accounts, a per-provider proactive-refresh skip list to keep short-TTL providers (Kimi) alive without re-exposing the Codex Auth0 cascade, token-expiry visibility on the provider cards, a new provider-stats dashboard, plus a wide batch of provider fixes (DeepSeek-web tool calls, Antigravity, Qoder, MiniMax, GitHub Copilot, Fireworks, llama.cpp, t3.chat-web, Kiro, Kilocode) and Podman deployment support.
✨ New Features
/api/provider-statsendpoint — per-provider and per-model aggregates fromcall_logsplus live combo/telemetry/tool-latency overlays. (feat(dashboard): provider stats API endpoint and dashboard page #3175 — thanks @pizzav-xyz / @diegosouzapw)previous_response_idfor stateless Responses upstreams, with an auto/strip/preserve setting + UI so stateless clients (e.g. VS Code Custom Endpoint) keep context. (Strip previous_response_id for stateless Responses upstreams #3143 — thanks @JxnLexn)CONTAINER_HOSThint) and larger upload body-size limits for/v1/files. (Feature/batch allow big #3128 — thanks @hartmark)🔧 Bug Fixes
PROVIDER_LIMITS_SYNC_SPACING_MS) so a host no longer bursts simultaneous usage/refresh requests; reactive forced re-mint after a 401 on the per-card refresh (recovers imported accounts); a genuine 401 now surfaces a re-authenticate hint. (fix(usage): sequential+spaced OAuth quota sync, reactive force-refresh, actionable 401 #3156 — thanks @diegosouzapw)OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) — keep rotating-cascade providers (Codex/OpenAI) reactive-only while short-TTL providers (Kimi-coding) keep refreshing proactively. (fix(healthcheck): per-provider proactive-refresh skip list (rescue short-TTL OAuth like Kimi) #3159 — thanks @diegosouzapw)?refresh=truewith no remote models, don't resurface the just-cleared synced cache into the local-catalog fallback. (fix(providers): empty refresh must not resurface just-cleared synced models #3181 — thanks @diegosouzapw)image_urlparts across every Responses input path (message content, replayed output items,function_call_output) to avoid upstream 400s. (fix(responses): normalize image_url parts across input paths #3150 — thanks @wilsonicdev)pt-) → Cosy, regular API key → dashscope — matching the executor's routing. (fix(qoder): bifurcate validation by token type — PAT→Cosy, regular API key→dashscope #3149 — thanks @herjarsa)datetime-localinput no longer silently shifts to UTC) + a clear button. (fix(api-manager): preserve API key expiration local time #3146 — thanks @xz-dev)caps.thinking → ModelV2.capabilities.interleavedfor single models and combos. (fix(opencode-plugin): map caps.thinking → ModelV2.capabilities.interleaved #3138 — thanks @mrmm)targetProvideron the social-OAuth exchange so Kiro-based providers can reuse the social login flow. (fix(kiro): minor social OAuth tweaks #3176 — thanks @pizzav-xyz)-free/zen/deepseek-v4), exportProviderProfile, and guard a non-string directory entry in the binary manager. (fix(misc): DeepSeek regex, ProviderProfile export, binary guard #3177 — thanks @pizzav-xyz)kilo-gateway). (fix(providerRegistry): update kilocode format and executor #3166 — thanks @androw)accounts/fireworks/routers/...) are no longer double-prefixed into an upstream 404. (Fireworks router model IDs are corrupted by hardcoded accounts/fireworks/models/ prefix #3133 — thanks @KooshaPari)max_tokensat the 8192 default — add the M3 model spec (512K output) and make model-spec lookups case-insensitive. ([BUG] Omniroute set's max_tokens = 8192 for minimax/MiniMax-M3 #3141 — thanks @totaltube)api.githubcopilot.com/modelsso Import Models refreshes and only entitled models are listed (with fallback to the static catalog). ([BUG] GitHub Copilot Import Models does not refresh latest model list #3120, [BUG] GitHub Copilot lists models that fail when tested #3121 — thanks @gabrielmoreira)📝 Maintenance
Quality Gate
no-explicit-anywarnings only)Coverage of commits since v3.8.9
v3.8.9..HEAD— 27 non-merge commits, all attributed in the CHANGELOG above (28 bullets).Contributors this release
@KooshaPari · @tjengbudi · @minhtran162 · @totaltube · @gabrielmoreira · @ViFigueiredo · @herjarsa · @pizzav-xyz · @wilsonicdev · @JxnLexn · @xz-dev · @mrmm · @hartmark · @androw · @dependabot · @diegosouzapw