From 555b21d296d950865a59d9371c8f850bc68ca300 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Fri, 26 Jun 2026 02:51:06 -0300 Subject: [PATCH] Release v3.8.37 (#5053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(release): open v3.8.37 development cycle * chore(ci): harden release flow — ratchet decoupling, fast-path drift gates, build-scope guard, heap default (#5054) Implements improvements 1-4 from the v3.8.36 release benchmark (_tasks/release-bench/v3.8.36/PLANO-MELHORIA.md): 1. Quality Ratchet decoupled from flaky coverage (ci.yml): the shard→coverage→ratchet chain meant a single flaky Coverage Shard SKIPPED the whole Quality Ratchet on the release PR (v3.8.36 #4854), so cycle drift only surfaced post-merge in #5029. The job now runs on !cancelled(); coverage download is continue-on-error and the ratchet runs --allow-missing, so the DETERMINISTIC gates (eslint/complexity/cognitive/duplication/ codeql) stay blocking even when coverage is unavailable. 2. Fast-path drift gates (quality.yml PR→release): added check:complexity, check:cognitive-complexity, and a new lightweight check:pack-policy (pack-artifact unexpected-files check WITHOUT a build, via --policy-only) so drift + stray-tarball-file regressions are caught/rebaselined PER-PR instead of cascading onto the release PR. 3. Build heap default 4096→8192 MB (build-next-isolated.mjs): the clean graph peaks ~3.9 GB and brushed the old 4 GB ceiling; 8 GB gives headroom. Comment notes heap is NOT the fix for a poisoned scope (run check:build-scope instead). 4. check:build-scope gate (new): fails if .ts/.tsx/.js/.jsx files in the tsconfig scope exceed a threshold — catches worktrees/cruft leaking into the build scope (the v3.8.36 OOM root cause: 355,215 vs 4,547 files) BEFORE it detonates next build. Wired into the fast-path. * fix(auth): only trust forwarding headers from loopback TCP peers (#4689) Integrated into release/v3.8.37 — loopback-gated forwarding headers (IP spoofing fix). Cherry-picked onto current release tip; ipUtils.test.ts 9/9 green. * fix(codex): treat OAuth 401 as unrecoverable refresh failure (#4686) Integrated into release/v3.8.37 — codex OAuth 401 treated as unrecoverable refresh. Cherry-picked onto release tip; token-refresh-service.test.ts 38/38 green. * fix(translator): preserve reasoning_effort for non-Copilot Responses clients (#4688) Integrated into release/v3.8.37 — preserve reasoning_effort for non-Copilot Responses clients. Cherry-picked onto release tip; tests 47/47 green. * fix(translator): coerce tool descriptions to strings in OpenAI normalization (#4675) Integrated into release/v3.8.37 — coerce tool descriptions to strings in OpenAI normalization. Cherry-picked onto release tip; tests 3/3 green. * feat(sse): x-omniroute-strip-reasoning header to drop reasoning_content (#4678) Integrated into release/v3.8.37 — x-omniroute-strip-reasoning header. Cherry-picked onto release tip (resolved chatCore.ts/headers.ts adjacency conflict, kept resolveCompressionHeader + isStripReasoningRequested); tests 8/8 green. * fix(combo): flatten Anthropic tool messages + tool history to prevent upstream 503 (#4648) Integrated into release/v3.8.37 — flattenToolHistory helper (combo anti-503). Cherry-picked onto release tip; tests 9/9 green. * feat(headroom): proxy lifecycle management + dashboard UI (Docker sidecar supported) (#4649) Integrated into release/v3.8.37 — headroom proxy lifecycle (status/start/stop, local-only + spawn-capable per Rules #15/#17). Cherry-picked onto release tip; lifecycle 7/7 + route-guard 43/43 + check:cycles green. * feat(cli): multi-model support for Factory Droid CLI (#4682) Integrated into release/v3.8.37 — Factory Droid multi-model support. Cherry-picked onto release tip (kept readJsoncConfig + droidCustomModels imports); droid-custom-models 11/11 green. * fix(providers): require Default Model in compatible-provider API-key setup (#4641) Integrated into release/v3.8.37 — require Default Model in compatible-provider API-key setup. Cherry-picked fix + test-move onto release tip (kept release providerSpecificData + QuotaScrapingFields; fixed moved-test import path; baseline rebaseline unneeded, 865<866); UI test 2/2 green. * fix(dashboard): stop double-masking already-masked API key in list (E2E 3/9 regression) (#4671) Integrated into release/v3.8.37 — render server-masked key verbatim (drop redundant maskKey call). Note: release's maskKey already guards '****' (since v3.8.34), so this is a safe simplification; added a contract test pinning the **** passthrough invariant (2/2 green, would fail against the pre-guard maskKey = the historical double-mask bug). * chore(quality): rebaseline file-size for rc17 PR batch drift Own growth from the merged rc17 PRs (#4678/#4686/#4688) at existing chokepoints — cohesive, not extractable: - open-sse/handlers/responseSanitizer.ts 1103->1122 (SanitizeOpenAIResponseOptions + stripReasoning, #4678) - open-sse/services/tokenRefresh.ts 2070->2090 (codex 401 unrecoverable-refresh guard, #4686) - tests/unit/token-refresh-service.test.ts 1322->1353 (401 regression case, #4686) - tests/unit/translator-openai-responses-req.test.ts 1047->1050 (reasoning_effort assertion, #4688) * docs(env): document HEADROOM_URL in .env.example + ENVIRONMENT.md The headroom proxy lifecycle (#4649) reads HEADROOM_URL (src/lib/headroom/detect.ts, default http://localhost:8787) but it was missing from the env contract, tripping check:env-doc-sync. Adds the var to both .env.example (commented, has a default) and the Proxy Health table in ENVIRONMENT.md. * fix(sse): stream writer mock abort() returns a Promise (#4788) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(cli): fall back to default data dir when DATA_DIR is not writable (#4767) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(oauth): verify Cursor installation on Linux before auto-import (#4770) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): track Ollama streaming usage from raw NDJSON chunks (#4754) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): strip enumDescriptions from antigravity tool schema (#4740) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): include low-level cause details in formatProviderError (#4741) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(translator): strip x-anthropic-billing-header in claude-to-openai (#4728) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): gate Kiro image attachments behind a Claude-capability check (#4763) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): read Antigravity usage from the response.usageMetadata envelope (#4785) Integrated into release/v3.8.37 — Antigravity response.usageMetadata envelope. Cherry-picked onto release tip (resolved test-tail adjacency with #4754 Ollama block); usage-extractor 23/23 green. * fix(api): fall back to existing access token for any OAuth provider on refresh failure (#4786) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(cli): verify launchd registration + skip self-SIGTERM in macOS autostart (#4765) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(executors): anthropic-compatible-* gateways get Bearer alongside x-api-key (#4729) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): json_schema fallback for OpenAI-compatible providers (#4766) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): use workos auth token shape for cline (#4787) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * feat(sse): parse Gemini CLI 429 retryDelay from structured RetryInfo (#4738) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; tests green. * fix(sse): finalize tool_calls finish_reason on early stream end in OpenAI Responses translator (#4764) Integrated into release/v3.8.37 — computeFinishReason finalizes tool_calls on early stream end (Responses translator). Cherry-picked onto release tip; responses-translation-fixes 29/29 green. * test(sse): golden-lock provider.ts translate-path across all providers (#4734) Integrated into release/v3.8.37 — golden-lock for provider.ts translate-path. Cherry-picked onto release tip; snapshot regenerated against the current provider set (UPDATE_GOLDEN=1, 167 entries); golden test 3/3 deterministic. * chore(quality): rebaseline file-size for rc17 leva2 PR batch drift Own growth from the merged leva2 PRs (cohesive, not extractable): - src/lib/usage/providerLimits.ts 950->955 (#4786) - open-sse/executors/default.ts NEW frozen @828 (#4729 + #4766 + #4787 header branches) - open-sse/translator/request/openai-to-kiro.ts 807->814 (#4763) - open-sse/translator/response/openai-responses.ts 923->937 (#4764) - tests/unit/executor-default-base.test.ts 1339->1440 (#4766) - tests/unit/translator-openai-to-kiro.test.ts 918->980 (#4763) * fix(dashboard): align Engine Combos editor engines with API schema (#4955) (#5062) The named-combos pipeline dropdown offered four engines (headroom, session-dedup, ccr, llmlingua) that stackedPipelineStepSchema rejects, so selecting one made PUT /api/context/combos/[id] return HTTP 400 while saveCombo swallowed the non-OK response (if (!res.ok) return). Editing the default 'Standard Savings' combo and changing an engine reproduced the 400. - Add canonical STACKED_PIPELINE_ENGINE_INTENSITIES next to the schema as the single source of truth; the client dropdown imports it so it can never drift from the discriminated union the API validates against. - Surface save errors and empty-name/empty-pipeline validation in the editor instead of failing silently. - Add a parity unit test asserting the UI engine map equals the schema union and that every (engine, intensity) the UI emits is accepted. * fix(sse): filter nameless hosted tools when converting Responses API to Chat format (#4789) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(dashboard): keep desktop sidebar visible via explicit CSS class (#4812) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): strip enumDescriptions from Antigravity tool schemas (#4813) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(dashboard): resolve passthrough model aliases by providerId in ModelSelectModal (#4815) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(oauth): allow per-connection refresh lead-time override via providerSpecificData.refreshLeadMs (#4818) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): strip X-Stainless-* headers and normalize SDK User-Agent for OpenAI-compatible endpoints (#4820) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): strip Gemini built-in tools when functionDeclarations present in Antigravity envelope (#4821) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(api): surface a Docker-localhost hint on provider-node validation connection errors (#4822) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): resolve bare model names to connection defaultModel before upstream calls (#4825) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(build): trace-include sql.js sql-wasm.wasm in standalone bundle (#4839) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): strip Composer <|final|> sentinel markers leaking after Composer reasoning (#4842) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(config): sync full SiliconFlow model list into registry (#4844) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): close reasoning before message content in Responses stream (#4848) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): reject unsupported Kiro [1m] context suffix (#4816) Integrated into release/v3.8.37 — cherry-picked onto release tip; test-tail conflict with #4763 resolved (kept both image + [1m] test blocks); CHANGELOG re-merged; 29/29 green. * fix(db): validate HuggingFace tokens via whoami-v2 auth probe (#4819) Integrated into release/v3.8.37 — defining commit re-homed onto the god-file-split validation module (validateHuggingFaceProvider in validation/openaiFormat.ts + map wiring); 115/115 green. * fix(sse): make anthropic-version default-guard case-insensitive (#4823) Integrated into release/v3.8.37 — conflict with #4729 Bearer-fallback resolved (kept both Bearer fallback + case-insensitive anthropic-version guard); 48/48 green. * fix(sse): sanitize Kiro tool schemas to avoid 400 "Improperly formed request" (#4847) Integrated into release/v3.8.37 — conflict in kiro-to-openai.ts resolved (kept release fallbackToolCallId + adopted #1375 toolNameMap remap); 7/7 green. * feat(sse): add GPT-4 to the GitHub Copilot provider (#4798) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(sse): add GPT-4o mini to GitHub Copilot provider (#4797) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(api): add MiniMax-M3 pricing row (#4814) Integrated into release/v3.8.37 — pricing row re-homed onto god-file-split pricing/regional.ts (pricing.ts is now a barrel); 4/4 green. * fix(cli): save runtime deps with --save-exact so a sibling install can't prune them (#4841) Integrated into release/v3.8.37 — trayRuntime conflict resolved (kept release SYSTRAY_SPEC + added --save-exact); 2/2 green. * fix(sse): preserve required fields in antigravity tool schemas (#4843) Integrated into release/v3.8.37 — conflict resolved (kept #4740/#4813 enumDescriptions strip + typed normalizeSchemaTypes, added required-preservation helpers; test-tail merged keeping both enumDescriptions + required tests); 7/7 green. * chore(quality): rebaseline file-size for rc17b leva3 PR batch drift * fix(sse): strip reasoning blobs from agentic context to prevent O(n^2) token growth (#4849) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): unwrap Qoder HTTP 200 SSE error envelope so fallback can trigger (#4850) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): strip temperature for Claude models with extended thinking (#4853) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): emit valid concatenable kiro tool_calls.arguments deltas (#4855) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(sse): add toggleable tool-source diagnostics (#4856) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): redact api key from the AUTH debug log in the chat handler (#4858) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): forward AI SDK image parts in Responses translator (#4859) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): resolve custom combos by id and case-insensitive name (#4446) (#4869) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): exclude WS bridge controller-closed error from provider breaker (#4602) (#4870) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(providers): add xAI Grok inbound translators and thinking patcher (#4910) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(embeddings): add dimensions override field to embedding combos (#4913) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * feat(oauth): Codex bulk-import endpoint — POST /api/oauth/codex/import (#4914) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(antigravity): retry transient upstream failures (#4941) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): surface malformed HTTP-200 upstream responses (#4942) Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. * fix(sse): normalize Codex custom tools (apply_patch) to { input: string } schema (#4862) Integrated into release/v3.8.37 — conflict in request/openai-responses.ts resolved (kept #4789 nameless-tool skip + added #1007 custom-tool {input:string} normalization); 48/48 green incl. #4789/#4859 regression. * fix(sse): dense, deterministic output ordering in Responses API response.completed (#4906) Integrated into release/v3.8.37 — manual integration with #4862 in response/openai-responses.ts (custom-tool funcItem + dense recordCompletedItem). Fixed a latent #4848 interaction: the close-reasoning-before-message guard force-closed -tag reasoning prematurely, which dense output (#4906) then snapshotted as a partial buffer ("plan" vs "planning") — scoped the guard to native reasoning_content (!inThinking) in BOTH transformer + translator paths. Full Responses suite 203/203 green incl. #4848/#4862 regression. * feat(sse): auto-promote successful combo model to position #1 (#4852) Integrated into release/v3.8.37 — dropped the stale file-size-baseline.json hunk (re-derived against the rc17b rebaseline); code+test applied clean; 13/13 green. * feat(providers): add Pioneer AI (Fastino Labs) provider (#4909) Integrated into release/v3.8.37 — providers.ts apikey block re-homed onto god-file-split src/shared/constants/providers/apikey/frontier-labs.ts (inline APIKEY_PROVIDERS no longer exists); registry/pioneer + providers/index.ts applied clean; 6/6 green. * add DGrid AI gateway provider (#4931) Integrated into release/v3.8.37 — rebased the contributor's commit onto the release tip; providers.ts god-file-split conflict resolved by relocating the dgrid APIKEY_PROVIDERS entry into apikey/gateways.ts; CHANGELOG added. 7/7 green. Thanks @dgridOP! * chore(quality): rebaseline file-size for rc17b leva4 PR batch drift * docs(routing): sync combo strategy docs for Fusion (17 strategies) (#5067) Fusion (16th strategy, panel fan-out + judge synthesis) and headroom shipped but the strategy-count docs were stale (14/15) and omitted both. Update every combo-strategy reference to the canonical 17, add fusion + headroom to all strategy tables, and add a dedicated Fusion section to AUTO-COMBO.md documenting judgeModel / fusionTuning config + an example. - CLAUDE.md, README.md, FEATURES.md, RESILIENCE_GUIDE.md, ARCHITECTURE.md, OPEN_SSE_ARCHITECTURE.md, OMNIROUTE_VS_ALTERNATIVES.md, docs/README.md, request-pipeline.mmd: 14/15 -> 17, list fusion + headroom - docs/routing/AUTO-COMBO.md: strategy table + new Fusion strategy section - docs/openapi.yaml: add reset-window, headroom, fusion to the strategy enum * fix(oauth): classify /api/oauth/cursor/auto-import as local-only (route-guard) (#5070) The Cursor auto-import route runs execFile("which", ["cursor"]) to verify a local Cursor install before importing credentials — a child-process spawn. The check:route-guard-membership gate (Hard Rules #15/#17) flagged it as an unclassified spawn-capable route: reachable past the loopback gate, an RCE-via-tunnel surface (a leaked JWT over a tunnel could trigger the spawn). Classify the specific path in LOCAL_ONLY_API_PREFIXES so loopback enforcement runs unconditionally before any auth check. Scoped to the exact path — the rest of /api/oauth/ (browser redirect/callback flows) stays remote-reachable. TDD: added a failing-then-passing assertion in route-guard-local-prefix.test.ts (classification + an over-broadening guard proving sibling OAuth paths stay remote). check:route-guard-membership now reports 0 new gaps. * chore(release): v3.8.37 — 2026-06-26 --------- Co-authored-by: dgridOP --- .env.example | 6 + .github/workflows/ci.yml | 21 +- .github/workflows/quality.yml | 12 + .gitignore | 2 + CHANGELOG.md | 156 + CLAUDE.md | 4 +- README.md | 42 +- bin/cli/runtime/nativeDeps.mjs | 13 +- bin/cli/runtime/trayRuntime.ts | 6 +- bin/cli/tray/autostart.mjs | 85 +- config/quality/complexity-baseline.json | 5 +- config/quality/file-size-baseline.json | 50 +- config/quality/quality-baseline.json | 15 +- docs/README.md | 2 +- docs/architecture/ARCHITECTURE.md | 8 +- docs/architecture/RESILIENCE_GUIDE.md | 2 +- docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md | 2 +- docs/diagrams/request-pipeline.mmd | 2 +- docs/frameworks/OPEN_SSE_ARCHITECTURE.md | 4 +- docs/guides/FEATURES.md | 2 +- docs/i18n/ar/CHANGELOG.md | 156 + docs/i18n/az/CHANGELOG.md | 156 + docs/i18n/bg/CHANGELOG.md | 156 + docs/i18n/bn/CHANGELOG.md | 156 + docs/i18n/cs/CHANGELOG.md | 156 + docs/i18n/da/CHANGELOG.md | 156 + docs/i18n/de/CHANGELOG.md | 156 + docs/i18n/es/CHANGELOG.md | 156 + docs/i18n/fa/CHANGELOG.md | 156 + docs/i18n/fi/CHANGELOG.md | 156 + docs/i18n/fr/CHANGELOG.md | 156 + docs/i18n/gu/CHANGELOG.md | 156 + docs/i18n/he/CHANGELOG.md | 156 + docs/i18n/hi/CHANGELOG.md | 156 + docs/i18n/hu/CHANGELOG.md | 156 + docs/i18n/id/CHANGELOG.md | 156 + docs/i18n/in/CHANGELOG.md | 156 + docs/i18n/it/CHANGELOG.md | 156 + docs/i18n/ja/CHANGELOG.md | 156 + docs/i18n/ko/CHANGELOG.md | 156 + docs/i18n/mr/CHANGELOG.md | 156 + docs/i18n/ms/CHANGELOG.md | 156 + docs/i18n/nl/CHANGELOG.md | 156 + docs/i18n/no/CHANGELOG.md | 156 + docs/i18n/phi/CHANGELOG.md | 156 + docs/i18n/pl/CHANGELOG.md | 156 + docs/i18n/pt-BR/CHANGELOG.md | 156 + docs/i18n/pt/CHANGELOG.md | 156 + docs/i18n/ro/CHANGELOG.md | 156 + docs/i18n/ru/CHANGELOG.md | 156 + docs/i18n/sk/CHANGELOG.md | 156 + docs/i18n/sv/CHANGELOG.md | 156 + docs/i18n/sw/CHANGELOG.md | 156 + docs/i18n/ta/CHANGELOG.md | 156 + docs/i18n/te/CHANGELOG.md | 156 + docs/i18n/th/CHANGELOG.md | 156 + docs/i18n/tr/CHANGELOG.md | 156 + docs/i18n/uk-UA/CHANGELOG.md | 156 + docs/i18n/ur/CHANGELOG.md | 156 + docs/i18n/vi/CHANGELOG.md | 156 + docs/i18n/zh-CN/CHANGELOG.md | 156 + docs/openapi.yaml | 5 +- docs/reference/ENVIRONMENT.md | 1 + docs/routing/AUTO-COMBO.md | 68 +- electron/package-lock.json | 4 +- electron/package.json | 2 +- next.config.mjs | 4 + open-sse/config/providers/index.ts | 4 + .../config/providers/registry/dgrid/index.ts | 15 + .../config/providers/registry/github/index.ts | 7 + .../providers/registry/pioneer/index.ts | 41 + .../providers/registry/siliconflow/index.ts | 70 +- open-sse/config/toolCloaking.ts | 51 +- open-sse/executors/antigravity.ts | 109 +- open-sse/executors/base.ts | 54 + open-sse/executors/codex.ts | 15 +- open-sse/executors/cursor.ts | 23 +- open-sse/executors/default.ts | 71 +- open-sse/executors/gemini-cli.ts | 37 +- open-sse/executors/kiro.ts | 128 +- open-sse/executors/qoder.ts | 112 +- open-sse/handlers/chatCore.ts | 95 +- open-sse/handlers/chatCore/headers.ts | 19 + open-sse/handlers/responseSanitizer.ts | 21 +- open-sse/package.json | 2 +- open-sse/services/model.ts | 28 + open-sse/services/provider.ts | 6 + open-sse/services/tokenRefresh.ts | 37 +- open-sse/transformer/responsesTransformer.ts | 187 +- .../helpers/geminiToolsSanitizer.ts | 37 +- open-sse/translator/helpers/openaiHelper.ts | 17 +- open-sse/translator/index.ts | 1 + .../request/antigravity-to-openai.ts | 95 +- .../translator/request/claude-to-openai.ts | 20 +- .../translator/request/openai-responses.ts | 138 +- .../translator/request/openai-to-claude.ts | 27 +- .../translator/request/openai-to-gemini.ts | 40 +- open-sse/translator/request/openai-to-kiro.ts | 43 +- .../translator/response/kiro-to-openai.ts | 7 +- .../translator/response/openai-responses.ts | 254 +- open-sse/utils/diagnostics.ts | 222 + open-sse/utils/error.ts | 11 +- open-sse/utils/flattenToolHistory.ts | 116 + open-sse/utils/kiroSanitizer.ts | 127 + open-sse/utils/streamHandler.ts | 20 +- open-sse/utils/toolSources.ts | 69 + open-sse/utils/usageTracking.ts | 28 +- package-lock.json | 118 +- package.json | 4 +- scripts/build/build-next-isolated.mjs | 7 +- scripts/build/validate-pack-artifact.ts | 17 +- scripts/check/check-build-scope.mjs | 95 + .../api-manager/ApiManagerPageClient.tsx | 3 +- .../cli-code/components/DroidToolCard.tsx | 181 +- .../combos/CompressionCombosPageClient.tsx | 39 +- .../[id]/components/modals/AddApiKeyModal.tsx | 14 + src/app/api/cli-tools/droid-settings/route.ts | 59 +- src/app/api/headroom/start/route.ts | 49 + src/app/api/headroom/status/route.ts | 26 + src/app/api/headroom/stop/route.ts | 19 + src/app/api/oauth/codex/import/route.ts | 107 + src/app/api/oauth/cursor/auto-import/route.ts | 68 + src/app/api/provider-nodes/validate/route.ts | 56 +- src/app/api/providers/[id]/models/route.ts | 3 + src/app/globals.css | 12 + src/i18n/messages/en.json | 2 + src/lib/combos/autoPromote.ts | 92 + src/lib/dataPaths.ts | 39 + src/lib/db/combos.ts | 18 + src/lib/db/core.ts | 4 +- src/lib/db/settings.ts | 4 + src/lib/embeddings/service.ts | 39 +- src/lib/headroom/detect.ts | 167 + src/lib/headroom/process.ts | 193 + src/lib/ipUtils.ts | 54 +- src/lib/localDb.ts | 1 + src/lib/oauth/services/codexImport.ts | 214 + src/lib/providers/validation.ts | 2 + src/lib/providers/validation/openaiFormat.ts | 29 + src/lib/providers/xai/thinking.ts | 115 + src/lib/providers/xai/translators/claude.ts | 368 ++ src/lib/providers/xai/translators/gemini.ts | 371 ++ .../providers/xai/translators/openai-chat.ts | 304 ++ .../xai/translators/openai-responses.ts | 77 + src/lib/usage/providerLimits.ts | 7 +- src/server/authz/routeGuard.ts | 5 + src/shared/components/ModelSelectModal.tsx | 17 +- .../components/layouts/DashboardLayout.tsx | 4 +- .../components/modelSelectModalHelpers.ts | 37 + src/shared/constants/config.ts | 1 + src/shared/constants/pricing/regional.ts | 16 + .../providers/apikey/frontier-labs.ts | 17 + .../constants/providers/apikey/gateways.ts | 17 + src/shared/services/droidCustomModels.ts | 118 + src/shared/utils/circuitBreaker.ts | 22 + src/shared/utils/clineAuth.ts | 62 + .../validation/compressionConfigSchemas.ts | 20 + src/shared/validation/schemas/cli.ts | 11 + src/shared/validation/schemas/combo.ts | 10 +- src/sse/handlers/chat.ts | 39 +- src/sse/handlers/chatHelpers.ts | 9 +- src/sse/services/auth.ts | 8 + src/sse/services/model.ts | 25 +- src/sse/services/tokenRefresh.ts | 2 +- tests/snapshots/provider/translate-path.json | 4146 +++++++++++++++++ tests/unit/antigravity-retry-hook.test.ts | 141 + ...strip-builtin-tools-funcdecls-1095.test.ts | 102 + tests/unit/antigravity-tool-cloaking.test.ts | 99 + .../api-manager-mask-key-passthrough.test.ts | 39 + .../authz/route-guard-local-prefix.test.ts | 19 + tests/unit/chat-auth-log-redaction.test.ts | 43 + ...uit-breaker-stream-controller-4602.test.ts | 79 + .../cli/autostart-macos-launchctl.test.ts | 91 + .../cline-workos-auth-token-shape.test.ts | 73 + tests/unit/codexBulkImport.test.ts | 245 + tests/unit/combo-auto-promote.test.ts | 154 + ...bo-flatten-anthropic-tool-messages.test.ts | 161 + tests/unit/combo-id-resolution-4446.test.ts | 84 + ...ombos-engine-ui-schema-parity-4955.test.ts | 51 + tests/unit/cursor-composer-thinking.test.ts | 56 + .../dashboard-sidebar-desktop-visible.test.ts | 64 + tests/unit/data-dir-writable-fallback.test.ts | 115 + tests/unit/dgrid-provider.test.ts | 162 + tests/unit/diagnostics.test.ts | 200 + tests/unit/droid-custom-models.test.ts | 122 + .../unit/embeddings-combo-dimensions.test.ts | 115 + tests/unit/executor-codex.test.ts | 5 +- ...efault-anthropic-compatible-bearer.test.ts | 68 + tests/unit/executor-default-base.test.ts | 138 + tests/unit/executor-gemini-cli.test.ts | 52 + ...utor-strip-stainless-openai-compat.test.ts | 83 + .../unit/format-provider-error-cause.test.ts | 47 + tests/unit/github-copilot-gpt-4o-mini.test.ts | 45 + tests/unit/headroom-proxy-lifecycle.test.ts | 90 + tests/unit/ipUtils.test.ts | 74 + tests/unit/kiro-tool-args-streaming.test.ts | 167 + .../kiro-tool-schema-sanitize-1375.test.ts | 131 + ...model-select-passthrough-alias-485.test.ts | 49 + tests/unit/next-config.test.ts | 7 + tests/unit/oauth-cursor-auto-import.test.ts | 65 + .../openai-responses-reasoning-effort.test.ts | 72 + ...-claude-strip-temperature-thinking.test.ts | 69 + tests/unit/pioneer-provider.test.ts | 83 + ...stoken-fallback-on-refresh-failure.test.ts | 85 + ...rovider-nodes-validate-docker-hint.test.ts | 95 + ...ider-registry-github-copilot-gpt-4.test.ts | 57 + .../provider-translate-path-golden.test.ts | 132 + .../provider-validation-specialty.test.ts | 49 + .../unit/qoder-unwrap-error-envelope.test.ts | 95 + ...re-model-to-connection-default-474.test.ts | 43 + ...ponses-nameless-hosted-tool-filter.test.ts | 66 + ...reasoning-close-before-message-466.test.ts | 158 + ...responses-transformer-dense-output.test.ts | 129 + tests/unit/responses-transformer.test.ts | 2 +- .../unit/responses-translation-fixes.test.ts | 54 + .../runtime-deps-save-exact-no-prune.test.ts | 88 + tests/unit/service-token-refresh.test.ts | 26 + .../unit/siliconflow-registry-models.test.ts | 61 + tests/unit/stream-handler.test.ts | 35 + ...asoning-blobs-agentic-context-1599.test.ts | 81 + tests/unit/strip-reasoning-header.test.ts | 124 + tests/unit/t12-pricing-updates.test.ts | 15 + tests/unit/token-refresh-service.test.ts | 31 + tests/unit/tool-source-diagnostics.test.ts | 62 + .../translator-antigravity-to-openai.test.ts | 129 + ...ude-to-openai-strip-billing-header.test.ts | 80 + ...r-helper-tool-description-coercion.test.ts | 58 + ...-openai-responses-custom-tool-1007.test.ts | 163 + .../translator-openai-responses-req.test.ts | 54 +- tests/unit/translator-openai-to-kiro.test.ts | 81 + .../compatible-provider-apikey-setup.test.tsx | 129 + tests/unit/usage-extractor.test.ts | 85 + tests/unit/xai-translators.test.ts | 490 ++ 233 files changed, 22552 insertions(+), 551 deletions(-) create mode 100644 open-sse/config/providers/registry/dgrid/index.ts create mode 100644 open-sse/config/providers/registry/pioneer/index.ts create mode 100644 open-sse/utils/diagnostics.ts create mode 100644 open-sse/utils/flattenToolHistory.ts create mode 100644 open-sse/utils/kiroSanitizer.ts create mode 100644 open-sse/utils/toolSources.ts create mode 100644 scripts/check/check-build-scope.mjs create mode 100644 src/app/api/headroom/start/route.ts create mode 100644 src/app/api/headroom/status/route.ts create mode 100644 src/app/api/headroom/stop/route.ts create mode 100644 src/app/api/oauth/codex/import/route.ts create mode 100644 src/lib/combos/autoPromote.ts create mode 100644 src/lib/headroom/detect.ts create mode 100644 src/lib/headroom/process.ts create mode 100644 src/lib/oauth/services/codexImport.ts create mode 100644 src/lib/providers/xai/thinking.ts create mode 100644 src/lib/providers/xai/translators/claude.ts create mode 100644 src/lib/providers/xai/translators/gemini.ts create mode 100644 src/lib/providers/xai/translators/openai-chat.ts create mode 100644 src/lib/providers/xai/translators/openai-responses.ts create mode 100644 src/shared/components/modelSelectModalHelpers.ts create mode 100644 src/shared/services/droidCustomModels.ts create mode 100644 src/shared/utils/clineAuth.ts create mode 100644 tests/snapshots/provider/translate-path.json create mode 100644 tests/unit/antigravity-retry-hook.test.ts create mode 100644 tests/unit/antigravity-strip-builtin-tools-funcdecls-1095.test.ts create mode 100644 tests/unit/api-manager-mask-key-passthrough.test.ts create mode 100644 tests/unit/chat-auth-log-redaction.test.ts create mode 100644 tests/unit/circuit-breaker-stream-controller-4602.test.ts create mode 100644 tests/unit/cli/autostart-macos-launchctl.test.ts create mode 100644 tests/unit/cline-workos-auth-token-shape.test.ts create mode 100644 tests/unit/codexBulkImport.test.ts create mode 100644 tests/unit/combo-auto-promote.test.ts create mode 100644 tests/unit/combo-flatten-anthropic-tool-messages.test.ts create mode 100644 tests/unit/combo-id-resolution-4446.test.ts create mode 100644 tests/unit/compression/combos-engine-ui-schema-parity-4955.test.ts create mode 100644 tests/unit/dashboard-sidebar-desktop-visible.test.ts create mode 100644 tests/unit/data-dir-writable-fallback.test.ts create mode 100644 tests/unit/dgrid-provider.test.ts create mode 100644 tests/unit/diagnostics.test.ts create mode 100644 tests/unit/droid-custom-models.test.ts create mode 100644 tests/unit/embeddings-combo-dimensions.test.ts create mode 100644 tests/unit/executor-default-anthropic-compatible-bearer.test.ts create mode 100644 tests/unit/executor-strip-stainless-openai-compat.test.ts create mode 100644 tests/unit/format-provider-error-cause.test.ts create mode 100644 tests/unit/github-copilot-gpt-4o-mini.test.ts create mode 100644 tests/unit/headroom-proxy-lifecycle.test.ts create mode 100644 tests/unit/ipUtils.test.ts create mode 100644 tests/unit/kiro-tool-args-streaming.test.ts create mode 100644 tests/unit/kiro-tool-schema-sanitize-1375.test.ts create mode 100644 tests/unit/model-select-passthrough-alias-485.test.ts create mode 100644 tests/unit/openai-responses-reasoning-effort.test.ts create mode 100644 tests/unit/openai-to-claude-strip-temperature-thinking.test.ts create mode 100644 tests/unit/pioneer-provider.test.ts create mode 100644 tests/unit/provider-limits-accesstoken-fallback-on-refresh-failure.test.ts create mode 100644 tests/unit/provider-nodes-validate-docker-hint.test.ts create mode 100644 tests/unit/provider-registry-github-copilot-gpt-4.test.ts create mode 100644 tests/unit/provider-translate-path-golden.test.ts create mode 100644 tests/unit/qoder-unwrap-error-envelope.test.ts create mode 100644 tests/unit/resolve-bare-model-to-connection-default-474.test.ts create mode 100644 tests/unit/responses-nameless-hosted-tool-filter.test.ts create mode 100644 tests/unit/responses-reasoning-close-before-message-466.test.ts create mode 100644 tests/unit/responses-transformer-dense-output.test.ts create mode 100644 tests/unit/runtime-deps-save-exact-no-prune.test.ts create mode 100644 tests/unit/siliconflow-registry-models.test.ts create mode 100644 tests/unit/strip-reasoning-blobs-agentic-context-1599.test.ts create mode 100644 tests/unit/strip-reasoning-header.test.ts create mode 100644 tests/unit/tool-source-diagnostics.test.ts create mode 100644 tests/unit/translator-claude-to-openai-strip-billing-header.test.ts create mode 100644 tests/unit/translator-helper-tool-description-coercion.test.ts create mode 100644 tests/unit/translator-openai-responses-custom-tool-1007.test.ts create mode 100644 tests/unit/ui/compatible-provider-apikey-setup.test.tsx create mode 100644 tests/unit/xai-translators.test.ts diff --git a/.env.example b/.env.example index c2b069c2da..3099694ed8 100644 --- a/.env.example +++ b/.env.example @@ -378,6 +378,12 @@ NEXT_PUBLIC_CLOUD_URL= #OMNIROUTE_KIE_CALLBACK_URL= #OMNIROUTE_PUBLIC_URL= +# Headroom token-saver proxy URL. The dashboard lifecycle (api/headroom/*) spawns +# a local headroom-ai CLI on loopback by default; override only to point at an +# external Docker sidecar proxy. Defaults to http://localhost:8787 when unset. +# Used by: src/lib/headroom/detect.ts. +#HEADROOM_URL=http://localhost:8787 + # Upstream quota endpoints used by the Usage page. Override only for # debugging or when routing through a corporate mirror. Used by: # open-sse/services/usage.ts. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5181ebc246..06dcd7f9e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,7 +140,15 @@ jobs: name: Quality Ratchet runs-on: ubuntu-latest needs: test-coverage - if: ${{ !cancelled() && needs.test-coverage.result == 'success' }} + # Run even when test-coverage was SKIPPED/FAILED (e.g. a single flaky Coverage + # Shard breaks the shard→coverage→ratchet chain). The DETERMINISTIC ratchets + # (eslint / complexity / cognitive-complexity / duplication / codeql) do NOT need + # the coverage artifact and MUST still run so cycle drift is measured on the + # release PR — otherwise a flake silently skips the whole gate (incident: v3.8.36 + # release PR #4854, where the drift cascade only surfaced post-merge in #5029). + # The coverage.* metrics degrade gracefully: the download is continue-on-error and + # the ratchet runs with --allow-missing, so absent coverage is skipped, not failed. + if: ${{ !cancelled() }} # security-events: read lets the CodeQL ratchet read open code-scanning alerts # via `gh api .../code-scanning/alerts`. contents: read keeps checkout working. permissions: @@ -156,7 +164,12 @@ jobs: cache: npm - uses: ./.github/actions/npm-ci-retry # Coverage mergeada (coverage-summary.json) p/ o ratchet de cobertura. + # continue-on-error: o artifact pode não existir se a job test-coverage foi + # SKIPPED (shard flaky). Nesse caso collect-metrics pula coverage.* (ausente sem + # erro) e o ratchet roda com --allow-missing — as métricas determinísticas + # (eslint/complexity/cognitive) seguem BLOQUEANTES. - uses: actions/download-artifact@v8 + continue-on-error: true with: name: coverage-report path: coverage/ @@ -164,8 +177,10 @@ jobs: # Catraca: falha se qualquer métrica regredir vs quality-baseline.json (commitado). # Hoje: contagem de warnings do ESLint. Fase 4 estende com cobertura (lida do # coverage mergeado). Tamanho de arquivo e duplicação têm gates dedicados. + # --allow-missing: pula métricas do baseline ausentes do collect (coverage.* quando + # o artifact não veio) em vez de falhar — mantém os gates determinísticos ativos. - name: Ratchet check - run: node scripts/quality/check-quality-ratchet.mjs --summary .artifacts/quality-ratchet.md + run: node scripts/quality/check-quality-ratchet.mjs --allow-missing --summary .artifacts/quality-ratchet.md # Fase 6A.5: require-tighten — BLOQUEANTE (promovido de advisory no fim do ciclo # v3.8.27). Falha quando uma métrica MELHOROU sem o baseline ter sido apertado no # mesmo PR (força capturar ganhos permanentes). As métricas coverage.* carregam @@ -174,7 +189,7 @@ jobs: # mergeada == baseline (ver a nota _require_tighten_flip_blocking em # config/quality/quality-baseline.json). - name: Require-tighten (blocking) - run: node scripts/quality/check-quality-ratchet.mjs --require-tighten + run: node scripts/quality/check-quality-ratchet.mjs --allow-missing --require-tighten # Catraca de duplicação (jscpd@4 sobre src+open-sse). Roda neste job (paralelo) # para não pesar no caminho crítico do lint. - name: Duplication ratchet diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 1c3fdc5e36..4242fb6648 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -53,6 +53,18 @@ jobs: - run: npm run check:test-discovery - run: npm run check:test-runner-api - run: npm run check:any-budget:t11 + # Build-scope guard: fails if worktrees/cruft leak into the tsconfig include + # scope (would OOM `next build`). Instant. See incident 2026-06-25 / #5031. + - run: npm run check:build-scope + # Pack-policy (unexpected-files allowlist) WITHOUT a build — catches a stray file + # leaking into the npm tarball (v3.8.36: 6 ops bin/*.sh) per-PR instead of only on + # the release PR's heavy Package Artifact job. + - run: npm run check:pack-policy + # Complexity + cognitive-complexity ratchets on the fast-path (PR→release) so + # cycle drift is rebaselined PER-PR instead of cascading onto the release PR's + # Quality Ratchet (v3.8.36: +30 complexity / +15 cognitive surfaced only post-merge). + - run: npm run check:complexity + - run: npm run check:cognitive-complexity - name: Typecheck (core) run: npm run typecheck:core # TIA: build the impact map at runtime (gitignored, ~21MB) and run only the diff --git a/.gitignore b/.gitignore index 4810f236f2..efdd25c7e5 100644 --- a/.gitignore +++ b/.gitignore @@ -161,6 +161,8 @@ typescript # Superpowers plans/specs (internal tooling, not project code) docs/superpowers/ +# Superpowers visual-companion brainstorm mockups (ephemeral) +.superpowers/ # TIA test-impact map — generated at runtime in CI (build-test-impact-map.mjs), never committed (~21MB) config/quality/test-impact-map.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a67ba8279..9fc6858653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,162 @@ --- +## [3.8.37] — 2026-06-26 + +### ✨ New Features + +- **feat(providers):** add DGrid AI gateway provider — OpenAI-compatible gateway at `api.dgrid.ai/v1` (alias `dgrid`, API-key auth, passthrough models). Free router tier (10 RPM / 100 RPD); a $5 lifetime top-up raises limits to 20 RPM / 1,000 RPD. ([#4931](https://github.com/diegosouzapw/OmniRoute/pull/4931) — thanks @dgridOP) + +- **feat(providers):** add Pioneer AI (Fastino Labs) provider — OpenAI-compatible chat completions at `api.pioneer.ai/v1`. Registered with alias `pn`, `X-API-Key` auth, and a catalog of 10 open-tier serverless models (Qwen3, Llama 3.1/3.2, Gemma 3, SmolLM3). Free $75 credits, no credit card required. Gated enterprise models (Claude/GPT/Gemini) require prior fine-tuning on the Pioneer platform and are intentionally excluded from the catalog. ([#4909](https://github.com/diegosouzapw/OmniRoute/pull/4909) — thanks @HikiNarou) + +- **feat(providers):** add xAI Grok inbound translators and a thinking patcher — Grok requests are now translated on the inbound path and reasoning is normalized so Grok modes behave consistently across clients. ([#4910](https://github.com/diegosouzapw/OmniRoute/pull/4910) — thanks @mugnimaestra) + +- **feat(oauth):** Codex bulk-import endpoint — `POST /api/oauth/codex/import` accepts multiple Codex OAuth credentials in one call for fast multi-account onboarding. ([#4914](https://github.com/diegosouzapw/OmniRoute/pull/4914) — thanks @beaaan) + +- **feat(embeddings):** add a `dimensions` override field to embedding combos so an embedding combo can pin the output vector size per target. ([#4913](https://github.com/diegosouzapw/OmniRoute/pull/4913) — thanks @wenzetan) + +- **feat(sse):** auto-promote successful combo model — a new opt-in `comboAutoPromoteEnabled` setting reorders a combo's persisted model list so that, when a combo model responds successfully, it is moved to position #1 for future requests. ([#4852](https://github.com/diegosouzapw/OmniRoute/pull/4852) — thanks @arssnndr) + +- **feat(sse):** add toggleable tool-source diagnostics — an opt-in switch surfaces where each tool definition originated when debugging tool-routing issues. ([#4856](https://github.com/diegosouzapw/OmniRoute/pull/4856) — thanks @DuyPrX) + +- **feat(headroom):** proxy lifecycle management + dashboard UI — start/stop/monitor a Headroom compression proxy from the dashboard, with Docker sidecar support. ([#4649](https://github.com/diegosouzapw/OmniRoute/pull/4649) — thanks @diegosouzapw / @carmelogunsroses) + +- **feat(sse):** `x-omniroute-strip-reasoning` request header to drop `reasoning_content` from upstream responses (opt-in, preserving reasoning-aware clients). ([#4678](https://github.com/diegosouzapw/OmniRoute/pull/4678) — thanks @anuragg-saxenaa / @diegosouzapw) + +- **feat(cli):** multi-model support for the Factory Droid CLI integration. ([#4682](https://github.com/diegosouzapw/OmniRoute/pull/4682) — thanks @anuragg-saxenaa / @diegosouzapw) + +- **feat(sse):** parse Gemini CLI 429 `retryDelay` from the structured `RetryInfo` payload so cooldowns honor the upstream-provided backoff. ([#4738](https://github.com/diegosouzapw/OmniRoute/pull/4738) — thanks @NoxzRCW) + +- **feat(sse):** add GPT-4 and GPT-4o mini to the GitHub Copilot provider catalog. ([#4798](https://github.com/diegosouzapw/OmniRoute/pull/4798), [#4797](https://github.com/diegosouzapw/OmniRoute/pull/4797) — thanks @decolua) + +- **feat(api):** add the `MiniMax-M3` pricing row (canonical + lowercase alias) so the new MiniMax default model gets accurate per-request cost accounting instead of falling back to a zero/default rate. ([#4814](https://github.com/diegosouzapw/OmniRoute/pull/4814) — thanks @octo-patch) + +### 🔧 Bug Fixes + +- **fix(sse):** dense, deterministic `response.output` ordering in `response.completed` — items are now sorted by their actual `output_index` (via a recorded-as-emitted accumulator + stable sort) instead of being rebuilt from unordered state dicts; `normalizeOutputIndex` replaces fragile `parseInt` calls for robust index coercion; superseded tool calls (replaced at the same index mid-stream) are excluded from the final output array. ([#4906](https://github.com/diegosouzapw/OmniRoute/pull/4906) — thanks @Marco9113) + +- **fix(sse):** normalize Codex custom/freeform tools (`apply_patch`, `type:"custom"` with no `parameters`) to a `{ input: string }` function schema instead of an empty schema — the empty schema made models invoke `apply_patch` with `{}`, breaking the Codex runtime which expects `{ input: string }`. Also maps `custom_tool_call` / `custom_tool_call_output` input items and streams `apply_patch` tool calls via `custom_tool_call_input.delta`/`.done` events. ([#4862](https://github.com/diegosouzapw/OmniRoute/pull/4862) — thanks @nstung463) + +- **fix(sse):** preserve the `required` array when translating Draft 2020-12 antigravity tool schemas (e.g. from OpenCode), stripping unsupported JSON Schema meta keywords while keeping mandatory arguments required so the model no longer calls tools without them. ([#4843](https://github.com/diegosouzapw/OmniRoute/pull/4843) — thanks @anuragg-saxenaa) + +- **fix(sse):** Kiro tool-schema sanitizer — strip unsupported JSON-Schema keywords (`anyOf`/`$ref`/`if`-`then`, etc.) and hash-truncate tool names >64 chars before dispatch, mapping the streamed tool-call name back for the client, so Kiro no longer rejects tool calls with `400 "Improperly formed request"`. ([#4847](https://github.com/diegosouzapw/OmniRoute/pull/4847) — thanks @smarthomeblack) + +- **fix(sse):** make the `anthropic-version` default-guard case-insensitive for `anthropic-compatible-*` providers, so a caller/operator-supplied `Anthropic-Version` (any casing) is no longer clobbered by a second lowercase `anthropic-version: 2023-06-01` header. ([#4823](https://github.com/diegosouzapw/OmniRoute/pull/4823) — thanks @zakirkun) + +- **fix(db):** validate HuggingFace API tokens via the `whoami-v2` endpoint as a pure auth probe so fine-grained Inference-Provider tokens (valid even when model/task endpoints reject them) are no longer falsely marked invalid; only 401/403 means an invalid key, other non-OK statuses surface as transient upstream errors. ([#4819](https://github.com/diegosouzapw/OmniRoute/pull/4819) — thanks @Delcado19) + +- **fix(sse):** reject the Anthropic-only `[1m]` context-1m suffix in `buildKiroPayload` before it reaches AWS Bedrock — Kiro is Bedrock-backed and cannot honor the beta, so a forwarded `kr/*[1m]` model id was malformed upstream; callers now get a clear error pointing them at a direct-Anthropic provider for 1M-context routing. ([#4816](https://github.com/diegosouzapw/OmniRoute/pull/4816) — thanks @Delcado19) + +- **fix(dashboard):** align the Engine Combos editor engines with the API schema — the named-combos pipeline dropdown offered four engines (`headroom`, `session-dedup`, `ccr`, `llmlingua`) that `PUT /api/context/combos/[id]` rejects, so selecting one made the save return 400 while the UI swallowed the error. The dropdown is now sourced from a single canonical engine map shared with `stackedPipelineStepSchema` (parity guarded by a unit test), and the editor surfaces save errors plus empty-name/empty-pipeline validation instead of failing quietly. ([#5062](https://github.com/diegosouzapw/OmniRoute/pull/5062) — closes #4955) + +- **fix(sse):** surface malformed HTTP-200 upstream responses instead of treating them as success, so combo fallback can trigger. ([#4942](https://github.com/diegosouzapw/OmniRoute/pull/4942) — thanks @haipham22) + +- **fix(antigravity):** retry transient upstream failures rather than failing the request outright. ([#4941](https://github.com/diegosouzapw/OmniRoute/pull/4941) — thanks @Jordannst) + +- **fix(sse):** exclude WS-bridge controller-closed errors from the provider circuit breaker so a client disconnect no longer trips the whole provider. ([#4870](https://github.com/diegosouzapw/OmniRoute/pull/4870) — closes #4602, thanks @huohua-dev) + +- **fix(sse):** resolve custom combos by id and case-insensitive name. ([#4869](https://github.com/diegosouzapw/OmniRoute/pull/4869) — closes #4446, thanks @herjarsa) + +- **fix(sse):** forward AI SDK image parts in the Responses translator. ([#4859](https://github.com/diegosouzapw/OmniRoute/pull/4859) — thanks @mugnimaestra) + +- **fix(sse):** emit valid concatenable Kiro `tool_calls.arguments` deltas. ([#4855](https://github.com/diegosouzapw/OmniRoute/pull/4855) — thanks @wahyuzero) + +- **fix(sse):** strip `temperature` for Claude models with extended thinking enabled (the upstream rejects it). ([#4853](https://github.com/diegosouzapw/OmniRoute/pull/4853) — thanks @noestelar) + +- **fix(sse):** unwrap the Qoder HTTP-200 SSE error envelope so combo fallback can trigger. ([#4850](https://github.com/diegosouzapw/OmniRoute/pull/4850) — thanks @vianlearns) + +- **fix(sse):** strip reasoning blobs from agentic context to prevent O(n²) token growth across multi-turn agent loops. ([#4849](https://github.com/diegosouzapw/OmniRoute/pull/4849) — thanks @GodrezJr2) + +- **fix(sse):** close the reasoning block before message content in the Responses stream so clients render reasoning and answer in the right order. ([#4848](https://github.com/diegosouzapw/OmniRoute/pull/4848) — thanks @kwanLeeFrmVi) + +- **fix(config):** sync the full SiliconFlow model list into the registry. ([#4844](https://github.com/diegosouzapw/OmniRoute/pull/4844) — thanks @letanphuc) + +- **fix(sse):** strip Composer `<|final|>` sentinel markers that leaked after Composer reasoning. ([#4842](https://github.com/diegosouzapw/OmniRoute/pull/4842) — thanks @noestelar) + +- **fix(build):** trace-include `sql.js`'s `sql-wasm.wasm` in the standalone bundle so SQLite-WASM works in the packaged build. ([#4839](https://github.com/diegosouzapw/OmniRoute/pull/4839) — thanks @Delcado19) + +- **fix(cli):** persist lazily-installed native runtime deps (`better-sqlite3`, `systray2`) to the shared runtime `package.json` with `--save-exact` instead of `--no-save`, so installing one no longer prunes the other as "extraneous" — fixing a "No SQLite driver available" failure after a `--tray` install. ([#4841](https://github.com/diegosouzapw/OmniRoute/pull/4841) — thanks @omartuhintvs) + +- **fix(sse):** resolve bare model names to a connection's `defaultModel` before upstream calls. ([#4825](https://github.com/diegosouzapw/OmniRoute/pull/4825) — thanks @anuragg-saxenaa) + +- **fix(api):** surface a Docker-localhost hint on provider-node validation connection errors. ([#4822](https://github.com/diegosouzapw/OmniRoute/pull/4822) — thanks @anuragg-saxenaa) + +- **fix(sse):** strip Gemini built-in tools when `functionDeclarations` are present in the Antigravity envelope (the two are mutually exclusive upstream). ([#4821](https://github.com/diegosouzapw/OmniRoute/pull/4821) — thanks @vanszs) + +- **fix(sse):** strip `X-Stainless-*` headers and normalize the SDK `User-Agent` for OpenAI-compatible endpoints. ([#4820](https://github.com/diegosouzapw/OmniRoute/pull/4820) — thanks @anuragg-saxenaa) + +- **fix(oauth):** allow a per-connection refresh lead-time override via `providerSpecificData.refreshLeadMs`. ([#4818](https://github.com/diegosouzapw/OmniRoute/pull/4818) — thanks @anuragg-saxenaa) + +- **fix(dashboard):** resolve passthrough model aliases by `providerId` in `ModelSelectModal`. ([#4815](https://github.com/diegosouzapw/OmniRoute/pull/4815) — thanks @anuragg-saxenaa) + +- **fix(sse):** strip `enumDescriptions` from Antigravity tool schemas. ([#4813](https://github.com/diegosouzapw/OmniRoute/pull/4813), [#4740](https://github.com/diegosouzapw/OmniRoute/pull/4740) — thanks @anuragg-saxenaa) + +- **fix(dashboard):** keep the desktop sidebar visible via an explicit CSS class. ([#4812](https://github.com/diegosouzapw/OmniRoute/pull/4812) — thanks @Delcado19) + +- **fix(sse):** filter nameless hosted tools when converting Responses API to Chat format. ([#4789](https://github.com/diegosouzapw/OmniRoute/pull/4789) — upstream, thanks Владимир Акимов) + +- **fix(sse):** stream-writer mock `abort()` now returns a Promise (test-stability fix). ([#4788](https://github.com/diegosouzapw/OmniRoute/pull/4788) — thanks @decolua) + +- **fix(sse):** use the WorkOS auth-token shape for Cline. ([#4787](https://github.com/diegosouzapw/OmniRoute/pull/4787) — thanks @apeltekci) + +- **fix(api):** fall back to the existing access token for any OAuth provider when a refresh fails. ([#4786](https://github.com/diegosouzapw/OmniRoute/pull/4786) — thanks @decolua) + +- **fix(sse):** read Antigravity usage from the `response.usageMetadata` envelope. ([#4785](https://github.com/diegosouzapw/OmniRoute/pull/4785) — thanks @decolua) + +- **fix(oauth):** verify Cursor installation on Linux before auto-import. ([#4770](https://github.com/diegosouzapw/OmniRoute/pull/4770) — upstream, thanks Ibrahim Ryan) + +- **fix(cli):** fall back to the default data dir when `DATA_DIR` is not writable. ([#4767](https://github.com/diegosouzapw/OmniRoute/pull/4767) — upstream, thanks Thiên Toán) + +- **fix(sse):** `json_schema` fallback for OpenAI-compatible providers that don't support structured outputs. ([#4766](https://github.com/diegosouzapw/OmniRoute/pull/4766) — thanks @mustafabozkaya) + +- **fix(cli):** verify launchd registration and skip self-SIGTERM in macOS autostart. ([#4765](https://github.com/diegosouzapw/OmniRoute/pull/4765) — thanks @ntdung6868) + +- **fix(sse):** finalize the `tool_calls` `finish_reason` on early stream end in the OpenAI Responses translator. ([#4764](https://github.com/diegosouzapw/OmniRoute/pull/4764) — thanks @decolua) + +- **fix(sse):** gate Kiro image attachments behind a Claude-capability check. ([#4763](https://github.com/diegosouzapw/OmniRoute/pull/4763) — thanks @decolua) + +- **fix(sse):** track Ollama streaming usage from raw NDJSON chunks. ([#4754](https://github.com/diegosouzapw/OmniRoute/pull/4754) — thanks @fresent) + +- **fix(sse):** include low-level cause details in `formatProviderError`. ([#4741](https://github.com/diegosouzapw/OmniRoute/pull/4741) — thanks @decolua) + +- **fix(executors):** `anthropic-compatible-*` gateways now get a `Bearer` token alongside `x-api-key`. ([#4729](https://github.com/diegosouzapw/OmniRoute/pull/4729) — thanks @hodtien) + +- **fix(translator):** strip the `x-anthropic-billing-header` in the claude-to-openai path. ([#4728](https://github.com/diegosouzapw/OmniRoute/pull/4728) — thanks @weimaozhen) + +- **fix(translator):** preserve `reasoning_effort` for non-Copilot Responses clients. ([#4688](https://github.com/diegosouzapw/OmniRoute/pull/4688) — thanks @ryanngit / @diegosouzapw) + +- **fix(codex):** treat an OAuth 401 as an unrecoverable refresh failure (stop retrying a dead token). ([#4686](https://github.com/diegosouzapw/OmniRoute/pull/4686) — thanks @sacwooky / @diegosouzapw) + +- **fix(translator):** coerce tool descriptions to strings in OpenAI normalization. ([#4675](https://github.com/diegosouzapw/OmniRoute/pull/4675) — thanks @East-rayyy / @diegosouzapw) + +- **fix(dashboard):** stop double-masking an already-masked API key in the list view (E2E 3/9 regression). ([#4671](https://github.com/diegosouzapw/OmniRoute/pull/4671) — thanks @diegosouzapw) + +- **fix(combo):** flatten Anthropic tool messages + tool history to prevent an upstream 503. ([#4648](https://github.com/diegosouzapw/OmniRoute/pull/4648) — thanks @warelik / @diegosouzapw) + +- **fix(providers):** require a Default Model in the compatible-provider API-key setup flow. ([#4641](https://github.com/diegosouzapw/OmniRoute/pull/4641) — thanks @arden1601) + +### 🔒 Security + +- **fix(auth):** only trust forwarding headers (`X-Forwarded-For` / `X-Real-IP`) from loopback TCP peers, so a non-loopback client can't spoof its origin to bypass local-only route guards. ([#4689](https://github.com/diegosouzapw/OmniRoute/pull/4689) — thanks @Jordannst / @diegosouzapw) + +- **fix(sse):** redact the API key from the AUTH debug log in the chat handler. ([#4858](https://github.com/diegosouzapw/OmniRoute/pull/4858) — thanks @sacwooky) + +- **fix(oauth):** classify `/api/oauth/cursor/auto-import` as a local-only route in the route guard, so the loopback-enforced process-spawning endpoint can't be reached through a tunneled/leaked JWT (Hard Rule #17). ([#5070](https://github.com/diegosouzapw/OmniRoute/pull/5070) — thanks @diegosouzapw) + +### 📝 Maintenance + +- **chore(ci):** harden the release flow — decouple the Quality Ratchet from coverage-shard flakes (`if: !cancelled()` + `--allow-missing`), add fast-path drift gates (`check:complexity`, `check:cognitive-complexity`, `check:pack-policy`, `check:build-scope`), and raise the default build heap to 8 GB. ([#5054](https://github.com/diegosouzapw/OmniRoute/pull/5054) — thanks @diegosouzapw) + +- **docs(routing):** sync the combo strategy docs for Fusion (17 strategies). ([#5067](https://github.com/diegosouzapw/OmniRoute/pull/5067) — thanks @diegosouzapw) + +- **test(sse):** golden-lock the `provider.ts` translate-path across all providers. ([#4734](https://github.com/diegosouzapw/OmniRoute/pull/4734) — thanks @diegosouzapw / @decolua) + +- **docs(env):** document `HEADROOM_URL` in `.env.example` + `ENVIRONMENT.md`. (thanks @diegosouzapw) + +- **chore(quality):** rebaseline the file-size ratchet across the rc17 PR-batch levas (leva2/leva3/leva4) to absorb cycle drift. (thanks @diegosouzapw) + +--- + ## [3.8.36] — 2026-06-25 ### ✨ New Features diff --git a/CLAUDE.md b/CLAUDE.md index efc6980f6f..29dfab1eda 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -72,7 +72,7 @@ Client → /v1/chat/completions (Next.js route) API routes follow a consistent pattern: `Route → CORS preflight → Zod body validation → Optional auth (extractApiKey/isValidApiKey) → API key policy enforcement → Handler delegation (open-sse)`. No global Next.js middleware — interception is route-specific. -**Combo routing** (`open-sse/services/combo.ts`): 15 strategies (priority, weighted, fill-first, round-robin, P2C, random, least-used, cost-optimized, reset-aware, reset-window, strict-random, auto, lkgp, context-optimized, context-relay). Each target calls `handleSingleModel()` which wraps `handleChatCore()` with per-target error handling and circuit breaker checks. See `docs/routing/AUTO-COMBO.md` for the 9-factor Auto-Combo scoring and `docs/architecture/RESILIENCE_GUIDE.md` for the 3 resilience layers. +**Combo routing** (`open-sse/services/combo.ts`): 17 strategies (priority, weighted, fill-first, round-robin, P2C, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion). Each target calls `handleSingleModel()` which wraps `handleChatCore()` with per-target error handling and circuit breaker checks. The `fusion` strategy is the exception: it fans out to a panel of models in parallel, then a judge model synthesizes one final answer (`open-sse/services/fusion.ts`). See `docs/routing/AUTO-COMBO.md` for the 9-factor Auto-Combo scoring + the full strategy table and `docs/architecture/RESILIENCE_GUIDE.md` for the 3 resilience layers. --- @@ -332,7 +332,7 @@ For any non-trivial change, read the matching deep-dive first: | Repo navigation | `docs/architecture/REPOSITORY_MAP.md` | | Architecture | `docs/architecture/ARCHITECTURE.md` | | Engineering reference | `docs/architecture/CODEBASE_DOCUMENTATION.md` | -| Auto-Combo (9-factor scoring, 15 strategies) | `docs/routing/AUTO-COMBO.md` | +| Auto-Combo (9-factor scoring, 17 strategies) | `docs/routing/AUTO-COMBO.md` | | Resilience (3 mechanisms) | `docs/architecture/RESILIENCE_GUIDE.md` | | Reasoning replay | `docs/routing/REASONING_REPLAY.md` | | Skills framework | `docs/frameworks/SKILLS.md` | diff --git a/README.md b/README.md index 37bde4d92e..58458f6e07 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ [![50+ Free](https://img.shields.io/badge/50%2B-Free_Tiers-00B894?style=for-the-badge)](#-231-ai-providers--50-free) [![1.6B Free Tokens/mo](https://img.shields.io/badge/1.6B-Free_Tokens%2Fmo-00B894?style=for-the-badge)](docs/reference/FREE_TIERS.md) [![Token Savings](https://img.shields.io/badge/up_to_95%25-Token_Savings-E17055?style=for-the-badge)](#%EF%B8%8F-save-1595-tokens--automatically) -[![15 Strategies](https://img.shields.io/badge/15-Routing_Strategies-0984E3?style=for-the-badge)](#-combos--the-flagship) +[![17 Strategies](https://img.shields.io/badge/17-Routing_Strategies-0984E3?style=for-the-badge)](#-combos--the-flagship) [![$0 to start](https://img.shields.io/badge/%240-To_Start-FDCB6E?style=for-the-badge&logoColor=black)](#-quick-start)
@@ -182,7 +182,7 @@ ▼ ┌──────────────────────────────────────────────────────────┐ │ OmniRoute — Smart Router │ -│ RTK + Caveman compression · 15 routing strategies │ +│ RTK + Caveman compression · 17 routing strategies │ │ Circuit breakers · TLS stealth · MCP · A2A · Guardrails │ └─────────────────────────┬──────────────────────────────────┘ ┌─────────────┬────┴────────┬─────────────┐ @@ -220,7 +220,7 @@ No combo to create. Set your model to `auto` (or a variant) and OmniRoute builds ## -### 🔀 Or build your own — 15 routing strategies +### 🔀 Or build your own — 17 routing strategies | Goal | Strategy / combo | | --------------------------------------- | -------------------------------------------------- | @@ -229,6 +229,8 @@ No combo to create. Set your model to `auto` (or a variant) and OmniRoute builds | 💸 Always cheapest viable model | `cost-optimized` · `auto/cheap` | | 🧠 Hand off long context between models | `context-relay` · `context-optimized` | | 🎲 Randomized / privacy routing | `random` · `strict-random` | +| 🧬 Fan out to a panel + judge synthesis | `fusion` | +| 📊 Route by remaining quota headroom | `reset-window` · `headroom` | | 🤖 Just make it smart | `auto` (9-factor scoring) · `lkgp` · `reset-aware` | The Auto-Combo engine scores every candidate on **9 factors** (health, quota, cost, latency, success rate, freshness…) — see [`docs/routing/AUTO-COMBO.md`](docs/routing/AUTO-COMBO.md). @@ -262,20 +264,20 @@ Result: 4 layers of fallback = zero downtime -| Feature | OmniRoute | Other routers | -| -------------------------------------- | ----------------------------------------------------------- | ------------- | -| 🌐 Providers | **231** | 20–100 | -| 🆓 Free providers | **50+ (11 free forever)** | 1–5 | -| 🔀 Routing strategies | **15** (priority, weighted, cost-optimized, context-relay…) | 1–3 | -| 🗜️ Token compression | **RTK + Caveman stacked (15–95%)** | None / 20–40% | -| 🧰 Built-in MCP server | **87 tools, 3 transports, 30 scopes** | Rare | -| 🤝 A2A agent protocol | **6 skills, JSON-RPC 2.0** | None | -| 🧠 Memory (FTS5 + vector) | **Yes** | Rare | -| 🛡️ Guardrails (PII, injection, vision) | **Yes** | Rare | -| ☁️ Cloud agents | **Codex, Devin, Jules** | None | -| 🥷 TLS fingerprint stealth | **JA3/JA4 via wreq-js** | None | -| 🖥️ Multi-platform | **Web · Desktop · Termux · PWA** | Web only | -| 🌍 i18n | **42 locales** | 0–4 | +| Feature | OmniRoute | Other routers | +| -------------------------------------- | ------------------------------------------------------------------- | ------------- | +| 🌐 Providers | **231** | 20–100 | +| 🆓 Free providers | **50+ (11 free forever)** | 1–5 | +| 🔀 Routing strategies | **17** (priority, weighted, cost-optimized, context-relay, fusion…) | 1–3 | +| 🗜️ Token compression | **RTK + Caveman stacked (15–95%)** | None / 20–40% | +| 🧰 Built-in MCP server | **87 tools, 3 transports, 30 scopes** | Rare | +| 🤝 A2A agent protocol | **6 skills, JSON-RPC 2.0** | None | +| 🧠 Memory (FTS5 + vector) | **Yes** | Rare | +| 🛡️ Guardrails (PII, injection, vision) | **Yes** | Rare | +| ☁️ Cloud agents | **Codex, Devin, Jules** | None | +| 🥷 TLS fingerprint stealth | **JA3/JA4 via wreq-js** | None | +| 🖥️ Multi-platform | **Web · Desktop · Termux · PWA** | Web only | +| 🌍 i18n | **42 locales** | 0–4 | 📊 Detailed comparison vs LiteLLM, OpenRouter & Portkey → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md) @@ -287,18 +289,18 @@ Result: 4 layers of fallback = zero downtime -> Recent highlights from **v3.8.20 → v3.8.36**. Full history in [`CHANGELOG.md`](CHANGELOG.md). +> Recent highlights from **v3.8.20 → v3.8.37**. Full history in [`CHANGELOG.md`](CHANGELOG.md). - **⚖️ Quota-Share routing** — a dedicated combo strategy that spreads load across accounts by _available quota_: Deficit-Round-Robin scheduling, per-connection `max_concurrent` with cooldown-wait queueing, multi-window usage buckets (5h / 7d / per-model), per-(key,model) caps, session stickiness for prompt-cache integrity, and proactive saturation from upstream token-usage headers. → [Resilience Guide](docs/architecture/RESILIENCE_GUIDE.md) - **🤖 One-command CLI/agent setup** — a dedicated `setup-*` command configures each coding tool to route through OmniRoute (Claude Code, Codex, Cline, Continue, Cursor, Roo Code, Kilo Code, Crush, Goose, Qwen Code, Aider, OpenCode, Gemini CLI); `omniroute launch` / `omniroute launch-codex` are zero-config launchers. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md) - **🛰️ Remote mode** — drive a remote OmniRoute from any machine with scoped access tokens (`omniroute connect` / `omniroute contexts` / `omniroute tokens`). → [Remote Mode](docs/guides/REMOTE-MODE.md) - **🧭 Smarter auto-routing** — OpenRouter-style `auto/:` combos (e.g. `auto/coding:fast`, `auto/reasoning:pro`), a **Fusion** strategy (16th — fan out to a panel of models in parallel, then synthesize via a judge), **task-aware routing** (best-fit connection per task type), per-request `X-Route-Model` override, live Arena-ELO + models.dev model intelligence, per-step account allowlists, provider-wildcard combo steps, nested combo-ref execution, sticky weighted selection, and `web_search`-aware routing. → [Auto-Combo](docs/routing/AUTO-COMBO.md) -- **🗜️ Pluggable compression** — an async pipeline of **9 composable engines** with Compression Studios, an LLMLingua-2 ONNX engine and a heuristic/SLM two-tier **Ultra**, RTK, delegated Anthropic Context Editing, **Output Styles** (output-axis steering: terse-prose / less-code / terse-CJK), an **adaptive context-budget dial** (escalate only as far as needed to fit the context window), per-request `x-omniroute-compression` control, an opt-in offline eval harness, and a unified panel with named profiles + an active-profile selector. → [Compression](docs/compression/COMPRESSION_ENGINES.md) +- **🗜️ Pluggable compression** — an async pipeline of **9 composable engines** with Compression Studios, an LLMLingua-2 ONNX engine and a heuristic/SLM two-tier **Ultra**, RTK, delegated Anthropic Context Editing, **Output Styles** (output-axis steering: terse-prose / less-code / terse-CJK), an **adaptive context-budget dial** (escalate only as far as needed to fit the context window), per-request `x-omniroute-compression` control, an opt-in offline eval harness, one-click **Headroom** proxy lifecycle management from the dashboard (Docker sidecar supported), and a unified panel with named profiles + an active-profile selector. → [Compression](docs/compression/COMPRESSION_ENGINES.md) - **🕵️ Transparent MITM decrypt (TPROXY)** — capture & translate traffic from CLIs that ignore proxy env vars, with a per-SNI certificate authority and a trust-store installer. → [MITM/TPROXY](docs/security/MITM-TPROXY-DECRYPT.md) - **💸 Cost telemetry everywhere** — `X-OmniRoute-*` cost/usage headers on every endpoint (including media), a non-token cost engine, a cache-HIT `X-OmniRoute-Cost-Saved` header, and per-key USD spend quotas. → [API Reference](docs/reference/API_REFERENCE.md) - **🧠 Memory you control** — opt-in int8 vector quantization (Qdrant + sqlite-vec), memory off by default, and a per-request `x-omniroute-no-memory` header. → [Memory](docs/frameworks/MEMORY.md) - **🛡️ Security** — a prompt-injection guard across every LLM route (backed by a red-team suite), plus a free DuckDuckGo last-resort web search. → [Guardrails](docs/security/GUARDRAILS.md) -- **🤝 More providers & agents** — Cursor Cloud Agent (a 4th cloud agent), CodeBuddy CN (`copilot.tencent.com`), a Google Flow video-generation provider, a refreshed 231-provider catalog (OrcaRouter, Wafer AI, OpenAdapter, dit.ai, TokenRouter, …), Vertex AI media generation (speech / transcription / music / video), and one-click account import from CLIProxyAPI (`~/.cli-proxy-api/`). → [Providers](docs/reference/PROVIDER_REFERENCE.md) +- **🤝 More providers & agents** — Cursor Cloud Agent (a 4th cloud agent), CodeBuddy CN (`copilot.tencent.com`), a Google Flow video-generation provider, new gateways **DGrid** and **Pioneer AI** (Fastino Labs), inbound **xAI Grok** translators, GPT-4 / GPT-4o-mini on the GitHub Copilot provider, multi-model **Factory Droid**, a refreshed 231-provider catalog (OrcaRouter, Wafer AI, OpenAdapter, dit.ai, TokenRouter, …), Vertex AI media generation (speech / transcription / music / video), and one-click account import from CLIProxyAPI (`~/.cli-proxy-api/`). → [Providers](docs/reference/PROVIDER_REFERENCE.md) - **⚡ Local performance & infra** — a one-click local Redis launcher (`omniroute redis up`, plus a dashboard Redis panel), one-click **Cloudflare Workers** and **Deno Deploy** relay deployers wired into the proxy pool, and an optional Bifrost Go sidecar that offloads the hottest relay path (`BIFROST_BASE_URL`, with automatic fallback to the TypeScript path on timeout). → [Environment](docs/reference/ENVIRONMENT.md)
diff --git a/bin/cli/runtime/nativeDeps.mjs b/bin/cli/runtime/nativeDeps.mjs index 852cff76b7..2a0787bd04 100644 --- a/bin/cli/runtime/nativeDeps.mjs +++ b/bin/cli/runtime/nativeDeps.mjs @@ -79,7 +79,18 @@ export function isBetterSqliteBinaryValid() { export function npmInstallRuntime(pkgs, opts = {}) { const cwd = ensureRuntimeDir(); - const npmArgs = ["install", ...pkgs, "--no-audit", "--no-fund", "--prefer-online", "--no-save"]; + // Persist to the runtime package.json (exact version) instead of --no-save so a later + // install of a sibling runtime dep (e.g. systray2 from trayRuntime.ts, which writes to the + // same runtime dir) does not prune this package as "extraneous" — that pruning otherwise + // reproduces "No SQLite driver available" after a tray install removes better-sqlite3. + const npmArgs = [ + "install", + ...pkgs, + "--no-audit", + "--no-fund", + "--prefer-online", + "--save-exact", + ]; // On Windows .cmd files cannot be executed without a shell; use cmd.exe /c explicitly // so we never set shell:true (which would propagate env and enable injection). const isWin = platform() === "win32"; diff --git a/bin/cli/runtime/trayRuntime.ts b/bin/cli/runtime/trayRuntime.ts index cc734b6f80..712bc720dc 100644 --- a/bin/cli/runtime/trayRuntime.ts +++ b/bin/cli/runtime/trayRuntime.ts @@ -83,8 +83,12 @@ function isInstalled(): boolean { } function installSystray(): void { + // --save-exact persists systray2 to the runtime package.json so installing it does not + // prune a sibling runtime dep (e.g. better-sqlite3 from nativeDeps.mjs, which writes to the + // same runtime dir) as "extraneous", and so the tray dep survives a later sibling install. + // Without it, a sibling install reproduces "No SQLite driver available". execSync( - `npm install --prefix "${RUNTIME_DIR}" ${SYSTRAY_SPEC} --no-audit --no-fund --silent`, + `npm install --prefix "${RUNTIME_DIR}" ${SYSTRAY_SPEC} --no-audit --no-fund --save-exact --silent`, { stdio: ["ignore", "ignore", "pipe"], timeout: 120_000 } ); } diff --git a/bin/cli/tray/autostart.mjs b/bin/cli/tray/autostart.mjs index 742bf99c20..605161c2a1 100644 --- a/bin/cli/tray/autostart.mjs +++ b/bin/cli/tray/autostart.mjs @@ -204,6 +204,64 @@ export function isAutostartEnabled() { return false; } +/** + * Pure parse of `launchctl list