mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
main
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
66c56ece9e |
Add cliproxy provider exposure controls and manifest injection (#7329)
* feat(fusion): let judge use its own knowledge and override the panel (#6804) The judge prompt said to write an answer 'grounded in that analysis', implicitly capping output at the panel's union. When all panel members miss or are collectively wrong on something, the judge should apply its own reasoning as a full participant and override consensus, while keeping an honesty guard against fabrication. Adds a regression test. Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com> * fix(api): raise provider apiKey cap for cookie-based web providers (#6715) (#6759) * fix(cli): fall back to settings.json when Claude Code binary is unresolvable (#6701) (#6734) getCliRuntimeStatus() only ever answered `installed` from binary resolution (known install paths + where/which PATH search), so a stale PATH, moved binary, or uncatalogued install method reported "not found" even when ~/.claude/settings.json proved the CLI was installed and used before — regressing behind upstream 9router's checkClaudeInstalled(), which already falls back to the settings file when where/which fails. withSettingsFallback() (new src/shared/services/cliInstallFallback.ts, kept out of the frozen cliRuntime.ts to respect its file-size ceiling) restores that parity: only when the binary lookup's own reason is "not_found" (never for deliberate security rejections like unsafe/relative env overrides or symlink escapes) and the tool's settings file exists on disk. * fix(providers): honor explicit thinking.budget_tokens 0 in openai->gemini transform (#6813) (#6821) The transform forwarded the Claude-style thinking.budget_tokens into generationConfig.thinkingConfig.thinkingBudget, but the presence check was truthy (&& thinking.budget_tokens). An explicit budget_tokens: 0 — the natural way to disable thinking — is falsy, so it was dropped and the request fell through to the default thinkingConfig injection, making the model think despite an explicit request for zero. Use an explicit numeric check so 0 is honored as thinkingBudget 0; includeThoughts is only set for a non-zero budget. * fix(compression): reconcile outer vs per-engine token counts (#6488) (#6741) * fix(compression): reconcile outer vs per-engine token counts on degenerate output (#6488) Outer originalTokens/compressedTokens (real tiktoken counter over extracted message text) diverged from engineBreakdown[0]'s counts (a crude JSON.stringify(requestBody).length/4 estimate), worst on small/degenerate inputs where JSON structural overhead dominates. A single-engine breakdown entry represents the exact same before/after transformation as the overall response, so reconcileSingleEngineTokens() now overwrites that one entry's counts with the outer, more accurate figures; multi-step pipeline breakdowns are left untouched. * chore(6741): resolve release sync — CHANGELOG.md restored to release tip, entry moved to changelog.d fragment (fragments-first) * fix(api): accept enableRenderers in RTK compression config schema (#6703) (#6757) * fix(db): break probe-failed/restore loop on large storage.sqlite (#6632) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's changes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * feat(cursor): add Opus 4.8, Fable 5, and Sonnet 5 model families (#6779) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's cursor registry + test changes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(translator): read PDF/video file attachments for Gemini/Antigravity and Claude (#6790) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's translator + test changes. Co-authored-by: Wital <witalorocha216@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(codex): strip include from compact responses requests (#6805) * fix(codex): strip include from compact responses requests Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's changes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(6805): move include-strip assertion to standalone test file to keep executor-codex.test.ts under frozen size cap Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(i18n): translate hardcoded Portuguese dashboard strings to English (#6769) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's changes. Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(bootstrap): filter empty process.env values to prevent Docker env crash loop (#6828) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR) and the direct CHANGELOG.md edit (fragments-first); keeps only the author's bootstrap change. Co-authored-by: Andrian B. <andrewbalanesq@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(providers): update SenseNova Token Plan support (#6330) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); the author's constants/registry/snapshot deltas were re-applied cleanly onto the release tip. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(providers): classify 404 as MODEL_NOT_FOUND to stop retry storm (#6829) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR) and the direct CHANGELOG.md edit (fragments-first); the author's chatCore/errorClassifier deltas were re-applied cleanly onto the release tip. Co-authored-by: Andrian B. <andrewbalanesq@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(api): accept all catalog engines on compression PUT schema (#6792) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR). Resolved the release's OmniGlyph engine addition additively (types.ts/compression.ts kept both 'relevance' and 'omniglyph') and extended stackedPipelineStepSchema + STACKED_PIPELINE_ENGINE_INTENSITIES with the omniglyph branch so the ENGINE_CATALOG-parity test passes. Co-authored-by: Pitchfork-and-Torch <Pitchfork-and-Torch@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(api): point CLI health command at /api/monitoring/health (#6677) (#6717) * fix(api): point CLI health command at /api/monitoring/health (#6677) bin/cli/commands/health.mjs called GET /api/health, a route that was moved to /api/monitoring/health without updating the CLI; the top-level /api/health handler never existed on disk (only degradation/ and ping/ sub-routes). Point runHealthCommand()/runHealthComponentsCommand() at /api/monitoring/health and read its real payload shape (activeConnections, circuitBreakers: {open,halfOpen,closed}, memoryUsage) instead of the old nonexistent requests/breakers/cache/memory fields. * chore(6717): re-sync onto release tip; move CHANGELOG entry to changelog.d fragment (fragments-first) * chore(cursor): add Grok 4.5 effort/fast model IDs (#6774) Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's changes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(providers): ensure DeepSeek Web SSE emits [DONE] after FINISHED (#6791) * fix(providers): ensure DeepSeek Web SSE emits [DONE] after FINISHED Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); keeps only the author's changes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(deepseek): extract done-terminator helper to keep frozen file under cap Extracts the FINISHED-drain scheduler and finish-once guard added for the [DONE] terminator fix (#6777) into a new deepseek-web-done-terminator.ts module, so deepseek-web.ts stays under its frozen line cap (1148). Behavior is unchanged. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Pitchfork-and-Torch <Pitchfork-and-Torch@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * feat(models): add capability override UI (#6727) * feat(models): add capability override UI Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); renumbered the migration 118 -> 119 to resolve the collision with 118_provider_param_filters.sql already on release/v3.8.47; the author's i18n/localDb deltas were re-applied cleanly onto the release tip. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(6727): import model-capability-overrides DB fns directly (not via localDb barrel) to keep localDb under file-size cap; aligns with anti-barrel convention * chore(db): satisfy known-symbols contract for modelCapabilityOverrides Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> * fix(cursor): use Agent CLI build id for x-cursor-client-version (#6795) * fix(cursor): use Agent CLI build id for x-cursor-client-version Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); the author's .env.example/docs deltas were re-applied cleanly onto the release tip. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(changelog): re-sync CHANGELOG.md to release tip (restore #6701 bullet) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(startup): rename reasoningControls.ts to avoid webpack casing collision (#6584) (#6718) * fix(startup): rename reasoningControls.ts to avoid webpack casing collision (#6584) * chore(6718): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(build): suppress Turbopack over-bundling warning from agentSkills generator (#6582) (#6720) * fix(build): suppress Turbopack over-bundling warning from agentSkills generator (#6582) generator.ts builds outputBase from a non-literal outputDir parameter, so Turbopack's file-tracing analyzer can't narrow it and emits an "Overly broad patterns" warning per entry point that imports the module (603 warnings on v3.8.46, up from 379). The fs access is legitimate and bounded, so next.config.mjs now suppresses this specific diagnostic via turbopack.ignoreIssue, mirroring the existing webpack.ignoreWarnings precedent in the same file. * chore(6720): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(providers): drop image_generation for Codex Spark models regardless of plan (#6651) (#6721) * fix(providers): drop image_generation for Codex Spark models regardless of plan (#6651) * chore(6721): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(providers): stop quota card re-sorting Codex/GLM bars by remaining % (#6687) (#6722) * fix(providers): stop quota card re-sorting Codex/GLM bars by remaining % (#6687) QuotaCardExpanded.tsx unconditionally re-sorted quotas by remaining percentage via sortQuotasByRemaining(), discarding the deterministic CODEX_QUOTA_ORDER/GLM_QUOTA_ORDER window order quotaParsing.ts's sortCodexOrder()/sortGlmOrder() had already established. A new hasFixedQuotaOrder() + resolveQuotaDisplayOrder() skip the re-sort for providers with a fixed window order (codex, glm family), threading providerId from QuotaCard.tsx through to the display layer. Regression guard: tests/unit/quota-card-expanded-fixed-order-6687.test.ts * chore(6722): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(startup): lazy-import ioredis in rateLimiter to fix MCP ERR_MODULE_NOT_FOUND (#6559) (#6725) * fix(startup): lazy-import ioredis in rateLimiter to fix MCP ERR_MODULE_NOT_FOUND (#6559) * chore(6725): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(resilience): resolve fp-pinned combo account back to real connection id (#6696) (#6732) * fix(resilience): resolve fp-pinned combo account back to real connection id (#6696) * chore(6732): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(api): Responses passthrough emits event-only SSE frames after filtering commentary output (#6561) (#6735) * fix(api): Responses passthrough emits event-only SSE frames after filtering commentary output (#6561) The #6199 commentary-drop `continue;` branches in stream.ts skipped the data: line for a dropped commentary event but never cleared the already-buffered event: line for the same frame, so the next blank line flushed the stale event: line alone -- an event-only SSE frame that crashes the OpenAI Python SDK's json.loads(). Both drop sites now call clearPendingPassthroughEvent() before continue. The commentary-drop decision was extracted into a new responsesCommentaryDrop.ts module so the fix does not grow the frozen stream.ts. * chore(6735): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(api): emit reasoning_content on claude-web + v0-vercel-web SSE (#6662) (#6743) * fix(api): emit reasoning_content on claude-web + v0-vercel-web /v1/chat/completions SSE (#6662) * chore(6743): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(sse): unwrap bare {function:{…}} tools in openai→claude translation (#6704) * fix(sse): unwrap bare {function:{…}} tools in openai→claude translation Some OpenAI-shape clients send a tool as a bare `{ function: {...} }` object, omitting the spec-required `type: "function"` parent wrapper. The tools-mapping in openai-to-claude.ts (~line 366) only unwrapped `tool.function` when `tool.type === "function"` was ALSO true, so a bare-function tool fell through to `toolData = tool` (the wrapper itself, with no `.name`), producing an empty `originalName` and silently dropping the tool from the translated request — worse than a 400, since the caller has no signal the tool never made it upstream. Unwrap `tool.function` whenever present, independent of the parent `type` field. Regression guard: tests/unit/openai-to-claude-bare-tool.test.ts. Co-authored-by: Samir Abis <me@samirabis.com> Inspired-by: https://github.com/decolua/9router/pull/2473 * chore(6704): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: Samir Abis <me@samirabis.com> * fix(oauth): avoid bare-email dedup of Codex OAuth logins (#6706) * fix(oauth): avoid bare-email dedup of Codex OAuth logins When an incoming Codex OAuth connection has no verifiable workspace/account id, do not merge it into an existing row on email match alone — that silently overwrote the other account's token pair. Require a matching chatgptUserId (a stable per-account JWT id) before merging; otherwise insert a distinct connection row. Co-authored-by: lucasjustinudin <34107354+lucasjustinudin@users.noreply.github.com> Inspired-by: https://github.com/decolua/9router/pull/2477 * chore(6706): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: lucasjustinudin <34107354+lucasjustinudin@users.noreply.github.com> * fix(sse): skip thinkingConfig for gemma models in openai→gemini translation (#6708) open-sse/translator/request/claude-to-gemini.ts already guards against sending thinkingConfig for gemma-4-* models (Gemma doesn't support it — Vertex returns 400: "Thinking budget is not supported for this model"), but the OpenAI-shape path (openai-to-gemini.ts) lacked the same guard, so OpenAI-shape clients hitting a vertex gemma-4-* model still got a 400. Mirrors the existing claude-to-gemini.ts guard: wrap the reasoning_effort and Claude-shape thinking.budget_tokens branches with a model.startsWith ("gemma-4") check. Branch 3 (default includeThoughts for modern Gemini models) already excludes non-"gemini" model ids and needed no change. Inspired-by: https://github.com/decolua/9router/pull/2480 Co-authored-by: chy1211 <31048289+chy1211@users.noreply.github.com> * fix(codex): surface capacity errors embedded in 200-OK SSE streams (#6710) * fix(codex): surface capacity errors embedded in 200-OK SSE streams Codex sometimes answers with HTTP 200 and a text/event-stream body whose payload carries a transient error mid-stream (e.g. "Selected model is at capacity...", server_is_overloaded, service_unavailable_error). Because the outer HTTP status was 200, this looked like a successful response to every caller — no retry, no circuit breaker, and no combo/account fallback ever engaged, so a healthy account sat idle while the request silently failed or truncated. Add peekCodexSseTransientError() to open-sse/executors/codex.ts: it peeks the first bytes of a text/event-stream Codex response, pattern-matches the known transient-error signatures, and converts a match into a real 503 Response via errorResponse() (Hard Rule #12 — sanitized, never raw upstream text). A 503 is already a recognized provider-failure status in accountFallback.ts, so combo routing and connection cooldown pick it up automatically. When no error signature is found, the peeked prefix is prepended back onto the remaining upstream body so the passthrough stays byte-identical to the unmodified response. Regression guard: tests/unit/codex-sse-capacity-fallback.test.ts — a model-at-capacity payload and a server_is_overloaded/service_unavailable_error payload both convert to 503; a normal single-chunk SSE stream and one split across multiple network chunks both reassemble byte-for-byte unchanged. Inspired-by: https://github.com/decolua/9router/pull/2452 (sub-bug #3 only — OmniRoute already covers PR #2452's other two sub-bugs: service_tier "fast" normalization and reasoning_effort "max" normalization). Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> * chore(6710): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> * fix(volcengine): clamp Kimi max_tokens to Ark endpoint cap (#6712) * fix(volcengine): clamp Kimi max_tokens to Ark endpoint cap VolcEngine Ark's Kimi coding-plan endpoint (ark.cn-beijing.volces.com) enforces max_tokens <= 32768 server-side and returns 400 "integer above maximum value, expected a value <= 32768" for anything over that ceiling. OmniRoute's StripRule only supported dropping params outright, with no numeric clamp mechanism, so a client sending a larger max_tokens (common default, e.g. 65536) 400s outright against volcengine's kimi-k2-5-260127. The 32768 cap is independently confirmed against two live-endpoint bug reports hitting this exact Ark endpoint for both kimi-k2.5 and kimi-k2.7-code (NousResearch/hermes-agent#51773, MoonshotAI/kimi-cli#1124), not just upstream's own value — same cap upstream 9router#2460 uses. StripRule gains two optional fields: `clampToModelMaxOutput` (clamp to the model's own catalog maxOutputTokens ceiling, when set) and `maxOutputCap` (a fixed endpoint-imposed ceiling); when both apply, the lower wins. The new rule is scoped to the literal id `kimi-k2-5-260127` (OmniRoute's real volcengine Kimi model, not upstream's `Kimi-K2.7-Code`), not a broad /kimi/i regex, so it can never clamp an unrelated future Kimi listing whose Ark cap may differ. glm-4-7-251222 (the other volcengine model) is unaffected. Inspired-by: https://github.com/decolua/9router/pull/2460 Co-authored-by: whale9820 <whale9820@users.noreply.github.com> * chore(6712): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: whale9820 <whale9820@users.noreply.github.com> * fix(antigravity): surface aborted Gemini tool calls off end_turn (#6713) * fix(antigravity): surface aborted Gemini tool calls off end_turn Gemini/Antigravity aborts a turn with finishReason MALFORMED_FUNCTION_CALL (or a sibling like UNEXPECTED_TOOL_CALL) instead of completing cleanly. Both Claude-facing translators collapsed these to a clean end_turn, hiding the aborted tool call as a successful completion: - the OpenAI hub path (openai-to-claude.ts convertFinishReason default), and - the DIRECT Gemini->Claude path (gemini-to-claude.ts), which is the one Claude Code actually hits through an antigravity/Gemini-routed model. Add isAbortFinishReason() to finishReason.ts and map these reasons to tool_use on both paths; genuinely unknown reasons still fall back to end_turn. Co-authored-by: anhdiepmmk <n08ni.dieppn@gmail.com> Inspired-by: https://github.com/decolua/9router/pull/2462 * chore(6713): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: anhdiepmmk <n08ni.dieppn@gmail.com> * fix(translator): strip empty cloud_base_branch from Cursor Subagent tool call (#6729) * fix(translator): strip empty cloud_base_branch from Cursor Subagent tool call (port from 9router#2446) The Responses->Chat tool-arg cleanup (stripEmptyOptionalToolArgs) only stripped empty-string/empty-array optional args for Claude Code's Read tool. Cursor's local Subagent tool call therefore passed through with the cloud-only field cloud_base_branch: "", which Cursor rejects ("cloud_base_branch may only be specified when environment equals cloud") before starting the subagent. Extend the cleanup to an allowlist of Read + Subagent; arbitrary tools stay untouched. Reported-by: like3213934360-lab (https://github.com/decolua/9router/issues/2446) * chore(6729): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) * fix(translator): defer content_block_start until GLM streams the tool name (#6730) * fix(translator): defer content_block_start until GLM streams the tool name (port from 9router#2077) GLM 5.2 (and similar OpenAI-compatible upstreams) stream a tool call's id and function.name across separate SSE delta chunks. The openai-to-claude streaming translator emitted content_block_start immediately on the id-only chunk with an empty name; the Claude SSE protocol cannot patch a block after emission, so the later name-only chunk was dropped and Claude Code rejected the tool_use with an empty tool name / "No such tool available:". Defer content_block_start until the name arrives (start on args if they arrive first), and emit a start for any orphaned id-only tool call at finish so content_block_stop is never orphaned. Reported-by: itiwant (https://github.com/decolua/9router/issues/2077) * chore(6730): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) * feat(dashboard): add search to Playground model picker dropdown (#4086) (#6811) * feat(dashboard): add search to Playground model picker dropdown (#4086) The shared ModelSelectModal (combo builder + CLI-code cards) already had search, but the Playground's raw model <select> in StudioConfigPane stayed a flat unsearchable list - unusable once a provider like OpenRouter contributed 50+ models. Adds a search input above the dropdown that filters options via filterModelsByQuery() (Turkish-safe accent/case-insensitive match, reusing matchesSearch()). The currently selected model always stays pinned in the list even when it doesn't match the query, so typing never silently swaps the active selection. Reuses the existing common.search i18n key already translated in all 42 locales - no new key needed. * chore(6811): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) * feat: request count log per provider, per date (#4009) (#6812) * feat(dashboard): request count log per provider, per date (#4009) Some providers bill by request rather than by token, so operators need a plain per-provider, per-date request count breakdown, not just token aggregates. Adds a new getProviderDailyUsageRows() aggregation query (src/lib/db/usageAnalytics.ts), a dedicated GET /api/usage/requests-by-provider-date route (kept separate from the frozen /api/usage/analytics route to respect the file-size baseline), and a sortable, single-date-filterable table on Dashboard -> Analytics. Closes #4009 * chore(6812): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) * feat(xai): route xAI clients to Grok native /v1/responses endpoint (#6709) * feat(xai): route xAI clients to Grok native /v1/responses endpoint xAI ships a native /v1/responses endpoint (https://api.x.ai/v1/responses) alongside /v1/chat/completions, but XaiExecutor extended BaseExecutor without overriding buildUrl(), so every request always resolved to the static chat-completions baseUrl regardless of target format — the last genuinely-missing slice of decolua/9router#2439 (grok-build-0.1, the reasoning-effort suffix routing, and bare grok-* routing were already ported in prior cycles). Add responsesBaseUrl to the xai registry entry and tag grok-4.20-multi-agent-0309 (upstream's own Responses-only id) with targetFormat: "openai-responses", mirroring the existing model-tag-driven routing pattern already used by the gh executor (9router#102) and the "openai" -pro heuristic in open-sse/executors/default.ts — the per-model registry tag is the single source of truth that also drives chatCore's body translation, so URL and body stay in lockstep. XaiExecutor.buildUrl now checks getModelTargetFormat("xai", model) and resolves to the native Responses endpoint only for tagged models, leaving every other grok-* model on the existing chat-completions bridge. TDD: tests/unit/executor-xai.test.ts adds a RED-then-GREEN case asserting grok-4.20-multi-agent-0309 resolves to https://api.x.ai/v1/responses and a control case asserting grok-4.3 still resolves to https://api.x.ai/v1/chat/completions. Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> Inspired-by: https://github.com/decolua/9router/pull/2439 * chore(6709): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first) --------- Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> * fix(resilience): route remaining credential-selection call sites through quota preflight (#6686) (#6742) * fix(resilience): route remaining credential-selection call sites through quota preflight (#6686) * chore(6742): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(resilience): apikey-provider 429s honor explicit quota-exhausted text (#6638) (#6731) * fix(resilience): apikey-provider 429s honor explicit quota-exhausted text (#6638) Ollama Cloud (and any other apikey-category provider) 429s skipped body-text quota classification entirely; a genuine multi-day quota exhaustion was misclassified as a plain rate_limit_exceeded with a few seconds of cooldown, so combo routing retried the account immediately. shouldPreserveQuotaSignals() now lets an explicit quota-exhausted signal (looksLikeQuotaExhausted) override the apikey-category default, and parseDayGranularityResetMs() adds day- granularity reset-hint parsing ("...reset in 3 days.") alongside the existing Xh/Ym/Zs parsing. Regression guard: tests/unit/issue-6638-ollama-quota.test.ts (RED before the fix, GREEN after). Aligned two tests/unit/account-fallback-service.test.ts cases that had codified the old buggy behavior for apikey-provider quota text. * chore(6731): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * feat(resilience): weekly-429 cooldown for fetcher-less providers (#3709) (#6817) * feat(resilience): weekly-429 cooldown for fetcher-less providers (#3709) Ollama Cloud free-tier accounts have a hard WEEKLY request cap. On cap the upstream returns 429 "you (<account>) have reached your weekly usage limit", but ollama-cloud is an apikey-category provider, so the existing oauth-only shouldUseQuotaSignal gate in checkFallbackError skips the subscription-quota-text classifier (Issue #2321) for its 429s -- the account fell through to the generic exponential backoff (~1s, capped at 2min) and got retried every few minutes for the rest of the week (one account took 285x429 in 48h). Adds a new, ungated weekly-usage-limit text classifier that applies a 24h QUOTA_EXHAUSTED cooldown regardless of provider category. Extracted the new classifier -- together with the existing #2321 subscription-quota logic -- into a new open-sse/services/quotaTextCooldowns.ts module so the frozen accountFallback.ts (file-size-baseline cap) didn't have to grow; net effect shrinks accountFallback.ts by 20 lines. This is Phase A of the plan (open-sse/services/accountFallback.ts:1038-1045 "weekly-429 cooldown"); Phase B (generic local request-counter preflight for manual provider_plans dimensions) is a separate, larger follow-up per the plan's own phasing. * chore(6817): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * fix(providers): Kiro adaptive-thinking allowlist excludes sonnet-4.5/haiku-4.5 (#6576) (#6726) * fix(providers): Kiro adaptive-thinking allowlist excludes sonnet-4.5/haiku-4.5 (#6576) * chore(6726): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first) * test(kiro): migrate selector-strip test to claude-sonnet-5 (only Kiro adaptive-thinking model, #6576) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(quality): rebaseline complexity 2053->2054 (merge-burst drift, v3.8.47) Inherited drift from today's /implement-prs merge burst (~36 PRs). check:complexity does not run on the PR->release fast-path, so the branch accrued +1 unmeasured. No orphan/feature PR introduces a NEW violation (complexity-net-zero); the only flagged function is the pre-existing getResolvedModelCapabilities. Owner-approved rebaseline to unblock the FQG of ~7 green-except-complexity orphans. * chore(stryker): register ollama-quota covering tests (merge-burst drift, v3.8.47) The 3 covering unit tests from #6731/#6817/#6742 (issue-6638-ollama-quota, ollama-cloud-weekly-quota-cooldown-3709, issue-6686-quota-preflight-coverage) exist on release but were never added to tap.testFiles when those PRs merged. Completes the registration so mutant kills count; unblocks every PR touching a mutated module. Part of the owner-approved merge-burst drift cleanup. * fix: auto-start WS server in-process and change default port to 20132 (#6072) * feat: change default LIVE_WS_PORT from 20129 to 20132 Update the default WebSocket port for the live dashboard server from 20129 to 20132 across all configuration files, documentation, code comments, and tests. Also consolidate OMNIROUTE_DISABLE_LIVE_WS and OMNIROUTE_ENABLE_LIVE_WS into a single OMNIROUTE_ENABLE_LIVE_WS flag. Wire the live WebSocket server to start in-process via instrumentation-node.ts. * feat: clarify NEXT_PUBLIC_LIVE_WS_PUBLIC_URL path usage and derive upgrade path from URL Update .env.example and ENVIRONMENT.md to document that the pathname portion of NEXT_PUBLIC_LIVE_WS_PUBLIC_URL (e.g. /live-ws) is used as the WebSocket upgrade path by the dev proxy, handshake response, and client connection logic. Extract deriveLiveWsPath() into shared/utils/wsPath.ts and wire it through: - src/app/api/v1/ws/route.ts — handshake response path field - src/hooks/useLiveDashboard.ts — build * fix: use the standard URL API to safely parse and update the effectiveWsUrl * build(docker): expose live WebSocket server port and configure CORS origins Add LIVE_WS_PORT (20132), LIVE_WS_HOST (0.0.0.0), and LIVE_WS_ALLOWED_ORIGINS environment variables to all Docker Compose profiles and expose the WebSocket port mapping. Prevent infinite self-loop in standalone-server-ws.mjs by skipping proxy when the server itself is running on the LiveWS port. * docs(env): fix comment formatting for HOST and HOSTNAME variables --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(logs): prevent stale detail refresh reopening modal (#6323) * fix(logs): prevent stale detail refresh reopening modal * chore(stryker): register ollama-quota covering tests (release drift from merge burst) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * \ feat: operator-configurable account rotation\ (#6763) * feat(resilience): operator-configurable account rotation Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR); the author's accountFallback/.env deltas were re-applied cleanly onto the release tip. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * docs(env): document configurable account-rotation env vars in ENVIRONMENT.md Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(rotation): extract rotation gate/context helpers to keep accountFallback.ts under frozen cap Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(changelog): re-sync CHANGELOG.md to release tip (restore lost base bullet) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test(stryker): register rotation-config test in tap.testFiles for mutation coverage Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test(stryker): register ollama-quota covering tests (drift from #6731/#6817/#6742) + re-sync Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> * fix(lmarena): modernize Arena web provider + static Direct-chat catalog (#6280) * fix(lmarena): modernize Arena web provider + static Direct-chat catalog Update the lmarena provider for arena.ai (product rebranded from LMArena): - Route chat via arena.ai create-evaluation with Chrome TLS impersonation (tls-client-node) and optional browser-minted recaptchaV3Token. - Seed Text+Search (48) into the chat registry; seed Image (27) only into IMAGE_PROVIDERS. Disable live HTML model discovery; resolve public names to Arena UUIDs from the static TypeScript allowlist (no scrape JSON in-repo). - Soft-exclude 404/502 model ids; slow/stop bulk test-all probes for this provider. - Do not fold IMAGE_PROVIDERS/video specialty into the chat provider catalog when a chat registry already exists (lmarena/openai/xai). - Display name Arena (Free); keep wire id `lmarena` / alias `lma` for back-compat. - Theme-aware provider icons: arena-light.svg / arena-dark.svg. - Preserve split Supabase SSR cookie reconstruction for arena-auth-prod-v1.*. * fix(providers): align provider-models-route test fixture + regen provider reference Fold the topaz image-only catalog entry's apiFormat/supportedEndpoints into the local-catalog test fixture (route now tags media-only providers per the lmarena PR's staticModels.ts change), regenerate PROVIDER_REFERENCE.md against the merged release providers.ts, and add the changelog fragment for #6280. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test: align web-cookie fallback suite — lmarena now has a registry entry (probe path) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * docs(changelog): reconcile 3-day merge burst — 16 fragments, 4 promised credits, contributors hall 32→63 - changelog.d fragments for the 20 merged PRs that landed without a bullet (#6072 #6308 #6323 #6538 #6556 #6586 #6611 #6647 #6675 #6698 #6757 #6759 #6804 #6821 + ci rollup #6781/#6691/#6693 + docs rollup #6643/#6644/#6646/#6663; omniglyph bump #6661 folded into the #6556 bullet) - deliver the 4 credits promised in close comments but never written: @alltomatos (#6819 dup of #6721), @samimozcan (#6762/#6753 subsumed by #6790), @chirag127 (#6756 dup of #6757), @Squawk7777 (#6565 dup of #6564 — appended to the existing #6564 bullet; changelog-integrity flags that edit as a removal, intentional: ALLOW_CHANGELOG_REMOVALS justification) - rebuild the v3.8.47 Contributors hall from merged-PR authors + thanks credits + prior hall: 32 → 63 contributors * Clamp reasoning token buffer to model output cap (#6714) * fix(combo): clamp reasoning buffer to model output cap * fix(routing): preserve near-cap reasoning max tokens * fix(routing): getExplicitModelOutputCap falls through to registry cap on non-numeric synced limit_output getExplicitModelOutputCap short-circuited to null whenever a synced capability row existed, even if that row's limit_output was not a number (models.dev commonly omits it). That silently disabled the reasoning-token buffer clamp for any model with a synced row lacking an output limit. Now only return the synced value when it IS a number; otherwise fall through to registryModel.maxOutputTokens / spec.maxOutputTokens, matching the ??-chain precedence already used by getResolvedModelCapabilities(). Adds a standalone regression test (proves the fallthrough returns the real registry cap, not null) and hardens the #6274 fixture id so its no-output-cap case does not prefix-match the real glm-5.2 static spec. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(stryker): register ollama-quota covering tests (release drift from merge burst) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * feat(i18n): add Traditional Chinese (zh-TW) localization for frontend and CLI (#6320) * feat(i18n): add Traditional Chinese (zh-TW) localization for frontend and CLI - Add src/i18n/messages/zh-TW.json translating frontend web UI - Add bin/cli/locales/zh-TW.json translating CLI commands and descriptors - Register zh-TW in config/i18n.json and docs/guides/I18N.md - Update scripts/i18n/generate-multilang.mjs matching the new locale setup * fix: update i18n locale count from 42 to 43 after adding zh-TW The docs strict checker (check-docs-counts-sync.mjs) validates that README.md and I18N.md reflect the real locale count. Adding zh-TW bumped the count from 42 → 43. * fix(i18n): translate providers free-filter labels in zh-TW (#6694 guard) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: lunkerchen <lunkerchen@users.noreply.github.com> * feat(proxy): implement latency-optimized proxy rotation strategy (#6798) * feat(proxy): implement latency-optimized proxy rotation strategy Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy files belong to #6620, not this PR) and the direct CHANGELOG.md edit (fragments-first); the author's env/docs/i18n deltas were re-applied cleanly onto the release tip. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(proxy): add latency-rotation env var to .env.example PROXY_LATENCY_WINDOW_HOURS was referenced in src/lib/db/proxies.ts and documented in docs/reference/ENVIRONMENT.md, but missing from .env.example, tripping the env/docs sync gate. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(changelog): re-sync CHANGELOG.md to release tip Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(proxy): extract latency-strategy helpers to keep frozen files under cap Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test(db-rules): expect 35 audited modules (proxyLatency joins INTENTIONALLY_INTERNAL) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * docs(readme): fix stale strategy/tool/scoring counts (#6853) README still claimed 17 routing strategies (the table was missing pipeline), 95 MCP tools, and 9-factor Auto-Combo scoring. Align with the source (ROUTING_STRATEGY_VALUES has 18 entries) and the canonical docs (MCP-SERVER.md: 94 tools; AUTO-COMBO.md: 12-factor). * fix(antigravity): sanitize Cloud Code safety settings (#6839) Co-authored-by: kfiramar <83420275+kfiramar@users.noreply.github.com> * fix(kiro): probe IdC region during profileArn discovery, cross-region (recovers #6099) (#6840) * fix(kiro): route Amazon Q runtime by profileArn region for cross-region IdC Enterprise AWS IAM Identity Center accounts whose IdC instance lives outside the two Amazon Q Developer profile regions (us-east-1 / eu-central-1) - e.g. eu-north-1 (Stockholm), start URL https://d-XXXX.awsapps.com/start - showed no limits and returned 502 on every request. Root cause: the backend used the IdC/OIDC token region (providerSpecificData.region, e.g. eu-north-1) for every CodeWhisperer runtime call, hitting q.eu-north-1.amazonaws.com - a host that does not exist as a Q Developer runtime endpoint. Per AWS docs ("Supported Regions for the Q Developer console and Q Developer profile"), the Q Developer *profile* (which produces the profileArn and hosts generateAssistantResponse / GetUsageLimits / ListAvailableModels / ListAvailableProfiles) is only hosted in us-east-1 and eu-central-1, regardless of the IdC region; "data is stored in the Region where you create the Amazon Q Developer profile." Fix (new open-sse/services/kiroRegion.ts) decouples the two regions: - providerSpecificData.region stays the IdC/OIDC region, used ONLY for oidc.{region}.amazonaws.com token mint/refresh. - The runtime region is derived from the profileArn (resolveKiroRuntimeRegion): profileArn region -> a valid stored profile region -> us-east-1. A stored IdC region that is not a Q profile region (eu-north-1) is ignored for runtime. - Profile discovery (discoverKiroProfileArnAcrossRegions) probes the Q profile regions (EU IdC -> eu-central-1 first) with the cross-region SSO token instead of q.{idcRegion}. Wired into: executors/kiro.ts (generateAssistantResponse targets the profile region), services/usage/kiro.ts (getKiroUsage multi-region discovery + profileArn runtime region so Limits resolves), services/kiroModels.ts (ListAvailableModels), and src/lib/oauth/providers/kiro.ts (login-time postExchange profile discovery). Adds tests/unit/kiro-idc-cross-region.test.ts (15 cases). All Kiro suites pass (60 tests). * fix(kiro): probe the IdC region too during profileArn discovery (any IdC region) Make profile discovery general for an IdC in ANY of the ~30 IdC-supported AWS regions (us-west-2, ap-southeast-2, me-central-1, af-south-1, ...), not just eu-north-1. buildKiroProfileDiscoveryRegions now probes the two documented Q Developer profile regions FIRST (us-east-1 / eu-central-1, EU-first for EMEA IdC regions to cut latency), then appends the IdC/stored region itself as a forward-compatible fallback: if AWS ever co-locates the profile with the IdC or expands the profile-region list, a same-region probe still finds it. Probing a region with no profile simply returns nothing and we fall through. The profileArn's own region remains authoritative for every runtime call (resolveKiroRuntimeRegion), so a newly-issued ARN in any region is honored automatically. Adds ap-southeast-2 (APAC) cross-region coverage and updates the discovery-order tests. --------- Co-authored-by: artickc <artur1992123@mail.ru> * feat(providers): manual context-window override for custom models (#4125) (#6822) Add a manual per-model "Context Window Override" so an operator can correct a provider's misreported context length (e.g. reports 1M when the real limit is 128K) instead of the model getting silently dropped from combo routing once the wrong value lands in the catalog. Reuses the existing Feature-5004 model_context_overrides table (source="manual") — already the priority-0 source getModelContextLimit() (the function combo's context-window filter calls) reads ahead of the models.dev/registry/static catalog — so no new resolver logic was needed, only the missing write path: - PUT /api/provider-models now accepts an optional contextWindowOverride (number to set, null to clear), persisted via setModelContextOverride/ removeModelContextOverride. - GET /api/provider-models surfaces the current override value + source back on each custom-model row. - CustomModelsSection.tsx: edit form gained a Context Window Override input + a badge on the model row when an override is set. Regression guard: tests/unit/provider-models-context-window-override-4125.test.ts (manual override wins over a misreported catalog value, GET round-trip, clearing via null, default-unchanged behavior). * feat(dashboard): improve Provider Quota page horizontal density (#3520) (#6815) QuotaCardGrid stacked every provider group vertically in a single flex flex-col container, and each group's own card grid didn't go multi-column until the md breakpoint. Provider groups now flow into a 2-column CSS multi-column layout on very wide (2xl) screens instead of an unconditional vertical stack, and each group's card grid starts at 2 columns immediately, filling horizontal whitespace sooner on narrower-but-not-mobile viewports. Regression guard: tests/unit/quota-card-grid-horizontal-layout.test.ts * refactor(usage): type saveRequestUsage with UsageEntry interface + any-budget ratchet (#3512) (#6809) Replace saveRequestUsage(entry: any) with a typed UsageEntry interface mirroring the usage_history columns 1:1. Fields stay optional/nullable since different writers (chatCore success/failure, rejected-request accounting, Codex Responses WS) populate the row incrementally; tokens stays unknown since callers pass either raw provider-shaped usage or the normalized {input,output,cacheRead,...} shape. Also cleaned the file's other any usages (getUsageHistory filter, getUsageDb next-cursor cast, appendRequestLog tokens param, getRecentLogs catch) so it now sits at zero any and can be added to the check:any-budget:t11 zero-any allowlist. Documents the DB-entity <-> TS-interface convention in docs/architecture/CODEBASE_DOCUMENTATION.md Sec 11. * feat(combo): strict budget-cap fallback policy for auto/* combos (#3470) (#6816) Auto-combo transparency + budget controls: the engine's budgetCap enforcement always degraded to the globally cheapest candidate when every candidate exceeded the cap - silently overspending instead of respecting the cap. - engine.ts: budgetFallback "cheapest" (default, legacy) | "strict" (BudgetExceededError when no candidate fits budgetCap) - requestControls.ts: X-OmniRoute-Budget-Fallback header + resolveRequestAutoControls() consolidating mode/budget/fallback parsing - resolveAutoStrategy.ts / autoConfig.ts: thread combo-level config.budgetFallback and catch BudgetExceededError into an HTTP 402 - chat.ts: switch to the consolidated resolveRequestAutoControls() helper (net line reduction, stays under the frozen file-size baseline) Regression guard: tests/unit/auto-combo-budget-fallback-3470.test.ts * fix(usage): honor xAI provider-reported exact cost (#6711) OmniRoute's calculateCost() always estimated request cost from token counts x static pricing, discarding xAI's exact provider-reported cost when present. xAI's chat-completions usage object reports the precise billed cost via cost_in_usd_ticks (docs.x.ai/developers/cost-tracking and the API reference's usage schema: "TICKS_IN_USD_CENT: i64 = 100_000_000" => 1e10 ticks/USD, e.g. 37756000 ticks ~= $0.0038). calculateCost()/computeCostFromPricing() now short-circuit to this exact figure when present -- before any pricing DB lookup, so it also works for models without a local pricing row -- and still fall back to the token-based estimate when it is absent. The field is threaded through both the streaming (extractUsage/normalizeUsage) and non-streaming (extractUsageFromResponse) usage-extraction paths. Corrected divisor vs upstream: the upstream PR used /1e12 (a 100x under-report, e.g. reporting $0.00123 as the doc's $0.123 example); this port uses the doc-verified /1e10 instead, confirmed against both the cost-tracking guide and the API reference's usage-object schema. Inspired-by: https://github.com/decolua/9router/pull/2453 Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> * docs: rename /implement-prs → /merge-prs in Hard Rule #21 (skill renamed 2026-07-11) (#6847) * docs: refresh stale llm.txt facts + relocate design.md to docs/architecture/DESIGN_SYSTEM.md (#6849) * docs: refresh stale llm.txt facts + move design.md to docs/architecture/DESIGN_SYSTEM.md llm.txt was frozen at the v3.8.8 era (177 providers, 37 MCP tools, 14 strategies, 9-factor scoring, 75% coverage gate). Update every factual claim to the current state (248 providers, 94 tools / 30 scopes, 18 strategies, 12-factor scoring, ratchet + 60% floor, TS 6, current docs/ layout) and re-sync the 42 exact-copy i18n mirrors. design.md at the root was a standardization plan whose phases 1-6 all shipped; rewrite its header as a permanent reference and relocate it to docs/architecture/DESIGN_SYSTEM.md per the root-hygiene policy (root = configs + canonical docs only). * docs: add MDX frontmatter to DESIGN_SYSTEM.md (in-app docs pipeline requires it) * feat: per-model web-search interception rule (#3384) (#6814) * feat(routing): per-model web-search interception rule (#3384) Adds a per-provider/per-model interceptSearch rule (src/lib/db/interceptionRules.ts, key_value namespace interception_rules) that overrides the existing native web-search bypass defaults (Codex/Gemini/Claude->Claude passthrough) in webSearchFallback.ts. Wired at the existing prepareWebSearchFallbackBody() call site in chatCore.ts. Resolution precedence: per-model rule > provider-level rule > existing native-bypass defaults. This lands Phase 1-2 of the plan (rule store + search interception). Web-fetch interception and the dashboard UI toggle are tracked as follow-up phases. * fix(db): register interceptionRules in localDb re-export layer (db-rules gate) * fix(db): renumber interception_rules migration 119→120 (collision with model_capability_overrides) * feat: sidebar search/filter input (#4013) (#6810) * feat(dashboard): add search/filter input to the dashboard sidebar (#4013) Adds a search box at the top of the expanded sidebar that filters nav sections/groups/items client-side by label, so users don't have to hunt through the growing nav tree. Reuses the existing common.search / common.noResults i18n keys (no new locale edits needed) and the shared Input icon="search" pattern. Matching sections auto-expand while searching and the accordion/pin state is restored once the query is cleared. Filtering logic is extracted into a pure filterSidebarSectionsByQuery() helper (src/shared/utils/sidebarSearch.ts) so it is trivially unit testable independent of React/next-intl/next-navigation. * fix(test): move Sidebar.search test to a runner-collected path (test-discovery gate) * fix(i18n): backfill 194 missing pt-BR keys (#6695) (#6723) * fix(i18n): backfill 194 missing pt-BR keys and add key-parity regression test (#6695) * Merge branch 'release/v3.8.47' into fix/6695-i18n-drift Resolve i18n key-parity and CHANGELOG-fragment conflicts: - Convert the #6695 CHANGELOG.md bullet to a changelog.d/ fragment (the fragment convention landed on release/v3.8.47 after this PR branched, per changelog.d/README.md). - Backfill 61 additional pt-BR keys that entered en.json on release/v3.8.47 after this PR's original 194-key backfill, so the PR's own key-parity regression test (tests/unit/i18n-pt-br.test.ts) stays green against the moving release baseline. * Discover live Codex models (#6776) * Add live model discovery for provider catalog * Fix model discovery request headers * fix(codex): sync live model limits with local catalog * test(codex): split live model discovery coverage into dedicated route tests * fix(codex): use chatgpt account id for live model sync * Add GitHub-backed Codex model discovery fallback * fix(providers): tighten oauth config tests and provider model display comments * test: align client version expectations with release default * fix(codex): keep discovery complexity within baseline * fix: rebase live Codex model discovery onto release/v3.8.47, preserving kimi-web buildHeaders (#6308) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * feat(codex): echo requested effort-suffixed model id in Responses payloads (#3697) (#6820) * feat(codex): echo requested effort-suffixed model id in Responses payloads (#3697) Codex CLI compatibility shim: the Responses API response.created/ response.in_progress/response.completed payloads now carry a `model` field (previously absent), and for Codex-CLI-originated requests it echoes the client-requested effort-suffixed model id (e.g. gpt-5.5-xhigh) instead of the bare upstream id (gpt-5.5), so the Codex CLI status line/model button shows the active reasoning effort. - openai-responses.ts translator threads the upstream model into the Responses event objects (additive, omitted when unknown). - New isCodexOriginatedHeaders() (codexIdentity.ts) reuses PR #3481's originator/User-Agent detection, header-based so it still fires when a combo routes codex/gpt-5.5-xhigh to a non-codex upstream. - chatCore's existing opt-in #1311 echoModel pipeline now also fires automatically for Codex clients on the Responses API, regardless of the echoRequestedModelName setting. - responseModelEcho.ts now also rewrites the nested response.model field the Responses API uses (previously only top-level model). - /v1/models keeps returning models: [] for Codex (unchanged, #3481). Regression guard: tests/unit/codex-effort-model-echo-3697.test.ts. Closes #3697 * chore(merge): re-sync with release/v3.8.47 (restore CHANGELOG, keep own bullet) * chore(merge): re-sync with release/v3.8.47; move changelog bullet to changelog.d fragment (merge-storm proof) * feat(usage): surface Antigravity weekly quota alongside the 5-hour window (#4017) (#6818) * feat(usage): surface Antigravity weekly quota alongside the 5-hour window (#4017) Antigravity enforces both a 5-hour and a weekly usage limit, but the agy/antigravity quota widget only exposed the 5-hour window. The weekly limit isn't in the per-model retrieveUserQuota response already fetched — it lives in a separate, undocumented retrieveUserQuotaSummary RPC that groups models into families (Gemini Models, Claude and GPT models) with one weekly bucket per family. Adds a self-contained usage/antigravityWeeklyQuota.ts leaf: a cached, best-effort fetch of that RPC + a pure parser that extracts the weekly-labeled bucket per group (window inferred from bucketId/displayName text, matching the reverse-engineered shape documented by third-party Antigravity clients) into gemini_weekly/ claude_gpt_weekly quota entries, merged into the existing quotas map the widget already renders generically. A failed/unavailable RPC never affects the existing per-model quotas. Live VPS validation attempt (192.168.0.15, real antigravity account): both retrieveUserQuota and retrieveUserQuotaSummary currently return 429 RESOURCE_EXHAUSTED for that account, so the live response shape could not be captured directly. The parser was instead validated via TDD against the bucket shape documented by CodexBar (steipete/CodexBar), a third-party Antigravity client that reverse-engineered the same RPC, and is defensive against both response envelopes it has observed (top-level groups[] and nested quotaSummary.groups[]). * chore(merge): re-sync with release/v3.8.47 (restore CHANGELOG, keep own bullet) * chore(merge): re-sync with release/v3.8.47; move changelog bullet to changelog.d fragment (merge-storm proof) * feat: add Z.ai Web free web-cookie provider (#4056) (#6823) * feat(providers): add Z.ai Web free web-cookie provider (#4056) New zai-web web-session provider drives the free chat.z.ai consumer chat UI via a pasted browser cookie, distinct from the existing API-key zai/glm/glm-cn/glmt providers (api.z.ai). ZaiWebExecutor posts to chat.z.ai/api/chat/completions with the cookie forwarded both as Cookie and Authorization: Bearer <token>, and normalizes both z.ai's internal delta_content/phase SSE envelope and a pass-through OpenAI-shaped choices[].delta frame into standard chat-completion chunks. Registered in WEB_COOKIE_PROVIDERS, WEB_SESSION_CREDENTIAL_REQUIREMENTS, the provider registry (GLM-4.6/4.5/4.5V models), the executor factory, and tokenExtractionConfig.ts for in-app cookie capture. * fix(providers): regenerate translate-path golden for zai-web + reduce cognitive complexity * fix(providers): rename ZaiWebExecutor.buildHeaders to avoid incompatible BaseExecutor override * chore(merge): re-sync with release/v3.8.47; move changelog bullet to changelog.d fragment (merge-storm proof) * fix(codex): bump default client version to 0.144.0 (#6780) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(usage): extract per-group parsing in antigravityWeeklyQuota (cognitive-complexity gate 886→885, release-level drift from #6818 merge) * ci(quality): cut PR gate wall time without dropping protection (#6716) Collapse duplicate CI spend while keeping each gate's existence reason: - quality.yml: TIA __RUN_ALL__ defers full unit to fast-unit 4-shard (#6781); path filters via classify-pr-changes; docs-gates split; draft skip - ci.yml: wire docs/i18n/code path filters; ESLint JSON artifact for quality-gate; drop advisory typecheck:noimplicit; float actions/cache@v6 - TIA parity: memory/usage/combo/serial; **/*.test.mjs any depth; electron/bin no longer force unit __RUN_ALL__ - check:complexity-ratchets: one ESLint walk, ruleId-isolated baselines + cache - check:api-docs-refs + lib/apiRoutes: shared API route inventory - husky pre-push: intentionally light (gates live in pre-commit); CLAUDE.md + QUALITY_GATES.md docs synced - collect-metrics / lint:json: path.resolve cache path; Windows-safe eslint bin - env-doc allowlist for ESLINT_RESULTS_JSON / COMPLEXITY_ESLINT_REPORT - release-green --full-ci expects check:api-docs-refs (not docs-symbols alone) Tests: select-impacted, classify-pr-changes, api-routes lib, complexity-rule-count, validate-release-green. Reconciled after #6781 (fast-unit 2→4 shards) per maintainer request on #6716. Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> * fix(docs): document Turbopack build memory tradeoff for RAM-constrained machines (#6409) (#6885) * fix(routing): recognize Kimi token-limit 400 as context overflow for combo fallback (#6637) (#6893) combo.ts's isContextOverflow400() guard required the literal word 'context' in the 400 error body before letting a combo fall through to the next target. Kimi's exact wording ('Your request exceeded model token limit: 262144 (requested: 308458)') never says 'context', so the guard misclassified it as a body-specific error and halted the whole combo instead of trying the next (larger-context) target. accountFallback.ts's CONTEXT_OVERFLOW_PATTERNS already recognized this wording one layer below (via checkFallbackError -> shouldFallback), so the two independently-maintained classifiers disagreed and the stricter one won. Export CONTEXT_OVERFLOW_PATTERNS from accountFallback.ts and reuse it inside combo.ts's isContextOverflow400() so both layers share a single source of truth. Regression test: tests/unit/repro-6637-kimi-token-limit.test.ts (RED on unfixed code -> GREEN after the fix). Existing #4519 guard tests (tests/unit/combo-param-validation-fallback-4519.test.ts) still pass, including the negative case that a genuinely body-specific 400 is NOT misclassified as overflow. * fix(providers): honor a provider-level proxy assigned to no-auth providers (#6272) (#6895) No-auth providers (mimocode, opencode, ...) are always dispatched with a single hardcoded connectionId ("noauth" — SYNTHETIC_NOAUTH_CONNECTION_ID in src/sse/services/auth.ts). No provider_connections row ever has id="noauth", so resolveProxyForConnection() in src/lib/db/settings.ts could never populate connectionRecord for them, and its provider-level proxy lookup (Steps 6/8) only runs when connectionRecord is present. A proxy assigned via Settings -> Providers -> mimocode was therefore silently ignored, reproducing the reporter's "same thing happen when i set the proxy directly in the provider menu" symptom. Adds a best-effort fallback (src/lib/db/settings/noAuthProxyFallback.ts): when connectionRecord could not be resolved, scan the known no-auth provider ids for a configured provider-level proxy (registry first, then legacy) before falling through to the global/direct steps. Regression test: tests/unit/proxy-noauth-provider-6272.test.ts (RED on unfixed code — resolved to level=direct/proxy=null; GREEN after the fix). * fix(dashboard): surface Claude extraUsage credits in quota card (#6806) (#6896) Enterprise-tier Claude accounts (default_raven_enterprise) don't get five_hour/seven_day utilization windows from Anthropic's OAuth usage endpoint — only an extra_usage credit-billing block. parseClaude() only read data.quotas, so quotas stayed {} and the dashboard showed "No quota data" even when extraUsage showed the account 100% exhausted. parseClaude() now folds an enabled extraUsage block into a credits-style quota row (mirroring parseCodex's bankedResetCredits pattern), both when quotas is empty and when it's already populated. * fix(db): share sql.js preinit across callers, fix named-param bind (#6628, #6802) (#6899) - preInitSqlJs() now memoizes an in-flight Promise (not just the resolved adapter) per filePath, so concurrent BATCH/STARTUP/HealthCheck/ ProviderLimitsSync callers at boot share one full-file read+WASM decode instead of each independently reloading the whole database — the thundering-herd amplifier of the OOM condition #6632 already partly fixed, left un-implemented by the reporter's own proposed fix (#6628). - sqljsAdapter's run/get/all now unwrap a lone named-parameter object (e.g. .all({ isActive: 1 }) for "WHERE is_active = @isActive", the same call shape getProviderConnections() already uses against better-sqlite3) before calling sql.js's stmt.bind(), expanding it to the @/:/$ sigil variants sql.js's own named-bind path requires. Previously the object was wrapped into an array and sql.js took the positional-bind path, throwing "Wrong API use : tried to bind a value of an unknown type ([object Object])." whenever the sql.js WASM fallback driver was active — exactly the error #6802 reported (misattributed to better-sqlite3). Regression tests added to tests/unit/db-adapters/driverFactory.test.ts and tests/unit/db-adapters/sqljsAdapter.test.ts, both proven RED against the prior code and GREEN after the fix. * fix(plugin): split OC-gate provider id from OmniRoute-facing routing id (#6859) (#6900) resolveOmniRoutePluginOptions() auto-prefixes providerId with "opencode-" (commit |
||
|
|
19d91d82e2 |
Release v3.8.34 (#4614)
* chore(release): open v3.8.34 development cycle * chore(quality): release-green pre-flight validator + nightly signal (C+D) (#4622) C — scripts/quality/validate-release-green.mjs (npm run check:release-green): reproduces the release-equivalent validation (typecheck, eslint, db-rules, public-creds, full unit, vitest, ratchets, optional --with-build package-artifact) against the current working tree and classifies each red as HARD (real defect, exit 1) vs DRIFT (ratchet — reported, never affects exit / never blocks). Pure helpers exported + orchestration behind a direct-run guard; unit-tested. D — .github/workflows/nightly-release-green.yml: runs C on the active release branch nightly (and on workflow_dispatch) and opens/updates a single tracking issue on HARD failures. Never a required check, never touches a contributor PR. Closes the gap where the full gate (ci.yml) only ran on the release PR, so reds accrued silently on release/** and surfaced in 40-min layers at release time. Non-blocking by construction; drift is the maintainer's to rebaseline at release. Co-authored-by: Diego Rodrigues de Sa e Souza <diego.souza@cdwasolutions.com.br> * fix(providers): show revealed connection API keys (#4583) Integrated into release/v3.8.34 * fix(resilience): respect upstream retry hint toggle (#4585) Integrated into release/v3.8.34 * feat(settings): expose stream recovery feature flags (#4586) Integrated into release/v3.8.34 * fix(logs): make active request stale sweep configurable (#4599) Integrated into release/v3.8.34 * fix(plugin): auto-prefix providerId with 'opencode-' for OC 1.17.8+ native gate (#4527) Integrated into release/v3.8.34 (supersedes #4445) * fix(models): treat unknown output caps as unset (#4584) Integrated into release/v3.8.34 * fix(executors): strip temperature for GitHub Copilot gpt-5.4 family (#4564) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(oauth): update Qwen OAuth URLs from chat.qwen.ai to qwen.ai (#4561) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(api/settings): prevent cached /api/settings responses (port from 9router#951) (#4566) Integrated into release/v3.8.34 (rebuilt onto tip) * feat(audio): MiniMax T2A v2 TTS dispatch in audioSpeech (port #1043) (#4553) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(dashboard): surface manual config CTA when Open Claw CLI auto-detect fails (#4562) Integrated into release/v3.8.34 (rebuilt onto tip) * feat(providers): optional model ID for custom API-key validation (#4555) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(cli): align data dir and env loading with runtime (#4607) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(quota): expose Bailian quota windows (#4610) Integrated into release/v3.8.34 (rebuilt onto tip) * fix: retain provider cooldowns for configured max window (#4588) Integrated into release/v3.8.34 (rebuilt — bundled commits stripped) * fix: reject invalid provider cooldown bounds (#4589) Integrated into release/v3.8.34 (rebuilt — bundled commits stripped) * fix: preserve production combo metrics on shadow eviction (#4590) Integrated into release/v3.8.34 (rebuilt — bundled commits stripped) * fix(stream): estimate input tokens when upstream reports prompt_tokens=0 (#4615) Integrated into release/v3.8.34 (rebuilt onto tip) * fix(catalog): shorten no-thinking gateway prefix to no-think/ (#4525) Integrated into release/v3.8.34 (rebuilt — kept only the prefix rename, dropped stale-base reverts) * fix(relay): apply IP rate limit to bifrost sidecar (#4593) Integrated into release/v3.8.34 (rebuilt onto tip; merge before #4612) * fix(bifrost): finalize SSE relay usage after stream (#4612) Integrated into release/v3.8.34 (rebuilt + reconciled with #4593) * feat(compression): per-request `x-omniroute-compression` header (Phase 3) (#4645) * docs(compression): Phase 3 per-request header design spec Approved brainstorming output for the x-omniroute-compression header: header-first precedence, name-first combo matching (Decision A), explicit value bypasses auto-trigger (Decision B), DerivedPlan.source, and the X-OmniRoute-Compression response header. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(compression): Phase 3 per-request header implementation plan 4-task TDD plan (resolver header-first + source, parser, chatCore wiring + response header, docs/file-size) with full code and exact commands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(compression): header-first resolver + plan source (Phase 3 core) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(compression): resolveCompressionHeader parser (Phase 3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(compression): wire x-omniroute-compression header + response header (Phase 3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(compression): extract plan-resolution leaf (planResolution.ts) under size cap (Phase 3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(compression): document x-omniroute-compression header (Phase 3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(compression): harden named-combo map + trim engine: header id (Phase 3 review) Addresses gemini-code-assist review on #4645: - Extract buildNamedComboLookup (pure) so a blank/whitespace/null combo name contributes only its id key (no '' key, no throw that disables all combos). - Trim the engine:<id> header value so 'engine: rtk' resolves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diego.souza@cdwasolutions.com.br> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix: exclude exhausted connections from auto scoring (#4592) Integrated into release/v3.8.34 (rebuilt + opt-in gate fix) * fix(dashboard): memoize compatible provider groups (#4613) Integrated into release/v3.8.34 (rebuilt + test added) * fix(dashboard): isolate quota widget refresh clock (#4611) Integrated into release/v3.8.34 (rebuilt + jsdom test) * fix(dashboard): gate topology side effects behind widget visibility (#4606) Integrated into release/v3.8.34 (rebuilt + jsdom test) * fix(dashboard): keep play_arrow spinning on provider Test All buttons (#4563) Integrated into release/v3.8.34 (rebuilt onto tip; UI-cosmetic per owner) * fix(db): schedule retention cleanup + fix cleanup table/column names (extracted from #4428) (#4691) Integrated into release/v3.8.34 (cleanup core extracted from #4428, credit @oyi77) * fix(telemetry): back off live-WS event forwarding when the sidecar is unreachable (#4604) (#4687) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(api): serve GET /v1/models/{model} as JSON, not the HTML dashboard (#4674) (#4677) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(opencode): add go deepseek reasoning variants (#4647) Integrated into release/v3.8.34 * fix(executors): robust deepseek-web tool-call parsing and agentic context retention (#4644) Integrated into release/v3.8.34 * fix(cli): authenticate `omniroute logs` and honor active context (#4638) Integrated into release/v3.8.34 (authored by Rahul Sharma, AI co-author trailer stripped per project policy) * fix(proxy): apply pipelining:0 + connections cap to the direct dispatcher (#4580) (#4684) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(executors): Firecrawl web_fetch 500 with include_metadata=true (#4692) Integrated into release/v3.8.34 * fix(routing): include all noAuth models in auto-combos + add reka-flash + best-free template (#4621) Integrated into release/v3.8.34 (dead getFirstRegistryModelId dropped, rebuilt onto tip) * fix(dashboard): gate home topology live-WS networking (#4596) (#4618) Integrated into release/v3.8.34 (adapted onto #4606's extracted topology section: default-hidden flip + enabled gate on useLiveDashboard) * fix(cli): align `omniroute` env loading with the runtime data dir (#4597) (#4619) Integrated into release/v3.8.34 (data-dir.mjs refactor reconciled with #4607; loadEnvFile aligned to getDefaultDataDir) * chore(quality): reconcile file-size baseline for #4644 (deepseek-web.ts 1117->1125) (#4695) file-size reconcile for #4644 * Support quota scraping for OpenCode Go and Ollama Cloud (#4642) Integrated into release/v3.8.34 (Ollama Cloud + OpenCode Go dashboard quota scraping; rebuilt onto tip, gates green: typecheck/public-creds/file-size/lint/docs-sync + 31 tests) * feat(executors): land M365 Copilot pure framing + connection helpers (#4042) (#4696) Land M365 pure modules ahead of draft #4400 * deps: bump production + development groups; migrate js-yaml to v5 ESM (#4697) Incorporates Dependabot #4667 + #4668 + js-yaml v5 ESM migration into release/v3.8.34 * fix: noAuth provider validation + kimi executor routing (#4699) Integrated into release/v3.8.34 (noAuth in NOAUTH_PROVIDERS dynamic check + remove misrouted kimi web alias; 9 tests) * refactor(imageGeneration): extract 8 provider families to co-located files (#4609) Integrated into release/v3.8.34 (extraction completed: added missing imports/exports per module, main imports handlers locally; 145 image-gen tests pass, typecheck/cycles/file-size green) * chore(release): v3.8.34 — finalize changelog, rebaseline drift, fix release-green reds - Finalize CHANGELOG [3.8.34] (43 bullets, full contributor attribution) + seed i18n mirrors - Rebaseline inherited cycle drift surfaced by release-green pre-flight: eslint warnings 3900->3907, cognitive-complexity 797->801 (release-finalize touches no prod code; all drift is from this cycle's contributor merges) - fix(providers): keep reka-flash-3 as the Reka provider default. #4621 inserted reka-flash at the head of the model list, silently changing the default from reka-flash-3 (the free-tier model) to reka-flash; reorder so reka-flash-3 stays default, reka-flash retained. - test: align provider-models-config / provider-models-route / web-cookie-providers-new with #4621 (reka-flash now in the Reka catalog) and #4699 (the `kimi` API-key provider correctly falls through to DefaultExecutor instead of KimiWebExecutor) - chore(quality): allowlist the COMPRESSION_GUIDE doc name in check-fabricated-docs (false-positive env-var match; docs/compression/COMPRESSION_GUIDE.md exists) * fix(release-green): resolve release-PR full-CI reds for v3.8.34 Surfaced only on the release PR (these gates don't run on PR->release fast-gates): - fix(quota): complete HTML-comment sanitization in opencodeOllamaUsage SSR reset-time parsing — strip any <!--...--> generically instead of the two literal React hydration markers, so no partial "<!--" can survive (CodeQL js/incomplete-multi-character- sanitization, HIGH, introduced by #4642). Regression test added. - test(codex): correct the Codex-fingerprint body key order assertion to match the canonical bodyFieldOrder (prompt_cache_key precedes include); #4584 flipped the two and integration tests don't run on fast-gates so it never executed until the release PR. - chore(quality): rebaseline inherited cycle drift surfaced by full CI — zizmorFindings 152->155 (+3 unpinned-uses in nightly-release-green.yml from #4622, same @vN convention as ci.yml) and openapiCoverage.pct 38.4->37.8 (-0.6, contributor routes added faster than openapi docs). Release-finalize touches no prod routes. * fix(release-green): complete CodeQL sanitization + rebaseline complexity drift - fix(quota): handle unterminated HTML comments in opencodeOllamaUsage SSR reset-time parsing — the `(?:-->|$)` arm consumes a trailing "<!--" with no closing "-->", so no partial "<!--" can survive (CodeQL js/incomplete-multi-character-sanitization persisted with the plain <!--...--> form because an unclosed comment could still leave "<!--"). - chore(quality): rebaseline cyclomatic complexity 1915->1916 (+1) — inherited v3.8.34 cycle drift (contributor feature branches); check:complexity does not run on PR->release fast-gates so it surfaced only on the release PR. Release-finalize adds 0 complexity (measured 1916 with/without the regex tweak). dead-code/cognitive/type-coverage/ compression-budget/codeql ratchets all pass. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diego.souza@cdwasolutions.com.br> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: Ronald Estacion <DevEstacion@users.noreply.github.com> Co-authored-by: Igor <60442260+BugsBag@users.noreply.github.com> Co-authored-by: Oonishi <275808243+ponkcore@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Jan Leon <Jan.gaschler@gmail.com> |
||
|
|
35dbf0eea1 |
Release v3.8.25 (#3866)
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (#3863): unblocked Build+Docker via #3864, plus #3837 (mimocode proxy) and #3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (#3834) (#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (#3861) (#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (#3850) (#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios #3848, compression UI #3860, injection-guard #3857, kiro discovery #3836, Veo #3839, mimocode proxy #3837, Arena ELO flag #3821), 9 more Fixed entries (#3811/#3807/#3759/#3849/#3838/#3835/#3814/#3820/#3819), a Security section (CCR IDOR #3859, supply-chain #3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked #3826, rolled up file-size re-baselines (#3823/#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (#3838/#3822/#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.) |
||
|
|
bf8b56b29f |
Release v3.8.20 (#3547)
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (#3554) (#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (#3537) (#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for #3560 thoughtSignature fix (#3414) The #3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original #3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (#3472) (#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (#3509) (#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (#3552) (#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (#3558) (#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (#3516) (#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule #12) (#3494, #3495) (#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (#3486, #3487) (#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (#3483) + docs(api): fix agent-bridge per-agent state route (#3489) (#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (#3497) (#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (#3508) (#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (#3505) (#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (#3506) (#3582) Integrated into release/v3.8.20 * docs(changelog): add the #3506 Kiro quota entry (missed in #3582 due to a stale-base CHANGELOG anchor) (#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR #3518 review comments (lifecycle hooks, regex, indentation, route params) (#3562) Integrated into release/v3.8.20. Addresses #3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule #18 regression test. * docs(changelog): credit @ViFigueiredo (#3423) for PROJECT_ROOT + log #3561/#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule #18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se> |
||
|
|
f59f8daa94 |
Release v3.8.6 (#2804)
* fix(gemini): preserve structured tool calls for antigravity * fix(gemini): parse prefixed textual tool calls * fix(antigravity): preserve textual SSE tool calls * fix(stream): normalize textual passthrough tool calls * fix(stream): normalize split textual tool calls * fix(stream): suppress malformed textual tool calls * fix(stream): suppress compact malformed tool calls * fix(stream): emit structured textual tool calls * fix(stream): suppress unknown textual tool calls * fix(stream): normalize responses textual tool calls * chore: ignore .claude/settings.local.json (per-user Claude Code permissions) * fix(opencode-go): route qwen3.x via claude messages + repair fixMissingToolResponses for Claude-shape upstreams (#2791) Integrated into release/v3.8.6 * fix: resolve npm install warnings — remove dead deps, relax engine constraint (#2792) Integrated into release/v3.8.6 * fix: register missing web-cookie validators (claude-web, gemini-web, copilot-web, t3-web) (#2793) Integrated into release/v3.8.6 * fix: Error: Unable to inspect existing database #2771 (#2795) Integrated into release/v3.8.6 * fix(oauth): repair Google loopback callback flow (#2796) Integrated into release/v3.8.6 * feat(logs): add clean history button (#2799) Integrated into release/v3.8.6 * [codex] home: restore settings-driven home layout and quota auto-refresh (#2800) Integrated into release/v3.8.6 * fix(gemini): emit signaturelessToolCallMode:text for GEMINI format models (#2801) Integrated into release/v3.8.6 * feat(modelSpecs): align opencode-go family with upstream provider limits (#2802) Integrated into release/v3.8.6 * chore: apply unit test fixes, polyfills, and environment precedence fixes * docs(agents): atualiza fluxos de release e triagem Expande os workflows de release para incluir auditoria de segurança, CHANGELOG completo por commits, quality gate obrigatório, homologação em VPS local, publicação oficial, deploy em Akamai e validação de artefatos. Reorganiza a triagem de features com arquivos permanentes por bucket, suporte a itens em andamento, regra de reclaim após 15 dias e novo tratamento para ideias viáveis catalogadas. Corrige a orientação de revisão de discussões para usar a ordem cronológica real dos comentários e respostas ao identificar a última atividade. * fix(lockout): classify Gemini Antigravity resource exhaustion as quota_exhausted * fix(reasoning): gate replay by interleaved field * docs(rule-16): permit human Co-authored-by, restrict only AI/bot trailers Rule #16 previously banned all `Co-Authored-By` trailers absolutely. That blocked the upstream-port workflows (`/port-upstream-features` and `/port-upstream-issues`), which must credit human upstream PR authors and issue reporters in OmniRoute commits. Refine the rule to ban only AI/bot-attributed trailers (Claude, GPT, Copilot, Bot; anthropic.com / openai.com / bot-owned noreply.github.com emails) while allowing standard human `Co-authored-by: Name <email>` attribution. Sync the rule across the source CLAUDE.md, the E2E shakedown doc note, and 41 i18n translations. * fix(gitlawb): add specialty validators for connection test — bypass /models probe GitLawB OpenGateway API (xiaomi-mimo compatible) does not expose a /models endpoint, causing validateOpenAILikeProvider to 404 on the initial probe and report 'Provider validation endpoint not supported'. Add specialty validators for both gitlawb and gitlawb-gmi that follow the same pattern as the existing xiaomi-mimo validator: skip GET /models, validate directly via POST /chat/completions with a minimal test message. Any 401/403 response means an invalid key; all other responses mean auth is OK. Fixes test-connection returning 404 for GitLawB providers. * test(gitlawb): add 12 unit tests for gitlawb and gitlawb-gmi specialty validators Covers success, auth failure (401/403), non-auth acceptance (400/422/429), network errors, and custom baseUrl overrides for both providers. * feat(gitlawb): serve models from static registry without API-unavailable warning GitLawB's OpenGateway API does not expose a /models endpoint per provider-path. Previously the models route fell through to the generic fallback which returned static catalog models with the misleading 'API unavailable — using local catalog' warning. Now gitlawb and gitlawb-gmi are handled as static model providers (same pattern as reka and qwen OAuth) — models are served from the provider registry without any warning, since all registered models are functional via POST /chat/completions. * refactor(gitlawb): extract shared opengateway validator factory, fix docs path in test - Extract gitlawb/gitlawb-gmi validators into buildOpengatewayValidator factory - Fix dockerignore-docs-coverage test: update stale docs/AUTO-COMBO.md -> docs/routing/AUTO-COMBO.md * fix(reasoning): guard interleaved capability lookup * feat(gitlawb): dynamic model fetch with gmi-cloud fallback Hybrid approach: - gitlawb (xiaomi-mimo): dynamic /models endpoint → 356 models - gitlawb-gmi (gmi-cloud): 404 fallback → local catalog gracefully Mimics Gitlawb/openclaude's model-routing pattern * i18n(pt-BR): complete missing translations and sync with en.json * feat(build): nix multi-OS package manager install (#2806) Integrated into release/v3.8.6 * fix(i18n): translate 144 new __MISSING__ pt-BR strings (#2816) Integrated into release/v3.8.6 * chore(docs): set coverage gate to 40/40/40/40 in CLAUDE.md Aligns the documented coverage gate with the v3.8.6 release decision (lowered from 75/75/75/70). Matches the threshold already set in package.json by the large feature PRs (planos 11-22). * fix(cli): respect PORT env var in serve command (#2845) Integrated into release/v3.8.6. * fix(deepseek-web): return 400 when client sends tools[] - chat.deepseek.com has no tool support (#2854) Integrated into release/v3.8.6. * fix(qoder): reject invalid/expired PATs returning Cosy 500 error (#2860) Integrated into release/v3.8.6. * fix(cli): register openclaw in tool-detector (#2833) (#2850) Integrated into release/v3.8.6. * fix(api): include noAuth providers in /v1/models catalog (#2798) (#2814) Integrated into release/v3.8.6. * fix(combo): resolve custom provider targets via combo name (#2778) (#2812) Integrated into release/v3.8.6. * fix(translator): strip safety_identifier in openai-responses cleanup (#2770) (#2809) Integrated into release/v3.8.6. * fix(quota): honor explicit per-connection preflight opt-out (#2831) (#2844) Integrated into release/v3.8.6. * fix(usage): un-invert GitHub Copilot Free/limited quota — limited_user_quotas is remaining (#2876) (#2881) Integrated into release/v3.8.6. * fix(nous-research): correct baseUrl to include /chat/completions (#2826) (#2835) Integrated into release/v3.8.6. * fix(opencode): qwen3.x max/plus models lack vision support (#2822) (#2836) Integrated into release/v3.8.6. * fix(translator): pass-through tool_search built-in tool type (#2766) (#2811) Integrated into release/v3.8.6. * fix(github): route claude-opus-4.6 via chat completions (#2821) Integrated into release/v3.8.6. * docs(oauth): add Windsurf login fix design (Phase 1 hotfix + Phase 2 Firebase OAuth) Two-phase plan to fix the broken Windsurf OAuth flow: - Phase 1: drop the dead app.devin.ai/editor/signin PKCE path, promote import-token from windsurf.com/show-auth-token as the primary path - Phase 2: port Firebase OAuth + RegisterUser flow from fendoushaonian/WindSurf-gRPC-API for full browser-based automation Spec only - no code changes yet. * docs(plan): Phase 1 windsurf login hotfix implementation plan 10 tasks covering: - TDD assertions for flowType + 410 Gone responses - Provider switch to import_token - Route handler retiring authorize/start-callback-server/poll-callback - OAuthModal UI override - i18n sync - Verification + PR steps * fix(cli): replace cli-table3 with hand-rolled formatter (#2752) (#2813) Integrated into release/v3.8.6. * fix(skills): skip interception for unregistered client-native tools (#2815) (#2817) Integrated into release/v3.8.6. * feat(sse): add RTK filters for kubectl, docker-build, composer, gh (#2824) Integrated into release/v3.8.6. * fix(geminiHelper): support rec.image content shape + warn on dropped remote URLs (refs #2807) (#2855) Integrated into release/v3.8.6. * fix(cli): allow nullable/optional apiKey in cliMitmStartSchema (#2857) Integrated into release/v3.8.6. * fix(combo): preserve system messages during context handoff summary generation (#2865) Integrated into release/v3.8.6. * fix: wire CLIProxyAPI fallback settings into chatCore routing engine (#2866) Integrated into release/v3.8.6. * fix(usage): add opencode quota fetcher (#2852) (#2867) Integrated into release/v3.8.6. * feat(claude): default xhigh support for newer Opus models (#2874) Integrated into release/v3.8.6. * fix(cli): restore omniroute logs command stream (#2756) (#2810) Integrated into release/v3.8.6. * fix(combo): normalize upstream Headers for Node 24 undici interop (#2751) (#2823) Integrated into release/v3.8.6. * Rename proxy log Public IP to Client IP (#2880) Integrated into release/v3.8.6. * fix(claude): preserve max effort for supported models (#2875) Integrated into release/v3.8.6. * fix(oauth): switch windsurf provider to import_token flow The PKCE auth URL targeting app.devin.ai/editor/signin returns 404 post-rebrand. Until Phase 2 ports Firebase OAuth + RegisterUser, the only supported path is import-token via windsurf.com/show-auth-token. - windsurf.ts: drop buildAuthUrl, set flowType=import_token - generateAuthData returns supported:false + helpful error for windsurf/devin-cli - tests: assert flowType + disabled stub * fix(oauth): return 410 Gone for retired windsurf/devin-cli PKCE actions start-callback-server, authorize, and poll-callback (GET + POST) now return 410 Gone with a pointer to /import-token. The 410 short-circuit runs before auth so the response is honest about the action being permanently gone, not gated. Codex PKCE flow unchanged. Tests: 5 new assertions cover GET + POST 410 paths and a Codex regression check. * refactor(oauth): annotate retired PKCE fields in WINDSURF_CONFIG No behaviour change - comment-only update documenting that authorizeUrl, codeChallengeMethod, callbackPort, callbackPath, apiServerUrl, and exchangePath are no longer consumed. Active fields (inferenceUrl, showAuthTokenUrl, firebaseApiKey, ideName) called out separately. * fix(cli,docs): use requireCliToolsAuth in logs route + document OPENCODE quota env Post-merge contract fixes for v3.8.6: - src/app/api/cli-tools/logs/route.ts (#2810) now uses the shared requireCliToolsAuth guard (param renamed req->request) to satisfy the cli-tools-auth-hardening contract test. - Document OMNIROUTE_OPENCODE_QUOTA_URL (#2867) in docs/reference/ENVIRONMENT.md to satisfy the env/docs sync contract. * fix(dashboard): force import-token panel for windsurf/devin-cli Phase 1 hotfix: hide the 'Browser Login' tab and start in Paste API Key mode. Removes windsurf/devin-cli from PKCE_CALLBACK_SERVER_PROVIDERS so no callback server is started for them. Codex still uses the PKCE flow. The 'Get token' link continues to point at windsurf.com/show-auth-token via the existing supportsTokenPaste form copy. * fix(oauth): windsurf import-token mapTokens signature mismatch The route at `src/app/api/oauth/[provider]/[action]/route.ts` invokes `providerData.mapTokens({ accessToken: token })` (object), matching the cursor/kiro signature. The windsurf provider was declared with `mapTokens(token: string)` instead, so the entire object was stored as `accessToken`. When the connection record reached the SQLite layer it crashed with: SQLite3 can only bind numbers, strings, bigints, buffers, and null Fix by aligning windsurf's `mapTokens` signature with the route caller and the cursor/kiro convention. Also dedupe a copy-pasted second `if (action === "import-token")` block in the route handler — the second block was unreachable but identical to the first. Adds two regression tests asserting that `provider.mapTokens({ accessToken })` returns a string `accessToken` for both windsurf and devin-cli, so a future signature drift trips the gate instead of the SQLite bind error in production. * feat(compression): expand pt-BR pack with troglodita rules (15 → 49) (#2818) Integrated into release/v3.8.6 * fix(sse): repair RTK engine defaults so dedup and direct calls work (#2825) Integrated into release/v3.8.6 * fix(mcp): redirect console.log/warn to stderr in --mcp stdio mode (#2840) Integrated into release/v3.8.6 * fix(gemini-cli): prefer real project IDs over default-project (#2841) Integrated into release/v3.8.6 * fix(opencode-go): add provider limits quota fetcher (#2861) Integrated into release/v3.8.6 * Audit & add web cookie providers: fix 4 missing registry entries + DuckDuckGo (#2862) Integrated into release/v3.8.6 * fix(antigravity): harden signatureless tool history (#2878) Integrated into release/v3.8.6 * fix: provider model sync pruning and dynamic antigravity MITM proxy mappings (#2886) Integrated into release/v3.8.6 * feat(usage): per-API-key token limits scoped to model/provider/global (#2888) Integrated into release/v3.8.6 * fix(audio): build multipart body manually to preserve Content-Type (#2842) Integrated into release/v3.8.6 * refactor: remove agent skill documentation files and streamline maintenance workflows * test(stabilization): resolve unit test failures in blackbox-web, schema-coercion, translator-helper-branches, usage-service-hardening, and audio-transcription * fix(security): mitigate Socket.dev supply-chain findings + secrets opt-in + minimal build profile (#2863) (#2871) Two real security gaps closed and four cosmetic Socket.dev fingerprints removed. See docs/security/SOCKET_DEV_FINDINGS.md for the per-finding maintainer attestation. Real bugs fixed: - cloudSync: HMAC verification of `X-Cloud-Sig` + opt-in `OMNIROUTE_CLOUD_SYNC_SECRETS=true` before overwriting `accessToken` / `refreshToken` / `providerSpecificData` from a remote response. Closes the silent-credential-swap surface (a misconfigured or hostile CLOUD_URL could previously replace local tokens unverified). - Zed import: split into 2-step `/discover` + `/import` flow. `/import` now requires `confirmedAccounts: [{ service, account, fingerprint }]` and re-reads the keychain server-side to filter by fingerprint, so a tampered discover response cannot trick the endpoint into saving an unrelated token. Cosmetic Socket.dev mitigations: - runElevatedPowerShell writes the elevated payload to a per-call temp `.ps1` file (mode 0o600) and references it via `-File`. Removes the textbook `-EncodedCommand <base64utf16le>` pattern flagged as malware by Socket's AI classifier. - Maintainer attestation `SECURITY-AUDITOR-NOTE:` blocks added at every flagged call site pointing to `docs/security/SOCKET_DEV_FINDINGS.md`. Build-time hardening: - `OMNIROUTE_BUILD_PROFILE=minimal` (`npm run build:secure`) physically removes the four sensitive modules from the standalone bundle via webpack `NormalModuleReplacementPlugin`. Stubs throw `FeatureDisabledError` at runtime. Intended for the `omniroute-secure` artifact. Tests: - 24 new unit tests in `tests/unit/security/` covering the wrapper builder, HMAC verification (4 cases), credential fingerprint determinism (5 cases), confirmedAccounts validation + fingerprint filtering (6 cases), and the minimal-build stubs (5 cases). Docs: - New `docs/security/SOCKET_DEV_FINDINGS.md` — per-finding attestation. - New `socket.yml` — Socket.dev v2 config pointing at the attestation. - Updated `SECURITY.md` — supply-chain scanner section. - Updated `.env.example` — three new env vars documented. Backwards compatibility: - Cloud sync token overwrite is OFF by default. Users who relied on it must set `OMNIROUTE_CLOUD_SYNC_SECRETS=true`. Breaking change documented in CHANGELOG. - Zed import 2-step is the new default; legacy 1-step preserved behind `OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true` and will be removed in v3.9. Closes #2863 * fix(security): redact public Firebase Web key from windsurf spec; doc SHA-256 cache-key rationale (#2894) Two security-scanning findings on release/v3.8.6: - Secret-scanning alert 7 (google_api_key): the windsurf login-fix design spec embedded the literal public Firebase Web API key on two lines. Firebase Web API keys are non-sensitive by design (they identify the project; access is gated by Firebase Security Rules + key restrictions), but the literal trips secret scanning. Redacted to a placeholder; the embedded default still goes through resolvePublicCred per rule #11. - Code-scanning alert 261 (js/insufficient-password-hash): tokenCacheKey() uses SHA-256 to derive an in-memory cache key from the session token, not for password-at-rest storage. Added a comment documenting why CWE-916 KDFs do not apply (false positive). * fix(ci): resolve release/v3.8.6 gate failures (docs-sync, any-budget, pack-artifact) (#2895) * fix(ci): resolve release/v3.8.6 gate failures (docs-sync, any-budget, pack-artifact) Three CI gates failed on release/v3.8.6 (run 26630300877): - docs-sync: CHANGELOG had a spurious "## [3.8.6-patch]" section above "## [3.8.6]", so the latest release no longer matched package.json (3.8.6) and the 41 i18n CHANGELOG mirrors were flagged as missing that section. Fold the lone #2752 entry into [3.8.6] and drop the patch heading. - any-budget:t11: open-sse/handlers/chatCore.ts regressed to 1 explicit `any` (budget 0). Type the persist callback arg as Record<string, unknown>, which matches runWithOnPersist's RefreshPersistFn contract exactly. - pack-artifact: open-sse/utils/setupPolyfill.ts ships via package.json "files" (bin/omniroute.mjs imports it at startup) but was missing from the pack policy allowlist. Allow it and add a regression test. * fix(security): redact public Firebase Web key from windsurf spec Redact the literal public Firebase Web API key (secret-scanning #7) to a placeholder, mirroring the redaction on release/v3.8.6 (PR #2894) and the windsurf fix branch. Non-sensitive public Web key; trips secret scanning. * feat(combo): Zero-Latency Combos (Hedging, Proactive Compression, Predictive TTFT) (#2868) * feat(combo): implement zero-latency combo optimizations (hedging, proactive compression, predictive TTFT) * fix(combo): fix predictive TTFT skip logic and unhandled promise rejections --------- Co-authored-by: Automation <automation@omniroute> * feat: implement automated skill workflows and update system configuration and validation schemas * test: eliminate dynamic cast warnings in cloud-sync unit test * test: isolate services-branch-hardening database directory to avoid concurrency issues * feat(providers): add 7 new web-cookie providers + research catalog + discovery tool New providers: - huggingchat: free LLM chat via huggingface.co/chat (no subscription) - phind: free dev-focused AI chat via phind.com/api/agent - poe-web: multi-model chat via poe.com GraphQL (p-b cookie) - venice-web: privacy-focused AI chat via venice.ai (session cookie) - v0-vercel-web: Vercel v0 code gen via v0.dev (session cookie) - kimi-web: Moonshot Kimi chat via kimi.moonshot.cn (session cookie) - doubao-web: ByteDance Doubao chat via doubao.com (session cookie) Additional: - Research catalog: docs/research/UNLIMITED_LLM_ACCESS.md - Discovery tool design + stub: src/lib/discovery/ + migration 073 - Unit tests: 33 tests for all 7 providers - Shared helpers consolidated in error.ts (slop cleanup) - All registered in WEB_COOKIE_PROVIDERS + providerRegistry + webSessionCredentials Closes #2885 * fix(typecheck): resolve typecheck errors in combo spec and compression modules * feat(api,oauth): add `agy` (Antigravity CLI) standalone provider with CLI token import (#2899) Add a standalone OAuth provider `agy` (Antigravity CLI) next to gemini-cli/antigravity. It reuses the antigravity inference backend (identical Google client_id + daily-cloudcode-pa.googleapis.com endpoint, executor and token-refresh) but ships its own model catalog — including the Claude models the backend exposes (claude-opus-4-6-thinking, claude-sonnet-4-6) — its own account pool, and four ways to connect: - token-file import (paste/upload the agy oauth token JSON) - auto-detect a local CLI login (~/.gemini/antigravity-cli/antigravity-oauth-token) - browser OAuth (via the shared OAuthModal Google loopback flow) - bulk / ZIP import New routes: POST /api/providers/agy-auth/{import,import-bulk,zip-extract,apply-local}. Catalog pinned from the live :fetchAvailableModels endpoint. Docs (openapi.yaml, ENVIRONMENT.md, .env.example, CHANGELOG) updated; new unit tests for registration, the token parser, and route auth-hardening. * fix(security): redact public Firebase Web key from windsurf spec (#2896) Redact the literal public Firebase Web API key (secret-scanning #7) to a placeholder. Firebase Web API keys are non-sensitive by design but the literal trips GitHub secret scanning. Mirrors the redaction landed on release/v3.8.6 (PR #2894). Embedded default still flows through resolvePublicCred (rule #11). * Pr 2871 (#2897) * fix(security): mitigate Socket.dev supply-chain findings + secrets opt-in + minimal build profile (#2863) Two real security gaps closed and four cosmetic Socket.dev fingerprints removed. See docs/security/SOCKET_DEV_FINDINGS.md for the per-finding maintainer attestation. Real bugs fixed: - cloudSync: HMAC verification of `X-Cloud-Sig` + opt-in `OMNIROUTE_CLOUD_SYNC_SECRETS=true` before overwriting `accessToken` / `refreshToken` / `providerSpecificData` from a remote response. Closes the silent-credential-swap surface (a misconfigured or hostile CLOUD_URL could previously replace local tokens unverified). - Zed import: split into 2-step `/discover` + `/import` flow. `/import` now requires `confirmedAccounts: [{ service, account, fingerprint }]` and re-reads the keychain server-side to filter by fingerprint, so a tampered discover response cannot trick the endpoint into saving an unrelated token. Cosmetic Socket.dev mitigations: - runElevatedPowerShell writes the elevated payload to a per-call temp `.ps1` file (mode 0o600) and references it via `-File`. Removes the textbook `-EncodedCommand <base64utf16le>` pattern flagged as malware by Socket's AI classifier. - Maintainer attestation `SECURITY-AUDITOR-NOTE:` blocks added at every flagged call site pointing to `docs/security/SOCKET_DEV_FINDINGS.md`. Build-time hardening: - `OMNIROUTE_BUILD_PROFILE=minimal` (`npm run build:secure`) physically removes the four sensitive modules from the standalone bundle via webpack `NormalModuleReplacementPlugin`. Stubs throw `FeatureDisabledError` at runtime. Intended for the `omniroute-secure` artifact. Tests: - 24 new unit tests in `tests/unit/security/` covering the wrapper builder, HMAC verification (4 cases), credential fingerprint determinism (5 cases), confirmedAccounts validation + fingerprint filtering (6 cases), and the minimal-build stubs (5 cases). Docs: - New `docs/security/SOCKET_DEV_FINDINGS.md` — per-finding attestation. - New `socket.yml` — Socket.dev v2 config pointing at the attestation. - Updated `SECURITY.md` — supply-chain scanner section. - Updated `.env.example` — three new env vars documented. Backwards compatibility: - Cloud sync token overwrite is OFF by default. Users who relied on it must set `OMNIROUTE_CLOUD_SYNC_SECRETS=true`. Breaking change documented in CHANGELOG. - Zed import 2-step is the new default; legacy 1-step preserved behind `OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true` and will be removed in v3.9. Closes #2863 * feat: implement automated skill workflows and update system configuration and validation schemas * test: eliminate dynamic cast warnings in cloud-sync unit test * test: isolate services-branch-hardening database directory to avoid concurrency issues * chore(docs): refresh generated docs collection index Update the generated Fumadocs browser collection mapping to keep documentation imports in sync with the current docs structure. * docs: update generated browser docs collection manifest Refresh the generated Fumadocs browser collection mapping so the docs site can resolve the current documentation files correctly. --------- Co-authored-by: OpenClaw <openclaw@kuzhomesrv.local> Co-authored-by: Dmitry Kuznetsov <139351986+dmitry@users.noreply.local> Co-authored-by: KuzyaBot <kuzya@local> Co-authored-by: JeferssonLemes <jeferssondev@gmail.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: akarray <akarray@users.noreply.github.com> Co-authored-by: Apostol Apostolov <theapoapostolov@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: Dmitry Kuznetsov <dmitry@kuznetsov.me> Co-authored-by: Nikolay Alafuzov <alafuzov_nn@rusklimat.ru> Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: Ronaldo Davi <alltomatos@users.noreply.github.com> Co-authored-by: levonk <277861+levonk@users.noreply.github.com> Co-authored-by: Lenine Júnior <lenine@engrene.com.br> Co-authored-by: Annas Alghoffar <aag.annas@gmail.com> Co-authored-by: Tushar Agarwal <76201310+Tushar49@users.noreply.github.com> Co-authored-by: GreatLiu <eurasiaxz@qq.com> Co-authored-by: yuna amelia <230527278+yunaamelia@users.noreply.github.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Container <78986709+disonjer@users.noreply.github.com> Co-authored-by: nickwizard <35692452+nickwizard@users.noreply.github.com> Co-authored-by: Rajvardhan Patil <rajvardhanpatil7890@gmail.com> Co-authored-by: Raxxoor <manker_lol@hotmail.com> Co-authored-by: Muhammad Mugni Hadi <mugnimaestra3@gmail.com> Co-authored-by: mi <123757457+soyelmismo@users.noreply.github.com> Co-authored-by: Automation <automation@omniroute> |