Skip to content

deps: bump qs from 6.14.1 to 6.14.2 - #13

Merged
diegosouzapw merged 1 commit into
mainfrom
dependabot/npm_and_yarn/qs-6.14.2
Feb 14, 2026
Merged

diegosouzapw merged 1 commit into
mainfrom
dependabot/npm_and_yarn/qs-6.14.2

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Feb 13, 2026

Copy link
Copy Markdown
Contributor

Bumps qs from 6.14.1 to 6.14.2.

Changelog

Sourced from qs's changelog.

6.14.2

  • [Fix] parse: mark overflow objects for indexed notation exceeding arrayLimit (#546)
  • [Fix] arrayLimit means max count, not max index, in combine/merge/parseArrayValue
  • [Fix] parse: throw on arrayLimit exceeded with indexed notation when throwOnLimitExceeded is true (#529)
  • [Fix] parse: enforce arrayLimit on comma-parsed values
  • [Fix] parse: fix error message to reflect arrayLimit as max index; remove extraneous comments (#545)
  • [Robustness] avoid .push, use void
  • [readme] document that addQueryPrefix does not add ? to empty output (#418)
  • [readme] clarify parseArrays and arrayLimit documentation (#543)
  • [readme] replace runkit CI badge with shields.io check-runs badge
  • [meta] fix changelog typo (arrayLength → arrayLimit)
  • [actions] fix rebase workflow permissions
Commits
  • bdcf0c7 v6.14.2
  • 294db90 [readme] document that addQueryPrefix does not add ? to empty output
  • 5c308e5 [readme] clarify parseArrays and arrayLimit documentation
  • 6addf8c [Fix] parse: mark overflow objects for indexed notation exceeding arrayLimit
  • cfc108f [Fix] arrayLimit means max count, not max index, in combine/merge/`pars...
  • febb644 [Fix] parse: throw on arrayLimit exceeded with indexed notation when `thr...
  • f6a7abf [Fix] parse: enforce arrayLimit on comma-parsed values
  • fbc5206 [Fix] parse: fix error message to reflect arrayLimit as max index; remove e...
  • 1b9a8b4 [actions] fix rebase workflow permissions
  • 2a35775 [meta] fix changelog typo (arrayLength → arrayLimit)
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](ljharb/qs@v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Feb 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@diegosouzapw
diegosouzapw merged commit 48fbea7 into main Feb 14, 2026
1 check passed
@dependabot
dependabot Bot deleted the dependabot/npm_and_yarn/qs-6.14.2 branch February 14, 2026 02:20
diegosouzapw added a commit that referenced this pull request Mar 1, 2026
- CHANGELOG: add new features section (multi-modal providers, media playground, unit tests, WFGY docs) and expand bug fixes
- README/README.pt-BR: add Video/Music to tagline, expand Pain Point #13 with all new modalities, update Multi-Modal APIs table with Video/Music Generation
diegosouzapw added a commit that referenced this pull request Mar 7, 2026
- CHANGELOG: add new features section (multi-modal providers, media playground, unit tests, WFGY docs) and expand bug fixes
- README/README.pt-BR: add Video/Music to tagline, expand Pain Point #13 with all new modalities, update Multi-Modal APIs table with Video/Music Generation
@gemini-code-assist gemini-code-assist Bot mentioned this pull request May 15, 2026
5 tasks
diegosouzapw added a commit that referenced this pull request May 28, 2026
The CJS proxy in `src/mitm/server.cjs` cannot import the TS
`getUserBypassPatterns` directly. Mirror the `targets.json` pattern: on
`startMitm()` the manager now also writes `<DATA_DIR>/mitm/bypass.json`
with the user-defined glob patterns from `agent_bridge_bypass`. The CJS
proxy reads the file at boot via the `_internal/bypass.cjs` shim's
`parseBypassJson` helper.

Defaults (banks / gov / okta / auth0) live hardcoded in the CJS shim —
they are not persisted to the JSON file. This matches the privacy
contract: defaults always apply, even when the DB or the JSON file is
missing or unreadable.

Plan reference: 11-agent-bridge.plan.md §4.6 + master-plan-group-A.md §3.5.
Hard Rule #13: file I/O only — no shell interpolation.
diegosouzapw added a commit that referenced this pull request May 29, 2026
…l) suffix

- FilesListTab: add (input)/(output)/(error) role label next to batch id in Used by column + tooltip (G-AUD1, plan §4 wireframe `b1 (input)`)
- BatchListTab: add -50% inline badge on Cost column per wireframe §3 `$6.20 (-50%)` (G-AUD2) + (partial) suffix on progress when expired_with_failures (G-AUD3)
- ExpirationBadge: document <1h/<6h/<24h tier semantics + >24h graceful fallback (G-AUD4)
- 4 new i18n keys in en + pt-BR (filesListUsedByRoleInput/Output/Error, batchListProgressPartial); 40 locales auto-filled via fill-missing-from-en.mjs
- Update list-regression test #13 to assert new used-by format (truncated id + role label + tooltip carries full id+role)
diegosouzapw added a commit to guanbear/OmniRoute that referenced this pull request Jun 1, 2026
Filesystem-only installation probes for antigravity, kiro, copilot,
codex, cursor, zed, claude-code, and open-code. detectAgent(id)
dispatcher returns {installed, path?} without ever spawning a shell
or interpolating runtime paths (Hard Rule cheaper-inference#13).

Trae has no detector — its entry in the dispatch table returns
{installed: false} until upstream viability is confirmed.
diegosouzapw added a commit to guanbear/OmniRoute that referenced this pull request Jun 1, 2026
…ols (plan 14 F3)

Adds 5 new settings route handlers for CLIs introduced by plan 14 that
declare configType:"custom" and need automated config file persistence:
forge (~/.forge/config.toml), jcode (~/.jcode/config.json),
deepseek-tui (~/.config/deepseek-tui/config.toml),
smelt (~/.smelt/config.json), pi (~/.pi/config.json).

Also registers the 5 tools in cliRuntime.ts path table so
getCliPrimaryConfigPath() resolves their config paths correctly.

Each handler follows the established pattern: requireCliToolsAuth guard on
every exported method, Zod body validation on POST, buildErrorBody/
sanitizeErrorMessage on all error paths (Hard Rule cheaper-inference#12), fs/promises only
(no exec/spawn — Hard Rule cheaper-inference#13), saveCliToolLastConfigured on success.

Integration tests: 7 subtests per handler (401 without auth, 200 GET,
400 missing-baseUrl, 400 missing-model, 200 POST writes file, 200 DELETE,
error sanitization + no exec/spawn static audit).
diegosouzapw added a commit to EmpRider/OmniRoute that referenced this pull request Jun 3, 2026
…mand

Remove the manual "${command}" interpolation into the shell command (hard rule
cheaper-inference#13 violation, and redundant — Node quotes for cmd.exe when shell:true; .exe runs
with shell:false where the OS handles spaces via argv). Export the helper and add
a cross-platform test asserting non-Windows never uses the shell.
diegosouzapw added a commit that referenced this pull request Jun 3, 2026
* fix(cli): handle Windows exe healthchecks with spaces

* Update src/shared/services/cliRuntime.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Update tests/unit/cli-runtime-extended.test.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix(cli): pass command to spawn unquoted; export shouldUseShellForCommand

Remove the manual "${command}" interpolation into the shell command (hard rule
#13 violation, and redundant — Node quotes for cmd.exe when shell:true; .exe runs
with shell:false where the OS handles spaces via argv). Export the helper and add
a cross-platform test asserting non-Windows never uses the shell.

---------

Co-authored-by: Empire Rider <anuruddhawijesiri@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
diegosouzapw added a commit that referenced this pull request Jun 18, 2026
Fase 3 spike — TPROXY command builder (pure, execFile-safe {bin,args[]} per Rule #13) + ProxyBridge capture-source decision. Integrado em release/v3.8.29.
diegosouzapw added a commit that referenced this pull request Jun 18, 2026
…4144)

TPROXY setup layer — transactional apply/revert (Epic A). execFile runner (Rule #13, args array, no shell) over the VPS-validated command builder (#4139); apply rolls back on mid-way failure, revert idempotent. Integrado em release/v3.8.29.
Raudbjorn added a commit to Raudbjorn/OmniRoute that referenced this pull request Sep 7, 2026
- chore(changelog): drop four stale fragments already in CHANGELOG (cheaper-inference#9435,
  cheaper-inference#9550, cheaper-inference#9568, cheaper-inference#9575) — stale-fragment gate exits nonzero on duplicate
- fix(translator/claudeHelper): re-filter empty messages after the Pass 1.4
  nameless-tool_use drop so non-final assistant messages whose only content
  was a nameless block do not survive into the request (#5, #6)
- fix(ws/responses-ws-proxy): serialize concurrent forwardClientMessage calls
  via dispatchQueue so a second client message arriving during ensureUpstream
  does not drop the late frame (cheaper-inference#7)
- fix(ws/v1-ws-bridge): close the session with code 1002 after a frame decode
  failure so an undecodable byte run does not loop forever (cheaper-inference#8)
- fix(ws/both): send the WebSocket close frame BEFORE flipping this.closed
  so the sendFrame guard does not turn the close handshake into a no-op
  (cheaper-inference#9)
- fix(oauth/freebuff): add 'network_error' to freebuffPollResponseSchema so
  the network-error return path typechecks (cheaper-inference#10)
- fix(oauth/freebuff): declare onProgress on FreebuffPollOptions so the
  poll-loop callback typechecks (cheaper-inference#11)
- fix(freebuff/cliEmulator): add readonly ok to FreebuffHttpResponse and
  populate it in tlsClientFetch, wreqFetch, and globalFetch so successful
  responses are not misclassified as failures (cheaper-inference#12)
- test(translator/openai-to-claude): defer content_block_start until a
  name arrives and throw on a permanently nameless streamed call so the
  Muse/GLM cheaper-inference#2077 sequence and the nameless-rejection test both pass (cheaper-inference#16)
- test(9568): resolve the three merge-marker regions in favor of HEAD —
  the test reflects the post-cheaper-inference#10392 translator behavior (cheaper-inference#13, cheaper-inference#14, cheaper-inference#15)
Raudbjorn added a commit to Raudbjorn/OmniRoute that referenced this pull request Sep 7, 2026
* fix(oauth): Kiro import token endpoint no longer overwrites existing connection when using shared cached OIDC clientId (cheaper-inference#9435)

Closes cheaper-inference#9435

(cherry picked from commit 9edefd4)

* fix(translator): add case-insensitive fallback for upstream tool call name lookups (cheaper-inference#9575)

Closes cheaper-inference#9575

(cherry picked from commit c9a3361)

* fix(translator): restore original tool name casing in Gemini response translators (cheaper-inference#9568)

Closes cheaper-inference#9568

(cherry picked from commit c9debe9)

* fix(model): add aq alias for amazon-q provider so parseModel resolves it instead of falling back to OpenAI (cheaper-inference#9550)

Closes cheaper-inference#9550

(cherry picked from commit f338363)

* fix(translator): reject nameless streaming tool calls

(cherry picked from commit e274819)

* fix(devin-desktop): sanitize Claude Code prompt triggers and enforce tool budget

(cherry picked from commit 8c1514a)
(cherry picked from commit a18771b)

* fix(devin-desktop): sanitize interactive Claude Code CLI identity declarations

(cherry picked from commit e5553c1)
(cherry picked from commit db089c8)

* fix(claude-code): format context overflow as 'Prompt is too long' to trigger reactive compact

(cherry picked from commit b5fec6b)
(cherry picked from commit 5e83dc6)

* fix(chat): import getCachedSettings from readCache

(cherry picked from commit 999c708)
(cherry picked from commit d8329dd)

* fix(image): add 'agy' alias for antigravity image generation models

(cherry picked from commit 2ac3e0d)
(cherry picked from commit 203cdb3)

* fix(translator): subtract cachedContentTokenCount from input_tokens in gemini-to-claude translator to avoid double-counting in Claude Code

(cherry picked from commit 4c5ec77)
(cherry picked from commit d82672d)

* fix(translator): add cache_creation_input_tokens, update tests, and set auto-compression defaults

(cherry picked from commit 9b68a4b)
(cherry picked from commit 6f4e1f4)

* fix(translator,compression): sanitize token metrics with Number.isFinite and restore opt-in compression defaults

(cherry picked from commit 985c3c2)
(cherry picked from commit cf9da8e)

* fix(vision-bridge): cross-check agy/antigravity aliases and declare SWE vision capabilities

(cherry picked from commit d1f2f5a)
(cherry picked from commit a80b6df)

* fix(vision-bridge): return skip if mixed combo has vision capable target

(cherry picked from commit a049fbb)
(cherry picked from commit fd2d093)

* fix(ratelimit): set 120s maxWaitMs floor for long-context providers to prevent 504 on 100k+ tokens

(cherry picked from commit 98cc4b0)
(cherry picked from commit 6195ebf)

* fix(ratelimit): clean up redundant zai-web entry, add null safety and long-context override tests

(cherry picked from commit 743a118)
(cherry picked from commit 4421ceb)

* test(ratelimit): add direct assertion for opencode in queue wait floor test

(cherry picked from commit dda584d)
(cherry picked from commit 5b987d9)

* fix(translator): synthesize fallback text block from reasoning when model emits only thinking for compaction

(cherry picked from commit 0e13723)
(cherry picked from commit bc9e1c5)

* fix(devin-desktop): classify content policy trailer errors as deterministic 400 and bypass cooldown

(cherry picked from commit 8820f15)
(cherry picked from commit f8a4a3b)

* feat(pricing): add SWE-1.7 Lightning pricing for devin-desktop and windsurf providers

(cherry picked from commit 11ec472)
(cherry picked from commit 0956840)

* feat(pricing): set swe-1-7 price at half Lightning rate (.25/zsh.5/.25 per 1M)

(cherry picked from commit 60def8f)
(cherry picked from commit 526c814)

* feat(models): add Gemini 3.8 Flash tiers and pricing

Introduce Gemini 3.8 Flash across OmniRoute on top of the existing
3.6/3.7 Flash support:

- modelSpecs: gemini-3.8-flash{,-high,-medium,-low,-tiered}
  with 1M context, 64K output, defaultReasoningEffort=medium.
- pricing: promo $0.75/$3.75 per 1M for gemini, antigravity/agy,
  frontier-labs, cheaperinference, orcarouter, and inference-hosts.
- provider registries: gemini, gemini-web, github, ghe-copilot,
  cursor, cheaperinference, kilocode, opencode/zen, orcarouter,
  raycast, tinycms, lmarena.
- AGY/Antigravity catalogs, aliases and free-model catalog.
- Fallback services: conol, githubCopilot, notionWeb, promptql.
- CLI tool model aliases and modelAliasSeed.
- modelFamilyFallback chains for the 3.8 Flash family.
- geminiRateLimits.json.

Tests: t28, models-catalog-route, model-capabilities-registry,
pricing-ag-flash-tiers, agy-gemini-3696-tier-passthrough and
model-family-fallback-notation all pass. npm run typecheck:core
and npm run lint pass.

(cherry picked from commit 7e44a6d)
(cherry picked from commit c8391ff)

* fix(chat): return resource pressure guard as a normal result and avoid cooldown

executeChatWithBreaker previously returned { localResourcePressureResult }
when the resource pressure guard tripped, but the caller in chat.ts only
destructures { result, tlsFingerprintUsed } and immediately reads
result.success. That caused a TypeError ('Cannot read properties of undefined
(reading "success")') and made combo fallback logs show a confusing crash.

Now the pressure guard is returned as a normal { result } with
errorCode/errorType "resource_pressure", and chat.ts surfaces the 503
immediately without marking the connection unavailable.

(cherry picked from commit 22b641e)
(cherry picked from commit ee2af6f)

* ops(docker): raise runtime heap to 4096MB and pin tls-client native version

OMNIROUTE_MEMORY_MB 1024MB was too tight for production traffic with large
fusion-combo panels, causing constant GC pressure and PSI CPU/memory critical
states. Raise the default runtime heap ceiling to 4096MB.

Also pin TLS_CLIENT_VERSION=1.15.1 so the tls-client-node postinstall does not
fetch an upstream "latest" release that may be missing the Linux .so asset.

(cherry picked from commit db021d9)
(cherry picked from commit 8583cfe)

* fix(providers): harden empty responses and oauth test classification

- stream: inject a space instead of empty text for the synthetic Claude
  empty-response fallback so clients do not trip on zero-length
  completions (502 noise seen in production call_logs).
- providers/test: return statusCode 400 for unsupported provider tests;
  add custom-oauth-connection-proxy to OAUTH_TEST_CONFIG (checkExpiry
  only — the proxy has no userinfo endpoint).
- resolveRoutingModel: default subagent routing model claude-sonnet-5
  -> claude-haiku-4.5 to reduce pressure on the antigravity lane.

(cherry picked from commit c219b43)
(cherry picked from commit 2892e9d)

* feat: port subagent routing + tool-call shim + devin/transport hardening from local production

(cherry picked from commit 2cb7b19)

* test: fix gemini-to-claude usage test fixture, drop repairedRaw tests

(cherry picked from commit 53462ff)

* chore: prune unused eslint suppressions

(cherry picked from commit 8515409)

* fix(docker): relax healthcheck to tolerate event-loop stalls under load

The 5s timeout / 3 retries / 15s start-period was too strict for this
single-process app: /healthz probes timed out during startup module
loading and under sustained heavy /v1/messages traffic (~180k-token
requests), flipping the container unhealthy and causing Docker/Dokploy
to kill mid-session — the observed restart loop / 502 source.

start-period=120s covers cold start; timeout=15s + retries=5 tolerate
transient event-loop stalls (~150s) while still catching dead processes.

(cherry picked from commit c749903)

* fix(devin-desktop): accumulate id-less tool-call argument deltas

Devin Desktop streams tool-call arguments as separate proto messages
carrying only field 3 (arguments) with no id/name. The decoder dropped
them (`if (toolCall.id)`), so clients received tool_use blocks with
empty input {} — Claude Code then rejected ~50% of tool calls with
InputValidationError, and the empty calls in history taught the model
to emit empty arguments itself, causing a self-reinforcing error loop.

Keep argument-only deltas and append them to the most recently started
tool call so input_json_delta reaches the client.

(cherry picked from commit 8a82a13)

* fix(translator): purge never-succeedable empty tool_use pairs from history

Clients whose history was poisoned by lost tool-call arguments keep
replaying tool_use {input:{}} + InputValidationError pairs, teaching the
model to emit empty arguments on new calls (self-reinforcing loop).

When translating a Claude-format request, drop tool_use blocks whose
input is empty AND whose tool schema declares required params (such a
call could never have succeeded), along with their matching tool_result
blocks and "(empty response)" placeholder texts. Tools with no required
params (e.g. chrome_read_page) and tools absent from the tools list are
left untouched.

(cherry picked from commit 164c61d)

* fix(review): adversarial-review hardening + deterministic stream error status

Code-review patches:
- chatDispatch: detect resource_pressure via typed error fields (dead
  localResourcePressureResult check evicted session affinity wrongly)
- chat: return resource-pressure 503 before safeLogEvents so it is not
  logged as an upstream error; fix stale "retrying once" log message
- stop.mjs: share isTestEnvironment() guard across POSIX and Win32 kill paths
- supervisor: mkdir log dir before createWriteStream (ENOENT crash)
- resolveRoutingModel: trim SUBAGENT_DEFAULT_MODEL env (whitespace-safe)
- claudeHelper: drop string-content "(empty response)" messages; normalize
  Claude Code file-unchanged sentinel for non-Anthropic Claude-shape targets
- toolCallShim: AskUserQuestion option objects emit only schema fields,
  question arrays join cleanly, options-only calls get a fallback question
- devin-desktop: sanitizeDevinPrompt scoped to system/developer roles only;
  document parallel tool-call arg-delta attribution limitation
- Dockerfile: healthcheck start-period 120s -> 60s (faster dead-detection,
  stall tolerance kept via timeout/retries)

Compact-incident fix (session log analysis):
- streamReadiness: a stream ending with only a deterministic upstream
  diagnostic (content policy / safety filter) now surfaces its real 400
  status instead of a retryable 502 STREAM_EARLY_EOF — stops the observed
  ~9x/10min retry loop on payloads that can never succeed
- sameAccountTransportRetry: 403 only retryable for the Devin
  permission_denied-internal-error quirk; content-policy text never retries
- test: bound assertion follows SAME_ACCOUNT_TRANSPORT_RETRY_MAX

(cherry picked from commit e37ae2b)

* fix(translator): error event for upstream-truncated tool-call arguments

When the upstream stream ends mid-tool-call (observed: Devin Desktop Connect
streams cut during argument deltas), the accumulated arguments buffer is
unparseable JSON. Closing the tool_use block normally handed the client a
truncated partial_json - Claude Code raised InputValidationError, and the
model retried with hallucinated stub args (seen across recent session logs).

The openai-to-claude finish path now validates each non-shimmed tool call's
argBuffer and emits a terminal error event instead of closing the block, so
the turn is retried rather than executed as a truncated command. Shimmed
tools are exempt (their shim repairs the buffer at close).

(cherry picked from commit 4dca2f3)

* feat(translator): schema-driven tool-call argument repair

Models that emit wrong-typed fields, extra keys, or missing required args hit
client-side InputValidationError retry loops (observed across recent Claude
Code session logs). Add a generic sanitizer that repairs parsed tool arguments
against the client-declared input_schema: coerce unambiguous type mismatches
(stringified numbers/booleans, scalar to array, JSON-stringified objects),
drop undeclared keys on closed schemas, fill missing required fields with
type-correct empties - nested and depth-capped.

openai-to-claude now buffers arguments for any tool with a declared schema
(previously only named-shim tools) and emits one corrected input_json_delta at
block close. The finish path also validates every accumulated argBuffer and
emits a terminal error event when upstream truncated the JSON mid-call, so the
turn is retried instead of executing a cut command.

chatCore now passes whichever body still carries tools into the stream state -
executor paths that consume/re-key the tools array (e.g. Devin Desktop) left
the dispatched body without client schemas.

(cherry picked from commit 84754f5)

* fix(devin-desktop): encode CompletionConfig to stop silent 1024-token output cap

The Devin Desktop Connect GetChatMessage wire was missing the
CompletionConfiguration sub-message (field cheaper-inference#8). Without it, the upstream
server defaulted output to ~1024 tokens for swe-1-7, which truncated
Claude Code multi-tool turns (e.g. five Agent calls), produced empty
Agent payloads, and led to the mid-response server error.

Encode field cheaper-inference#8 with the OpenAI request's max_tokens (default 8192),
temperature clamped to >=0.001, top_p, and top_k. Set max_newlines to
a safe context-window value so it cannot accidentally become the binding
output cap. Log the resolved max_tokens for monitoring.

Update the golden fixture and add a focused test for custom values and
the temperature=0 clamp.

(cherry picked from commit 62effb4)

* feat: add Kiro PWA bridge and websocket proxy support

Publish the Kiro OAuth/PWA bridge flow together with websocket proxy scripts and route updates so the branch can be shared for iteration before full test validation completes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 056a413)

* feat(kiro): implement automatic account deactivation on quota exhaustion

(cherry picked from commit 6a98790)

* fix(health): add public /api/health route for external liveness probes

- Add '/api/health' to PUBLIC_READONLY_API_ROUTE_PREFIXES so the
  auth pipeline classifies it as public (GET-only).
- Create src/app/api/health/route.ts with a lightweight { status, timestamp }
  response, parallel to the existing /api/health/ping handler.

External healthcheck/monitoring services probing /api/health were
returning HTTP 401 (AUTH_001) because the route was not in any public
prefix list. /api/monitoring/health was public but /api/health was not.

(cherry picked from commit 6dac784)

* feat: implement Freebuff CLI emulator and provider meta-service for connection and quota management

(cherry picked from commit 1ac3383)

* feat(freebuff): flip default from opt-in to opt-out

Previously the Freebuff provider required FREEBUFF_ENABLED=1 to be
exposed under /providers/freebuff. This commit flips the default so the
provider is on by default (no env var required) and FREEBUFF_ENABLED=0
disables it explicitly.

Changes:
- base.ts: isFreebuffEnabled() returns true when env var is unset,
  empty, or any value other than 0/false.
- registry.ts: error messages reference FREEBUFF_ENABLED=0 instead of =1.
- en.json / fr.json: notEnabled.description updated to match.
- .env.example + docs/providers/freebuff*.md: documentation reflects the
  new default and the disable-by-setting-FREEBUFF_ENABLED=0 flow.
- freebuff-base.test.ts + freebuff-registry.test.ts: tests for the new
  default behaviour.

(cherry picked from commit 050a34c)

* fix(security): resolve freebuff public client credential and satisfy db re-export gate

(cherry picked from commit a5b141f)

* fix(review): address PR #1 review threads

- chore(changelog): drop four stale fragments already in CHANGELOG (cheaper-inference#9435,
  cheaper-inference#9550, cheaper-inference#9568, cheaper-inference#9575) — stale-fragment gate exits nonzero on duplicate
- fix(translator/claudeHelper): re-filter empty messages after the Pass 1.4
  nameless-tool_use drop so non-final assistant messages whose only content
  was a nameless block do not survive into the request (#5, #6)
- fix(ws/responses-ws-proxy): serialize concurrent forwardClientMessage calls
  via dispatchQueue so a second client message arriving during ensureUpstream
  does not drop the late frame (cheaper-inference#7)
- fix(ws/v1-ws-bridge): close the session with code 1002 after a frame decode
  failure so an undecodable byte run does not loop forever (cheaper-inference#8)
- fix(ws/both): send the WebSocket close frame BEFORE flipping this.closed
  so the sendFrame guard does not turn the close handshake into a no-op
  (cheaper-inference#9)
- fix(oauth/freebuff): add 'network_error' to freebuffPollResponseSchema so
  the network-error return path typechecks (cheaper-inference#10)
- fix(oauth/freebuff): declare onProgress on FreebuffPollOptions so the
  poll-loop callback typechecks (cheaper-inference#11)
- fix(freebuff/cliEmulator): add readonly ok to FreebuffHttpResponse and
  populate it in tlsClientFetch, wreqFetch, and globalFetch so successful
  responses are not misclassified as failures (cheaper-inference#12)
- test(translator/openai-to-claude): defer content_block_start until a
  name arrives and throw on a permanently nameless streamed call so the
  Muse/GLM cheaper-inference#2077 sequence and the nameless-rejection test both pass (cheaper-inference#16)
- test(9568): resolve the three merge-marker regions in favor of HEAD —
  the test reflects the post-cheaper-inference#10392 translator behavior (cheaper-inference#13, cheaper-inference#14, cheaper-inference#15)

* fix(review): address PR #1 review round 2

- docs(freebuff-api): replace nonexistent provider-specific routes with the
  generic [provider]/{models,limits,chat,embeddings,images} surface so the
  doc no longer documents 404-bound URLs (#1)
- fix(translator/claudeHelper): scope the '(empty response)' placeholder
  drop to placeholders whose adjacent message actually had a paired
  tool_use/tool_result that this pass dropped; previously every historical
  placeholder was removed whenever any declared tool had required fields,
  silently deleting unrelated content and reordering turns
- fix(translator/openai-to-claude): suppress input_json_delta passthrough
  while content_block_start is pending; replay the accumulated argBuffer in
  one shot after the late name arrives so the cheaper-inference#2077 Muse sequence produces
  a single start event with the full argument history instead of orphan
  deltas (cheaper-inference#16 follow-up)
- fix(guardrails/visionBridge): a mixed combo (some targets lack vision)
  now returns 'process' instead of 'skip' so images are described before
  fan-out; matches the contract test at
  tests/unit/guardrails/visionBridge-combo-reroute.test.ts:147
- refactor(freebuff/httpClient): remove the tls-client-node fallback — it
  is not a declared dependency and tests/unit/tls-client-wreq-residue.test.ts
  asserts it stays absent; only wreq-js + global fetch remain as backends
- fix(publicApiRoutes): remove '/api/health' from the CORS-relaxed list —
  the file's own comment says it must stay only in
  PUBLIC_READONLY_API_ROUTES_EXACT to avoid widening CORS
- feat(pwa-register): wire shouldEnablePwaRegistration and
  isOmniRouteServiceWorkerScript into PwaRegister; loopback hostnames now
  unregister only matching OmniRoute workers rather than every worker and
  every cache entry
- fix(oauth/kiro): extend CREDITS_EXHAUSTED_SIGNALS with Kiro-specific
  patterns ('usage limit exceeded', 'ThrottlingException') so the
  auto-deactivate path detects Kiro quota exhaustion; anchored on
  Kiro-distinguishing language to avoid broadening generic 429
  classification
- test(oauth-kiro-poll): drop 'as any' on connections[0] in favor of the
  inferred Record<string, unknown> from getProviderConnections

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Thinh <thinh0704hcm@users.noreply.github.com>
Co-authored-by: Vonic <phanquochoipt@gmail.com>
Co-authored-by: Aminetwiti <93622642+Aminetwiti@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Moutia <114811455+Moutia-Ben-Yahia@users.noreply.github.com>
Co-authored-by: amine <amine@TweeDev.localdomain>
Co-authored-by: Mohamed Benyahia <benyahiamohamd@gmail.com>
Co-authored-by: Raudbjorn <Raudbjorn@users.noreply.github.com>
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…cheaper-inference#4343)

* fix(cli): honor TAILSCALE_AUTHKEY for non-interactive tailscale login (port from 9router#1263)

startTailscaleLogin built `tailscale up` without ever reading
process.env.TAILSCALE_AUTHKEY, so a pre-authenticated / headless daemon
waited for an interactive auth URL and timed out (~15s). When
TAILSCALE_AUTHKEY is set it is now passed via `--auth-key=` (an argv element
to spawn(binary, args) — no shell interpolation, Hard Rule cheaper-inference#13); when unset,
behavior is unchanged. The arg builder is extracted into a pure exported
`tailscaleUpArgs()` for testing.

Reported-by: ipeterpetrus (decolua/9router#1263)
Co-authored-by: ipeterpetrus <93033698+ipeterpetrus@users.noreply.github.com>

* chore(quality): rebaseline tailscaleTunnel.ts file-size to 1202 (cheaper-inference#1263 +13)

---------

Co-authored-by: ipeterpetrus <93033698+ipeterpetrus@users.noreply.github.com>
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…erence#4139)

Fase 3 spike — TPROXY command builder (pure, execFile-safe {bin,args[]} per Rule cheaper-inference#13) + ProxyBridge capture-source decision. Integrado em release/v3.8.29.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…heaper-inference#4144)

TPROXY setup layer — transactional apply/revert (Epic A). execFile runner (Rule cheaper-inference#13, args array, no shell) over the VPS-validated command builder (cheaper-inference#4139); apply rolls back on mid-way failure, revert idempotent. Integrado em release/v3.8.29.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
cheaper-inference#13 (cheaper-inference#5285)

roadmap cheaper-inference#13: saliency heatmap in the compression studio (opt-in, dry-run). Locally validated release-green (typecheck + heatmap tests + file-size). Integrated into release/v3.8.40.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…erence#5770)

* chore(release): open v3.8.42 cycle

Bump version to 3.8.42, add CHANGELOG placeholder, sync openapi/electron/open-sse + 42 i18n CHANGELOG mirrors.

* chore: remove unused qdrant schema aliases (cheaper-inference#5404)

Integrated into release/v3.8.42

* chore: remove unused memory schema aliases (cheaper-inference#5403)

Integrated into release/v3.8.42

* chore: remove unused quota schema types (cheaper-inference#5402)

Integrated into release/v3.8.42

* chore: remove unused playground row type (cheaper-inference#5401)

Integrated into release/v3.8.42

* chore: remove unused codegraph exports (cheaper-inference#5400)

Integrated into release/v3.8.42

* chore: remove unused notion client type (cheaper-inference#5399)

Integrated into release/v3.8.42

* chore: remove unused settings types (cheaper-inference#5398)

Integrated into release/v3.8.42

* chore: remove unused combo types (cheaper-inference#5396)

Integrated into release/v3.8.42

* chore: remove unused provider types (cheaper-inference#5393)

Integrated into release/v3.8.42

* chore: remove unused skillssh skill type (cheaper-inference#5392)

Integrated into release/v3.8.42

* chore: remove unused status hex key type (cheaper-inference#5391)

Integrated into release/v3.8.42

* chore: remove unused batch provider type (cheaper-inference#5390)

Integrated into release/v3.8.42

* chore: remove unused skills schema types (cheaper-inference#5389)

Integrated into release/v3.8.42

* chore: remove unused codex auth input type (cheaper-inference#5388)

Integrated into release/v3.8.42

* chore: remove unused memory schema types (cheaper-inference#5387)

Integrated into release/v3.8.42

* chore: remove unused playground row type (cheaper-inference#5386)

Integrated into release/v3.8.42

* chore: remove unused qdrant schema types (cheaper-inference#5385)

Integrated into release/v3.8.42

* chore: remove unused kiro social schema (cheaper-inference#5384)

Integrated into release/v3.8.42

* chore: remove unused memory schema types (cheaper-inference#5383)

Integrated into release/v3.8.42

* chore: remove unused audit action type (cheaper-inference#5382)

Integrated into release/v3.8.42

* chore: remove unused agent skills schema types (cheaper-inference#5381)

Integrated into release/v3.8.42

* chore: remove unused shared logger default export (cheaper-inference#5380)

Integrated into release/v3.8.42

* chore: remove unused sse logger helpers (cheaper-inference#5378)

Integrated into release/v3.8.42

* chore: remove unused sse model legacy helpers (cheaper-inference#5377)

Integrated into release/v3.8.42

* chore: remove unused v1 search response schema (cheaper-inference#5376)

Integrated into release/v3.8.42

* chore: remove unused cloud agent result schemas (cheaper-inference#5375)

Integrated into release/v3.8.42

* chore: remove unused a2a routing logger readers (cheaper-inference#5374)

Integrated into release/v3.8.42

* chore: remove unused webhook delivery detail export (cheaper-inference#5372)

Integrated into release/v3.8.42

* chore: remove unused api key type (cheaper-inference#5395)

Integrated into release/v3.8.42

* chore: remove unused usage types (cheaper-inference#5397)

Integrated into release/v3.8.42

* chore: remove unused cloud agent input types (cheaper-inference#5373)

Integrated into release/v3.8.42

* deps: bump electron from 42.4.1 to 42.5.1 in /electron (cheaper-inference#5413)

Integrated into release/v3.8.42

* deps: bump the production group with 11 updates (cheaper-inference#5414)

Integrated into release/v3.8.42

* fix: frame non-streaming JSON responses (cheaper-inference#5416)

Integrated into release/v3.8.42

* fix(services): runNpm shell on win32 + prefix via env for Node 24 EINVAL (cheaper-inference#5379) (cheaper-inference#5474)

Node 24 refuses execFile of npm.cmd without a shell (nodejs/node#52554),
so embedded-service install (9Router/CLIProxy) failed with spawn EINVAL on
Windows. runNpm now enables shell on win32 only; to stay Hard-Rule-cheaper-inference#13 safe
under a shell, the install --prefix is passed via npm_config_prefix (env)
instead of an argv path (survives spaces), and the user-supplied version is
constrained by SERVICE_VERSION_PATTERN at the route boundary.

* fix(cli): restore dist/tls-options.mjs to npm tarball (cheaper-inference#5452) (cheaper-inference#5503)

Closes cheaper-inference#5452

* fix(dashboard): render onboarding wizard on /providers/new (cheaper-inference#5427) (cheaper-inference#5505)

Closes cheaper-inference#5427

* fix(db): EBUSY-safe database import on Windows (cheaper-inference#5406) (cheaper-inference#5507)

Closes cheaper-inference#5406

* chore: remove unused gamification streak exports (cheaper-inference#5463)

* chore: remove unused headroom log tail export (cheaper-inference#5464)

* chore(dead-code): remove unused prompt cache control helper (cheaper-inference#5466)

* chore(duplication): share vscode metadata helpers (cheaper-inference#5471)

* chore(duplication): share auth zip extractors (cheaper-inference#5475)

* chore(duplication): share vscode tokenized request helper (cheaper-inference#5479)

* chore(duplication): share quota strategy ranking helpers (cheaper-inference#5482)

* chore(duplication): share recharts donut card (cheaper-inference#5484)

* chore(duplication): share provider specific validation (cheaper-inference#5485)

* chore(duplication): share batch response formatter (cheaper-inference#5488)

* chore(duplication): share redis runtime helpers (cheaper-inference#5490)

* chore(duplication): share version manager request parsing (cheaper-inference#5492)

* chore(duplication): share media generation route helpers (cheaper-inference#5493)

* chore(duplication): share settings transform schemas (cheaper-inference#5496)

* chore(duplication): share relay stream finalizer (cheaper-inference#5497)

* chore(duplication): share machine id fallback (cheaper-inference#5498)

* chore(duplication): share node sqlite adapter (cheaper-inference#5500)

* fix: treat terminal stream cancels as complete (cheaper-inference#5491)

* fix post-merge ci regressions (cheaper-inference#5467)

* fix: gate claude adaptive thinking defaults (cheaper-inference#5480)

Co-authored-by: KooshaPari <koosha@example.com>

* fix(fallback): normalize provider error rule headers (cheaper-inference#5473)

Co-authored-by: KooshaPari <koosha@example.com>

* fix(rate-limit): normalize queue refresh settings (cheaper-inference#5499)

Co-authored-by: KooshaPari <koosha@example.com>

* chore(ci): add npm fetch-retry + release-freeze protocol (Hard Rule cheaper-inference#21) (cheaper-inference#5506)

- .npmrc: bump fetch-retries 2->5 with backoff so transient registry ECONNRESET during npm ci (electron-release, v3.8.41) retries instead of failing the job; applies repo-wide.
- CLAUDE.md Hard Rule cheaper-inference#21: release-freeze coordination marker (label release-freeze) that campaign workflows honor before merging into the active release branch, preventing the mid-release commit races that forced CHANGELOG re-reconciliation in v3.8.40/v3.8.41.

* chore(duplication): share service install helpers (cheaper-inference#5495)

Share service install helpers; re-add SERVICE_VERSION_PATTERN regex to the shared schema (dropped in extraction, cheaper-inference#5474) + tests rejecting malformed versions.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* chore(duplication): share proxy route handlers (cheaper-inference#5472)

Share proxy route handlers; add resolveProxyLookupResponse regression test (3 branches + custom whereUsed param name).

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* chore(duplication): share combo builder model options (cheaper-inference#5477)

Share combo builder model options; add regression test locking custom-model source classification (manual->custom, api-sync->imported).

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* chore(dead-code): ratchet dead code baseline (cheaper-inference#5468)

Ratchet dead-code baseline to the true measured value (310 -> 225) after the v3.8.42 dead-code + duplication wave. Measured by check-dead-code.mjs on the tip.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix(dashboard): provider-add UX — i18n labels, surface import warning, default key name (cheaper-inference#5511)

* fix(dashboard): provider-add UX — real i18n labels, surface import warning, default key name (cheaper-inference#5421 cheaper-inference#5428 cheaper-inference#5429 cheaper-inference#5431 cheaper-inference#5435)

Three rough edges in the Add-API-Key / model-import flow, all from the
provider-catalog audit:

1. Validation Model + Account ID form fields shipped untranslated i18n
   stub copy ('Validation Model Id Label', etc.) that rendered verbatim.
   Replaced with real copy in en.json.
2. Model import silently fell back to the cached/local catalog — the route
   returns a 'warning' field the import hook never read. New pure helper
   extractImportWarning surfaces it as a log line.
3. Required connection-name field defaulted to '' (let browser autofill
   inject garbage like 'wiw'); now defaults to 'main'.

Regression guard: tests/unit/provider-add-ux-i18n-import-warning.test.ts.

* fix(dashboard): compress AddApiKeyModal comment to keep file under frozen size cap

* fix(providers): align Muse Spark (Meta AI) cookie copy to ecto_1_sess (cheaper-inference#5449) (cheaper-inference#5513)

* fix(providers): align Muse Spark (Meta AI) cookie copy to ecto_1_sess (cheaper-inference#5449)

The default Meta AI session cookie migrated from the retired abra_sess to
ecto_1_sess (META_AI_DEFAULT_COOKIE), but the provider form hint and one
401 auth-failure message still named abra_sess, telling users to paste a
cookie that no longer exists. Both strings now name ecto_1_sess.

Regression guard: tests/unit/muse-spark-cookie-copy-5449.test.ts.

* chore: reconcile CHANGELOG with release (keep cheaper-inference#5449 + cheaper-inference#5511 bullets)

* fix(providers): correct FriendliAI (serverless) + Novita (/openai/v1) endpoints (cheaper-inference#5430 cheaper-inference#5455) (cheaper-inference#5515)

* fix(providers): correct FriendliAI (serverless) and Novita (/openai/v1) endpoints (cheaper-inference#5430 cheaper-inference#5455)

Both rejected valid keys, verified live with real provider keys:
- FriendliAI baseUrl was /dedicated/v1/... which 403s a serverless flp_* token;
  switched to /serverless/v1/... + serverless modelsUrl.
- Novita baseUrl was the legacy /v3/... with a typo'd model id ai-ai/...
  (both 404); switched to OpenAI-compat /openai/v1/... + meta-llama/llama-3.1-8b-instruct.

Regression guard: tests/unit/provider-endpoints-friendliai-novita.test.ts.

* chore: reconcile CHANGELOG with release (keep cheaper-inference#5430/cheaper-inference#5455 + prior bullets)

* fix(providers): gate import for tool-only providers + sanitize Coze validation error (cheaper-inference#5420 cheaper-inference#5426) (cheaper-inference#5522)

cheaper-inference#5420: the 'Import Models' button now hides for tool-only providers
(web search / web fetch) via a capability check over resolved serviceKinds,
not just the -search suffix — firecrawl/jina-reader (webFetch) no longer
show an Import button that 400s. No LLM/media provider is affected.

cheaper-inference#5426: Coze key validation no longer leaks the raw upstream envelope
({code,msg,logId,from}) into the UI; the Coze error becomes a friendly
message, scoped to provider === 'coze' so no other provider is affected.

Regression guards: tests/unit/model-listing-capability-5420.test.ts,
tests/unit/coze-validation-error-5426.test.ts.

* fix(providers): correct LongCat free tier — GA LongCat-2.0, one-time 10M (KYC) (cheaper-inference#5508)

LongCat's preview ended and the Flash-* line was retired (2026-05-29);
the API now exposes only the GA LongCat-2.0 (1M context, 128K output).
The free tier is a ONE-TIME 10M-token grant unlocked after account
signup + KYC verification — NOT a recurring daily/monthly allowance.
The catalog still described the retired preview/Flash models and a
recurring 150M / 5M-per-day budget; this corrects every reference.

Config / code:
- registry/longcat: model LongCat-2.0-Preview -> LongCat-2.0, name +
  comment reflect one-time 10M (KYC) and pay-as-you-go beyond it.
- freeModelCatalog: longcat-2.0-preview (150M, recurring-daily) ->
  LongCat-2.0 (10M, freeType one-time-initial via creditTokens).
- freeTierCatalog: drop longcat from the recurring-monthly budget map
  (one-time credits are excluded by that catalog's own rule).
- regional.ts freeNote: one-time 10M after signup + KYC, not recurring.
- providerCostData: longcat-flash-lite -> longcat-2.0 (pay-as-you-go
  0.75/2.95 per 1M, 10M free quota).
- validation probe model longcat -> LongCat-2.0.

Tests:
- free-tier-catalog: longcat now absent from FREE_TIER_BUDGETS;
  providerCount 22->21 (clean 21->20); documented total ~1.39B.
- tierResolver: sample model flash-lite -> LongCat-2.0.

Docs:
- README, PROVIDERS-GUIDE, FREE-TIERS-GUIDE, FREE_TIERS: 50M/day
  Flash-Lite -> one-time 10M LongCat-2.0 (KYC); 'No auth' -> API key + KYC.
- Regenerated PROVIDER_REFERENCE.md (picks up the new freeNote).

typecheck:core clean; changed-file lint 0 errors; docs-sync PASS.

* fix(providers): Bytez OpenAI-compat base URL + auth-only key validation (cheaper-inference#5422) (cheaper-inference#5528)

Bytez IS OpenAI-compatible at .../models/v2/openai/v1, but the registry
stored the bare .../models/v2 base, so validation's chat-probe hit
.../models/v2/chat/completions -> 404 -> 'endpoint not supported'.

Part A: registry baseUrl -> full OpenAI-compat chat path.
Part B: a Bytez account only serves catalog-provisioned models, so chat-probe
validation 404s even for valid keys. validateBytezProvider instead probes the
auth-only GET .../models/v2/list/tasks (200=valid, 401/403=invalid).

Verified live with a real key: list/tasks -> 200 (valid) / 401 (invalid).
Regression guard: tests/unit/bytez-validation-5422.test.ts.

* fix(providers): remove dead Phind provider + dedupe HuggingChat catalog listing (cheaper-inference#5530)

Integrated into release/v3.8.42 (round 3). Dead Phind removal + HuggingChat dedupe, verified complete.

* fix: protect dynamic dashboard tests with CSRF (cheaper-inference#5405)

Integrated into release/v3.8.42 (round 3). Reworked CSRF (HMAC-signed synchronized token).

* docs: clarify bifrost relay backend envs (cheaper-inference#5520)

Integrated into release/v3.8.42 (round 3). Doc-only: bifrost relay envs.

* test(quota): guard Claude-Code identity version lockstep (Phase 2) (cheaper-inference#5514)

Integrated into release/v3.8.42 (round 3). Claude-Code identity version lockstep guard.

* feat(compression): T02 — honest default-on pipeline inflation guard (H1) (cheaper-inference#5527)

Integrated into release/v3.8.42 (round 3). T02 pipeline inflation guard

* feat(compression): T05/C2 — caveman dedup + ultra packs for de, fr, ja (cheaper-inference#5529)

Integrated into release/v3.8.42 (round 3). T05/C2 caveman packs de/fr/ja

* feat(compression): T05/C6 — Chinese (zh / wenyan) caveman pack + detection (cheaper-inference#5532)

Integrated into release/v3.8.42 (round 3). T05/C6 zh/wenyan pack + detection

* feat(compression): T07/R9 — gradle + dotnet RTK catalog filters (cheaper-inference#5537)

Integrated into release/v3.8.42 (round 3). T07/R9 RTK gradle+dotnet filters

* refactor(dashboard): T11 — drop duplicate caveman on/off toggle from the compression settings tab (cheaper-inference#5524)

Integrated into release/v3.8.42 (round 3). T11 consolidate duplicate caveman controls; i18n'd the panel hint string (source key).

* test relay routing fallback headers (cheaper-inference#5526)

Integrated into release/v3.8.42 (round 3). Relay fallback header extraction + tests (drift-shed: dependabot cheaper-inference#5415 commit dropped).

* fix(opencode-plugin): bump to 0.2.0 + auto-publish on release (cheaper-inference#5363)

- Bump @omniroute/opencode-plugin from 0.1.0 to 0.2.0 so CI publishes
  the accumulated fixes (auto combos, schema fields, debug logging) that
  were merged after the initial 0.1.0 publish on May 24.
- Add auto-bump step in npm-publish.yml: detects if the plugin dir
  changed since the last release tag and auto-increments patch version,
  so the plugin never falls behind again on future releases.

Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>

* [codex] add bifrost auto fallback cooldown (cheaper-inference#5519)

Integrated into release/v3.8.42 (round 3). Bifrost auto fallback cooldown; header reconciled with cheaper-inference#5526 helper + env-doc.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix onboarding schema client import (cheaper-inference#5525)

Integrated into release/v3.8.42 (round 3). Browser-safe onboarding schema import (drift-shed: dependabot cheaper-inference#5415 dropped).

* docs: add relay backend strategy guide (cheaper-inference#5547)

Port cheaper-inference#5533 relay strategy guide to release/v3.8.42 (doc-only).

* fix(chatgpt-web): support GPT-5.5 Pro handoff (cheaper-inference#5536)

Integrated into release/v3.8.42 (round 3). GPT-5.5 Pro async stream_handoff support (drift-shed: dependabot cheaper-inference#5415 dropped).

* fix(providers): persist Configured filter across page reloads (cheaper-inference#5510)

Integrated into release/v3.8.42 (round 3). Persist Configured filter across reloads; extracted shouldSyncProviderDisplayMode race guard + TDD test (Closes cheaper-inference#4059).

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix(mimocode): route per-account traffic through SOCKS5 proxy dispatchers (cheaper-inference#5521)

Integrated into release/v3.8.42 (round 3). Per-account SOCKS5 dispatcher routing — completes cheaper-inference#3837's stored proxy config with the actual undici dispatcher layer. Rebased onto .42 (dropped the CI-workflow-deletion commits; merged proxyUrlMap dispatch with cheaper-inference#3837's acct.proxy storage).

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix(chatgpt-web): portable SHA3-512 for sentinel PoW under Electron/BoringSSL (cheaper-inference#5531) (cheaper-inference#5540)

* fix(build): keep ioredis out of the client/CLI bundle via SPAWN_CAPABLE_PREFIXES leaf (cheaper-inference#5546)

Fix the dast-smoke ioredis client-bundle regression (proven: dast-smoke green). Remaining reds are pre-existing base-reds/flakes (base.ts file-size, GOLDEN provider drift, shard-1 compression flakes) inherited by all PRs — not from this change.

* chore(release): finalize v3.8.42 CHANGELOG + cycle-close reconciliation

- Reconcile CHANGELOG.md for v3.8.42: 40 bullets covering all 89 commits
  since v3.8.41 (4 features, 26 fixes, 10 maintenance incl. 2 rollups for
  the 35-PR dead-code sweep + 17-PR DRY consolidation), dedup the merge-
  artifact duplicate New Features headers, set release date 2026-06-30.
- Sync 42 docs/i18n/*/CHANGELOG.md mirrors.
- Document 3 new chatgpt-web/TLS env vars in .env.example + ENVIRONMENT.md
  (OMNIROUTE_CGPT_WEB_PRO_TIMEOUT_MS, _PRO_POLL_INTERVAL_MS,
  OMNIROUTE_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS).
- Cycle-close ratchet rebaselines: eslintWarnings 4116->4121, file-size
  base.ts/chatgpt-web.ts/strategySelector.ts/chatgpt-web.test.ts (all
  inherited drift, justified inline).
- Regenerate provider translate-path golden snapshot for the merged
  bytez/friendliai/novita endpoint fixes.

* chore(changelog): cover cheaper-inference#5415 dev-deps bump merged from main

The release/v3.8.42 ↔ main merge (783d1f4) brought cheaper-inference#5415 (development
dependency group, 9 updates) and cheaper-inference#5533 (relay backend guide) from main.
cheaper-inference#5533's content is already covered by the cheaper-inference#5547 port bullet; add a
Maintenance bullet for cheaper-inference#5415 and re-sync the 42 i18n CHANGELOG mirrors.

* test: relocate 2 orphaned test files to collected runner paths

check:test-discovery flagged two cycle-merged tests that no runner
collects (they never ran → false coverage confidence):
- compression-settings-tab-consolidation.test.tsx (cheaper-inference#5524) → tests/unit/ui/
  (vitest UI runner collects tests/unit/ui/**/*.test.tsx); 3/3 pass.
- providers/providerPageStorage.test.ts (cheaper-inference#5510) → tests/unit/dashboard/
  ('providers' is not a collected subdir; 'dashboard' is, same ../../../
  import depth); 30/30 pass under the node runner.

Both confirmed green when actually executed; no assertions weakened.

* fix(release): repair inherited base-red tests from cheaper-inference#5480/cheaper-inference#5527/cheaper-inference#5427/cheaper-inference#5521

The fast-path (PR->release/**) does not run the full unit+integration suites,
so four merged feature PRs shipped with stale/incorrect tests that only surface
on the release PR (PR->main). Repairs (features are correct; align tests to the
new behavior — no assertions weakened):

- cheaper-inference#5480 (gate claude adaptive thinking): adaptive thinking is now injected only
  for a real Claude Code client (x-app:cli / claude-code UA), not for any bare
  Claude OAuth token. claude-thinking-tool-choice-guard + base-thinking-budget-5312
  now identify as a Claude Code client to exercise the adaptive path (3 tests).

- cheaper-inference#5527 (T02 inflation guard): the guard reverts a stacked body that did not
  shrink in tokens. The bail-out/advancement fixtures used growth-appending mock
  engines; they now carry a droppable padding message the engines empty, so the
  body realistically shrinks and the marker assertions survive. bailout (5),
  stacked-async (3), engine-enabled-toggle (2).

- cheaper-inference#5427 (render onboarding wizard at /providers/new): integration-wiring asserted
  the old redirect stub; now asserts the route renders ProviderOnboardingWizard.

- cheaper-inference#5521 (mimocode SOCKS5 per-account proxy): the constructor's default account
  omitted the proxy field (undefined), breaking the 'all proxies null' backward
  compat guard. Default it to null, mirroring syncAccountsFromCredentials().

* fix(proxyfetch): skip fallback for non-replayable bodies

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Jan Leon <Jan.gaschler@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Randi <55005611+rdself@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com>
Co-authored-by: KooshaPari <koosha@example.com>
Co-authored-by: backryun <bakryun0718@proton.me>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
Co-authored-by: Arthur Bodera <abodera@gmail.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: OpenClaw Auto <openclaw-auto@example.invalid>
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…ll helper (cheaper-inference#5542) (cheaper-inference#5797)

The in-app auto-update flow called execFileAsync("npm", ...) directly for the
version lookup (versionCheck.getLatestVersionFromNpmCli), dependency install,
global install, and native rebuild. On Windows npm is npm.cmd and Node >=24
refuses to execFile a .cmd without a shell (nodejs/node#52554), so those calls
threw 'spawn npm ENOENT'. Route them through buildNpmExecOptions (the same
win32-shell helper the embedded-services installer uses, fix cheaper-inference#5379). The global
install spec is validated with SERVICE_VERSION_PATTERN before it is shell-joined
(Hard Rule cheaper-inference#13). Not the pnpm/npx swap the issue proposed — that is the wrong
direction for an 'npm install -g' flow already solved elsewhere in-repo.

Regression guard: tests/unit/autoupdate-npm-win32-5542.test.ts.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…k anchor (cheaper-inference#10446)

Deploying the internal gateway was a manual build/pack/scp/npm-i/pm2-restart sequence with no record of what landed and no proof it served traffic. On 2026-08-14 that shipped a package built from a branch predating cheaper-inference#10373: the process came up, health said 'healthy', and every request returned 502 until a human hit it.

scripts/ops/deployCanary.ts holds the policy as pure functions — refuse an artifact that is not traceable to the release line (reusing cheaper-inference#10427), and grade the deploy on health PLUS at least one real completion. Zero probes fails: 'no probe ran' must never read as 'everything is fine', which is exactly how a broken egress path hides behind a green health check. Remote steps are argv arrays, never shell strings (Hard Rule cheaper-inference#13), ordered so the rollback anchor is captured before the install overwrites it.

scripts/ops/deploy-canary.mjs performs the side effects, supports --dry-run, and prints the rollback command when the smoke fails.

Closes cheaper-inference#10429
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
)

Adds Mux (coder/mux — local agent-orchestration daemon) as a fourth-tier
embedded service built on the existing ServiceSupervisor framework, the
same shape as 9Router and CLIProxyAPI:

- Installer (src/lib/services/installers/mux.ts): npm install/update via
  runNpm (array args + env-based prefix, no shell interpolation), modeled
  on ninerouter.ts. Mux ships an npm package (`mux`) with a documented
  headless `mux server --host <host> --port <port>` mode, so no
  git-clone+build path was needed.
- Registered in bootstrap.ts (SERVICES[] + buildSpawnArgsFactory).
- DB seed migration 113 (version_manager row, not_installed/auto_start=0).
- 7 API endpoints under /api/services/mux/ (install/start/stop/restart/
  update/status/auto-start) plus the shared [name]/logs SSE endpoint,
  mirroring the cliproxy route shape and delegating errors through
  createErrorResponse().
- Dashboard tab (MuxServiceTab) reusing ServiceStatusCard,
  ServiceLifecycleButtons, AutoStartToggle, ServiceLogsPanel.
- Docs: EMBEDDED-SERVICES.md (service table, architecture diagram, API
  reference, key-injection section), openapi.yaml, ENVIRONMENT.md,
  .env.example.

Security:
- Every /api/services/mux/* route is covered by the existing
  LOCAL_ONLY_API_PREFIXES "/api/services/" prefix (Hard Rule cheaper-inference#17);
  added an explicit isLocalOnlyPath regression test for all 8 routes.
- Mux binds to 127.0.0.1 explicitly (never 0.0.0.0) as defense-in-depth,
  since it orchestrates AI agents that can execute host commands.
- The bearer token is generated the same way as 9Router's key
  (getOrCreateApiKey) and injected via MUX_SERVER_AUTH_TOKEN (mux's
  documented env form) rather than a CLI flag, so it never appears in
  `ps`/process listings.
- No shell interpolation anywhere in the installer (Hard Rule cheaper-inference#13): all
  npm/spawn args are static arrays; the install prefix and auth token
  travel via the env option.


Inspired-by: decolua/9router#1802

Co-authored-by: Ansh7473 <Ansh7473@users.noreply.github.com>
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…VAL (cheaper-inference#5379) (cheaper-inference#5474)

Node 24 refuses execFile of npm.cmd without a shell (nodejs/node#52554),
so embedded-service install (9Router/CLIProxy) failed with spawn EINVAL on
Windows. runNpm now enables shell on win32 only; to stay Hard-Rule-cheaper-inference#13 safe
under a shell, the install --prefix is passed via npm_config_prefix (env)
instead of an argv path (survives spaces), and the user-supplied version is
constrained by SERVICE_VERSION_PATTERN at the route boundary.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…heaper-inference#4397)

* chore(release): open v3.8.31 development cycle

* fix(mitm): exact host membership in MITM hosts test (CodeQL false positive) (cheaper-inference#4386)

getMitmToolHosts returns string[], so .includes(host) is Array.prototype.includes
(exact membership). CodeQL's js/incomplete-url-substring-sanitization heuristic
misreads it as a String.includes() URL-substring sanitization check and raises a
HIGH alert. Switch to .some(h => h === host) — identical semantics, explicit intent,
no flagged pattern. Surfaced post-v3.8.30 (cheaper-inference#4325) once the test landed on main.

Test-only change (no runtime behavior); the suite still passes and the CodeQL
re-scan on merge clears the alert.

* fix(codex): request reasoning summaries (cheaper-inference#4359)

Adds reasoning.summary=auto + reasoning.encrypted_content include for Codex. Thanks @xz-dev.

* fix(embeddings): inject NVIDIA NIM input_type for asymmetric embed models (cheaper-inference#4341)

NVIDIA NIM asymmetric embedding models (e.g. nvidia/nv-embedqa-e5-v5) reject
requests without an `input_type` ("query" | "passage") with 400 "'input_type'
parameter is required". The embedding registry now carries a model-level
default param for the asymmetric NVIDIA model, and the embeddings handler
injects a model's default params into the upstream body only when the client
omitted them, leaving a client-supplied value untouched.

Reported-by: hydraromania (decolua/9router#1378)

Co-authored-by: hydraromania <252583922+hydraromania@users.noreply.github.com>

* fix(api): migrate deprecated Codex [features].codex_hooks to [features].hooks (cheaper-inference#4342)

Codex renamed the `codex_hooks` feature flag to `hooks`; recent Codex CLI
versions ignore the old key and warn. When OmniRoute rewrites an existing
config.toml (configure/reset Codex provider) it now renames
[features].codex_hooks -> [features].hooks, preserving the value and never
clobbering an already-present `hooks`, then drops the deprecated key. The
migration is a no-op when the flag is absent and runs on both the POST and
DELETE config paths.

Reported-by: Bian-Sh (decolua/9router#1327)

Co-authored-by: Bian-Sh <24520547+Bian-Sh@users.noreply.github.com>

* fix(translator): drop the null flush on the same-format response path (cheaper-inference#4344)

The streaming response translator's same-format fast path returned
`[chunk]` unconditionally, so the end-of-stream null/flush signal
(chunk === null) propagated as a literal `[null]`. Downstream this surfaced
as an empty `data: null` SSE event between chunks and crashed strict clients
(e.g. Factory Droid BYOK on /v1/responses). The fast path now returns `[]`
for the null flush while still passing real chunks through unchanged.

Reported-by: thaitryhand (decolua/9router#1052)

Co-authored-by: thaitryhand <248103256+thaitryhand@users.noreply.github.com>

* fix(translator): strip assistant echo fields on the OpenAI target path (Mistral 422) (cheaper-inference#4350)

Strict OpenAI-compatible upstreams (e.g. mistral/codestral-latest) reject
client-only assistant echo fields sent back as input with 422
extra_forbidden (the report hit messages[].assistant.reasoning_content via
Codex /responses). Only reasoning_content was stripped on the OpenAI target
path; the sibling fields reasoning / refusal / annotations / cache_control
leaked through. They are now all dropped on the non-reasoner OpenAI target
path. `audio` is intentionally preserved (OpenAI audio models reference a
prior assistant audio response by id; Mistral never emits audio).

Reported-by: xxy9468615 (decolua/9router#1649)

Co-authored-by: xxy9468615 <63351664+xxy9468615@users.noreply.github.com>

* fix(cli): honor TAILSCALE_AUTHKEY for non-interactive tailscale login (cheaper-inference#4343)

* fix(cli): honor TAILSCALE_AUTHKEY for non-interactive tailscale login (port from 9router#1263)

startTailscaleLogin built `tailscale up` without ever reading
process.env.TAILSCALE_AUTHKEY, so a pre-authenticated / headless daemon
waited for an interactive auth URL and timed out (~15s). When
TAILSCALE_AUTHKEY is set it is now passed via `--auth-key=` (an argv element
to spawn(binary, args) — no shell interpolation, Hard Rule cheaper-inference#13); when unset,
behavior is unchanged. The arg builder is extracted into a pure exported
`tailscaleUpArgs()` for testing.

Reported-by: ipeterpetrus (decolua/9router#1263)
Co-authored-by: ipeterpetrus <93033698+ipeterpetrus@users.noreply.github.com>

* chore(quality): rebaseline tailscaleTunnel.ts file-size to 1202 (cheaper-inference#1263 +13)

---------

Co-authored-by: ipeterpetrus <93033698+ipeterpetrus@users.noreply.github.com>

* fix(dashboard): OAuth modal surfaces the real error on a non-JSON response (cheaper-inference#4351)

* fix(dashboard): OAuth modal surfaces real error on non-JSON responses (port from 9router#1318)

The OAuth connect/reauth modal called `await res.json()` unconditionally, so
a non-JSON error response (e.g. a plain-text 500 page from a build/OAuth
endpoint) threw `Unexpected token 'I'...` and hid the real failure. New
shared helpers parseResponseBody / getErrorMessage (src/shared/utils/api.ts)
read the body safely (JSON when JSON, raw text otherwise) and produce a clean
message either way; every modal fetch site now uses them.

Reported-by: DNNYF (decolua/9router#1318)
Co-authored-by: DNNYF <74033321+DNNYF@users.noreply.github.com>

* fix(dashboard): type OAuth modal response body as Record<string, unknown> (t11 any-budget)

Switch the parseResponseBody casts from Record<string, any> to
Record<string, unknown> so OAuthModal.tsx stays within its t11 explicit-any
budget. getErrorMessage already takes unknown; the success paths typecheck
clean under strict:false. No runtime change.

---------

Co-authored-by: DNNYF <74033321+DNNYF@users.noreply.github.com>

* fix(translator): accept AI SDK-style { type: image, image: data-URL } content parts (cheaper-inference#4345)

* fix(translator): accept AI SDK-style { type: image, image: "data:..." } parts (port from 9router#1330)

Several OpenAI-input translators only recognized images shaped as
`image_url.url` (or an object with `.source`/`.url`), so an AI SDK-style
content part where `image` is a bare data-URL STRING was silently dropped
before reaching a vision provider (OpenCode is one affected client; the gap
is generic). The OpenAI->Claude, OpenAI->Kiro and OpenAI->Gemini/Antigravity
translators now parse a string `image` data URL into each provider's native
image shape (Claude base64 source, Kiro images[].source.bytes, Gemini
inlineData).

Reported-by: mugnimaestra (decolua/9router#1330)
Co-authored-by: mugnimaestra <13349159+mugnimaestra@users.noreply.github.com>

* chore(quality): freeze openai-to-kiro.ts file-size at 807 (cheaper-inference#1330 +9, over 800 cap)

---------

Co-authored-by: mugnimaestra <13349159+mugnimaestra@users.noreply.github.com>

* fix(dashboard): show a disabled connection's last error in the row (cheaper-inference#4352)

* fix(dashboard): show a disabled connection's last error in the row (port from 9router#1447)

The provider card's error badge counts a disabled connection (isActive ===
false) that has an error — its effective status is still
error/expired/unavailable — but the connection row hid the lastError text for
disabled rows, so the operator saw the count without the cause. The row's
error-visibility decision is extracted into shouldShowConnectionLastError()
and now shows the error whenever there is one, regardless of the active
toggle.

Reported-by: ntdung6868 (decolua/9router#1447)
Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>

* chore(quality): rebaseline ConnectionRow.tsx file-size to 942 (cheaper-inference#1447 +1 import)

---------

Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>

* fix(providers): bound the OAuth connection-test probe with a timeout (cheaper-inference#4347)

* fix(providers): bound OAuth connection-test probe with a timeout (port from 9router#1449)

The OAuth path of "Test Connection One-by-One" called bare fetch() with no
AbortController/signal, so a provider probe that accepted the socket but never
responded wedged the test queue forever. Both the initial probe and the
post-refresh retry are now bounded with AbortSignal.timeout(30s) — matching the
API-key path's existing budget — and a timed-out probe resolves as a failure
with a clear "Test timed out after 30s" message in the route's normal error shape.

Reported-by: ntdung6868 (decolua/9router#1449)
Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>

* chore(quality): rebaseline providers test route file-size to 887 (cheaper-inference#1449 + sibling cheaper-inference#1444 growth)

---------

Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>

* fix(providers): label a deactivated account distinctly from a revoked token (cheaper-inference#4353)

A Codex connection whose OAuth refresh is fully healthy but whose ChatGPT
account has been deactivated by the provider gets a 401 from the upstream
API. The connection test labeled that the same as a bad credential
("Token invalid or revoked" -> upstream_auth_error), so an operator could not
tell a deactivated account from a revoked token. The test now reads the
401/403 body and, when it indicates account deactivation, classifies it as
account_deactivated (which the dashboard already renders as "Account
Deactivated"); a plain auth 401 is unchanged.

Reported-by: ntdung6868 (decolua/9router#1444)

Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>

* fix(db): cascade-delete orphaned model aliases when a provider is removed (cheaper-inference#4348)

* fix(db): cascade-delete orphaned model aliases when a provider is removed (port from 9router#1409)

Deleting a custom provider removed its connections and node but left the
imported model-alias rows (key=<alias>, value="<providerId>/<model>") behind,
so re-importing the same provider was blocked by stale "already exists" aliases.
Add a deleteModelAliasesForProvider(providerId) DB helper that drops every alias
whose stored value begins with "<providerId>/", and call it from the provider-node
DELETE handler so a fresh import is unblocked.

Reported-by: nguyenvanhuy0612 (decolua/9router#1409)
Co-authored-by: nguyenvanhuy0612 <57367674+nguyenvanhuy0612@users.noreply.github.com>

* chore(quality): rebaseline models.ts file-size to 1221 (cheaper-inference#1409 + sibling cheaper-inference#1294 growth)

---------

Co-authored-by: nguyenvanhuy0612 <57367674+nguyenvanhuy0612@users.noreply.github.com>

* fix(api): persist max_input_tokens/max_output_tokens when adding a custom model (cheaper-inference#4349)

The POST /api/provider-models handler read the rest of the body but never
the two token-limit fields, and addCustomModel() had no parameter for them,
so the form values were dropped on write while the DB layer and /v1/models
catalog already round-trip inputTokenLimit/outputTokenLimit. Accept the two
optional limits in the schema, forward them through the handler, and persist
them in addCustomModel(). TDD: failing-then-passing unit test.

Reported-by: codename-zen (decolua/9router#1294)

Co-authored-by: codename-zen <263238141+codename-zen@users.noreply.github.com>

* docs: feature-documentation catch-up (v3.8.20 → v3.8.30) (cheaper-inference#4391)

One-time reconciliation of the docs with every user-facing feature shipped since
v3.8.20 (we had never done a dedicated pass, so debt had accumulated):

- README: new '✨ What's New' section (curated v3.8.20→v3.8.30 highlights).
- New guides: CLI-INTEGRATIONS (all setup-*/launch commands), MITM-TPROXY-DECRYPT
  (transparent-decrypt epic), CONTEXT_EDITING (delegated Anthropic clear_tool_uses).
- Refreshed: AUTO-COMBO (auto/<category>:<tier> + Arena-ELO), API_REFERENCE
  (x-omniroute-no-memory), MEMORY (int8 quantization + off-by-default), RESILIENCE
  (model-lockout success-decay), RTK, AGENTBRIDGE, TRAFFIC_INSPECTOR, GUARDRAILS,
  CLOUD_AGENT, ENVIRONMENT, SETUP_GUIDE, CLI-TOOLS, MCP-SERVER.
- Regenerated PROVIDER_REFERENCE (231 providers); synced the count in README/CLAUDE/AGENTS.
- Allowlisted external-tool env vars (OPENAI_API_BASE, PROMPTFOO_PROVIDER_KEY) and the
  STREAM_RECOVERY config-object name in the docs-accuracy gates.

All claims source-verified; check:docs-all (sync/counts/env/links/fabricated) passes.
Going forward this runs every release via generate-release step 6b.

* fix(executors): don't inject thinking when tool_choice forces a tool (native Claude) (cheaper-inference#4389)

Forced tool_choice now strips the adaptive thinking injection to avoid Anthropic 400. Thanks @NomenAK.

* fix(translator): Gemini accepts HTTP/HTTPS image URLs (port from 9router#344) (cheaper-inference#4373)

OpenAI-style `image_url` parts with an `http://` or `https://` URL reached
`convertOpenAIContentToParts` and were dropped with only a `console.warn`,
because Gemini's `inlineData` requires base64 (the helper is synchronous and
cannot fetch+encode upstream assets). Gemini's `Part` schema, however, natively
accepts `fileData: { fileUri }` for remote URIs — the model fetches the asset
itself.

The helper now emits a `fileData` part (`mimeType: "image/*"`, inferred upstream
on fetch) for HTTP/HTTPS URLs instead of silently dropping them. Vision requests
that pass a URL — not a data: URI — now reach Gemini intact.

No behavioral change for:
- `data:` URIs → still emitted as `inlineData` with the parsed media type.
- Unsupported schemes (e.g. `ftp:`) → still skipped (Gemini would reject them).

The openai-to-claude side already passed HTTP/HTTPS URLs through as
`source: { type: "url", url }` (lines 573–578) — the upstream PR's Claude-side
change was already covered.

Regression test: tests/unit/gemini-helper-http-image-url-port344.test.ts
(4 cases: https URL, http URL, data: URI no-regression, unsupported-scheme guard).


Inspired-by: decolua/9router#344

Co-authored-by: Ibrahim Ryan <ryan@nuevanext.com>

* fix(executors): strip stream_options for qwen non-streaming / thinking Claude Code requests (port from 9router#663) (cheaper-inference#4374)

Claude-Code-compatible providers force the executor-level `stream` flag on
via `upstreamStream = stream || isClaudeCodeCompatible`
(open-sse/handlers/chatCore.ts), but the outgoing body keeps the caller's
original `stream: false`. The shared `stream && targetFormat === "openai"`
branch in DefaultExecutor.transformRequest then injected
`stream_options: { include_usage: true }` onto a body that still said
`stream: false`, and qwen upstream rejected the request with
`400 "'stream_options' only set this when you set stream: true"`. The same
rejection surfaced when the body carried `thinking` / `enable_thinking`.

The qwen branch now skips the injection (and strips any client-sent
`stream_options`) when the body explicitly says `stream: false` or
requests thinking, leaving regular qwen streaming requests with the
include_usage injection intact. Other providers are unaffected.

Adds a TDD regression with 4 cases covering both opt-out paths and the
normal-streaming positive control.


Inspired-by: decolua/9router#663

Co-authored-by: anuragg-saxenaa <anuragg.saxenaa@gmail.com>

* fix(security): scope OAuth callback postMessage to a trusted-origin allowlist (port from 9router#998) (cheaper-inference#4372)

The OAuth callback at `/callback` previously fell back to
`window.opener.postMessage({ code, state, ... }, "*")` whenever the opener
was cross-origin. The fallback was intended to support remote-OmniRoute +
local-loopback callbacks (where opener and callback live on different
origins), but the same code path also delivers the OAuth code/state to any
hostile opener that pops the well-known callback URL — letting that
attacker complete the OAuth flow as the user.

Replace the wildcard fallback with iteration over a fixed allowlist:
`window.location.origin` (same-origin parent — the popup-mode dashboard)
plus Codex's fixed loopback helper (`http://localhost:1455` and the IPv4
literal `http://127.0.0.1:1455`). The browser drops `postMessage` to any
opener whose actual origin is not in `targetOrigin`, so the message reaches
only known parents and is silently dropped for any other. The same-origin
fallback path is unchanged — methods 2 (`BroadcastChannel`) and 3
(`localStorage` storage event) still cover same-origin openers that COOP
severed.

The `openerSameOrigin` probe stays in place to drive the auto-close vs
manual-copy UI decision (no behavior change for the success path).

Adds a regression test (`tests/unit/ui/oauth-callback-postmessage-scope.test.tsx`)
that mounts the page with a stubbed cross-origin opener and asserts no
`postMessage` call ever uses `"*"` and every call lands on an allowlisted
origin. The test failed against the pre-fix code (red), passes after the
fix (green) — TDD per CLAUDE.md hard rule cheaper-inference#18.

Partial port of upstream decolua/9router#998: the upstream PR also
re-enabled TLS verification on a DNS-bypass fetch in `open-sse/utils/proxyFetch.js`;
that part is N/A here because OmniRoute's `proxyFetch.ts` never disabled
TLS verification (no `rejectUnauthorized: false` anywhere in the file).


Inspired-by: decolua/9router#998

Co-authored-by: aeonframework <aeon@aeonframework.dev>

* fix(sse): default combo per-target timeout to 120s for fast failover (cheaper-inference#4365)

Combo per-target timeout inherited the full FETCH_TIMEOUT_MS (600s) when a
combo did not set its own targetTimeoutMs, so a single hung/slow target stalled
the whole combo for up to 10 minutes before falling through to the next model.

Introduce DEFAULT_COMBO_TARGET_TIMEOUT_MS (120s) as the unset-default in
resolveComboTargetTimeoutMs (new 3rd arg) and wire it in phaseComboSetup. The
upstream ceiling (600s) and per-combo opt-out (targetTimeoutMs, up to the
ceiling) are preserved; single non-combo requests are unchanged. For streaming
requests this only bounds time-to-first-headers, so token generation is not cut
short.

TDD: failing-then-passing unit test in tests/unit/combo-config.test.ts.

* refactor(combo): de-dup exhausted-target skip predicate across both dispatchers (cheaper-inference#4362)

Primeiro incremento da de-dup dos 2 dispatchers de combo (handleComboChat +
handleRoundRobinCombo). O bloco de pre-check cheaper-inference#1731/#1731v2 (skip de target já
exhausted no provider/connection) era BYTE-IDÊNTICO nos dois (mesmas condições,
mesmas mensagens), diferindo só na tag de log e no control-flow.

- comboPredicates.ts: getExhaustedTargetSkipReason(target, exhaustedProviders,
  exhaustedConnections) — predicate PURO que retorna a mensagem de skip (ou null);
  cada dispatcher mantém seu próprio log-tag + control-flow (return null / continue)
  + fallbackCount. No mutate do stryker (cobertura de mutação).
- combo.ts: −20 linhas (os 2 blocos viram 1 chamada cada).
- 7 testes de caracterização travam condições + strings exatas.

Comportamento preservado: 376/376 testes combo (357 caracterização + 7 novos),
integração sse-correctness 5/5, typecheck 0, complexity neutro (1895), file-size
encolhe. Próximo incremento: de-dup do error-handling/exhausted-tracking (handleTargetError).

* refactor(combo): de-dup upstream-error exhaustion classification across both dispatchers (cheaper-inference#4366)

Segundo incremento da de-dup dos 2 dispatchers (handleTargetError). Após cada erro
de target, ambos rodavam um bloco quase-idêntico que marca o provider exhausted
(cheaper-inference#1731), a conexão connection-errored (#1731v2) ou o provider transiently rate-limited.

- combo/targetExhaustion.ts: applyComboTargetExhaustion(target, opts) — atualiza os
  3 Sets de exhaustion e retorna providerExhausted. As MUTAÇÕES de Set (que dirigem o
  skip de targets, lidas por getExhaustedTargetSkipReason) são BYTE-IDÊNTICAS nos dois;
  as diferenças reais viram parâmetros: tag, allAccountsRateLimited (termo extra do RR,
  false no handleComboChat), exhaustedLogLevel (info no handleComboChat, debug no RR).
  Connection-level extraído p/ markConnectionLevelExhaustion (privado, <15 complexity).
- combo.ts: −73 linhas; 4 imports órfãos removidos.
- 7 testes de caracterização travam as mutações + o return.

ÚNICA mudança de comportamento: o WORDING das mensagens de log do RR ganha o sufixo
'on remaining targets' (cosmético; mesmo #code, mesmas mutações, mesmos níveis de log).
376/376 combo (caracterização preservada), integração sse 5/5, typecheck 0, complexity
neutro (1895), file-size encolhe.

* refactor(chatCore): extract checkHeapPressureGuard leaf (god-file decomposition start) (cheaper-inference#4371)

Primeiro incremento da decomposição do chatCore.ts (5127 LOC, hot-path mais quente).
O guard de memória do topo do handleChatCore (rejeita 503 quando o heap V8 passa o
threshold de shed) vira um leaf testável, co-locado com o threshold em heapPressure.ts.

- heapPressure.ts: checkHeapPressureGuard(heapUsedMb, thresholdMb) — retorna o result
  503 pronto ou null. Byte-idêntico ao guard inline (mesmo check, mesma 503, mesmo warn).
  A figura de heap fica em telemetria INTERNA, nunca no response do cliente (Hard Rule cheaper-inference#12).
- chatCore.ts: o bloco inline (~22 ln) vira 3 linhas; import órfão de HEAP_PRESSURE_THRESHOLD_MB
  trocado por checkHeapPressureGuard.
- 3 testes novos (incl. assert Rule cheaper-inference#12: o MB medido não vaza no payload).

complexity-baseline 1895->1896: drift de base pós-cheaper-inference#4338 (medido com minhas mudanças
stashed = 1896); esta mudança é complexity-NEUTRA (helper complexity 2, handleChatCore só
perde código). 190/190 chatcore tests, typecheck 0, file-size encolhe.

* Localize CLI and stabilize fetch, memory, and coverage handling (cheaper-inference#4383)

en-only i18n, fetch-start-timeout hardening, EngineConfigPage icon fix, CI build-artifact-reuse overhaul. Memory production hunk dropped as a no-op (tests kept). Thanks @JxnLexn.

* test(combo): reset circuit breakers between stream-readiness cases (restore green) (cheaper-inference#4396)

The combo-dispatch cases in combo-stream-readiness-fallback.test.ts deliberately
fail `glm` (zombie streams / repeated 504s), which legitimately trips the
per-provider circuit breaker. That OPEN state is a module-level singleton, so it
leaked into the next test and combo.ts then SKIPPED `glm/*` targets entirely
("Skipping … circuit breaker OPEN"). That made "combo does not retry stream
readiness timeouts on the same model" never attempt glm/zombie — expected
['glm/zombie','openai/gpt-5.4-mini'] but got ['openai/gpt-5.4-mini'].

This was a pre-existing red on release/v3.8.31 (present at the cycle-open tip),
order-dependent: the test passes in isolation, fails after the preceding cases.
Add a test.beforeEach(resetAllCircuitBreakers) so each scenario starts from a
clean breaker slate. Test-isolation only — the breaker behavior is correct and
no production code or assertion changes. Full combo suite: 390/390 green.

* fix(cli): decline confirm() cleanly on non-interactive stdin + document contexts workflow

The `contexts remove` command already has `--yes` to skip confirmation, but when
run without it under a non-interactive stdin (pipe, CI, EOF) the [y/N] prompt could
never be answered — the readline question stayed pending and Node warned about an
"unsettled top-level await" at exit. confirm() now detects `!process.stdin.isTTY`
and declines cleanly (returns false), pointing at `--yes` for non-interactive use.
Exported confirm() for a regression test.

Docs: REMOTE-MODE.md gains a full "Managing contexts" section (list/current/use to
switch between remote and local, add/show/rename, remove with --yes, export/import),
fixes a `context current` -> `contexts current` typo, and the README remote-mode
snippet now shows switching back to local. Verified against the live CLI: command
signatures, --yes, and the non-TTY decline path all behave as documented.

Tests: cli-contexts.test.ts asserts confirm() declines on non-TTY stdin (RED before,
GREEN after). All docs gates (fabricated/links/symbols) pass.

* ci(t11): bump any-budget for executors/base.ts (2 false-positive "any" strings)

Unblocks the Fast Quality Gates on release/v3.8.31: `check:any-budget:t11` was red on
`open-sse/executors/base.ts` for ALL PRs (pre-existing base drift, unrelated to this
branch). The checker counts `\bany\b` after stripping comments but NOT strings, and the
native-Claude tool_choice logic uses the API value `"any"` in two string literals
(`tb.tool_choice === "any"`, `.type === "any"`). There are zero actual TypeScript
`any` types in the file — budget set to the matched count, mirroring the existing
cursor.ts false-positive entry right below it.

* perf: combos UI split + next config + 1-click redis + bifrost sidecar (cheaper-inference#3932) (cheaper-inference#4381)

Combos UI split + next.config perf + 1-click local Redis launcher + bifrost relay. Review fixes (co-author): --rm/--restart conflict, error sanitization, UI/route names, dead-guard re-doc, bifrost Zod, IPv6 + CLI test fixes. Thanks @KooshaPari.

* fix(plugin): prefix OC static-catalog combo+raw keys with providerId (cheaper-inference#4384)

OC parses model ids on '/'; combo keys now carry 'omniroute/' (was 'combo/'). Live-validated against the VPS via OpenCode. Thanks @herjarsa.

* docs(env): document TAILSCALE_AUTHKEY (env/docs contract drift on .31)

Second pre-existing base-drift fix needed to get Fast Quality Gates green: the
`repository contract is in sync` test (check:env-doc-sync) was red on ALL .31 PRs.
PR cheaper-inference#4343 added a code reference to `process.env.TAILSCALE_AUTHKEY`
(src/lib/tailscaleTunnel.ts) for non-interactive `tailscale up`, but never added the
var to .env.example / docs/reference/ENVIRONMENT.md — the contract requires code vars
to appear in both. Add the (commented) entry to .env.example next to TAILSCALE_BIN and
a row to ENVIRONMENT.md. Verified: `node scripts/check/check-env-doc-sync.mjs` → in sync.

Unrelated to this branch's confirm()/docs change; surfaced because touching a quality
script triggers the TIA fail-safe full unit suite.

* chore(release): v3.8.31 — 2026-06-20

Finalize the v3.8.31 release: reconcile the CHANGELOG (full commit-to-bullet
coverage, 26 bullets across Features/Fixed/Security/Maintenance), refresh the
README What's New section, back-fill the .30/.31 sections into the 41 i18n
CHANGELOG mirrors, and add TAILSCALE_AUTHKEY to the env contract
(.env.example + ENVIRONMENT.md).

* chore(release): align mitm-hosts test comment with main to clear merge conflict

The same CodeQL false-positive fix landed twice — cheaper-inference#4386 on release/v3.8.31 and
cheaper-inference#4387 directly on main — with only the explanatory comment differing (the
assertion is byte-identical). Adopt main's comment wording on the release branch
so the release PR merges without a comment-only conflict.

* test(translator): align stale openai->gemini remote-URL tests with cheaper-inference#4373

Third pre-existing base-drift fix to get Fast Quality Gates green on .31. PR cheaper-inference#4373
('Gemini accepts HTTP/HTTPS image URLs', port of 9router#344) intentionally changed
convertOpenAIContentToParts so remote http(s) image URLs pass through as a native
`fileData: { fileUri }` part instead of the old cheaper-inference#2807 drop+warn — and added its own
test (gemini-helper-http-image-url-port344.test.ts) for the new behavior. But it left
three tests in translator-openai-to-gemini.test.ts asserting the OLD drop+warn
contract, so they fail deterministically (verified: the file fails in isolation on
clean .31). These only surface under the TIA fail-safe FULL suite, which a quality-
script touch triggers.

Align the three stale tests to the real, intended behavior (captured by running the
function): remote URLs -> fileData.fileUri (mimeType image/*), still never inlineData
(the sync path cannot fetch+encode). This is test-vs-code alignment to a deliberate,
separately-tested change — not a weakened assertion. 40/40 in the file; 94/94 across
the translator + env-doc combo that previously failed.

* chore(quality): reconcile complexity baseline 1896->1900 (/review-prs v3.8.31 batch) (cheaper-inference#4410)

* fix(release): reconcile full-CI drift for v3.8.31 (gemini tests cheaper-inference#4373, any-budget cheaper-inference#4389, masking allowlist cheaper-inference#4384)

The release PR's full CI surfaced cumulative cycle drift the per-PR fast gates
skip:
- tests/unit/translator-openai-to-gemini.test.ts: realign 3 cases to cheaper-inference#4373's
  HTTP/HTTPS-URL fileData pass-through (they asserted the old warn-and-drop).
- scripts/check/check-t11-any-budget.mjs: base.ts budget 0→2 — cheaper-inference#4389 compares
  tool_choice against the string literal "any" (not a TS any type).
- config/quality/test-masking-allowlist.json: allowlist cheaper-inference#4384's opencode combos
  net-assert reduction (obsolete combo/ namespace removed).
No production behavior change.

* chore(release): re-trigger full CI for v3.8.31 finalization

Force a fresh pull_request CI run on the head carrying the cycle-drift fixes
(gemini cheaper-inference#4373 tests, any-budget cheaper-inference#4389, masking allowlist cheaper-inference#4384) — the prior
synchronize event did not spawn a ci.yml run.

* chore: re-trigger CI (no Actions runs registered for prior push)

---------

Co-authored-by: Xiangzhe <32761048+xz-dev@users.noreply.github.com>
Co-authored-by: hydraromania <252583922+hydraromania@users.noreply.github.com>
Co-authored-by: Bian-Sh <24520547+Bian-Sh@users.noreply.github.com>
Co-authored-by: thaitryhand <248103256+thaitryhand@users.noreply.github.com>
Co-authored-by: xxy9468615 <63351664+xxy9468615@users.noreply.github.com>
Co-authored-by: ipeterpetrus <93033698+ipeterpetrus@users.noreply.github.com>
Co-authored-by: DNNYF <74033321+DNNYF@users.noreply.github.com>
Co-authored-by: mugnimaestra <13349159+mugnimaestra@users.noreply.github.com>
Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>
Co-authored-by: nguyenvanhuy0612 <57367674+nguyenvanhuy0612@users.noreply.github.com>
Co-authored-by: codename-zen <263238141+codename-zen@users.noreply.github.com>
Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com>
Co-authored-by: Ibrahim Ryan <ryan@nuevanext.com>
Co-authored-by: anuragg-saxenaa <anuragg.saxenaa@gmail.com>
Co-authored-by: aeonframework <aeon@aeonframework.dev>
Co-authored-by: Jan Leon <Jan.gaschler@gmail.com>
Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant