⭐5 — Documenta o multiplicador de escala suportado hoje: N processos independentes com DATA_DIR/volume próprios (não replicas>1 numa PVC SQLite única); Redis (QUOTA_STORE_DRIVER=redis) compartilha só contadores de quota. Doc-only, teste de asserção do Docker Guide + ENVIRONMENT. Fecha #11024.
⭐5 — Documenta runtime RAM real para coding-agent /v1/responses (8-12GB heap medido em gateway K8s de produção, V8 abort em ~12GB); a imagem continua com OMNIROUTE_MEMORY_MB=1024 (dashboard) inalterado. Doc-only. Fecha #10982.
⭐5 — Provider x-search de primeira classe (SuperGrok/xAI x_search) em POST /v1/search e MCP omniroute_x_search. Fallback de credenciais xai-oauth→xao→xai; distinto de web search e do X Developer MCP.
Reconciliado com o release tip (que já incluía #10981 "skip catalog-default SearXNG" deste mesmo lote): merge trouxe 5 conflitos reais de contagem gerada (llm.txt/README.md/AGENTS.md/PROVIDER_REFERENCE.md/SVGs/46 mirrors i18n, todos verificados como bump puro 347→348, sem perda de conteúdo do HEAD) + 1 conflito real de mergeable=CONFLICTING.
Durante a validação, os 3 testes novos de SearXNG expuseram um bug real de interação com #10981: `isUnconfiguredLoopbackSearchProvider()` checava o baseUrl ESTÁTICO do catálogo em vez do baseUrl efetivo (após override de `provider_options.baseUrl` ou `providerSpecificData.baseUrl` da conexão), então QUALQUER request a searxng-search — mesmo com override customizado — era rejeitado como se fosse o default não-configurado. Corrigido em `open-sse/handlers/search.ts` (resolve o baseUrl efetivo via `resolveSearchBaseUrl()` antes do skip-check, tanto para o provider primário quanto o alternate). Um teste do próprio #10988 que assumia o comportamento pré-#10981 (default localhost:8888 sempre atendido) foi atualizado para refletir o comportamento já mesclado e intencional (503 quando não configurado).
Validação completa: typecheck limpo, 70/70 testes unit (search-route/search-registry/x-search-provider/searxng-loopback-default), 24/24 vitest MCP, 14/14 integration (search-providers-catalog), lint limpo nos arquivos tocados, docs-counts-sync OK (2 drifts soft pré-existentes, não relacionados), gates estáticos (file-size/complexity/cognitive/dead-code/changelog) todos OK.
⭐5 — Adiciona GET/HEAD /readyz como re-export de /healthz para probes de readiness estilo Kubernetes pararem de 404. Mesmos corpos/status de lifecycle; não é liveness probe. Testes de paridade + matcher omission. Fecha #10850.
⭐5 — ENVIRONMENT.md dizia que DEFAULT_RATE_LIMIT_PER_DAY unset = 1000/dia (legado); código e testes desde #2289 tratam unset/vazio como sem cap implícito. Doc-only, guardado por teste de asserção da tabela. Fecha #11017.
⭐5 — Remove ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE, flag morta desde 5b5e21a99 (que removeu o guard que a lia, resolvendo #1566). Zero mudança de comportamento; EXPECTED_FEATURE_FLAG_COUNT é o regression guard. Sibling de #10973 (mesma raiz).
Canonical provider id renamed freepik → magnific (Magnific Mystic official API), with a permanent redirect + runtime alias so old freepik/<model> traffic and /dashboard/providers/freepik URLs keep working. Existing provider=freepik connection rows are rewritten to magnific by migration 160.
Closes#10604.
Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 138 files):
- Focused suite: 54/54 tests pass (magnific-image-handler, provider-validation-image-only, provider-alias-uniqueness, redirects-cli-renames).
- check-file-size, check-changelog-integrity: OK.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
Co-authored-by: RaviTharuma <RaviTharuma@users.noreply.github.com>
Rescoped from #10606 — see PR body for the full rationale (combo-routing half made moot by #10162's advisory-only architecture, chatCore.ts hard-reject bypass retains real value).
Validated in an isolated worktree boarded onto origin/release/v3.8.50:
- 65/65 focused unit tests pass (chatcore-model-output-cap-wiring + feature-flags-settings).
- check-file-size, check-changelog-integrity: OK.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
Co-authored-by: JxnLexn <10897478+JxnLexn@users.noreply.github.com>
Obrigado — PR muito bem documentado e verificado. Adiciona o gateway TabiToken (Anthropic-first, /v1/messages, x-api-key) e estende hcnsec de 1 para 4 protocolos (Chat, Responses, Anthropic Messages, Gemini). AlternateFormat ganha o hook urlBuilder opcional (necessário para o path model-scoped do Gemini), compartilhado com o provider gemini nativo em vez de duplicado.
Reconciliado nesta sessão contra o release tip atualizado (base drift real: 343→345 canônicos entre quando o PR foi criado e o merge, mais os PRs #10673/#10658 mergeados nesse meio-tempo). Conflitos em contagens de providers (docs, file-size baseline, teste de partição) resolvidos additivamente.
Validação (reconciliação a partir de origin/release/v3.8.50):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- npm run check:provider-consistency — OK (266 REGISTRY entries, 346 providers canônicos, 0 exceções)
- 40/40 testes passando (newapi-gateway-providers, hcnsec-provider, providers-constants-split, alternate-formats)
Merged — extraction of the one still-uncovered fix from #8634 (the other two items — mode "search"→CONCISE downgrade, pplx-opus generation — were already applied on this release tip). typecheck/file-size/changelog/complexity/cognitive-complexity gates all clean, 32/32 tests passing.
Obrigado — feature substancial e bem estruturada: separa qualidade operacional (comportamento de wire: 4xx/5xx, 429, respostas malformadas, stream interrompido) de qualidade semântica (só setada por avaliadores externos, nunca inferida do sucesso HTTP), com confidence/sample-awareness para não deixar poucos sucessos de sorte dominarem o ranking. Instrumentação de streaming (TTFT/ITL) threaded até RoutingEvent, endpoint de explicabilidade, e teste E2E determinístico cobrindo degradação→recuperação→blip.
Validação (worktree própria a partir de origin/release/v3.8.50, merge limpo, 0 conflitos):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- 59/59 testes passando (mlx-provider, routing-adaptive-e2e, routing-events(-concurrency), routing-otel, routing-quality, routing-scoring-quality, stream-timing, auto-combo-scoring-clamp)
Obrigado — bug real e bem raiz-causado: api64.ipify.org é IPv6-first e derruba tunnels IPv4-only, o que estava reportando proxies vivos como mortos.
Validação (worktree combinado a partir de origin/release/v3.8.50, 0 conflitos):
- typecheck:core limpo, complexity 2563/2774, cognitive-complexity 1155/1223 (baseline)
- tests/unit/proxy-echo-ipv4-fallback-9694.test.ts — 8/8 passando (cobre ordem, split de budget, override, proxy morto de verdade)
- Suítes proxy-relacionadas: 805/817 na branch vs 797/809 no release, as 11 falhas são idênticas em ambos os lados e não relacionadas (TLS transport, tproxy CA, SSRF fallback)
Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related maxmad64bis PRs in one combined worktree (typecheck:core clean, complexity/cognitive-complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related maxmad64bis PRs in one combined worktree (typecheck:core clean, complexity/cognitive-complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Today's merge-train batch1 (#10722 Token Kiosk, #10729 Cursor) each added one
new APIKEY_PROVIDERS entry, bringing the live provider count to 343 — the
hardcoded '342' in README.md, AGENTS.md, llm.txt, package.json's description,
PROVIDER_REFERENCE.md, and 4 hero/comparison SVGs went stale as a result.
check:docs-counts (STRICT) now passes; regenerated PROVIDER_REFERENCE.md via
npm run gen:provider-reference. The v3.8.50 growth-log table row in README.md
(line 66) is left as-is — it's a historical point-in-time snapshot, not a
live claim.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
* feat(docker): expose DASHBOARD_ALLOW_EMBED as a build argument
The dashboard's frame-ancestors policy is compiled into the route manifest at
build time, so the only way to get an embed-enabled image was to edit the
Dockerfile: Docker silently drops a --build-arg with no matching ARG, so
`docker build --build-arg DASHBOARD_ALLOW_EMBED=vscode` produced the default
image and no error.
Declared as ARG+ENV in the builder stage, mirroring OMNIROUTE_BASE_PATH, and
empty by default — the unframable default posture is unchanged. The runtime
stages deliberately do not carry it: the headers are already baked, so a
runtime value would advertise an effect it cannot have.
Guarded by tests/unit/dockerfile-dashboard-embed-arg-10273.test.ts, verified by
mutation (a bare ENV in place of the ARG fails 2 of the 3 assertions). Docs
updated across the guide, ENVIRONMENT.md and .env.example.
The guide also carries prettier normalization (emphasis markers, table
padding) applied by lint-staged on commit.
Refs #10273
* chore(changelog): correct the fragment to the real PR number (#10701)
---------
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Counts (check:docs-counts STRICT, 8 drifts → 0):
- 153 → 154 migrations in README.md, AGENTS.md and llm.txt (+ its 42 i18n mirrors,
which must stay byte-identical to the root file)
- 340 → 341 providers in README.md, AGENTS.md, llm.txt, the package.json description
and the 4 SVG diagrams; PROVIDER_REFERENCE.md regenerated via gen:provider-reference
(the new entry is the cloudflare-playground no-auth provider)
Undocumented environment variables:
- 13 CLI_*_BIN vars that exist in cliRuntime but were in neither ENVIRONMENT.md nor
.env.example (kilo, opencode, hermes, forge, jcode, deepseek-tui, codewhale, smelt,
pi, crush, omp, letta, windsurf — windsurf ships no default command)
- OMNIROUTE_DEBUG and OMNIROUTE_HEALTHCHECK_PATH, read in code but absent from
.env.example
- CLI_CURSOR_BIN documents both fallbacks (agent, then cursor)
Front-matter: bump the seven CLI/reference docs this effort touched from the stale
3.8.40/2026-06-28 stamp to the current release.
Out of scope but blocking check:docs-all, fixed with evidence: ENVIRONMENT.md and
.env.example still documented the Adobe Firefly CDP Chrome runtime removed in #9255.
Seven of its variables are read nowhere in the codebase and its source file no longer
exists; surviving vars are repointed at adobeFireflyBrowserLogin.ts and CHROME_PATH at
its real readers. The two Gemini CLI auth vars the run launcher scrubs from the child
env are added to the fabricated-docs external-tool allowlist, next to the existing
CODEX_HOME/COPILOT_PROVIDER_BASE_URL entries.
npm run check:docs-all now exits 0 for the first time on this base.
- ENVIRONMENT.md: CLI_ALLOW_CONFIG_WRITES default is true (matches cliRuntime),
CLI_QODER_BIN default is qodercli (also in .env.example), CLI_GEMINI_BIN is
server-side detection only (omniroute run resolves from PATH)
- CLI-TOOLS.md: catalog counts 26 code / 8 agents (adds the missing zcode row),
setup targets without auto-discovery list Qwen (not Gemini; Gemini is
launch-only), hostSetupCommand only for the six tools with a host recipe,
global env block uses GOOGLE_GEMINI_BASE_URL at the root, mention
omniroute run as the generic launcher
- CLI-INTEGRATIONS.md: manifest aliases, per-target --model wiring (openai/ and
omniroute/ prefixes, qwen hard-requires --model), run exit-code contract,
gemini child-env scrub notes
- CODEX-CLI-CONFIGURATION.md: document omniroute configure codex / run codex
- SETUP_GUIDE.md + QUICK-START.md: surface the generic omniroute run launcher
- ENVIRONMENT.md: disambiguate OMNIROUTE_SMOKE_API_KEY (canary) from the
OMNIROUTE_SMOKE_* CLI smoke-harness variables
A single orphaned "<<<<<<< HEAD" line (no matching =======/>>>>>>>
pair) leaked into release/v3.8.50 via PR #10039's merge-conflict
resolution during this session's serial-merge sweep. Repo-wide sweep
confirms no other stray markers exist. Table structure verified
intact before/after removal.
- README: 'run any supported CLI in one command' block (7 targets incl. gemini),
updated one-command setup bullet with run/configure
- CLI-INTEGRATIONS: gemini in the master table + run examples + base-URL row
(GOOGLE_GEMINI_BASE_URL → /v1beta), opt-in smoke sweep section
- REMOTE-MODE: 'launching a CLI against the remote' section (run + contexts)
- CLI-TOOLS: gemini install step in Quick Start
- ENVIRONMENT/.env.example: CLI_AIDER_BIN, CLI_GOOSE_BIN, CLI_GEMINI_BIN
- API_REFERENCE: apply endpoint row documents dryRun/422/migration contract
- smoke harness fixes proven against a live local OmniRoute: node:test treats
timeout:0 as 'time out immediately' (sized budget from the per-target cap),
and resolve on child 'exit' instead of 'close' so grandchildren holding the
stdio pipes cannot hang a target (qwen was blocked 431s past its 120s cap).
Live evidence: gemini exit=0 pass via /v1beta against localhost; all four
installed CLIs (codex/opencode/qwen/gemini) reached the upstream end-to-end
with correctly classified upstream errors (free-tier 429 / ddgw 400).
* feat(providers): add Cloudflare AI Playground as No Auth provider (closes#10389)
Reverse-engineered access to the free, anonymous Cloudflare AI Playground:
chat runs over a PartySocket WebSocket speaking Cloudflare's cf_agent RPC
protocol with zero credentials (no account, no API key, no cookies). The
WS upgrade is gated on a browser-grade TLS fingerprint, so the executor
drives a headless Chromium via Playwright and speaks the protocol from
inside the page context.
- registry entry: cloudflare-playground (alias cfp), authType none,
curated 20-model catalog (GLM 5.2, Kimi K2.7 Code, DeepSeek V4 Pro,
gpt-oss-120B, Llama 3.3 70B, Qwen2.5 Coder 32B, ...) captured from the
live getModels RPC (2026-08-15)
- executor: cf_agent frame stream -> OpenAI SSE translation, id-filtered
parser (RPC done:true frames cannot kill the stream), in-band upstream
errors mapped to HTTP 429/502, abort + timeout handling, clean errors
- noauth UI entry with reverse-engineered-endpoint notice
- tests: 12 unit tests using real captured frames (incl. the 3021
rate-limit error) + fake transport; ESLint clean; open-sse typecheck clean
* fix(providers): define __name helper in page context before evaluate
Bundlers with keepNames (esbuild/tsx, webpack) inject a __name() call into
serialized function bodies. page.evaluate(openPlaygroundSession) therefore
threw ReferenceError: __name is not defined in real browser sessions.
Define the helper on window before evaluating the session opener.
* fix(providers): sync docs counts, golden snapshots and add reasoning_content support for cloudflare-playground
* chore: remove ad-hoc cfp-shim debug script per review feedback
The standalone shim duplicated the executor's frame-parsing and transport
logic and is superseded by open-sse/executors/cloudflare-playground.ts.
Requested in PR #10442 review.
* feat(gemini-web): expose image generation through /v1/images/generations (closes#10466)
Adds a gemini-web image-generation path following the chatgpt-web precedent:
- imageRegistry: gemini-web provider entry (format gemini-web, cookie auth)
with the nano-banana-web model. The -web suffix keeps the bare
nano-banana id owned by adobe-firefly (operator decision 2026-07-31).
- gemini-web executor: new parseStreamResponseImages() extracts generated
image URLs from the StreamGenerate candidate extension block
(inner[4][0][12][7][0], url at entry[0][3][3] — string or list form),
dedupes cumulative frames, upgrades to =s2048, and deliberately skips
web-search thumbnails at [12][1]. Image mode (x_gemini_web_image_mode)
captures every StreamGenerate frame, resolves on first image, and gets
a 90s window; chat mode is byte-for-byte unchanged.
- handlers/imageGeneration/providers/geminiWeb.ts: drives the executor in
image mode with an explicit generation directive prompt (the web UI
otherwise answers with web-search images), caps n at 4, returns URLs or
b64_json (downloads the public googleusercontent asset), and surfaces
refusal text when no image was produced.
- Dispatch branch on format gemini-web in handleImageGeneration.
Tests: 21 new tests with fixtures built from the documented frame layout
(string/list url forms, cumulative-frame dedupe, web-image exclusion,
size-directive handling, refusal visibility, n-cap, b64_json, registry
wiring incl. the bare nano-banana → adobe-firefly regression guard).
Adjacent suites: gemini-web (6 files), chatgpt-web image, image handler,
route, registry, adobe-firefly, freepik, designer — all green.
ESLint clean on touched files (2 pre-existing any warnings unchanged);
tsc -p open-sse 0 errors.
* fix(media): close browser leak, surface timeout errors, and fall back accounts for gemini-web images
Addresses pre-merge review findings on #10494 (closes#10466):
- cloudflare-playground executor: close the launched browser on EVERY
non-success start() path, including the detected Cloudflare "Attention
Required" challenge branch (was leaking a Chromium process per blocked
request).
- cloudflare-playground executor: a streaming chat timeout now emits an
explicit timeout_error SSE chunk before [DONE] instead of silently
completing, so a client can no longer mistake an empty/partial timed-out
stream for a successful answer. Timeout duration is now injectable for
deterministic tests.
- gemini-web image handler + imageCredentialRetry: classify the underlying
GeminiWebExecutor's expired/blocked-session failure modes (400/500, per
its own Playwright timeout/catch-all branches) as retryable, so
executeImageWithCredentialFallback advances to the next eligible account
instead of only doing so on a plain 401.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs: regenerate provider counts after merging release/v3.8.50 (341 -> 342)
The previous merge commit resolved all 51 auto-generated-file conflicts by
taking release/v3.8.50's content, which still said 341 providers. Merging in
this branch's Cloudflare Playground provider brings the live catalog to 342,
so npm run check:docs-counts-sync now flags stale claims. Fix:
- docs/reference/PROVIDER_REFERENCE.md: regenerated via
`npm run gen:provider-reference`.
- README.md/AGENTS.md/llm.txt/package.json description: 341 -> 342.
- docs/diagrams/{readme-hero,promise-pillars,comparison-table,cli-terminal}.svg:
341 -> 342 in the embedded "NNN providers" text (targeted replace, matched
against the exact pattern check-docs-counts-sync.mjs validates).
check:docs-counts-sync and check:changelog-integrity are both clean after
this commit.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs(env): document CLOUDFLARE_PLAYGROUND_CHROME_PATH
Used by open-sse/executors/cloudflare-playground.ts but missing from
.env.example and docs/reference/ENVIRONMENT.md, caught by the
env-doc-sync gate when combined with other PRs in the release
merge-train.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: user.email <freakymustard67@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* feat(admission): per-target lane-aware probes for combo/fusion fan-out (#9654 Wave 2)
Combo and fusion fan out N targets without ever consulting the adaptive-admission
layer: the parent request holds one lease, but each fan-out target is dispatched
unconditionally. With virtual lanes enabled (OMNIROUTE_CHAT_VIRTUAL_LANES=1), a
connection whose lane queue is full now SKIPS additional fan-out targets instead
of piling more queued work onto an already-congested session.
Adds PerTargetAdmissionHook (admission/types.ts) + createPerTargetAdmissionHook
factory (chatAdmission.ts): strictly non-blocking (maxWaitMs 0 - skip, never
queue), a no-op when virtual lanes are off, keyed to the parent tenantKey, and
release-on-admit so the probe is a capacity gate, not a hold.
Threaded through every parallel fan-out path:
- priority/weighted executeTarget + round-robin skip chains (combo.ts)
- fusion panel before fan-out (fusion.ts), judge fallback prefers survivors
- chaos parallel panel (autoCombo/chaosEngine.ts)
- tryFusionDispatch / tryRuntimeUnitDispatch / buildBaseOptions (dispatchPrelude.ts)
- chat.ts primary + safety-net redirect call sites
Snapshot exposes virtualLanes so the no-op gate is cheap and honest.
Tests: tests/unit/combo-lane-awareness-9654.test.ts (10 tests) - factory
semantics, priority/RR skip, fusion panel drop + all-skipped 503, no-hook
backward-compat baseline.
* feat(flags): activation UX - env-wins adaptive virtual-lanes flag + env docs (#9654 Wave 2)
U7: make adaptive virtual admission lanes discoverable + activatable.
- New OMNIROUTE_CHAT_VIRTUAL_LANES feature flag (boolean/runtime/requiresRestart) in featureFlagDefinitions + en.json i18n key.
- lib/admissionVirtualLanes.ts: env-wins resolver (env > DB > default) + boot warm folding a DB-sourced override into the process-global runtime env via reloadAdaptiveAdmissionRuntime(options.env) - no process.env mutation, no open-sse changes. Env still wins; DB toggle gates at next boot.
- GET /api/settings/feature-flags special-cases the flag to report the gate true source (ccDiscoveryAliases precedent); flagPayload helper dedupes the payload shape.
- Wire the warm into instrumentation-node registerNodejs (non-fatal, DB-ready).
- Document the master switch in .env.example + ENVIRONMENT.md with the system-1/system-2 distinction; zero new env-doc-sync drift.
- 11 new tests (resolver precedence + warm); 60/60 across feature-flag suites; typecheck core clean; ESLint + doc gates green.
* feat(mcp): surface adaptive admission lane data in omniroute_get_health (#9654 Wave 2)
U8: make adaptive virtual-lane admission visible to agents via the MCP health tool. handleGetHealth now surfaces a curated adaptiveAdmission block from the health payload (which already carried the runtime snapshot but was dropping it): virtualLanes/pressure/utilization/laneCount/laneQueuedCount/laneQueuedCost, laneTenants capped at top-10 by queued cost, admitted/rejected/wouldReject counts, shutdown. Block omitted entirely when the health endpoint reports none.
isLaneFlagOn mirrors the runtime 1|true convention so a string serialization can never invert a boolean lane report. getHealthOutput schema extended with the matching optional shape; tool description updated.
4 new dispatch tests (full block, top-10 cap/order, omission, defensive coercion of string flags + malformed lane entries) - 22/22 in essentialTools.test.ts. README: Adaptive Admission Lane Data table + Skills & Tool Navigability audit (29/43 schema entries covered, 14 undocumented, tool_search keyword runtime discovery, full catalog in docs/frameworks/MCP-SERVER.md).
No new lint errors (4 pre-existing in server.ts), typecheck core clean, doc counts + fabricated-docs gates green.
* docs: add changelog entry for #9654 Wave 2 (#10039)
* fix(codeql): suppress js/insufficient-password-hash false positive in lane-key fingerprinting (#10039)
resolveSessionId sha256-hashes bearer/x-api-key/x-goog-api-key to derive a deterministic, non-reversible per-key lane-bucket ID for virtual admission lanes (#9654). This is not password storage or verification, so the rule is a false positive; suppress it inline (same house style as src/lib/sync/tokens.ts) to clear the codeqlAlerts ratchet (2 > baseline 1) that blocks #10039 and every PR against release/v3.8.50.
* docs(mcp): complete MCP server README tool reference (#10039)
The MCP server README covered only 29 of the 43 schema entries, listing the
remaining tools solely as a gap note with omniroute_tool_search as the runtime
fallback. Add tool-reference tables for the agent-skills trio, oneproxy trio,
web_fetch/web_search, tool_search, create_combo, set_routing_strategy,
pick_fastest_model, sync_pricing, and db_health_check so the README covers the
full schemas catalog, and fold the coverage note into the tool_search discovery
paragraph.
* fix(chat): drop unused correlationId from safety-net combo redirect (#10039)
handleComboChat's HandleComboChatOptions has no correlationId member and
the combo pipeline never consumes it; the property was copied from the
handleSingleModelChat options shape by accident and introduced a new
TS2353 under the open-sse workspace typecheck gate.
* fix(i18n): translate featureFlagChatVirtualLanesEnabledDescription into 42 locales (#10039)
en.json gained the flag description in this PR but the locale catalogs
were never mirrored, failing the pt-BR key-parity (#6695) and vi
completeness gates. Adds a real translation to every locale, keeping the
zh-CN/zh-TW glossary canonical terms (提供者/儀表板) and no ICU drift.
* chore(quality): ratchet open-sse-typecheck baseline down (#10039)
The Wave 2 admission refactor removed 66 baselined open-sse type errors;
re-freeze the baseline so the gate pins the new, tighter state.
* docs: resync provider reference to 341 and CLI tools to 34
The release branch gained an 11th no-auth provider (freeaiapikey registry
resync, #10233) and a 26th CLI Code tool without regenerating the
auto-generated docs, leaving every PR against release/v3.8.50 failing the
Docs Gates strict validator (code 341 vs doc 340, CLI 34 vs "33 tools").
Regenerate docs/reference/PROVIDER_REFERENCE.md and sync the provider/tool
counts across README.md, AGENTS.md, llm.txt plus 42 i18n mirrors,
package.json description, and the four diagram SVGs.
* fix(tests): align count expectations with live catalogs (pre-existing release drift)
Release/v3.8.50 currently fails five gates on its own tree; this PR inherits
them. Fix the stale expectations to match live code:
- feature-flags-settings: 48 -> 49 flags (Wave 2 adds OMNIROUTE_CHAT_VIRTUAL_LANES)
- cli-tools-schema / cli-catalog-counts: 33 -> 34 tools (zcode added; 26 code = 21 visible + 5 none)
- optional-transformers-dependency: onnxruntime-node ~1.24.3 -> ~1.27.0 (bump #10382)
- stryker.conf.json: register chatcore-header-drop-warn-dedupe-10315 test
- check-public-creds: freeze zcodeProtocol clientId false positive (client identifier, not a credential)
* fix(tests): follow release's onnxruntime-node revert to ~1.24.3
release/v3.8.50's #10543 pinned onnxruntime-node back to ~1.24.3 after
#10403's ~1.27.0 bump caused npm to nest a second native copy under
@huggingface/transformers and broke the Docker SONAME contract. This
PR's own drift-alignment commit (57b9c033) predates that revert and
still expected ~1.27.0; the 3-way merge did not flag it as a textual
conflict since only one side touched this exact line, but the merged
tree became internally inconsistent (package.json ~1.24.3 vs test
expecting ~1.27.0). Align the test with the now-canonical release
value.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(quality): dedupe stryker.conf.json chatcore-header-drop-warn-dedupe entry
The 3-way merge applied both sides' insertion of the same test-file entry
at different positions, producing a duplicate with broken indentation.
Adopted release's clean version of the file.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: Brandon Bennett <brandonbennett@macbookair.myfiosgateway.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: Brandon Bennett <branben@users.noreply.github.com>
* fix(logging): redact client IPs and account prefixes by default
ProxyEgress and AUTH logs exposed client IPs, egress IPs, and account
prefixes at info level — a privacy leak in multi-tenant/shared-log
environments. Now redacted by default, only shown when debugMode=true.
Fixes#10348
* fix(sse): default SSE comment lines to disabled
Strict SSE clients (WorkBuddy, etc.) JSON.parse every SSE line and
crash on comment lines. Changed OMNIROUTE_SSE_COMMENTS
default from enabled to disabled. Operators can opt in with
OMNIROUTE_SSE_COMMENTS=on.
Fixes#10524
* fix(logging): gate AUTH account-prefix redaction on a narrow flag, not debugMode
The proxy-log redaction half of #10348 is superseded by an already-merged
fix (PROXY_LOG_INCLUDE_IPS, decoupled from debugMode). The remaining gap was
the chat.ts AUTH log line ("Using <provider> account: <prefix>..."), which
this PR gated on the broad `debugMode` setting. `debugMode` is a general
dashboard-visibility toggle unrelated to log privacy — coupling redaction to
it means any future, unrelated change to debugMode's default silently
changes whether account prefixes leak into logs.
Add a dedicated AUTH_LOG_INCLUDE_ACCOUNT_ID feature flag (default off,
security category) and gate the AUTH log line on it via
isFeatureFlagEnabled(), which reads the DB override synchronously on every
call (no stale in-memory cache to invalidate) and fails safe to redacted on
any lookup error.
Also update the SSE-comments tests/docs that still asserted the old
enabled-by-default behavior (tests/unit/sseHeartbeat.test.ts,
tests/unit/sse-comments-optout-9305.test.ts, docs/reference/ENVIRONMENT.md)
to match the new default-off behavior from this PR's earlier commit.
Refs #10348, #10524
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(audio): fall back nested STT models when the prefix provider has no credentials
Bare ids such as deepgram/nova-3 prefix-match the native provider and 400
when that key is missing, even if OpenRouter lists the same model. Retry
the gateway and mention qualified catalog ids in the error.
Closes#10583
* test(audio): scope whisper-1 fallback test to a 2-provider registry
nanogpt was added to AUDIO_TRANSCRIPTION_PROVIDERS (already merged,
unrelated to this fix) with a bare "whisper-1" model id, which now
intercepts findAlternateAudioProvider's first candidate before the
qualified-alias branch this test exists to cover. Scope the test to a
local {openai, openrouter} registry subset so it deterministically
exercises the qualified `${provider}/${model}` fallback regardless of
future providers that also list a bare "whisper-1" id.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* feat(providers): complete Jina AI via OmniRoute including Omni multimodal
Dashboard and env keys share one Jina credential pool, native v5 Omni
{text}/{image}/{content} docs pass through /v1/embeddings intact, and
classify/segment/search are proxied without a third unused Jina card.
* chore(changelog): name Jina complete-provider fragment for #10581
* feat(providers): make Gemini Embedding 2 multimodal work via OmniRoute
Route gemini-embedding-2 through embedContent/batchEmbedContents so N
OpenAI input items become N vectors, pass through native multimodal
parts, and use dashboard Gemini keys (GEMINI_API_KEY only as fallback).
* fix(providers): resolve rebase fallout for Jina/Gemini embeddings
- narrow the two new no-explicit-any violations introduced by this PR
(validateJinaFoundationProvider's params + catch, search.ts's
normalizeJinaSearchResponse data param)
- cast credentials to Record<string, unknown> at the two quota-preflight
call sites in src/sse/services/auth.ts so the new JinaEnvCredentials /
GeminiEnvCredentials union members type-check without loosening the
allRateLimited narrowing used elsewhere in the same function
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(opencode): session stability, free-tier routing, and CLI defaults
- Wire generateSessionId() into opencodeHeaders so x-opencode-session
is a deterministic fingerprint instead of randomUUID() per request,
enabling upstream prompt caching across a conversation
- Thread request body through buildHeaders() so session fingerprint
has access to model, system, messages, and tools
- Default CLI header synthesis to ON (opt-out via false), align
values with 9router proven defaults (opencode/desktop/global)
- Auto-echo listing-valid model names for noAuth providers so
response.model matches /v1/models listing
- Short-circuit free-tier model resolution to opencode provider first
to prevent prefix inference misrouting when catalog is unreachable
* fix(opencode): make free-tier default flip self-consistent + add coverage
PR #10571 flipped OPENCODE_SYNTHESIZE_CLI_HEADERS to on-by-default and
changed the synthesized UA/client/project default values, but shipped
with 2 broken assertions in the existing #5997 regression test and no
coverage for the new session-fingerprinting, free-tier routing, or
noAuth echoModel logic (Hard Rule #18).
- Update tests/unit/opencode-cli-headers-synthesis-5997.test.ts to match
the new on-by-default behavior and new default values; add an explicit
opt-out coverage test so the forward-only path is still guarded.
- Fix 20 further test failures in tests/unit/opencode-executor.test.ts
and tests/unit/refactor-buildHeaders-opencode.test.ts caused by the
same default flip (pin OPENCODE_SYNTHESIZE_CLI_HEADERS=false for the
characterization suites that predate #10571; use a genuinely
CLI-looking UA where the preserved-UA test requires one).
- Fix a real bug found via TDD while adding the mandated free-tier
routing regression test: the big-pickle/*-free short-circuit in
open-sse/services/model.ts checked activeProviders?.has("opencode")
literally, but getActiveProviderSet() canonicalizes every connection's
provider id through resolveProviderAlias(), which rewrites "opencode"
to "opencode-zen" via a manual override — so an active no-auth
opencode connection could never satisfy the check. Now checks both
opencode-family candidate ids. Proven with a test that fails on the
original code and passes with the fix (both connections active with a
stale synced catalog omitting big-pickle).
- Extract the noAuth-provider echoModel aliasing in chatCore.ts into a
pure, directly-testable helper (open-sse/handlers/chatCore/noAuthEchoModel.ts),
matching the existing chatCore god-file decomposition pattern.
- Add regression tests for generateSessionId()-based x-opencode-session
fingerprinting (stable within a conversation, changes on model/message
changes), the free-tier routing short-circuit, and the noAuth echoModel
aliasing.
- Add the changelog.d/ fragment and sync docs/reference/ENVIRONMENT.md's
OPENCODE_SYNTHESIZE_CLI_HEADERS/OPENCODE_USER_AGENT/OPENCODE_CLIENT/
OPENCODE_PROJECT rows to the new defaults.
Does NOT resolve whether flipping OPENCODE_SYNTHESIZE_CLI_HEADERS's
default was the right call, and does NOT touch the separate open PR
#10357 which flips the same flag with a different literal default value
- that decision is left to the maintainer at merge time.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(memory): auto-check Qdrant health on mount and stop false-red badge
The Qdrant engine card on /dashboard/memory?tab=engine showed a red
"Error" badge after every page refresh even when Qdrant was healthy:
the badge derives its state from a health check, but the mount effect
only fetched settings + embedding models — health started as null and
the render treated `health?.ok` (undefined) as a failure. Clicking
"Test connection" (which runs the same server-side /readyz check)
immediately turned it green, proving the connection was fine.
Two changes:
- Auto-run the health check on mount once settings load and Qdrant is
enabled, so a refreshed page reflects the real state (verified live:
/api/settings/qdrant/health returns ok:true in ~2ms on a healthy
compose deployment).
- While health has not been checked yet (null), render a neutral gray
"Testing..." state instead of red — red is now reserved for an
actual failed health check.
Regression test added (fails on the old code): with enabled settings
and a healthy mock, the card must hit /api/settings/qdrant/health on
mount and show statusActive, never statusError.
* chore(changelog): fragment for #10489
* Merge branch 'release/v3.8.50' into fix/qdrant-health-badge
* test(fix): refresh expired alibaba quota sample validity and onnxruntime pin for v3.8.50 base
- alibaba-free-tier-quota-fetcher.test.ts: sample quotaValidityPeriod
(2026-08-16 16:00 UTC) is in the past, making every quota entry classify
as expired/not_capable; bump to 2028-01-01 UTC so the text/merge
classification tests exercise the intended path again.
- optional-transformers-dependency.test.ts: onnxruntime-node pin assertion
updated from ~1.24.3 to ~1.27.0 to match package.json (bumped by #10403);
the regular-not-optional intent is unchanged.
* test(fix): align optional-transformers-dependency with onnxruntime ~1.24.3 pin (base #10543)
* docs(fix): sync 150-migration count and document PROXY_LOG_INCLUDE_IPS (base drift #10348/#10507)
* fix(memory): re-check Qdrant health after saving settings
save() optimistically flipped enabled and started the PUT while the mount
effect could immediately GET /api/settings/qdrant/health against the OLD
persisted settings. If that GET won, it returned not_configured/failed and -
because health was non-null - the effect never retried after the PUT
succeeded, leaving a healthy Qdrant red until a manual Test connection.
Invalidate health (generation counter + setHealth(null)) at save start and
after a successful PUT, then explicitly schedule a fresh check: setting
health to null alone is not enough, React bails on the no-op when health is
already null (the exact GET-wins ordering). Stale responses are dropped via
the sequence guard so an in-flight pre-save check can never overwrite the
post-save result. Adds a regression test covering enable ordering.
Addresses PR #10489 review finding (issuecomment-5312271806).
* fix: narrow omniglyph transform result union (merge base aa912c42a typecheck gate)
* test(compression): align contract tests with base aa912c42a merge (providerTransport shape, engine metadata)
* fix(memory): silence set-state-in-effect on Qdrant auto health-check
The health-check re-check fix (3469234) introduced an effect that calls
checkHealth() (an async fetch that eventually calls setState) directly
from a useEffect gated on loading/enabled/health. The
react-hooks/set-state-in-effect rule flags this as a potential cascading
render, matching the same pattern already accepted elsewhere in the
dashboard (FreePoolTab.tsx, ConnectionsTable.tsx) for gated async
data-fetch effects. Suppress with the established inline convention;
no behavior change.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(memory): drop unused set-state-in-effect disable (rule inert on pinned react-hooks 7.0.1)
The eslint-disable-next-line for react-hooks/set-state-in-effect is unused:
eslint-plugin-react-hooks@7.0.1 (lockfile-pinned) does not report this rule,
so the directive itself was flagged as a warning and the 'No new ESLint
warnings' CI gate failed with --max-warnings 0. The effect body only calls
checkHealth() (async fetch) with no raw setState, so no disable is needed.
* ci(quality): sync ratchet configs to release/v3.8.50 (0a74bfbde) merge
- re-freeze open-sse typecheck baseline at merged-tree live counts
(64 stale entries dropped, 11 frozen; base video/usage drift covered)
- register tests/unit/video-bridge-drilldown-route.test.ts in stryker tap.testFiles
- regenerate skills/cli-contexts/SKILL.md (contexts migrate docs from CLI closure)
---------
Co-authored-by: Rouzbeh <rqzbeh@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(sse): gate structural chat admission shedding on real heap pressure
Closes#10183, Closes#10268
3.8.49 (#9654/#9940) replaced the 3.8.48 heap-ratio shed
(heapUsed/heapLimit >= 0.75) in chatBodyAdmission.ts with an
unconditional CHAT_MAX_HEAVY_IN_FLIGHT=1 structural lease. A second
concurrent "structurally heavy" chat request (>=200 messages, >=64
tools, or >=32k estimated tokens — routine for coding-agent fan-out
like Hermes/Cursor/Claude Code) was hard-rejected with a retryable
HTTP 503 chat_admission_busy/structure_limit regardless of actual
heap pressure, even on a host with ample free RAM.
Restore the heap-conditional gate as an ADDITIONAL check layered on
top of (not a replacement for) the #9654 bounded-concurrency /
per-connection-lane protection: when heavyweight capacity is busy,
only enter the bounded-wait/shed path when a live heap-pressure probe
(heapUsed / v8 heap_size_limit >= OMNIROUTE_CHAT_ADMISSION_HEAP_SHED_RATIO,
default 0.75) confirms real pressure. A healthy heap now admits the
second heavy request immediately via a no-op lease instead of parking
or shedding it. The probe is injectable via
admitChatStructure({ heapPressureCheck }) for deterministic tests.
Regression tests:
- tests/unit/bug-10183-admission-heavy-healthy-heap.test.ts (new,
permanent): healthy-heap 2nd heavy request now admitted (was RED);
genuinely pressured heap still sheds it.
- tests/unit/probe-10268-structural-503.test.ts (promoted to
permanent): the exact reported 503 chat_admission_busy shape is
still produced under real heap pressure, and the same fan-out is
admitted on a healthy heap.
- tests/unit/chat-body-admission.test.ts,
tests/unit/chat-body-admission-queue.test.ts,
tests/unit/per-connection-admission-9654.test.ts updated to inject
heapPressureCheck: () => true where they exercise the busy/shed
path, preserving #9654/#4380 coverage.
Gates run: npm run typecheck:core (clean), eslint --suppressions-location
config/quality/eslint-suppressions.json on changed files (clean),
scripts/check/check-file-size.mjs (OK), scripts/check/check-test-discovery.mjs
(OK), focused admission suite (68/68 passing) and npm run test:unit
(in progress at commit time under heavy shared-devbox contention from
a 13-way parallel session fan-out; no admission-related failures
observed through 1873 lines of output, the sole failure seen was a
pre-existing unrelated proxy/search timeout consistent with known
load-induced flakiness, not a regression from this change).
⚠️ base-red inherited: #9985 — ESLint errors (2) from #10250
* docs(env): document OMNIROUTE_CHAT_ADMISSION_HEAP_SHED_RATIO (#10183, #10268)
* fix(sse): bound the healthy-heap admission fast path (#10437)
The #10183/#10268 fix admitted a busy heavyweight request immediately
whenever the heap was healthy, via an unconditional no-op lease with no
bound of its own -- an unlimited number of "healthy heap" requests could
pile in ahead of the heap-pressure shed path, defeating the point of
admission control.
Adds an independent, bounded healthy-heap headroom budget
(CHAT_ADMISSION_HEALTHY_HEADROOM, tryAcquireHealthyHeadroom()) that the
healthy-heap fast path draws from; once exhausted, requests fall through
to the same bounded-wait/shed path used under real heap pressure, which
is otherwise unchanged. Also fixes a pre-existing gap in
per-connection-admission-9654.test.ts's shared-budget test, which needed
an explicit heapPressureCheck override to keep exercising the #10110
invariant now that a healthy heap gets bounded headroom instead of an
outright reject.
* docs(env): document OMNIROUTE_CHAT_ADMISSION_HEALTHY_HEADROOM in .env.example
Documented in docs/reference/ENVIRONMENT.md but missing from .env.example,
caught by the env-doc-sync gate when combined with other PRs in the
release merge-train.
---------
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
* remove: drop sunset MiMoCode provider from model catalog
* remove: drop sunset MiMoCode provider from model catalog (shared.ts)
Remove unused imports, types, and comments from shared.ts.
* remove: MiMoCode provider (Xiaomi sunset) — executor, registry, no-auth config, icon, tests
* refactor(providers): finish MiMoCode removal — sweep remaining no-auth references
Drop the leftover mimocode entries from the no-auth provider controls, the
translate-path snapshot, the eslint suppressions, and the #3061 auth-loop
test. Re-point the fingerprint-pin (#6696) and proxy-noauth (#6272) tests at
opencode, which exercises the same fingerprint path, so the removal does not
break runtime behavior.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs(providers): reconcile provider/executor counts after MiMoCode sunset
The base's parallel doc-count sync (#10433) pinned 340 providers / 101
executors. With mimocode removed, live code has 339 providers and 100
executors; refresh the user-facing counts (package.json description,
llm.txt, README/AGENTS, i18n llm.txt, provider reference, diagrams) so the
check-docs-counts STRICT gate stays green.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* test(providers): fix orphaned mimocode references after MiMoCode sunset
The sunset removed mimocode/mcode from the free-onboarding candidates and
from FINGERPRINT_PROVIDERS, but two tests still referenced them:
- free-provider-onboarding-setup: the mimocode->theoldllm substitution
introduced duplicate 'opencode' rows (impossible given the request-set
dedupe) and the wrong display name; align expectations with the actual
{opencode, theoldllm} dedupe behavior and 'The Old LLM (Free)' name.
- combo-system-prompt-templates-5501: resolveTargetFingerprint tested with
provider 'mcode', which is no longer a fingerprint provider; point it at
the remaining fingerprint provider 'opencode'.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: Tushar49 <Tushar49@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* feat(quota): Phase 2 adapters, reset timers, analytics, and dashboard API
* feat(routing): add quota-aware provider scheduling (opt-in)
* fix(db): rename migration to 148_provider_quota_state.sql
* fix(quota): harden quota state route, isolate phase2 tests, slim env diff
- route: requireManagementAuth + Zod body validation + buildErrorBody
sanitization (Hard Rule #12); fix clearProviderQuotaState -> clearProviderQuota
- .env.example/ENVIRONMENT.md: drop ~20 foreign vars, keep only
OMNIROUTE_QUOTA_AWARE_ROUTING (migration 148)
- tests/unit/quota-phase2.test.ts: DATA_DIR mkdtemp + resetDbInstance teardown
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* chore(ci): fix docs-sync + eslint-suppression drift for quota branch
CI gates flagged on PR #10126 head 43335f07:
- migration counts in README/AGENTS/llm.txt were stale (145 -> 146)
- regenerate docs/reference/PROVIDER_REFERENCE.md (gen-provider-reference)
- sync root llm.txt body into all 42 i18n mirrors (headers preserved)
- prune eslint suppressions that no longer occur
--no-verify: pre-commit docs-sync was failing on a pre-existing
release-base artifact (changelog 3.8.49 vs package 3.8.50) — fixed by
the changelog entry in the prior commit; re-verify in CI.
* chore(skills): regenerate agent skills (add omni-settings)
Merge-integrity CI gate flagged a missing generated skill. Regenerated
with check:agent-skills-sync --apply: +omni-settings, 45 unchanged.
* fix(ci): resolve Fast Quality Gates regressions on quota branch
- check-migration-numbering: migration 148 (provider_quota_state) landed
on this branch, so the KNOWN_GAPS allowlist entry is stale — remove it
(stale-enforcement 6A.3: 'REMOVA a entrada')
- open-sse/utils/stream.ts: duplicate sseCommentsEnabled import from a
bad merge (lines 31 + 77) — TS2300 duplicate identifier; drop the
duplicate so the open-sse typecheck gate is back within baseline
* docs: sync migration count to 149 after release merge
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* test(migrations): align 148 gap assertion after 148_provider_quota_state.sql landed
The phase-2 branch added 148_provider_quota_state.sql, and 148 was already
removed from KNOWN_GAPS in scripts/check/check-migration-numbering.mjs. The
frozen-allowlists assertion still expected 148 to be a gap, so it failed.
Flip the assertion to match the allowlist (same pattern as 143/147).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
---------
Co-authored-by: benzntech <benzntech@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Adds docs/guides/VSCODE-COPILOT.md covering the OmniCopilot extension: install
from either store, connection setup, what the picker actually shows and why,
the dashboard-in-a-tab mode, and a troubleshooting table.
Documents two contracts that existed in code but nowhere in the docs:
- The ?prefix= query parameter on GET /v1/models, with the warning that
"canonical" omits providers whose alias already is the canonical id — so
"alias" is the safe direction for a de-duplicated list.
- MODELS_CATALOG_PREFIX_MODE in .env.example and ENVIRONMENT.md, matching how
ARENA_ELO_SYNC_ENABLED and PII_REDACTION_ENABLED are already documented.
The fabricated-docs gate cannot see this flag being read, because
resolveFeatureFlag() indexes process.env by key rather than naming it; added
an allowlist entry explaining that, in the style of the existing entries.
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
* fix(deps): bump nanoid, dompurify for 2 new Dependabot alerts (#189, #190)
Bumps: nanoid ^3.3.17 (was transitive, now overridden), dompurify ^3.4.13
(with monaco-editor scoped override). Closes Dependabot #189, #190.
Remaining #182-#188 (js-yaml + mermaid) already closed by #9651 merge —
awaiting Dependabot re-scan.
npm audit → 0 vulnerabilities.
* fix(repo): harden .gitignore to also ignore a _tasks symlink (/_tasks)
_tasks is a SEPARATE nested git repo (gitignored). The pattern _tasks/ (trailing
slash) ignores only a directory, not a SYMLINK named _tasks. A self-referential
_tasks symlink can slip in via git add -A and, once pulled, checkout materializes
it over the real _tasks repo (destroying plans/specs/hands-off). Anchored /_tasks
ignores the symlink too, preventing re-capture.
* Hide health-check excluded models from /v1/models catalog (#10026)
Mirror the request-time exclusion rule (provider_specific_data.excludedModels)
in the unified catalog builder: a model is hidden when its provider has
connections but none of them is eligible for it. Applied across the
PROVIDER_MODELS, synced, custom, alias-backed, and managed-fallback loops
so ghost models no longer appear as available.
Co-authored-by: ritheshcn25 <ritheshcn25@users.noreply.github.com>
* fix(models): memoize getModelsDevPricing (event loop / healthz) (#10055)
* fix(models): memoize getModelsDevPricing for /v1/models catalog
resolveCatalogPricing called getModelsDevPricing once per model while
building GET /v1/models. Each call re-scanned models_dev_pricing and
JSON.parsed every row (~10k SQL scans + multi-GB parse work), pegging
the event loop so even /healthz timed out (#9685, #10052).
Memoize the parsed map until saveModelsDevPricing / clearModelsDevPricing
and add a unit test for invalidation.
Signed-off-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
* fix(db): invalidate modelsDevPricing cache on DB reset (#10055)
Copilot review fixes:
1. Register invalidateModelsDevPricingCache() with DB state reset system
so resetDbInstance() clears the process-local memo, preventing stale
pricing data from surviving across DB reset/restore operations.
2. Add test assertion verifying DB reset bypasses the memo (Copilot #10055).
The process-local memo at modelsDevSync.ts:204 caches getModelsDevPricing()
results until saveModelsDevPricing()/clearModelsDevPricing() to avoid
re-scanning all pricing rows on every /v1/models request. Without this hook,
backup restore and test DB resets would serve stale cached data from the
previous connection.
Tests: npm run test:unit:serial -- tests/unit/modelsDevSync-extended.test.ts
---------
Signed-off-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(models): honor MODELS_DEV_SYNC_ENABLED=0 over dashboard settings
The file header already advertised this env var but nothing read it.
When catalog/compression pin the event loop, the dashboard (same process)
cannot turn models.dev sync off. Let 0/false/off win over sqlite so an
operator can recover with env + restart. Skip getModelsDevPricing SQL
scans while the kill switch is set.
* fix(models): restore prettier formatting after base merge
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* test(models): cover env kill switch during live settings updates
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Signed-off-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@outlook.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: ritheshcn25 <rithesh.chandran@snb.ca>
Co-authored-by: ritheshcn25 <ritheshcn25@users.noreply.github.com>
Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>