Repository navigation
fix(combo): preserve body-specific 400 stop - #2
Closed
KooshaPari wants to merge 2 commits into
Closed
KooshaPari wants to merge 2 commits into
KooshaPari wants to merge 2 commits into
Conversation
diegosouzapw
added a commit
that referenced
this pull request
Jul 3, 2026
…er-inference#5670) (cheaper-inference#5817) Promotes Bifrost (@maximhq/bifrost — Go AI-gateway) from an env-only relay sidecar to a first-class embedded/supervised service, matching the existing cliproxy/9router model. Implements item #2 of cheaper-inference#5670; the broader RouterBackend contract (items #1, #3-cheaper-inference#5) stays out of scope. - Installer (npm-style, ninerouter model): install/update/getInstalledVersion/ getLatestVersion (1h cache)/resolveSpawnArgs (Go single-dash flags, pinned BIFROST_TRANSPORT_VERSION), needsApiKey=false - Bootstrap SERVICES entry (healthPath /v1/models) + spawn-args factory branch - Migration 113 seeds the version_manager row (not_installed, port 8080, auto_update=1, provider_expose=1) - 7 lifecycle API routes under /api/services/bifrost/ (verbatim from cliproxy, errors sanitized) — loopback-only via existing LOCAL_ONLY_API_PREFIXES - Shared [name]/logs branch for bifrost - Dashboard tab + registration in the services page shell - Relay auto-wiring: getBifrostRoutingConfig defaults BIFROST_BASE_URL to the supervised port when the instance is running; explicit env still wins; the env-only relay path (/v1/relay/.../bifrost) stays unchanged (compat layer) - Docs (EMBEDDED-SERVICES, openapi) + unit tests (installer/route-guard/routing, 19 tests) + RUN_SERVICES_INT-gated integration lifecycle Note: the actual Go-binary install/start/health path requires a documented VPS live-test before merge (Hard Rule cheaper-inference#18 / spec section 7); the gated integration harness is the vehicle for that run.
diegosouzapw
added a commit
that referenced
this pull request
Jul 18, 2026
…aper-inference#6318) * feat(cli): add CLI tools for pi, omp, letta, codewhale and jcode * fix(build): resolve CI build and lint errors * fix(cli): resolve merge conflicts, add tests, align error handling for cli-additions Resolve duplicate codewhale key from base merge, add unit/integration tests for omp/letta settings routes and the omp DB module, and align omp-settings/letta-settings error handling with sanitizeErrorMessage() + the pattern used by sibling jcode/pi/codewhale routes in this PR. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(quality): correct cliRuntime.ts file-size baseline to actual post-merge line count Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(changelog): re-restore cheaper-inference#6318 bullet after release sync Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(merge): restore cheaper-inference#6126 clinepass files reverted by release auto-resolve + baseline re-merge The release sync's auto-resolve reverted sibling PR cheaper-inference#6126's clinepass work (registry, catalog, oauth constants, clineAuth.ts, token-refresh case, tests) and the file-size baseline — all outside this PR's scope. Restored to the release versions, re-applied only this PR's own baseline entries, restored the cheaper-inference#6126 CHANGELOG bullet (re-inserting only this PR's own). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(db): re-export db/omp from localDb (check:db-rules #2) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(db): keep localDb.ts at the 800-line cap after the omp re-export Folded the MemoryVecMeta type re-export into the memoryVec named-export block (inline 'type' specifier) so adding the db/omp line stays within the new-file cap. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(cli): reduce cheaper-inference#6318 scope to omp + letta (pi/codewhale/jcode already shipped) pi, codewhale, and jcode landed via a separate PR before this one was reconciled — re-adding parallel versions of their catalog entries, routes, dashboard card, and i18n strings would have been a straight regression (duplicate "pi" key silently shadowing the release's own entry, orphaned JcodeToolCard/BaseUrlSelect/ApiKeySelect/cliEndpointMatch UI files with no release-side wiring, and unrelated formatting/refactor drift in codewhale-settings/pi-settings/config-generator/routeGuard picked up along the way). This PR now ships only the two tools that are genuinely new: omp (Oh My Pi) and letta. Both settings routes shell out to `which omp`/`which letta` to detect the local install, so they're loopback-gated in LOCAL_ONLY_API_PREFIXES (Hard Rules cheaper-inference#15/cheaper-inference#17) in addition to the shared requireCliToolsAuth() guard every cli-tools route requires (tests/unit/cli-tools-auth-hardening.test.ts) — neither route had the guard wired in yet. cli-catalog-counts.test.ts is updated to the real cardinality (8 agent entries / 32 total, since omp+letta are both category "agent"; pi/codewhale/jcode were always category "code" and are unaffected). The integration tests for omp/letta now pass a Request object to GET/DELETE and assert the 401-when-auth-required path, matching the pattern already used by the codewhale/jcode sibling routes. complexity-baseline.json is back to the release's 2053 (the cheaper-inference#6318 rebaseline note is gone — dropping the duplicate JcodeToolCard.tsx/BaseUrlSelect.tsx removed the violations it was covering); file-size-baseline.json's cliTools.ts entry shrank 955->915 to match the smaller real file. CHANGELOG bullet rewritten to describe only omp+letta, with a note on why pi/codewhale/jcode aren't part of this PR; also restores the Kiro External IdP bullet that a prior merge auto-resolve had dropped from the living section. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test(cli-tools): align cli-tools-schema registry count with omp+letta (30→32) Second exact-count guard missed in the scope-reduction pass; same legitimate alignment as cli-catalog-counts. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(cli-tools): omp entry needs docsUrl (CliCatalogEntrySchema requires it) https://github.com/can1357/oh-my-pi — verified official repo. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(quality): cliTools.ts frozen 915→916 (+1 omp docsUrl line, own growth) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(changelog): restore base + re-insert cheaper-inference#6318 bullet after release sync Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(sync): merge release tip + restore own CHANGELOG bullet Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: hamsa0x7 <hamsa0x7@users.noreply.github.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
diegosouzapw
added a commit
that referenced
this pull request
Jul 18, 2026
…805) + cheaper-inference#6807 (translator test 1195) Owner-approved /merge-prs tail freeze. localDb.ts is re-export-only (Hard Rule #2); translator test grew from cheaper-inference#6807's regression suite. Both frozen (shrink-only).
Chewji9875
pushed a commit
that referenced
this pull request
Aug 9, 2026
…n collision #2 + broken import) (cheaper-inference#9688) * test(base): realign six suites with contracts that cheaper-inference#9100/cheaper-inference#8990/cheaper-inference#9009 deliberately changed Continuing the base-red drain — every one of these reproduces on the pure tip. - tests/snapshots/provider/translate-path.json: regenerated via UPDATE_GOLDEN=1. The diff is ADDITION-ONLY — the unorouter block from cheaper-inference#9009; no existing provider entry changed. 3/3. - tests/unit/provider-models-route.test.ts: ff012ff added onboardUser as a bootstrap fallback next to loadCodeAssist; the mock now excludes it from the discovery-URL ledger like it already excluded loadCodeAssist, otherwise it consumed the injected 503 and the retry assertion misfired. 59/59. - tests/unit/responses-commentary-passthrough-6199.test.ts: cheaper-inference#8990 (c996dc9) deliberately preserves `tools` on the TERMINAL response.completed snapshot (Codex CLI rebuilds its tool list from it); the assertion now pins the echoed tools instead of their absence. Still stripped on created/in_progress. 7/7. - tests/unit/vision-compression-authoritative-capability-7237.test.ts: 68cb678 added the 'gpt-5' fragment, so the heuristic-vs-spec DRIFT this suite documented no longer exists; the cases now guard the agreement, keep a conservative-for-unknown-ids probe, and reproduce the strip-bug shape with an explicit false instead of deriving it. 4/4. - tests/unit/provider-limits-proxy-fail-closed.test.ts + tests/unit/image-generation-route.test.ts: cheaper-inference#9100 made the proxy reachability probe NON-BLOCKING (optimistic dispatch; the probe aborts only in-flight requests — its own t14 sibling was updated to this exact pattern). Instant mocks therefore won the race and the PROXY_UNREACHABLE 503 became unobservable (a success or a generic 502). The mocks now stay in flight (never-resolving, so the aborted continuation cannot reach the restored real fetch), and the fail-closed proof is the settled rejection itself plus zero egress AFTER the fast-fail. Production fail-closed semantics are unchanged — the proxy dispatch path still throws; only the mock timing was stale. 3/3 and 20/20. Refs cheaper-inference#9298 * fix(guardrails): forward the router deps seam through callVisionModel tests/unit/guardrails/vision-bridge-sse-and-reasoning.test.ts was 7/7 red on any clean box (CI shard 3/4): callVisionModel() called getBestVisionModel()/ getFallbackModels() WITHOUT the routers' existing VisionBridgeRouterDeps seam, so the credential check always hit the live connections DB — no vision-capable connection meant 'No vision-capable provider connected' before the mocked fetch was ever reached, and on a dev box auto-selection could swap the fixed model under the assertions. The routers already accepted deps; only the forwarding was missing. Added the optional 5th param (backward compatible — the sole production caller, visionBridge.ts, injects its own callVisionModel and is unaffected) and the suite now pins selection with hasUsableCredentials: async () => null (indeterminate → the fixed model is honored, DB untouched). 7/7. Sibling suites re-run green: vision-bridge-callmodel 2/2, visionBridge 25/25, visionBridgeHelpers.callVisionModel 8/8, visionBridgeRouter 10/10, vision-bridge-cc-no-reroute 8/8. Refs cheaper-inference#9298 * fix(db,combo): clear the NEW base-reds the 08-06 merge batch introduced The tip moved while the first sweep PR (cheaper-inference#9600) was in review, and three fresh base-reds landed with it — same classes as before, all reproduced on the pure tip 9995bc4: 1. ANOTHER migration collision: cheaper-inference#9061 shipped 134_ccr_blocks.sql onto the slot 134_proxy_logs_egress_ip.sql (cheaper-inference#9291) has held since 08-04. getMigrationFiles() throws on collision, so every DB-touching test died at bootstrap again. Renumbered to 139 (next free slot). No retroactive guard needed this time: both statements are IF NOT EXISTS, and no DB can have applied it as 134 — the runner refused to run at all while the collision existed. 2. BROKEN IMPORT killing the combo module graph: cheaper-inference#8894 imported preferAntigravityConnectionsWithStoredProject from ../antigravityProjectPersistence.ts — a module that exists NOWHERE in the repo (it came from an unmerged sibling branch). Anything importing quotaStrategies.ts died with ERR_MODULE_NOT_FOUND. Implemented the helper in the real persistence module (antigravityProjectPersist.ts, cheaper-inference#8491) with the semantics the call site needs — prefer connections that already carry a stored projectId, never emptying the pool — and pointed the import there. New regression suite tests/unit/antigravity-prefer-stored-project.test.ts (5/5), including an import-graph probe that reproduces the break shape. 3. Sibling-test drift from cheaper-inference#9106 (gemini-3.1-pro-high now user-callable): its own suites were updated but provider-models-route.test.ts was not. Expected discovery list realigned; testFrozen 1784->1787 justified in the baseline (irreducible +2 after comment compression; gate counts split-newlines). Also regenerated tests/snapshots/provider/translate-path.json — addition-only: devin-cli-agentic, raycast, regolo (today's provider merges), zero removals. image-generation-route 20/20 (was import-dead), provider-models-route 59/59, antigravity-prefer-stored-project 5/5, provider-translate-path-golden 3/3. Refs cheaper-inference#9298 * fix(changelog): convert the cheaper-inference#9415 fragment to the required bullet shape Another base-red from the 08-06 batch: bd4407c landed changelog.d/features/9415-newapi-sub2api-aggregator-balance.md as YAML frontmatter + a prose paragraph. Every other fragment in changelog.d/ is a single markdown bullet, and both consumers enforce that — scripts/check/check-changelog-integrity.mjs:97 and the release aggregator (scripts/release/aggregate-changelog.mjs:57) reject anything that does not start with '- ', so 'Merge integrity (changelog + generated skills)' was red for every PR targeting the release branch. Rewritten as a bullet with the standard issue link, preserving the feature description (aggregator gateway toggle, /api/user/self balance read, dashboard badge, quota-preflight skip, NEWAPI_AGGREGATOR_BALANCE flag default off, quotaPerUnit override). Swept the rest of changelog.d/ — this was the only malformed fragment. check:changelog-integrity OK. Refs cheaper-inference#9298 * fix(types,docs): clear the 5 typecheck errors and the fabricated env vars on the base Third pass over the base-reds, from the 2026-08-06T22:51Z verdict on cheaper-inference#9298 — it reported "Typecheck (core)" with only the FIRST error; there are five, all on the pure tip 9995bc4. Two are real production defects. **Real bugs** - open-sse/services/compression/engines/ccr/index.ts:295 called enforceGlobalBudget(entry.bytes) against an (owner, bytes) signature. The `bytes` argument arrived undefined, so `ccrTotalBytes + undefined` is NaN, `NaN > MAX` is false (the eviction loop exits immediately) and `NaN <= MAX` is false (the re-admit is refused). The cheaper-inference#9061 durable tier therefore NEVER repopulated its in-memory map: every retrieve after a restart or an eviction re-read from SQLite forever, and evictions could not prefer the owning principal. Fixed and pinned by a new case in tests/unit/ccr-durable-store-9061.test.ts (11/11) — verified failing against the buggy call and passing against the fix. - open-sse/services/combo/fusionPanel.ts:54 read `step.model` after cheaper-inference#8894 widened ComboStep with ComboProviderWildcardStep (which carries modelPattern, not model), so a wildcard step in a fusion panel pushed `undefined` onto the panel. Now resolved through getComboModelString(), which already handles every step shape and returns null for the ones without a concrete model id. **Type-only** - accountSemaphore.ts:203 — isBypassed() returns a plain boolean and cannot narrow `number | null` (an `x is null | undefined` predicate would be unsound: 0 bypasses too). Added resolveActiveCap(), the narrowing companion isBypassed is now defined in terms of; the acquire path uses the narrowed value. - comboStructure.ts:140 — same cheaper-inference#8894 widening: `prompt` only exists on a model step, so it is now read under a kind check. - firecrawlQuotaFetcher.ts:136 — the function returns full FirecrawlQuota objects but was annotated Promise<QuotaInfo | null>, which made the custom-base literal an excess-property error. Widened to the accurate type (FirecrawlQuota extends QuotaInfo, so callers are unaffected). **Fabricated docs (the "Docs sync + fabricated-docs (strict)" HARD failure)** docs/ops/VM_DEPLOYMENT_GUIDE.md recommended OMNIROUTE_MAX_POOL_SIZE and OMNIROUTE_DB_POOL_SIZE (cheaper-inference#9471). Neither is read anywhere in the codebase. Replaced with the two knobs that do exist and are already documented in ENVIRONMENT.md: OMNIROUTE_MEMORY_MB and OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT. typecheck:core 5 errors -> 0. check:fabricated-docs + check:env-doc-sync OK. accountSemaphore 6/6, ccr-durable-store 11/11, ccr-protocol 9/9, combo-fusion-strategy 10/10, combo-fusion-comboref 5/5, combo-fusion-warn 4/4, firecrawl-executor 7/7, executor-firecrawl-fetch 4/4. Refs cheaper-inference#9298 * fix(tests): type the cheaper-inference#3440 vertex helpers instead of `any` (the 3 base ESLint errors) The "ESLint errors: 3 error(s)" HARD failure in the cheaper-inference#9298 verdict is tests/unit/vertex-functioncall-id-3440.test.ts lines 32/41/50: the three find*(result: any) walkers. `@typescript-eslint/no-explicit-any` is an ERROR in tests/ (and open-sse/) since cheaper-inference#6218, and this file landed on 2026-08-04 without a suppressions entry, so every run of `lint:json --max-warnings 0` failed. That step prints nothing on failure, which is why the gate looked like a silent crash across the open PRs. Replaced with a GeminiRequestLike interface describing exactly what the three walkers traverse (contents[].parts[]), so the assertions keep their meaning and nothing is cast away. eslint on the file: clean. Suite: 6/6. Refs cheaper-inference#9298 * docs(proxy): use an RFC 5737 documentation IP in the proxy examples The cheaper-inference#9298 verdict headlines its docs failure with `L810 [stale-version] 1.2.3: const removed = await failOneproxyProxy("1.2.3.4", 8080)`. That is a false positive: check-deprecated-versions.mjs matches `/\bv?[12]\.\d+\.\d+\b/`, and the example IP literal 1.2.3.4 contains "1.2.3". Swapped both occurrences in PROXY_GUIDE.md (and its pl mirror) for 203.0.113.7, from the RFC 5737 documentation range that exists precisely for examples — it cannot collide with a version pattern and is the correct thing to print in docs regardless. Drift count 64 -> 62; no gate threshold was touched. The gate that actually FAILED under "Docs sync + fabricated-docs (strict)" was check:fabricated-docs (the invented pool env vars), fixed in the previous commit; this one removes the misleading line the verdict quotes. * test(base): allowlist probeUtils and realign the cheaper-inference#7849 suite to the replacement bound Two more base-reds, both visible only after the migration collision stopped killing the shards. **check-db-rules — src/lib/db/probeUtils.ts not classified** cheaper-inference#9541 added probeUtils.ts (transient-error retry for the SQLite corruption probe). It is imported ONLY by src/lib/db/core.ts, exactly like its siblings schemaColumns / optimizationSettings / providerNodeSelect, so re-exporting it through localDb.ts would push callers toward the barrel-import anti-pattern the gate exists to prevent. Added to INTENTIONALLY_INTERNAL with that rationale. check-db-rules 22/22, check:db-rules exit 0. **session-dedup-memory-7849 — pinned a mechanism that was replaced** 7f36b19 (cheaper-inference#7855 follow-up) swapped the shared "suffix work budget" for the MAX_SUFFIX_STARTS / MAX_TOTAL_BLOCK_BYTES guards and deleted both the budget and its SUFFIX_WORK_BUDGET_WARNING string. It updated session-dedup.test.ts but not this sibling, so 3 of its 4 cases asserted a warning that can no longer be emitted. Realigned to the contract that actually survives — which is the invariant cheaper-inference#7849 was opened for, not the mechanism: - the pathological pair must stay BOUNDED (completes in <4s, body intact) — measured at ~280ms on the current guards; - it must FAIL OPEN — original body returned by identity, compressed false, stats null (the explanatory zero-savings stats belonged to the removed budget path, which skipped before producing any); - the 512 MiB child fixture must still exit 0 with the full engine chain (session-dedup, lite, rtk, headroom, caveman) — that IS the OOM guard — and session-dedup must still report its skip, now pinned by prefix since the reason string moved with the mechanism. No threshold was loosened and no case was deleted: 4/4 here, 8/8 on the sibling session-dedup.test.ts. Refs cheaper-inference#9298 * docs(mcp): bump the tool count to 105 and realign two vitest count pins Three more base-reds from the same 08-06 batch, all count/contract drift that the merged PRs left in sibling files. **Docs Gates (fast-path) — 3 STRICT drifts** check:docs-counts measures the MCP tool set from live code: it is 105 now (cheaper-inference#8925 added omniroute_create_combo), while README.md, AGENTS.md and docs/frameworks/MCP-SERVER.md still claimed 104. Updated all five occurrences (two of them inside SVG alt text). check:docs-all exits 0. **Vitest (fast-path) — 2 failures** - open-sse/mcp-server/__tests__/essentialTools.test.ts pinned 11 phase-1 tools; cheaper-inference#8925 shipped omniroute_create_combo as phase 1, making it 12. Verified by enumerating MCP_ESSENTIAL_TOOLS directly. - tests/unit/autoCombo/provider-family-combos.test.ts pinned the auto/glm provider set to [auggie, glm, zai]. cheaper-inference#8914 (Devin ACP bridge) added devin-cli-agentic, whose catalog (registry/devin/catalog.ts:90-93) advertises the glm-5-2* line — so it belongs in the family pool for exactly the reason the test's own comment gives for auggie: a no-auth backend that genuinely serves a family model is a legitimate member. Expected set updated, invariant unchanged. npm run test:vitest 36/36 files, 340/340 tests. Refs cheaper-inference#9298 * fix(combo,usage,oauth): drain the base-reds the shard fix exposed With the migration collision and the broken import out of the way the four unit shards actually run, and a further layer of base-reds became visible on the pure tip 9995bc4. Three are production defects. **Production defects** - open-sse/services/combo/runtimeUnitCapacity.ts:58 called resolveComboTargets() WITHOUT the hidden-model snapshot, so it fell back to the default getHiddenModelsByProvider() — a fresh full key_value read PER nested combo-ref unit, on every request. cheaper-inference#8878 threaded the snapshot through the other call sites and missed this one. Threaded it from executeRuntimeUnitCombo (and from the dispatchPrelude call site), restoring the one-snapshot-per-request invariant combo-hidden-leaf-routing.test.ts pins. 9/9. - open-sse/services/usage/firecrawl.ts silently ignored its own `apiKey` parameter: 91bb6aa moved the fetch to fetchFirecrawlQuota(connectionId, connection), which reads the key off the connection record, so any caller passing the key directly got "Firecrawl API key not available". The explicit key is now merged into the connection passed down. firecrawl-usage 8/8. - src/lib/oauth/constants/oauth.ts was missing a RAYCAST entry in PROVIDERS while src/lib/oauth/providers/index.ts registers `raycast` (cheaper-inference#8895), so every consumer reading PROVIDERS did not know Raycast Pro exists. Also added its OAUTH_TEST_CONFIG entry (checkExpiry only — it is an `import_token` provider with refreshToken always null), which cheaper-inference#8408's guard explicitly requires rather than grandfathering. oauth-providers-config 25/25, oauth-test-config-8408 2/2. **Count / contract drift from the same batch** - feature flags 45 -> 46, APIKEY_PROVIDERS 197 -> 198 (Raycast Pro cheaper-inference#8895), unique MCP tools 107 -> 108. Each re-derived from the source of truth. - vi + pt-BR locales: translated the 8 keys cheaper-inference#9415 added (providers.newApiAggregator* and providers.modelTestQuotaTooltip) instead of relaxing the parity guard. i18n-vi 5/5, i18n-pt-br 3/3. - login-bootstrap-route: cheaper-inference#9491 added `authenticated` to the require-login payload so /login can redirect an active session; the three deepEqual bodies now carry it. 10/10. **Flaky-by-construction, made deterministic** tests/unit/chat-combo-live-test.test.ts asserted the early-keepalive frame with a 100ms mocked upstream while resolveKeepaliveThreshold() is 2000ms for openai/*. It only ever passed while unrelated handler latency happened to push the total past the threshold — incidental, not deterministic, and it stopped holding once the handler got faster. The mock now sleeps 2400ms so the slow path is guaranteed and the assertion means what it says. 5/5. typecheck:core exit 0. check:file-size (base-relative) OK. Refs cheaper-inference#9298 * test(base): run the orphaned cheaper-inference#8890 suite and realign three mechanism pins **check:test-discovery — a suite that had NEVER executed** cheaper-inference#8890 landed open-sse/services/__tests__/fail-fast-concurrency-gate.test.ts into a directory no runner collects (only one explicit file from that folder is in vitest.mcp.config.ts), so it ran zero times since it merged. Wired it into the runner AND into check-test-discovery.mjs's mirrored collector list, which the gate keeps in sync deliberately. It passes 4/4 now that it actually runs — test:vitest goes 36 -> 37 files, 340 -> 344 tests. **check-db-rules-classification** — 37 -> 38 audited modules, adding probeUtils alongside the INTENTIONALLY_INTERNAL entry from the previous commit. **ratelimit-reservoir-refresh** — cheaper-inference#9604 (rolling RPM leases) DELETED Bottleneck's fixed-window reservoir, so currentReservoir() is null and the poll for `reservoir === 2` could never settle. It updated several sibling suites but not this one. The pin on the removed mechanism is gone; what remains is the invariant the original Bottleneck heartbeat bug actually broke and that cheaper-inference#9529 opened this test for — after a header-learned updateSettings() the limiter must keep admitting work, proven by racing a post-exhaustion request against a 5s timer. 1/1. **translator-openai-to-gemini** — cheaper-inference#9568 (c9a3361) made buildChangedToolNameMap emit IDENTITY entries too, because Gemini lowercases tool names in functionCall responses and the response translator needs a key to map them back. Any request carrying tools therefore carries `_toolNameMap` in the Antigravity envelope now. Expected key list updated and the map's contents asserted explicitly rather than left implicit. 45/45. Refs cheaper-inference#9298 * fix(db): restore node-backed synced catalogs and realign the cheaper-inference#8944 context hints **Production regression from cheaper-inference#9294 (d69f521)** lookupModelMeta moved from getSyncedAvailableModels(providerId) to getActiveSyncedCatalog(providerId). The new reader unions models only from rows in `provider_connections` with isActive = 1 — but a provider NODE lives in `provider_nodes` and NEVER has a connections row, so filtering by active connection ids silently dropped every node's synced catalog. The consequence was not just a missing list: lookupModelMeta reads that catalog for RUNTIME METADATA, so for openai-compatible nodes it took out - `supportedThinkingEfforts`, which is what splitSyncedEffortSuffix needs — so `<prefix>/<model>-high` stopped resolving to the base id and the effort was never derived (cheaper-inference#7694), and - `contextWindow` / `maxInputTokens`, used by the combo context-window filter. getActiveSyncedCatalog now falls back to the provider-wide key_value set — the exact pre-cheaper-inference#9294 source — when no active connection carries a catalog, and marks that fallback explicitly NON-authoritative. cheaper-inference#9294's live-catalog gating is about what an active connection actually serves, so a node-backed catalog informs metadata while never being able to reject a model as unavailable. `available` therefore stays fail-open for nodes, as it was before. sync-reasoning-supported-efforts-7694 23/23 (was 21/2). live-model-catalog-reconciliation-8926 11/11 and combo-provider-wildcard 23/23 confirm cheaper-inference#9294's own coverage is untouched. **cheaper-inference#8944 sibling-test drift** 714a315 ("Treat context metadata as a routing hint") deliberately turned the context-window check from a HARD filter into an ordering hint: a catalog-too-small target is demoted, not removed, because a stale catalog entry must never delete the only target that could accept the request at runtime. The PR updated one case in this suite and left three asserting the old drop behaviour. Realigned to the new contract — the too-small target must lose the ordering to the fitting one while remaining present — and renamed them from "still rejects"/"still dropped" to "is demoted"/"ordered last" so the names stop describing the removed behaviour. 14/14. **file-size** tests/unit/translator-openai-to-gemini.test.ts testFrozen 1616 -> 1619: the frozen value sat exactly at the base size, so the 3 lines the previous commit's _toolNameMap alignment needs could not fit. Justified in the baseline. typecheck:core exit 0. Refs cheaper-inference#9298 * chore(stryker): register the two covering suites missing from tap.testFiles check:mutation-test-coverage flags any unit test that covers a mutated module but is absent from stryker.conf.json tap.testFiles — without the entry its mutant kills do not count toward the module's score. - tests/unit/antigravity-prefer-stored-project.test.ts covers open-sse/services/combo/quotaStrategies.ts (added earlier in this PR). - tests/unit/executor-devin-cli-agentic-acp.test.ts covers src/sse/services/auth.ts — pre-existing drift, same gate, same fix. Inserted in alphabetical position only; the rest of the file is byte-identical (it is not prettier-formatted upstream and reformatting it is out of scope here). Refs cheaper-inference#9298 * fix(db): drop the never-wired getSessionModelUsageCounts (knip regression) The dead-code ratchet only ran once the earlier Fast Quality Gates steps stopped failing, and it lands at 228 vs baseline 227. The extra symbol is src/lib/db/contextHandoffs.ts::getSessionModelUsageCounts, added by cheaper-inference#8894 "for least-used strategy" and never wired: the least-used branch in applyStrategyOrdering.ts uses the pre-existing sortTargetsByUsage(), and the helper has no caller in src/, open-sse/ or tests/. It is the same incomplete-PR shape as that PR's import of a module which does not exist in the repo (fixed earlier in this branch). Removed rather than baselined — bumping the ratchet would loosen the gate, and removal is exactly the remedy the gate prescribes. Same treatment the Dario installer's never-wired uninstall() got in cheaper-inference#9600. The implementation is recoverable from a598fbb whenever someone actually wires a session-aware least-used strategy. check:dead-code 228 -> 227 (baseline untouched). check:db-rules exit 0. context-handoff 13/13, db-context-handoffs 7/7, service-context-handoff 11/11. Refs cheaper-inference#9298 * fix(security): embed the Raycast signature secret via resolvePublicCred (HR#11) The secret-scan ratchet only ran once the earlier Fast Quality Gates steps stopped failing, and it lands at 1 finding vs baseline 0. The finding is open-sse/services/raycast.ts:19 — RAYCAST_DEFAULT_SIG_SECRET, a 64-hex request-signature secret that cheaper-inference#8895 committed as a bare string literal. It is genuinely public (community-extracted from the Raycast macOS client; the SAME value ships to every install, it is not a per-user credential), which is exactly the category Hard Rule cheaper-inference#11 governs: public upstream credentials MUST go through resolvePublicCred() (open-sse/utils/publicCreds.ts), never a literal — see docs/security/PUBLIC_CREDS.md. So the fix is the mandated pattern, not a .gitleaks.toml allowlist entry: added `raycast_sig_secret` to EMBEDDED_DEFAULTS as the XOR-masked byte sequence and resolved it with the existing RAYCAST_SIG_SECRET env override. The providerSpecificData.sigSecret override is untouched. Verified the decoded value is byte-identical to the literal it replaces. check:secrets secretFindings 1 -> 0. check:public-creds exit 0. publicCreds 12/12, raycast-auth 6/6, raycast-local-extract 1/1, trae-publiccred 3/3. typecheck:core exit 0. Refs cheaper-inference#9298 --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Chewji9875
pushed a commit
that referenced
this pull request
Aug 9, 2026
…routing (cheaper-inference#9195) Three linked bugs prevented the Custom Models 'Vision capable' toggle from affecting Combo routing, causing 400 capability_mismatch on image requests sent through Combos targeting a custom vision model. Bug #1 (catalog, dead guard): modelType === 'chat' was always false for chat models because modelType was only assigned 'embedding', 'rerank', 'image', or 'audio'. Changed the guard to !modelType || modelType === 'chat' so getCustomVisionCapabilityFields() fires for custom chat models. Bug #2 (catalog, synced-first ordering): When a model appeared in both syncedAvailableModels (from discovery) and customModels, the custom row was skipped entirely, losing the vision override. Now merge vision fields into the existing synced entry when the custom model has an explicit supportsVision boolean. Bug #3 (routing capabilities): getResolvedModelCapabilities() / resolveVisionCapability() had no path to consult the customModels supportsVision flag. Added a sync DB lookup helper and a new customVisionOverride parameter so the dashboard toggle affects Combo routing. Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
diegosouzapw
added a commit
that referenced
this pull request
Aug 11, 2026
…n package (cheaper-inference#8299) * fix: align three stub implementations with original code - chatUrlMatcher: restore original 3-arg signature (u, matchDomain, chatUrl) with PLACEHOLDER-aware path segment matching - shouldUseGrokBrowserBacked: remove required param, restore env-var logic checking both WEB_COOKIE_USE_BROWSER and OMNIROUTE_BROWSER_POOL - browserPool.ts: add Turbopack rationale comment and join-trick helper to satisfy the optional-import test assertions - browserBackedChat.ts: replace any types with typed BrowserPoolModule interface Verification: 40/40 browser node:test pass, typecheck:core 0 errors * fix: remove duplicate getMod/modPromise in browserBackedChat stub Two copies of the module proxy got committed — the typed BrowserPoolModule version at lines 50-56 and a stale any-typed duplicate at lines 64-71. Removed the duplicate, keeping the typed version. Verification: - 40/40 browser tests pass (both previously-failing suites now green) - typecheck:core: 0 errors - env kill switch (OMNIROUTE_BROWSER_POOL=off): verified * fix(pr-8299): address all 5 review issues Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null Issue cheaper-inference#4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync Issue cheaper-inference#5: Add test case for package-absent fallback in tryBackedChat All 25 browser tests pass across 4 suites. typecheck:core passes. * chore: move sqlite-vec to optionalDependencies, fix js-tiktoken static import Both changes ensure native binary dependencies are properly categorized as optional: - sqlite-vec: moved from dependencies to optionalDependencies. Only used via lazy _require("sqlite-vec") in vectorStore.ts — zero static imports. - js-tiktoken: already in optionalDependencies, import changed to createRequire pattern to avoid crash when package is not installed (same pattern as sqlite-vec in vectorStore.ts). Resolves ScoutDeps findings from browser-pool pluginization audit. * docs(issues): fix stale interfaces.ts path in browser-pool proposal The proposal originally planned open-sse/interfaces/browserPool.ts for the BrowserPoolProvider interface, but the shipped implementation puts it in packages/browser-pool/src/interfaces.ts instead. Update the references so the doc matches what was actually built — the stale path was tripping check:fabricated-docs (--strict). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix: sync package-lock.json with playwright 1.62.0 Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * test: keep browser warmup disabled in tryBackedChat unit tests * fix(pr-8299): keep grokClearance on the evolved release implementation (rebase reconciliation) --------- Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 11, 2026
…resh (cheaper-inference#9173) * refactor(cursor): extracts token extraction into shared lib Moves tryIdeAuth/tryAgentAuth and supporting helpers out of the auto-import route into src/lib/cursor/tokenExtractor.ts, and adds an agent-cli-state.json fallback candidate path to tryAgentAuth (alongside the existing auth.json candidate) so the extraction logic can be reused by the upcoming renewal orchestrator. * feat(cursor): adds cursor-agent-backed token renewal orchestrator Builds the renewal orchestrator in src/lib/cursor/renewal.ts: a bounded, unattended-safe --list-models nudge, a side-effect-free status availability check, an in-flight spawn lock keyed by command, and renewCursorConnection() which nudges cursor-agent then independently re-scrapes the IDE and cursor-agent credential sources to detect whichever refreshed. Extends cursorAgent.ts's binary resolution and spawn helper with fixed-paths-only mode and a SIGKILL follow-up for background use. Adds a generic keyed-mutex utility (src/shared/utils/keyedMutex.ts) for serializing a connection's renew-then-persist cycle, and forwards a busy-timeout through driverFactory's node:sqlite fallback path. * feat(cursor): proactively renews Cursor sessions in the sweep Adds src/lib/tokenHealthCheckCursor.ts, sweep-side glue that calls the renewal orchestrator and persists the result, wired into tokenHealthCheck.ts's checkConnection() via a new Cursor-specific branch placed ahead of the generic no-refresh-token fallthrough. Carves out a non-terminal exception for a Cursor connection that already landed at testStatus "expired" via the request-time 401 path, excluding permanently-dead account_deactivated connections. Extends buildRefreshFailureUpdate() with an overrides param so Cursor's failure path can use a distinct, non-terminal errorCode instead of the generic refresh_failed/expired taxonomy. * feat(cursor): adds local-only manual refresh route Adds POST /api/providers/[id]/refresh-cursor, a dedicated loopback-only route that calls the renewal orchestrator on demand for a single Cursor connection, bounded by a 30s per-connection cooldown. Classifies the new route in LOCAL_ONLY_API_PATTERNS and closes the manage-scope-bypass gap for dynamic-segment spawn-capable routes under /api/providers/ via a new SPAWN_CAPABLE_PATTERNS / SPAWN_CAPABLE_PATTERN_ANCESTORS mechanism, which also retroactively covers the pre-existing /login route. The existing shared /api/providers/[id]/refresh route is untouched and stays remote-reachable for every other provider. * feat(cursor): surfaces a dismissible cursor-agent nudge Adds GET /api/providers/cursor/agent-availability, a credential-free LOCAL_ONLY route returning only { cursorAgentAvailable: boolean }, backed by a 5-minute cached wrapper around the renewal orchestrator's existing availability check. Surfaces a dismissible dashboard banner on the Cursor provider page suggesting cursor-agent installation when it isn't detected, following the existing dismissible-banner convention. Also fixes a pre-existing bracket character in a routeGuard.ts comment that was silently truncating check-openapi-security-tiers.mjs's view of LOCAL_ONLY_API_PREFIXES. * fix(cursor): wires manual refresh button to the new route Branches handleRefreshToken to call the dedicated Cursor refresh route instead of the generic /refresh route, which silently 502s for Cursor connections today since they carry no refresh token. Every other provider's refresh behavior is unaffected. Adds the cursorSessionUnchanged i18n key and syncs it (plus a pre-existing, unrelated 28-key backlog) across all 42 locale files. * fix(cursor): addresses Phase 4/4.5 review findings Restores the legacy stdout/stderr auth-pattern fallback in checkCursorAgentAvailability() that the plan's Task 2 Step 4 required but the implementation had dropped. Threads an optional deps parameter through checkCursorConnectionIfNeeded() so its error branch is reachable in tests, and switches both it and the manual-refresh route to exhaustive switch statements over the renewal result. Adds a short-lived host-keyed dedup cache around tryIdeAuth() so multiple due Cursor connections sharing a host don't each open the same state.vscdb file in one sweep tick. Adds opportunistic eviction to the manual-refresh cooldown map, an outer try/catch to the availability route for defense-in-depth consistency with the plan's other routes, and corrects a stale JSDoc claim about the /login route's auth check. Documents the now-empirically-confirmed agent-cli-state.json schema mismatch found while validating against a real cursor-agent install. * docs(cursor): adds changelog fragments for the renewal plan Adds one fragment per user-facing outcome per changelog.d/README.md's convention for a PR that both fixes and adds. PR number placeholder to be filled in once the PR is opened. * fix(i18n): translates the new Cursor keys into Vietnamese The i18n:sync-ui run in an earlier commit left __MISSING__ sentinels for the 4 new Cursor keys in every locale, but Vietnamese has a dedicated completeness test requiring zero internal missing markers. Provides real translations for cursorSessionUnchanged, cursorAgentNudgeTitle, cursorAgentNudgeBody, and cursorAgentNudgeDismiss. * fix(cursor): addresses quality-gate Layer 1.5 findings Restores a comment that misrepresented execFile's actual argv shape after an earlier bracket-removal fix, this time avoiding literal closing-bracket characters entirely so the openapi checker's naive array parser can't be broken by either version. Bounds the sweep- and manual-route-triggered tryIdeAuth() busy-timeout to 250ms (down from the interactive auto-import path's 2000ms), since both share the main event loop with all other in-flight requests and should fail fast on a WAL-lock collision rather than block the whole instance for up to ~4s. Has the manual refresh route bypass the sweep's IDE-auth dedup cache so a click always sees a fresh read, consistent with this plan's existing "manual actions never see stale cached data" convention. Documents the previously-missing agent-availability route in ROUTE_GUARD_TIERS.md's spawn-capable table. * fix(cursor): adds SIGKILL follow-up to the status-check spawn Matches the nudge spawn's existing SIGTERM+SIGKILL pattern so an unresponsive cursor-agent status check can't leak a lingering process if it ignores SIGTERM. * docs(cursor): fills in the PR number for changelog fragments Renames the 3 changelog.d fragments to their PR-numbered filenames and replaces the (#PR) placeholder with cheaper-inference#9173, now that the PR exists. * fix(cursor): corrects changelog fragments to reference PR cheaper-inference#9173 The prior commit only staged the git mv rename — a git add invocation with a stale (pre-rename) pathspec aborted before the actual (#PR) -> (cheaper-inference#9173) content edit was staged, so the rename landed without the fix it was meant to carry. This captures the actual content change. * docs(cursor): regenerates the agent-skills catalog for the new route check:agent-skills-sync (CI's Merge integrity gate) requires SKILL.md files to stay in sync with the live route catalog. Adding /api/providers/cursor/agent-availability in an earlier commit needed a regen this branch never ran. * chore(quality): rebaselines file-size caps grown by agentrouter merges Two already-merged agentrouter commits (564c204, ec150a0) on release/v3.8.50 grew open-sse/executors/base.ts, open-sse/handlers/chatCore.ts, and tests/unit/chatcore-translation-paths.test.ts past their frozen caps before this PR branched — unrelated to the Cursor renewal changes here. No PR branch is left to fix the growth in-place, so the caps are bumped to the current real sizes, following the existing release-green rebaseline precedent in this file. * fix(sse): imports getModel helpers from db/models, not localDb A recently-merged agentrouter commit added a @/lib/localDb import in chatCore.ts, violating the no-restricted-imports rule (Hard Rule #2 — never barrel-import from localDb.ts). Points the import at the owning module, src/lib/db/models.ts, where both functions are actually defined, and prunes the now-stale suppression entry. * fix(sse): scopes CC-relay anthropic-beta to its own requestDefaults Two already-merged agentrouter commits widened usesClaudeCodeProtocol()'s native-Claude system-transform block (billing header + selectBetaFlags-derived anthropic-beta) to also run for generic CC-compatible relay connections, not just real claude traffic and agentrouter's own wire-image mimicry. selectBetaFlags() has no visibility into a relay's own providerSpecificData.requestDefaults, so its header replacement silently wiped out an earlier context-1m append and force-included redact-thinking regardless of the relay's own opt-in. Restores both for plain CC-compatible relays only; real claude/agentrouter traffic is unaffected. Also bumps four stale hardcoded Codex/Claude Code CLI version-string test assertions (0.144.1->0.146.0, 2.1.219->2.1.220) that drifted when the same two commits bumped the version constants without updating their tests, and rebaselines base.ts's frozen file-size cap for this fix's own +35 lines. * fix(sse): preserves bare CC-relay native treatment and context-1m The previous commit's fix was too broad in one direction: excluding ALL CC-compatible relays from the native-Claude header block broke two pre-existing tests (cc-compatible-provider.test.ts, v3.6.6) that rely on that treatment for a 'vanilla' relay with no providerSpecificData.requestDefaults configured. Refines the gate to this whole native-Claude header-replacement block: replace headers for real claude traffic, agentrouter's wire-image mimicry, OR a CC-relay with no requestDefaults at all — only a relay with EXPLICIT requestDefaults (context1m/redactThinking/summarizeThinking) gets to keep buildHeaders()'s own correctly-computed header set. A redact-thinking-beta strip (unconditional, a no-op when native treatment didn't apply) covers the one remaining gap: selectBetaFlags() force-includes it for a bare relay's opaque client, which a bare relay never explicitly opted into. Verified against all three previously-conflicting pre-existing tests simultaneously: executor-default-base.test.ts's '1M beta' test, both cc-compatible-provider.test.ts SSE-forcing tests, and provider-request-failure-pipeline.test.ts's 'keeps request beta headers' test (the last of which was already broken by the raw agentrouter merge, confirmed via direct comparison against that exact commit). * fix(sse): fills in remaining stale CLI version literals The same two agentrouter commits bumped Codex/Claude Code CLI version constants (0.144.1->0.146.0, 2.1.219->2.1.220) without updating every hardcoded test assertion. This round covers the ones the previous version-string commit missed: the anthropic-cache-fingerprint billing-version constant, a cc-bridge-transforms body assertion, the UI-mirror parity test's own snapshot plus its RoutingTab.tsx source of truth, an integration test's User-Agent assertion (inconsistent with its own dynamic Version assertion two lines up), and the translate-path golden snapshot. Also updates a stale doc comment referencing the old literal by value instead of by constant name. * fix(cursor): imports from db/ modules, not the localDb barrel Both files violated Hard Rule #2 (never barrel-import from localDb.ts) — a genuine lint error that had gone uncaught locally. refresh-cursor/route.ts imported getCachedProviderConnectionById from @/lib/localDb instead of its owning module, @/lib/db/readCache. tokenHealthCheckCursor.ts copied the same pattern from its sibling tokenHealthCheckCopilot.ts (an existing, already-suppressed violation) for updateProviderConnection; imports it from @/lib/db/providers instead, with no circular-import fallout (verified via the existing token-health-check-cursor and refresh-cursor-route test suites). * fix(db): removes stale raw-SQL allowlist entry for cursor route The cursor auto-import route no longer contains raw SQL — that query now lives in src/lib/cursor/tokenExtractor.ts, outside the route/handler scope check-db-rules scans. The allowlist entry was stale, tripping the stale-enforcement gate. * fix(test): registers cursor test files in stryker tap.testFiles Three unit test files covering mutation-tested modules (route-guard-cursor-agent-availability, route-guard-cursor-refresh, cursor-renewal) were missing from stryker.conf.json's tap.testFiles, tripping the mutation-test-coverage gate's drift detection. * chore(ci): retriggers checks (stuck GH Actions runner on shard 2/4) * fix(sse): restores CC-relay context1m/redact-thinking test coverage Rebasing onto release/v3.8.50's new tip (35405be, an unrelated agentrouter protocol-inference commit) silently flipped two assertions this branch's own earlier fix (687fbda62) depends on, in the same test files that commit touched for other reasons: - executor-default-base.test.ts: calls[0] (a bare CC-relay with no requestDefaults) expected redact-thinking-beta absent; flipped to present. calls[1] (context1m+redactThinking requestDefaults) expected the context-1m beta preserved; flipped to absent. - provider-request-failure-pipeline.test.ts: expected Accept: text/event-stream and the context-1m beta present for a relay with explicit requestDefaults; flipped to application/json and absent. 35405be did not touch open-sse/executors/base.ts at all, so these were test-only edits made without visibility into the still-unmerged CC-relay header-preservation fix on this branch — they quietly matched the assertions back to the pre-fix (buggy) behavior instead. Restores the original, validated expectations; all three interdependent test files (executor-default-base, cc-compatible-provider, provider-request-failure-pipeline) verified passing together again. * ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved) * ci: re-trigger checks (previous push event was dropped) * fix(quality): restore dropped vi.json cursor-renewal keys + rebaseline test growth vi.json was missing 4 keys (cursorSessionUnchanged, cursorAgentNudgeTitle/Body/Dismiss) that this PR's own pre-merge branch had translated -- the original merge's 'git checkout --theirs' resolution for the 7 conflicted locale files discarded them since upstream's vi.json has no cursor-token-renewal feature. Restored from pre-merge tip a38003e30. Also rebaselines combo-routing-engine.test.ts (3457->3464) for the comment growth from the ALL_ACCOUNTS_INACTIVE fix, caught by CI's PR-mode check:file-size. * chore(tests): drop explanatory comments on ALL_TARGETS_SKIPPED assertions Kept the assertion value fix (ALL_ACCOUNTS_INACTIVE -> ALL_TARGETS_SKIPPED); the comments were unnecessary. Reverts the file-size baseline bump these comments caused (combo-routing-engine.test.ts back to its original 3457).
Chewji9875
added a commit
that referenced
this pull request
Aug 12, 2026
…e#9584) * feat(providers): add Zylo UnoRouter and Poolside registries * feat(providers): integrate audited free-tier gateways * feat: add wave2 free-tier provider registries * feat(providers): add Mixlayer Speka and TokenReply registries * feat: add wave 2 free-tier provider registries * fix: align meganova provider slug * feat(providers): integrate wave2 free-tier gateways * feat(providers): add Wave 3-A free-tier registries * feat(providers): add HelyxAI Auriko and Poixe registries * feat(providers): add Naga AI and Chat Oripe registries * feat(providers): integrate wave3 free-tier gateways * feat(providers): add FreeInference registry * feat(providers): add Free.ai registry * feat(providers): integrate wave4 free-tier gateways * feat: add RTL layout compatibility CSS (fixes #7680) (#7987) Co-authored-by: Austin Liu <austinliu@Austins-MacBook-Air-3.local> * [v3.8.50] feat(ci): extend i18n glossary-consistency gate to ko (#8244) * fix(dashboard): correct machine-translated Korean UI strings in ko.json Fix 527 mistranslated values in the Korean locale, all verified against the en.json source: - Restore protected product/protocol names garbled by machine translation (응록→ngrok, 인류/인류학→Anthropic, 쌍둥이자리→Gemini, 반중력→Antigravity, 꼬리비늘 깔때기→Tailscale Funnel, 진공→VACUUM, 우편번호→ZIP) - Fix wrong-sense homonym translations (달리기→실행 중 for Running, 장애인→비활성화됨 for Disabled, 열쇠→키 for Key, 안타→적중 for Hits, 유물→아티팩트 for Artifacts, 건강검진→상태 확인 for Healthcheck) - Repair translated identifiers that broke literal values (양말5→socks5, 볼록-세션-id→convex-session-id, 채팅/완료→chat/completions, 메시지/보내기→message/send JSON-RPC methods) - Replace key-name dumps shipped as values ("Table Name", "Overview Title", "Cli Tools Redirect Title" etc.) with real Korean translations - Unify ngrok casing (Ngrok→ngrok) and trailing punctuation with the English source; align terminology across fixes (공급자, 폴백, 사용자 정의) All {placeholder} tokens, markdown, and protected terms preserved verbatim; i18n UI coverage and ko validation gates pass. * feat(ci): extend i18n glossary-consistency gate to ko Follow-up to #8224 (ko.json mistranslation cleanup): the glossary gate only checked zh-CN, leaving the Korean catalog unguarded against the next machine-translation run reintroducing the garbage it fixed. - Add scripts/i18n/glossary/ko.json: 9 canonical concepts (provider, fallback, running/disabled states, key, export, healthcheck, port, artifacts) plus protectedTermMistranslations for 10 verified garbled renderings (응록→ngrok, 인류→Anthropic, 쌍둥이자리→Gemini, 반중력→Antigravity, 꼬리비늘→Tailscale, 진공→VACUUM, 양말5→socks5, 우편번호→ZIP, 클로드→Claude, 옴니루트→OmniRoute) - Extend check-glossary-consistency.mjs to merge per-locale protectedTermMistranslations from the glossary file with the legacy zh-CN KNOWN_MISTRANSLATIONS map (behavior for zh-CN unchanged) - Add ngrok/Anthropic/Claude/Gemini/Antigravity/Tailscale/VACUUM/ socks5/ZIP to protected-terms.json - Wire --locale=ko into the i18n-glossary CI job and add the i18n:check-glossary:ko npm script - Tests: merge semantics (3 new unit tests), #8224 regression guards for src + bin/cli ko catalogs, and real-file pass assertions for ko Every enforced synonym/mistranslation was verified to have zero occurrences in both real ko catalogs; collision-prone candidates (안타 ⊂ 안타깝게도, 배우 ⊂ 배우기) were deliberately excluded. * test(tail): retire stale i18n __MISSING__ repro + fix qianfan website URL (#8263) Base-red slice 6, rebased onto the advanced release/v3.8.49 (91fd5f9). The oauth grok-cli #7610 guard was already fixed on the base by #8027 (it reads the warning from grokCliAuthJson.ts) — dropped from this slice to avoid a conflicting duplicate. Remaining two, still red on the current base: - i18n #7258: the "focused repro" asserted zh-TW.json STILL carries raw __MISSING__: placeholders. That backlog was filled (the "no locale has a raw __MISSING__: leaf" invariant is the durable guard); retired the now-inverted repro. - qianfan: Baidu renamed the product page (product/wenxinworkshop -> product-s/ qianfan_home); updated the expected website URL. Validated (clean env): i18n 4/0, qianfan 5/0; oauth-modal-grok 2/0 already green on base. Co-authored-by: Probe Test <probe@example.com> * [v3.8.50] feat(ui): add global model search to Combo builder (#8285) * Feat: Busca Global de Modelos no Combo Builder * Fix: assembleStandalone src and dest equality check on Windows * fix(ui): i18n global model search + drop pnpm-lock + extract search panel - Drop pnpm-lock.yaml (repo is npm-workspaces; package-lock.json is canonical). - i18n: replace hardcoded Portuguese strings in the new global model search UI (Combo Builder) with getI18nOrFallback()/t() EN-fallback calls; add the 10 new keys (builderModeStep, builderModeGlobal, builderGlobal*) to en.json and propagate __MISSING__ placeholders to all 42 locales. - Extract the mode-toggle + global-search panel JSX into a new GlobalModelSearchPanel component, and the allGlobalModels/ filteredGlobalModels/add-step/add-all logic into pure, unit-tested helpers (buildGlobalModelList, filterGlobalModelList, addGlobalModelStep, addAllGlobalSearchMatches) in src/lib/combos/builderDraft.ts, keeping combos/page.tsx under its frozen file-size budget. - Revert the unrelated local-tooling .source/dynamic.ts one-liner to match origin/release/v3.8.49. - Add unit tests for the new builderDraft helpers. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Gleisson de Jesus Santos <T034183@embasanet.ba.gov.br> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: ikelvingo <im.kelvinwong@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * [v3.8.50] feat: extract CloakBrowser/browser-pool into optional plugin package (#8299) * fix: align three stub implementations with original code - chatUrlMatcher: restore original 3-arg signature (u, matchDomain, chatUrl) with PLACEHOLDER-aware path segment matching - shouldUseGrokBrowserBacked: remove required param, restore env-var logic checking both WEB_COOKIE_USE_BROWSER and OMNIROUTE_BROWSER_POOL - browserPool.ts: add Turbopack rationale comment and join-trick helper to satisfy the optional-import test assertions - browserBackedChat.ts: replace any types with typed BrowserPoolModule interface Verification: 40/40 browser node:test pass, typecheck:core 0 errors * fix: remove duplicate getMod/modPromise in browserBackedChat stub Two copies of the module proxy got committed — the typed BrowserPoolModule version at lines 50-56 and a stale any-typed duplicate at lines 64-71. Removed the duplicate, keeping the typed version. Verification: - 40/40 browser tests pass (both previously-failing suites now green) - typecheck:core: 0 errors - env kill switch (OMNIROUTE_BROWSER_POOL=off): verified * fix(pr-8299): address all 5 review issues Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync Issue #5: Add test case for package-absent fallback in tryBackedChat All 25 browser tests pass across 4 suites. typecheck:core passes. * chore: move sqlite-vec to optionalDependencies, fix js-tiktoken static import Both changes ensure native binary dependencies are properly categorized as optional: - sqlite-vec: moved from dependencies to optionalDependencies. Only used via lazy _require("sqlite-vec") in vectorStore.ts — zero static imports. - js-tiktoken: already in optionalDependencies, import changed to createRequire pattern to avoid crash when package is not installed (same pattern as sqlite-vec in vectorStore.ts). Resolves ScoutDeps findings from browser-pool pluginization audit. * docs(issues): fix stale interfaces.ts path in browser-pool proposal The proposal originally planned open-sse/interfaces/browserPool.ts for the BrowserPoolProvider interface, but the shipped implementation puts it in packages/browser-pool/src/interfaces.ts instead. Update the references so the doc matches what was actually built — the stale path was tripping check:fabricated-docs (--strict). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix: sync package-lock.json with playwright 1.62.0 Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * test: keep browser warmup disabled in tryBackedChat unit tests * fix(pr-8299): keep grokClearance on the evolved release implementation (rebase reconciliation) --------- Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * [v3.8.50] fix(adobe-firefly): live x-arp-session-id / Arkose wire (stop HTTP 408) (#8571) * feat(adobe-firefly): reference image attach + /v1/images/edits (follow-up #8006) Upload source images to Firefly storage (POST /v2/storage/image) and attach them as referenceBlobs on generate-async, matching live firefly.adobe.com captures (usage:general for nano multi-ref; usage:subject for gpt-image). Also wire built-in adobe-firefly through OpenAI-compatible POST /v1/images/edits (multipart or JSON data URLs, up to 4 refs) so Media edit-with-references and Open WebUI image-edit hit the same path as image2image generate. Unit suite: tests/unit/adobe-firefly.test.ts 41/41. * test(api): add route-level coverage for Adobe Firefly /v1/images/edits + fix typecheck/file-size drift Covers the referenceBlobs upload path, the 4-reference cap error, and the credentials/rate-limit branches added to the /v1/images/edits route for adobe-firefly (#8510). Also fixes a Buffer/BodyInit typecheck mismatch in uploadAdobeFireflyImage and corrects the adobeFireflyClient.ts file-size baseline entry to match the gate's actual LOC count (it counts the trailing newline, so the frozen value is 2317, not 2316), plus a testFrozen entry for adobe-firefly.test.ts's own +159 line growth from this PR. Moves the handleAdobeFireflyImageGeneration re-export out of the middle of the import block in imageGeneration.ts for readability. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * [v3.8.50] fix(adobe-firefly): durable session, Chrome recovery, browser sign-in (#8578) * fix(adobe-firefly): durable session, off-screen Chrome recovery, browser sign-in Rebuild x-arp-session-id from Cookie pieces (sid/ark/forter) so aux_sid is never sent as ARP. Sticky ARP + submit spacing reduce mid-batch colligo 408 thrash. Add optional managed Chrome warm (off-screen headed by default; Forter rejects headless) and POST /api/providers/{id}/login browser sign-in that returns JWT+Cookie after a fresh SSO. Visible sign-in resets off-screen window placement and clears prior Adobe session when adding another account. * fix(adobe-firefly): cast Node Buffer to ArrayBuffer and harden chrome runtime null close Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(docs): sync docs-counts gate and env var contract for adobe-firefly Update executor/OAuth-provider counts in ARCHITECTURE.md and CODEBASE_DOCUMENTATION.md to match the real code (89 executors, 21 OAuth providers), and document the Adobe Firefly Chrome-driven session-refresh env vars in .env.example and ENVIRONMENT.md so the env/docs contract tests pass. Co-authored-by: artickc <artickc@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: artickc <artickc@users.noreply.github.com> * fix(github): honor per-model targetFormat override for Copilot custom models (#8713) GithubExecutor.buildUrl() only consulted the static PROVIDER_MODELS registry via getModelTargetFormat("gh", model), so a custom Copilot model (e.g. gpt-5.6-terra/gpt-5.6-luna) with its dashboard "Target Format" set to OpenAI Responses API always still routed to /chat/completions and got rejected upstream with "model ... is not accessible via the /chat/completions endpoint" — the setting had no effect on real routing. chatCore already resolves the correct per-request targetFormat (including the custom-model override) via resolveChatCoreTargetFormat(), but that value was never threaded past chatCore into the executor's own URL-building decision. Mirrors the zai/glm-coding-apikey fix (#7364) for the identical class of bug: chatCore/executionCredentials.ts now surfaces the resolved override onto providerSpecificData.targetFormat when it resolves to openai-responses for the github provider, and GithubExecutor.buildUrl() prefers that value over the static registry lookup when present. Verified: 6 new regression tests plus all 95 pre-existing github/executor tests green. Co-authored-by: Wital <wital@example.com> * fix(test): revive orphaned vitest tests and fix CI routing (#8718) * [v3.8.50] fix(api): serve stale model catalog during refresh (#8728) * fix(api): make model catalog refresh response-safe * fix(api): invalidate model catalog mutation paths * fix(db): preserve aliases backup import after catalog rebase --------- Co-authored-by: Erick Kinnee <erick@ekinnee.dev> * fix(antigravity): quota-aware account selection and projectId persistence (#8891) * fix(antigravity): per-model quota + 30min credits_exhausted reprobe - accountFallback.ts: hasPerModelQuota() now treats antigravity/agy as per-model quota. A single-model 429 no longer cascades to all models in the provider. - connectionRecovery.ts: credits_exhausted removed from terminal set; isCreditsExhaustedReprobeCandidate() with 30min default. Loads active+inactive rows so inactive credits_exhausted accounts can recover. - tests/unit/quota-connection-recovery.test.ts: 6 cases covering pure helpers + tick wiring. * fix(antigravity): persist projectId and prefer healthy accounts Save Cloud Code projectId after runtime discovery, skip accounts missing projectId when alternatives exist, and mark missing_project_id on 422. * fix(antigravity): skip quota-exhausted models during account selection Avoid repeatedly dispatching to Antigravity models that already report exhausted quota, reducing wasted upstream calls and combo fallback latency. --------- Co-authored-by: hermes <hermes@nous.local> * feat(alibaba): free-tier routing with live quota sync (#8893) * feat(alibaba): add free-tier routing with console quota and builtin allowlist Classify DashScope free vs paid models via console quota API, a hardcoded operator allowlist fallback, and per-connection drained tracking. Wire wildcard combo expansion, model refresh, combo exhaustion, and audit redaction for Alibaba console credentials. * fix(routing): reset forced connection pin and persist Alibaba free-tier drain Drop session affinity pins when a forced connection is excluded after 429, and record Alibaba free-tier exhaustion on upstream 403 so per-key drained lists stay accurate without blocking sibling keys. * fix(alibaba): prefer live quota sync over static free-tier allowlist Stop unioning the builtin text allowlist when a console quota snapshot exists, treat expired quotaValidityPeriod as not_capable, and add a dated JSON pack plus sync-alibaba-allowlist script for operator refresh without code edits. * docs(alibaba): document free-tier console path + allowlist env overrides Adds the 4 ALIBABA_FREE_TIER_*_FE_PATH / ALIBABA_FREE_TIER_ALLOWLIST_PATH env vars (referenced by alibabaFreeTierQuotaFetcher.ts and alibabaFreeTierAllowlist.ts) to .env.example and docs/reference/ENVIRONMENT.md so the env/docs contract check passes. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(open-sse): split alibabaFreeTierQuotaFetcher.ts under file-size cap Extract pure parsing/classification/eligibility-filtering logic into alibabaFreeTierQuotaClassify.ts and shared types/primitives into alibabaFreeTierQuotaTypes.ts, leaving the HTTP/console-fetch flow in the original file. Public API is unchanged (re-exported), behavior is identical. Co-authored-by: AndrianBalanescu <AndrianBalanescu@users.noreply.github.com> * fix: resolve typecheck errors in alibaba-free-tier routing --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: AndrianBalanescu <AndrianBalanescu@users.noreply.github.com> Co-authored-by: AndrianBalanescu <andrian@balanescu.dev> * feat: improve provider quota layouts (#8916) * feat: improve provider quota layouts (#8916) Adds Full/Compact layout toggle for provider quota cards. Compact mode shows condensed card grid with key metrics; Full mode shows expanded detail. Toggle persists via localStorage. Changes: - ProviderLimits/index.tsx: layout mode state + toggle button - QuotaCardGrid.tsx: compact/full card rendering - ProviderQuotaWidget.tsx: compact/home view - HomePageClient.tsx: minor wiring fix - tests/unit/quota-card-grid-compact-layout-8916.test.ts: structural guard - file-size-baseline.json: rebaseline for ProviderLimits/index.tsx (1163) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(ci): restore providerId contract + reorder grid source + rebaseline translator drift - ProviderQuotaWidget.tsx: restore size={18} on non-compact ProviderIcon to satisfy base-branch test #3064 pinned contract. - QuotaCardGrid.tsx: reorder branches so non-compact (default) layout renders first in source. Same runtime behavior; satisfies base tests #3520/#6815/#7072 that inspect the first div/grid-cols class. - file-size-baseline.json: bump testFrozen translator-openai-to-gemini 1619->1622 (+3 upstream drift absorbed in merge of release/v3.8.50). Closes upstream CI: Unit Tests 2/4, 3/4, 4/4 + Fast Quality Gates. codeql-ratchet is upstream repo-wide (not our code) — external. --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(i18n): localize SubscriptionTab UI strings instead of hardcoded Chinese (#8930) The proxy subscription tab (System -> Proxy -> Subscriptions) displayed Chinese text regardless of the selected language. The component called useTranslations("settings") but bypassed t() for all ~50 UI strings. - Replace every hardcoded Chinese string in SubscriptionTab.tsx with t("proxySubscription.<key>") calls - Add 53 new keys under settings.proxySubscription to en.json (English) and zh-CN.json (Chinese) with full manual translations - Propagate to all 41 other locales via generate-multilang.mjs (Google Translate), per docs/guides/I18N.md workflow All 42 locales at 100% i18n coverage with zero __MISSING__ markers. * Fix custom tool output pairing during context compression (#8933) * Fix custom tool output pairing during compression (#8932) * Bypass proxy compaction for native Codex context * fix(sse): extract Codex tool-call output repair to leaf module for file-size gate repairMissingCodexToolCallOutputs (added by #8932 for custom_tool_call pairing) pushed codex.ts past the frozen file-size baseline. Extract it to open-sse/executors/codex/toolCallRepair.ts, leaving only the wiring call in codex.ts. Rebaseline the test file's genuine +41 line growth from #8932's new custom_tool_call_output coverage. Co-authored-by: JxnLexn <JxnLexn@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: JxnLexn <JxnLexn@users.noreply.github.com> * feat(combos): let combo builders test providers and add only working models (#9011) * fix(sse): preserve Claude Code tool-name casing via Gemini/Antigravity (#9008) (#9016) Stop blindly lowercasing PascalCase tool_use names on the Gemini→Claude path so Claude Code no longer rejects Read/WebSearch as missing tools. * fix(vision): preserve images for text-only routes (#9037) * fix(vision): preserve images for text-only routes * fix(i18n): complete Vietnamese vision bridge copy * fix(ci): drain prerelease tag input --------- Co-authored-by: rinseaid <rinseaid@rinseaid.net> * feat(i18n): complete zh-CN localization for compression engines and dashboard UI (#9038) * feat(i18n): complete zh-CN localization for compression engines and dashboard UI - Translate all compression engine names and descriptions (Caveman, Lite, Aggressive, Ultra, OmniGlyph, Headroom, Session Dedup, RTK, CCR, LLMLingua) - Translate all __MISSING__ entries (50+ strings) across settings, cache, OAuth, compression exclusions, and provider onboarding - Translate hardcoded dashboard UI strings (analytics tables, playground, cliproxy/9Router exposure cards, Qdrant config, OneProxy, forgot-password) - Localize PWA manifest and A2A agent card (manifest.ts, agent.json route) - Add missing translation keys (hermes roles, API protocol, embedded services, memory/Qdrant, Obsidian, Codex auto-ping, reasoning routing) * fix(i18n): restore cliCommon.comparison.acp keys dropped in the release merge The release merge kept only the author's translated `flow` value and dropped `title`, `desc` and `examples`, which exist on every sibling entry (code/agent). Restore the three from the release while keeping the author's `flow` translation. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(resilience): recover idle-capacity limiter wedges early (#9041) * fix(resilience): recover idle-capacity limiter wedges early * docs(changelog): note limiter wedge recovery * fix(resilience): harden limiter wedge recovery * fix(resilience): close limiter recovery review gaps * test(resilience): preserve scoped exhaustion guards * docs(changelog): remove self-credit suffix * test: include limiter regressions in mutation coverage * chore(quality): reconcile v3.8.50 file-size baselines * fix(docs): add WAF MDX title frontmatter * fix(docs): complete WAF frontmatter metadata * fix: skills & memory — tool-name encoding, schema normalization, warm-cache, combo id, Ponytail catalog (#9058) * feat(skills): add Ponytail minimalism skill as external catalog entry - Add 'external' SkillCategory + SkillArea - Register ponytail (MIT, DietrichGebert/ponytail) in CURATED_SKILLS - Generator: external skills carry content in custom block, no api/cli body - Generate skills/ponytail/SKILL.md with original content preserved - Update catalog test counts 45 -> 46 * fix(skills+memory): builtin handler fallback in executor, skip vector upsert for deleted memories - skills: Next.js compiles SkillExecutor into multiple chunks (own singleton each); route chunk lacked builtin handlers registered at startup via instrumentation. execute() now falls back to builtinSkills registry, so POST /api/skills/executions works for file_read/web_fetch/etc. - memory: scheduleVectorUpsert is fire-and-forget and embeddings are slow; health-check verify (create->delete test memory) left queued upserts failing with 'memory not found' every 30s. Check existence before embedding and skip quietly. * fix(skills): encode tool names with @ and . for providers rejecting them Skill tools were advertised as 'name@version' (e.g. test-fr2@1.0.0), but DeepSeek/Groq/OpenAI reject function names not matching ^[a-zA-Z0-9_-]+$. Names already valid are left untouched; invalid ones are reversibly encoded as omr_skill_<base64url> and decoded in interception before registry lookup. * fix(combos): include DB id column in combo records for dashboard links getCombos() selected only data/sort_order/context_cache_protection, so combos whose JSON blob lacked an id field returned id: undefined. The dashboard then linked to /dashboard/combos/undefined and Combo Control Center failed with 'Combo not found'. Merge the id column into parsed rows (authoritative, only when the blob has no id). * fix(skills): normalize flat skill schemas to object schema for Gemini/Claude Stored skill schemas are flat property maps ({ text: { type: string } }), which OpenAI-compatible providers tolerate but Gemini (function_declarations[].parameters) rejects with 'Unknown name ... Cannot find field'. Wrap bare maps into { type: 'object', properties: {...} } for all three tool formats. * fix(skills): warm registry cache before skill injection in chat path injectSkills() lists the in-memory skillRegistry, which is empty after a cold start until something calls loadFromDatabase(). The interception path already warms the cache (#2815); the injection path did not, so skills were silently skipped (no_enabled_skills) for the first requests after restart. Warm the cache for the chat owner before injection. --------- Co-authored-by: Egor <egorich-print@users.noreply.github.com> * fix(translator): honor Chat targets for Responses clients (#9161) Honor explicit Chat targets for Responses-shaped clients while preserving native Responses providers and selecting token fields from the outbound protocol. Includes focused regression coverage and the required changelog fragment. * test(mcp): guard Node 24 bundled MCP startup (#9162) * feat(cursor): proactively renews Cursor sessions and fixes manual refresh (#9173) * refactor(cursor): extracts token extraction into shared lib Moves tryIdeAuth/tryAgentAuth and supporting helpers out of the auto-import route into src/lib/cursor/tokenExtractor.ts, and adds an agent-cli-state.json fallback candidate path to tryAgentAuth (alongside the existing auth.json candidate) so the extraction logic can be reused by the upcoming renewal orchestrator. * feat(cursor): adds cursor-agent-backed token renewal orchestrator Builds the renewal orchestrator in src/lib/cursor/renewal.ts: a bounded, unattended-safe --list-models nudge, a side-effect-free status availability check, an in-flight spawn lock keyed by command, and renewCursorConnection() which nudges cursor-agent then independently re-scrapes the IDE and cursor-agent credential sources to detect whichever refreshed. Extends cursorAgent.ts's binary resolution and spawn helper with fixed-paths-only mode and a SIGKILL follow-up for background use. Adds a generic keyed-mutex utility (src/shared/utils/keyedMutex.ts) for serializing a connection's renew-then-persist cycle, and forwards a busy-timeout through driverFactory's node:sqlite fallback path. * feat(cursor): proactively renews Cursor sessions in the sweep Adds src/lib/tokenHealthCheckCursor.ts, sweep-side glue that calls the renewal orchestrator and persists the result, wired into tokenHealthCheck.ts's checkConnection() via a new Cursor-specific branch placed ahead of the generic no-refresh-token fallthrough. Carves out a non-terminal exception for a Cursor connection that already landed at testStatus "expired" via the request-time 401 path, excluding permanently-dead account_deactivated connections. Extends buildRefreshFailureUpdate() with an overrides param so Cursor's failure path can use a distinct, non-terminal errorCode instead of the generic refresh_failed/expired taxonomy. * feat(cursor): adds local-only manual refresh route Adds POST /api/providers/[id]/refresh-cursor, a dedicated loopback-only route that calls the renewal orchestrator on demand for a single Cursor connection, bounded by a 30s per-connection cooldown. Classifies the new route in LOCAL_ONLY_API_PATTERNS and closes the manage-scope-bypass gap for dynamic-segment spawn-capable routes under /api/providers/ via a new SPAWN_CAPABLE_PATTERNS / SPAWN_CAPABLE_PATTERN_ANCESTORS mechanism, which also retroactively covers the pre-existing /login route. The existing shared /api/providers/[id]/refresh route is untouched and stays remote-reachable for every other provider. * feat(cursor): surfaces a dismissible cursor-agent nudge Adds GET /api/providers/cursor/agent-availability, a credential-free LOCAL_ONLY route returning only { cursorAgentAvailable: boolean }, backed by a 5-minute cached wrapper around the renewal orchestrator's existing availability check. Surfaces a dismissible dashboard banner on the Cursor provider page suggesting cursor-agent installation when it isn't detected, following the existing dismissible-banner convention. Also fixes a pre-existing bracket character in a routeGuard.ts comment that was silently truncating check-openapi-security-tiers.mjs's view of LOCAL_ONLY_API_PREFIXES. * fix(cursor): wires manual refresh button to the new route Branches handleRefreshToken to call the dedicated Cursor refresh route instead of the generic /refresh route, which silently 502s for Cursor connections today since they carry no refresh token. Every other provider's refresh behavior is unaffected. Adds the cursorSessionUnchanged i18n key and syncs it (plus a pre-existing, unrelated 28-key backlog) across all 42 locale files. * fix(cursor): addresses Phase 4/4.5 review findings Restores the legacy stdout/stderr auth-pattern fallback in checkCursorAgentAvailability() that the plan's Task 2 Step 4 required but the implementation had dropped. Threads an optional deps parameter through checkCursorConnectionIfNeeded() so its error branch is reachable in tests, and switches both it and the manual-refresh route to exhaustive switch statements over the renewal result. Adds a short-lived host-keyed dedup cache around tryIdeAuth() so multiple due Cursor connections sharing a host don't each open the same state.vscdb file in one sweep tick. Adds opportunistic eviction to the manual-refresh cooldown map, an outer try/catch to the availability route for defense-in-depth consistency with the plan's other routes, and corrects a stale JSDoc claim about the /login route's auth check. Documents the now-empirically-confirmed agent-cli-state.json schema mismatch found while validating against a real cursor-agent install. * docs(cursor): adds changelog fragments for the renewal plan Adds one fragment per user-facing outcome per changelog.d/README.md's convention for a PR that both fixes and adds. PR number placeholder to be filled in once the PR is opened. * fix(i18n): translates the new Cursor keys into Vietnamese The i18n:sync-ui run in an earlier commit left __MISSING__ sentinels for the 4 new Cursor keys in every locale, but Vietnamese has a dedicated completeness test requiring zero internal missing markers. Provides real translations for cursorSessionUnchanged, cursorAgentNudgeTitle, cursorAgentNudgeBody, and cursorAgentNudgeDismiss. * fix(cursor): addresses quality-gate Layer 1.5 findings Restores a comment that misrepresented execFile's actual argv shape after an earlier bracket-removal fix, this time avoiding literal closing-bracket characters entirely so the openapi checker's naive array parser can't be broken by either version. Bounds the sweep- and manual-route-triggered tryIdeAuth() busy-timeout to 250ms (down from the interactive auto-import path's 2000ms), since both share the main event loop with all other in-flight requests and should fail fast on a WAL-lock collision rather than block the whole instance for up to ~4s. Has the manual refresh route bypass the sweep's IDE-auth dedup cache so a click always sees a fresh read, consistent with this plan's existing "manual actions never see stale cached data" convention. Documents the previously-missing agent-availability route in ROUTE_GUARD_TIERS.md's spawn-capable table. * fix(cursor): adds SIGKILL follow-up to the status-check spawn Matches the nudge spawn's existing SIGTERM+SIGKILL pattern so an unresponsive cursor-agent status check can't leak a lingering process if it ignores SIGTERM. * docs(cursor): fills in the PR number for changelog fragments Renames the 3 changelog.d fragments to their PR-numbered filenames and replaces the (#PR) placeholder with #9173, now that the PR exists. * fix(cursor): corrects changelog fragments to reference PR #9173 The prior commit only staged the git mv rename — a git add invocation with a stale (pre-rename) pathspec aborted before the actual (#PR) -> (#9173) content edit was staged, so the rename landed without the fix it was meant to carry. This captures the actual content change. * docs(cursor): regenerates the agent-skills catalog for the new route check:agent-skills-sync (CI's Merge integrity gate) requires SKILL.md files to stay in sync with the live route catalog. Adding /api/providers/cursor/agent-availability in an earlier commit needed a regen this branch never ran. * chore(quality): rebaselines file-size caps grown by agentrouter merges Two already-merged agentrouter commits (564c204ef, ec150a006) on release/v3.8.50 grew open-sse/executors/base.ts, open-sse/handlers/chatCore.ts, and tests/unit/chatcore-translation-paths.test.ts past their frozen caps before this PR branched — unrelated to the Cursor renewal changes here. No PR branch is left to fix the growth in-place, so the caps are bumped to the current real sizes, following the existing release-green rebaseline precedent in this file. * fix(sse): imports getModel helpers from db/models, not localDb A recently-merged agentrouter commit added a @/lib/localDb import in chatCore.ts, violating the no-restricted-imports rule (Hard Rule #2 — never barrel-import from localDb.ts). Points the import at the owning module, src/lib/db/models.ts, where both functions are actually defined, and prunes the now-stale suppression entry. * fix(sse): scopes CC-relay anthropic-beta to its own requestDefaults Two already-merged agentrouter commits widened usesClaudeCodeProtocol()'s native-Claude system-transform block (billing header + selectBetaFlags-derived anthropic-beta) to also run for generic CC-compatible relay connections, not just real claude traffic and agentrouter's own wire-image mimicry. selectBetaFlags() has no visibility into a relay's own providerSpecificData.requestDefaults, so its header replacement silently wiped out an earlier context-1m append and force-included redact-thinking regardless of the relay's own opt-in. Restores both for plain CC-compatible relays only; real claude/agentrouter traffic is unaffected. Also bumps four stale hardcoded Codex/Claude Code CLI version-string test assertions (0.144.1->0.146.0, 2.1.219->2.1.220) that drifted when the same two commits bumped the version constants without updating their tests, and rebaselines base.ts's frozen file-size cap for this fix's own +35 lines. * fix(sse): preserves bare CC-relay native treatment and context-1m The previous commit's fix was too broad in one direction: excluding ALL CC-compatible relays from the native-Claude header block broke two pre-existing tests (cc-compatible-provider.test.ts, v3.6.6) that rely on that treatment for a 'vanilla' relay with no providerSpecificData.requestDefaults configured. Refines the gate to this whole native-Claude header-replacement block: replace headers for real claude traffic, agentrouter's wire-image mimicry, OR a CC-relay with no requestDefaults at all — only a relay with EXPLICIT requestDefaults (context1m/redactThinking/summarizeThinking) gets to keep buildHeaders()'s own correctly-computed header set. A redact-thinking-beta strip (unconditional, a no-op when native treatment didn't apply) covers the one remaining gap: selectBetaFlags() force-includes it for a bare relay's opaque client, which a bare relay never explicitly opted into. Verified against all three previously-conflicting pre-existing tests simultaneously: executor-default-base.test.ts's '1M beta' test, both cc-compatible-provider.test.ts SSE-forcing tests, and provider-request-failure-pipeline.test.ts's 'keeps request beta headers' test (the last of which was already broken by the raw agentrouter merge, confirmed via direct comparison against that exact commit). * fix(sse): fills in remaining stale CLI version literals The same two agentrouter commits bumped Codex/Claude Code CLI version constants (0.144.1->0.146.0, 2.1.219->2.1.220) without updating every hardcoded test assertion. This round covers the ones the previous version-string commit missed: the anthropic-cache-fingerprint billing-version constant, a cc-bridge-transforms body assertion, the UI-mirror parity test's own snapshot plus its RoutingTab.tsx source of truth, an integration test's User-Agent assertion (inconsistent with its own dynamic Version assertion two lines up), and the translate-path golden snapshot. Also updates a stale doc comment referencing the old literal by value instead of by constant name. * fix(cursor): imports from db/ modules, not the localDb barrel Both files violated Hard Rule #2 (never barrel-import from localDb.ts) — a genuine lint error that had gone uncaught locally. refresh-cursor/route.ts imported getCachedProviderConnectionById from @/lib/localDb instead of its owning module, @/lib/db/readCache. tokenHealthCheckCursor.ts copied the same pattern from its sibling tokenHealthCheckCopilot.ts (an existing, already-suppressed violation) for updateProviderConnection; imports it from @/lib/db/providers instead, with no circular-import fallout (verified via the existing token-health-check-cursor and refresh-cursor-route test suites). * fix(db): removes stale raw-SQL allowlist entry for cursor route The cursor auto-import route no longer contains raw SQL — that query now lives in src/lib/cursor/tokenExtractor.ts, outside the route/handler scope check-db-rules scans. The allowlist entry was stale, tripping the stale-enforcement gate. * fix(test): registers cursor test files in stryker tap.testFiles Three unit test files covering mutation-tested modules (route-guard-cursor-agent-availability, route-guard-cursor-refresh, cursor-renewal) were missing from stryker.conf.json's tap.testFiles, tripping the mutation-test-coverage gate's drift detection. * chore(ci): retriggers checks (stuck GH Actions runner on shard 2/4) * fix(sse): restores CC-relay context1m/redact-thinking test coverage Rebasing onto release/v3.8.50's new tip (35405be60, an unrelated agentrouter protocol-inference commit) silently flipped two assertions this branch's own earlier fix (687fbda62) depends on, in the same test files that commit touched for other reasons: - executor-default-base.test.ts: calls[0] (a bare CC-relay with no requestDefaults) expected redact-thinking-beta absent; flipped to present. calls[1] (context1m+redactThinking requestDefaults) expected the context-1m beta preserved; flipped to absent. - provider-request-failure-pipeline.test.ts: expected Accept: text/event-stream and the context-1m beta present for a relay with explicit requestDefaults; flipped to application/json and absent. 35405be60 did not touch open-sse/executors/base.ts at all, so these were test-only edits made without visibility into the still-unmerged CC-relay header-preservation fix on this branch — they quietly matched the assertions back to the pre-fix (buggy) behavior instead. Restores the original, validated expectations; all three interdependent test files (executor-default-base, cc-compatible-provider, provider-request-failure-pipeline) verified passing together again. * ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved) * ci: re-trigger checks (previous push event was dropped) * fix(quality): restore dropped vi.json cursor-renewal keys + rebaseline test growth vi.json was missing 4 keys (cursorSessionUnchanged, cursorAgentNudgeTitle/Body/Dismiss) that this PR's own pre-merge branch had translated -- the original merge's 'git checkout --theirs' resolution for the 7 conflicted locale files discarded them since upstream's vi.json has no cursor-token-renewal feature. Restored from pre-merge tip a38003e30. Also rebaselines combo-routing-engine.test.ts (3457->3464) for the comment growth from the ALL_ACCOUNTS_INACTIVE fix, caught by CI's PR-mode check:file-size. * chore(tests): drop explanatory comments on ALL_TARGETS_SKIPPED assertions Kept the assertion value fix (ALL_ACCOUNTS_INACTIVE -> ALL_TARGETS_SKIPPED); the comments were unnecessary. Reverts the file-size baseline bump these comments caused (combo-routing-engine.test.ts back to its original 3457). * fix(dashboard): make connection Default Model editable and optional (#9172) (#9179) * fix(dashboard): make connection Default Model editable and optional * docs(changelog): retitle fragment with PR number --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> * fix(combo): recover provider circuit breaker from HALF_OPEN on success (#9207) The combo success path called recordProviderSuccess (cooldown-only) without notifying the circuit breaker. When a provider breaker entered HALF_OPEN after repeated failures, successful probe requests never transitioned it back to CLOSED -- the breaker stayed stuck indefinitely. Production evidence: agy breaker HALF_OPEN with 699 requests at 98% success rate, never recovering. Root cause: combo.ts calls recordProviderSuccess from providerCooldownTracker.ts (resets cooldown failureCount only) but never calls breaker._onSuccess(). The failure path in accountFallback.ts calls breaker._onFailure(), creating an asymmetry. Fix: add recordProviderSuccess to accountFallback.ts as the symmetric counterpart of recordProviderFailure. Uses getProviderBreaker (not configureProviderBreaker) to avoid overwriting the breaker's resetTimeout with default profile values. Calls breaker._onSuccess() for all non-OPEN states (CLOSED/DEGRADED/HALF_OPEN), matching execute()'s behavior. * fix(command-code): preserve literal max effort for command-code provider (#9257) * fix(command-code): preserve literal max effort for command-code provider * test(command-code): type the new sanitizeReasoningEffortForProvider assertions The 3 new command-code reasoning-effort test cases cast the function's unknown return value with `as any`, which pushes the file's frozen no-explicit-any suppression count (48) to 51 and trips the "No new ESLint warnings" gate. Use a minimal EffortCarrierResult shape instead of any, matching the fields the assertions actually read. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * test(v1-models): type the API key lookup in the #9320 auth-leak regression test The release-tip test file added by #9320 used `(k: any)` in an Array.find callback, which is not covered by config/quality/eslint-suppressions.json (the file was added after the suppressions snapshot was frozen). That leaves the "No new ESLint warnings" gate red for any branch that merges this exact release/v3.8.50 tip, unrelated to this PR's own diff. Fixing it here with a minimal derived type (Awaited<ReturnType<typeof getApiKeys>>[number]) unblocks the gate without touching the frozen suppressions baseline. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * feat(sse): server-side template expansion for combo system prompts (#5501) (#9414) * feat(sse): server-side template expansion for combo system prompts (#5501) * fix(quality-gates): register combo-system-prompt-templates-5501 test in stryker tap.testFiles check:mutation-test-coverage --strict flagged tests/unit/combo-system-prompt-templates-5501.test.ts as covering src/shared/utils/circuitBreaker.ts without being listed in stryker.conf.json tap.testFiles, so its mutant kills wouldn't count. Co-authored-by: maxmad64bis <maxmad64bis@users.noreply.github.com> --------- Co-authored-by: Max <maxmad64@gmail.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: maxmad64bis <maxmad64bis@users.noreply.github.com> * fix(translator): normalize streamed optional tool arguments (#9423) * fix: preserve Codex cache usage for Claude suggestions Co-Authored-By: Claude <noreply@anthropic.com> * fix: normalize streamed optional tool arguments Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Kittisak Tangsiri <kittisak@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> * ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved) (#9441) * fix(sse): preserve client cache boundaries when hoisting system roles (#9457) Hoisting a mid-conversation `system`/`developer` message into the top-level `system` field carried its `cache_control` marker along. Anthropic assembles the cache prefix as tools -> system -> messages, so the marker ended the cached prefix at the system block and left the accumulated conversation without a breakpoint: that turn was billed as fresh input and the next one rebuilt the cache. `relocateHoistedCacheBoundary` moves the marker to the nearest preceding block that can carry a breakpoint, skipping thinking blocks, empty text and anything the upstream normalisation discards or empties out. If that block already carries the client's own marker, both are kept - unless the hoisted one, now ahead of the target in `system[]`, would put a 5m breakpoint before a 1h one, which Anthropic rejects; it is dropped in that case. Either way the breakpoint count never grows. normalizeClaudeUpstreamMessages rewrites tool_result and inlined file/document blocks into plain text after the hoist, which silently discarded any marker on them - including a relocated one. The replacement block now inherits it. Both hoisting implementations share the helper; a fix touching only claudeSystemRole.ts would leave extractSystemMessagesToBody broken, and the native Claude path reaches the former through normalizeClaudeUpstreamMessages. Capability-gated hoisting for strict providers (#7293) is unaffected. Fixes #9436 Co-authored-by: LeonG606 <leongudat01@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> * fix(adobe-firefly): harden CDP warm, risk session, and browser sign-in (#9549) * fix(adobe-firefly): open browser sign-in and resolve provider slug in /login POST /api/providers/[id]/login passed the connection DB id to inAppLoginService.startLogin, but TOKEN_EXTRACTION_CONFIGS is keyed by provider slug — so browser login never launched for web-cookie providers. Adobe Firefly also cannot use cookie extraction: the IMS JWT only appears on Authorization headers to firefly-3p.ff.adobe.io. Add a dedicated Playwright interceptor and persist credentials with camelCase keys that updateProviderConnection actually reads. * fix(adobe-firefly): use system Chrome/Edge CDP for browser sign-in Playwright is not available inside the pkg-packaged VibeProxyServices.exe, so import('playwright') always failed with 'Playwright not installed' and never opened a window. Launch Chrome/Edge with --remote-debugging-port and capture the firefly-3p Authorization Bearer via pure CDP WebSocket instead. * fix(adobe-firefly): live x-arp-session-id / Arkose wire (stop 408 under load) Browser generate-async requires x-arp-session-id as base64({sid,ark,ftr}) with a real Arkose blob (sherlockToken). JWT alone frequently returns colligo HTTP 408 system under load while credits still work. - Match live ftr magic __UDF43-m4_31ck + Arkose pk in synthetic ARP fallback - Ranked extract of sherlockToken / x-arp from Cookie, HAR, fetch() paste, and space-joined JWT+ARP (PasswordBox newline collapse) - Reuse one ARP for storage upload + generate-async - Clearer 408 errors when browser ARP is missing vs stale - Unit suite 42/42 * fix(adobe-firefly): durable session ARP rebuild and aux_sid false-positive Rebuild x-arp-session-id from forterToken/arkose/ff_session_guid instead of ranking long Cookie pairs (e.g. aux_sid=…) as opaque ARP, which caused colligo HTTP 408. Cache IMS JWT + cookie sessions, rotate ARP on 408 retries, and keep Playwright warm-up opt-in only (headless Forter is rejected). Also expand synthetic ARP shape with bfp/fpjs to match live successful captures. * fix(adobe-firefly): renew sessions through durable CDP * fix(adobe-firefly): isolate browser sessions per account * fix(adobe-firefly): make account login fresh and deterministic * docs(adobe-firefly): document renewal controls * fix(adobe-firefly): harden CDP warm, risk session, and browser sign-in Stop colligo 408 thrash from stale Forter and frozen Google login during Sign in with browser: - CDP warm: clear Firefly origin storage + risk cookies (keep SSO); require forter age under 10 minutes on loop and timeout paths; dual CDP queues; await Runtime.runIfWaitingForDebugger; profile-lock launch retries - Session: connectionId fingerprint; write-back JWT+Cookie; warm-fail cooldown; fail closed risk_session_stale when forter is known-stale - Client: submit gate around generate-async; max 2 attempts when forter known-stale; poll 401 one refresh; pass sessionBrowserKey through handlers - Login route: pure system Chrome/Edge CDP only; camelCase credential persist - Unit: browser-login + firefly suites green (60) * fix(adobe-firefly): dedupe CDP session hardening blocks after rebase Remove duplicated guard blocks and test bodies introduced when rebasing the CDP session hardening work onto release/v3.8.50, which already carries the hardened implementation. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(translator): preserve Kimi K3 Responses reasoning (#9556) * fix(translator): preserve Kimi K3 Responses reasoning * fix(translator): make K3 reasoning preservation model-driven * fix(translator): replay cached Kimi reasoning before fallback * fix(translator): keep authentic K3 reasoning through cleanup * refactor(reasoning): use replay policy for K3 * fix(settings): use provider prefixes in model overrides (#9569) * [v3.8.50] feat(providers): add support for TinyCMS Web (#8736) * feat(providers): add support for TinyCMS Web including WASM-based cryptographic signing and Proof-of-Work emulation * feat(providers): add unit tests, ESLint suppressions, and fix hardcoded userid for TinyCMS Web - Add unit tests for WASM init, UUID validation, challenge flow (15 tests) - Add WASM source comment explaining binary origin - Replace hardcoded userid with dynamic provider-specific data - Add ESLint suppressions for no-explicit-any in WASM bridge code - Add explanatory comments for DOM shim (runtime WASM-bindgen, not test mocks) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(providers): extract TinyCMS DOM shims into an explicit setup function tinycmsSigner.ts installed its window/document/HTMLCanvasElement/ CanvasRenderingContext2D shims for the wasm-bindgen glue as a module-load side effect. That meant merely importing the module (even transitively, e.g. through the provider registry from an unrelated test) mutated global state for the rest of the test process. Extract the shim installation into setupDomMocks(), which returns a restore callback: - initTinyCmsWasm() calls it once before instantiating the WASM module (production path — unchanged behavior, still automatic). - tests/unit/provider-tinycms-web.test.ts now calls it explicitly in a `before` hook and restores the previous globals in `after`, so the shims never leak into other test files. As a side effect, replacing five separate `as any` casts with a single typed `global as Record<string, any>` handle drops the file's no-explicit-any count from 5 to 1; eslint-suppressions.json updated to match. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * docs(providers): regenerate PROVIDER_REFERENCE.md for tinycms-web Mechanical `npm run gen:provider-reference` run after merging release/ v3.8.50 into this branch — the generated table was stale for both the new tinycms-web entry this PR adds and the release's own cheaperinference addition. Total providers 290 -> 292, Web Cookie Providers 31 -> 32. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * [v3.8.50] fix: passthrough non-standard cache token fields for DeepSeek / MiniMax / Bedrock across streaming, non-streaming, and Dashboard paths (#8591) * fix(#8171): map DeepSeek prompt_cache_hit_tokens into prompt_tokens_details.cached_tokens DeepSeek native API returns cache stats in flat top-level fields (prompt_cache_hit_tokens / prompt_cache_miss_tokens) instead of the standard prompt_tokens_details.cached_tokens. The usage sanitizer (sanitizeUsage / sanitizeResponsesUsage) was stripping these non-standard fields, so clients never received real cache hit counts even when the upstream served cached responses. Changes: - sanitizeUsage(): map prompt_cache_hit_tokens into prompt_tokens_details.cached_tokens when the latter is unset - sanitizeResponsesUsage(): same mapping for input_tokens_details - filterUsageForFormat(): add prompt_cache_hit_tokens and prompt_cache_miss_tokens to the default format allow list so they survive field-level filtering * fix: passthrough non-standard cache token fields for DeepSeek / MiniMax / Bedrock across streaming, non-streaming, and Dashboard paths * fix(sse): shrink cache-hit token passthrough to fit file-size gate PR #8591 added a DeepSeek/MiniMax/Bedrock flat cache-hit-token -> nested prompt_tokens_details.cached_tokens mapping (#8171) that grew responseSanitizer.ts and stream.ts past their frozen file-size baselines. - Extract the chat-completions/Responses-API mapping logic into a new leaf module (responseSanitizer/cacheHitTokens.ts). - Move the streaming-path rebuild into filterUsageForFormat() (usageTracking.ts), the single conversion chokepoint both stream.ts call sites already used, eliminating the duplicated stream.ts patch entirely. - Rebaseline responseSanitizer.ts by the 2 lines that remain irreducible (the mandatory ES import for the extracted helper). Behavior verified unchanged via the existing response-sanitizer and stream-handler unit suites. Co-authored-by: ikelvingo <ikelvingo@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: ikelvingo <ikelvingo@users.noreply.github.com> * docs: fix stale tool count (105 -> 104) in MCP server docs (#10002) The doc's own breakdown at line 11 (42+3+4+3+6+8+8+6+22+2) sums to 104, matching the two existing '104 unique tools' mentions. The '105 tools' mentions in the intro and cardinality-reduction section were stale and inconsistent with the documented source of truth. * refactor(providers): remove retired GitHub Models (#9023) * docs: clarify free-provider model refresh outcomes (#9087) * docs: document provider model refresh fix Document the verified live-model refresh path for stale provider catalogs, record the current Pollinations anonymous-access limitation, and sync the provider-count references after regenerating the provider reference. Co-Authored-By: Oz <oz-agent@warp.dev> * docs: note codex local env and mac path Co-Authored-By: Oz <oz-agent@warp.dev> --------- Co-authored-by: Oz <oz-agent@warp.dev> * feat(providers): add Naga.ac and ChatAnywhere aggregator providers (#6674) (#9421) Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * fix(providers): switch minimax from claude to openai format so images work (#9463) * fix(providers): switch minimax from claude to openai format so images work The Anthropic-compatible /anthropic/v1/messages endpoint rejects image input with 403. MiniMax's OpenAI-compatible /v1/chat/completions endpoint supports image_url natively for MiniMax-M3. - minimax + minimax-cn: format claude→openai, baseUrl→/v1/chat/completions - Remove Anthropic-Version header + ?beta=true suffix (not needed for openai) - Remove minimax/minimax-cn from ?beta=true executor case - Update cache-control tests (openai format uses different caching path) - Fix reasoning-split test names (no longer claude format) TDD: 2 registry tests assert format=openai (red→green). Refs: Hermes Agent #15715, MiniMax OpenAI-compatible API docs. * fix(sse): re-align stream-readiness-policy tests with minimax's openai format PR #9463 switched minimax/minimax-cn from claude to openai format so images work. The stream-readiness bump for Claude-format replicas is keyed off the registry's format field (single source of truth), so minimax legitimately falls out of that group now. Swap the "Claude-format replica" test fixtures to agentrouter (still format: "claude") and add explicit coverage that minimax no longer gets the claude_format_heavy_reasoning bump. --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * fix(providers): reject the dashboard password as a connection API key (#9572) * fix(providers): refuse to store the dashboard password as a connection API key A browser autofilled the management password into a connection's API-key field. The resulting credential authenticates against nothing, so every request routed through that connection came back 401, and because the field looks like any other password input the same autofill fired again while the connection was being repaired by hand. The refusal belongs on the write path rather than in the form. Twenty routes create or update connections and all of them funnel through createProviderConnection and updateProviderConnection, so one check there covers every entry point including a future one. The two other places that write api_key are left alone on purpose: one re-encrypts rows that already exist and the other is the one-time db.json import, and neither takes a value an operator just typed. Update checks the incoming value, never the merged one. A connection that already holds the password has to stay editable or the operator cannot repair the exact state this prevents, and re-checking the merged value would spend a bcrypt round on every unrelated field edit. Only a real match blocks the write. An unreadable settings row or a throwing bcrypt call logs and allows, because a guard against one specific mistake must not turn into a way to lock out every connection write. Signed-off-by: Minxi Hou <houminxi@gmail.com> * fix(providers): compare the untrimmed credential, and cover the guard's branches The guard trimmed the incoming value before comparing it, which catches a paste carrying whitespace the password does not have. It missed the mirror case: neither the login route nor the set-password route trims, so a dashboard password may itself begin or end with a space, and an autofill reproducing it exactly was trimmed into a value that no longer matched the stored hash. The write then went through, which is the state this guard exists to prevent. Both forms are compared now, the second only when the first fails on a string that differs, so an ordinary key still costs a single bcrypt round. Two branches carried no coverage and both are load-bearing. The catch that logs and allows is the only path that lets a write through; a stored hash bcrypt cannot parse reaches it without needing a mock, since the shape check accepts an impossible cost factor that the comparison then rejects. The early return is what keeps a token renewal -- a write carrying tokens but no apiKey -- from paying for a settings read and a bcrypt round every time it fires, and the same unparseable hash makes that path observable, so an absent warning is proof the return happened. The narrower scope is deliberate and now says so in the code: the OAuth tokens arrive from a provider's token endpoint rather than from a form, so extending the comparison to them would charge every renewal for a field no autofill can reach. Signed-off-by: Minxi Hou <houminxi@gmail.com> --------- Signed-off-by: Minxi Hou <houminxi@gmail.com> * fix: restore unorouter api and catalog metadata (#9594) Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * ci(test): route orphaned Vitest tests through blocking CI (#9605) * ci(test): route orphaned Vitest tests through blocking CI * docs: fix advisory status in AGENTS.md and refresh baseline note * fix(changelog): fix fragment format for #9415 * fix(changelog): preserve upstream fragment format --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> * fix: pass max reasoning effort through by default, add global model registry fallback (#8057) (#9612) * feat(db): add a job registry for scheduled background work (#9631) * feat(db): add a job registry for scheduled background work Background jobs each ship their own timer today, so there is no list of what is scheduled, no history of what ran, and no way to pause one without an environment variable and a restart. The registry gives them one home: a jobs table holding the schedule, a job_runs table holding the outcomes, and a loopback-only API to inspect and control both. Cron jobs read their expression through an optional cronGetter rather than the stored column, so an operator changing OMNIROUTE_WARMUP_CRON does not need the row rewritten. register() is an idempotent upsert that refreshes the schedule but never overwrites `enabled` or `created_at`, which is what lets a job be re-registered on every boot without discarding the operator's toggle. Run history is pruned per job rather than globally, and safeRun records a failure for a handler that throws as well as one that returns success:false, so a crashing job leaves a trail instead of a gap. The API is under /api/jobs and gated to loopback in the route guard. It can trigger a run and flip a job off, which is runtime administration and does not belong on a remotely reachable surface. Signed-off-by: Minxi Hou <houminxi@gmail.com> * feat(jobs): move the budget reset and token health check onto the registry Both jobs owned their own timer and started themselves as an import side effect, so nothing could report whether they were running, when they last ran, or why a run failed. They now register with the job registry and are started from it, which also means their schedule and run history are visible through /api/jobs. startAll() runs each interval job's first tick synchronously, so both entry points start the registry only after initializeCloudSync() has been awaited. The old wiring reached that ordering two different ways: the budget reset was started after the init call, and the health check's first sweep sat behind a 10s timer. Replacing both with one startAll() would otherwise have moved the two handlers in front of the initialisation they run against. Both entry points also register the same pair of jobs. Registering one and not the other is how a background job goes missing without anything failing. sweep() now returns how many connections it swept, so the health check can record a real records_affected the way the budget reset does. The migration documents that column as a per-job count, and hardcoding zero would have left one of the two jobs reporting a number the schema promises but the code never produces. A skipped or empty sweep reports zero. Every existing caller ignores the return value. The token health check keeps its own disable semantics: the handler still calls isHealthCheckDisabled() before sweeping, so OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK, the production-build phase and the automated-test guard behave as before. Its registry adapter lives in src/lib/jobs/ next to the budget reset rather than in tokenHealthCheck.ts, which is already above its frozen size ceiling on the base branch and should not grow further. The adapter lets a failing sweep throw rather than reporting it itself, matching the budget reset: safeRun records a thrown error as a failure run with its message. The warmup job is seeded disabled. Its handler arrives with the warmup scheduler, and startAll() filters on enabled before it looks for a handler, so seeding it enabled here would warn about the missing handler on every boot. * fix: allowlist cron-parser dep and document OMNIROUTE_RUNNOW_TIMEOUT_MS env var Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * chore: align rebased branch with release tip (migration renumbered 139->146 in release; feature already cherry-picked in #9886) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Signed-off-by: Minxi Hou <houminxi@gmail.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> *…
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 29, 2026
…ck-boot) check:pack-boot booted the packed tarball fine but failed its version assertion: `version "undefined" (expected "3.8.50")`. The artifact was not broken — the health payload was. cheaper-inference#11040 (GHSA-mvf8-qc78-5mxm) reduced GET /api/monitoring/health to a liveness-only view for non-management callers. But that route is classified PUBLIC (src/shared/constants/publicApiRoutes.ts:67) and runAuthzPipeline deletes CLI_TOKEN_HEADER from the forwarded headers for EVERY route class (src/server/authz/pipeline.ts), so a handler can only learn that a local CLI authenticated from the subject the policy stamped. publicPolicy stamped `anonymous` unconditionally, so requireManagementAuth in the route 401'd even for a valid loopback machine token and every caller got `{status, setupComplete}` — no `version`. Verified on the installed tarball before the fix: the same token that returns 200 on /api/cli/whoami (MANAGEMENT, where the pipeline does stamp the subject) got the anonymous body on /api/monitoring/health. publicPolicy now stamps the same loopback-gated `local-cli-token` subject the MANAGEMENT policy already produced. The shared verdict (peer-locality resolution + constant-time token compare) moves to src/server/authz/peerContext.ts so both policies use one implementation — no behavior change on the MANAGEMENT side. Anonymous callers keep the liveness-only view. Tests: publicPolicy stamps the CLI subject only for a loopback peer with a valid token (both negative controls asserted; the positive case fails on the pre-fix policy), plus a health-route pin that a stamped local-CLI caller receives `version`. check:pack-boot green end to end (boot #1, machine-token contrast, sql.js round trip, boot #2 persistence).
diegosouzapw
pushed a commit
that referenced
this pull request
Sep 1, 2026
…heaper-inference#11615) `node_modules/.bin/dpdm` is an npm shell wrapper, so `node <that path>` crashed with `SyntaxError: missing ) after argument list` and the advisory circular-deps gate in ci.yml (job quality-extended) reported an error instead of a result on every run. Pointing DPDM_BIN at `node_modules/dpdm/lib/bin/dpdm.js` restores it: the gate now completes and reports circularDeps=154 (exit 0). Scope reduced during merge — the branch was 522 commits behind and carried three base-drift files that were reconciled back to the release tip: open-sse/services/combo.ts (reverted routing code + a @/lib/localDb barrel import, Hard Rule #2), config/quality/eslint-suppressions.json (dropped ~45% of the frozen suppressions), and tests/unit/cli-env-inline-comment-10100.test.ts (replaced a working module import with new Function() source scraping, Hard Rule #3). Rationale documented in the PR discussion. Verified: check:circular-deps crashes on the pure tip and completes on the merged branch; tests/unit/cli-env-inline-comment-10100.test.ts 5/5 green against the restored version. Thanks @benzntech for catching the dpdm breakage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a small helper patch for upstream PR cheaper-inference#5249.
It preserves the intended cheaper-inference#5249 behavior for generic model-catalog 400s like
requested model is not supported, while keeping account/body-specific 400s terminal, e.g.model is not supported when using Codex with a ChatGPT account.Validation:
env DISABLE_SQLITE_AUTO_BACKUP=true node --max-old-space-size=8192 --import tsx --import ./open-sse/utils/setupPolyfill.ts --import ./tests/_setup/isolateDataDir.ts --test --test-force-exit tests/unit/combo-strategies.test.ts tests/unit/combo-body-specific-400-stop-4279.test.ts tests/unit/accountfallback-ratelimit-400-4976.test.ts-> 22/22 passnpm run check:file-size-> ok