Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
8d50c9d
chore(release): open v3.8.36 development cycle
Jun 23, 2026
e494afe
refactor(chatCore): extrai resolveCompressionSettings (#3501) (#4826)
diegosouzapw Jun 23, 2026
e420c34
refactor(chatCore): extrai predicados puros de combo de compressão (#…
diegosouzapw Jun 23, 2026
34b510a
refactor(chatCore): extrai emitOutputStyleTelemetry (#3501) (#4811)
diegosouzapw Jun 23, 2026
812f2f2
refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics…
diegosouzapw Jun 23, 2026
eb1920b
refactor(chatCore): extrai runPluginOnRequestHook (#3501) (#4827)
diegosouzapw Jun 23, 2026
e85fb9b
refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de…
diegosouzapw Jun 23, 2026
5c0b29e
refactor(chatCore): extrai buildPostCallGuardrailContext (contexto gu…
diegosouzapw Jun 23, 2026
1244e49
refactor(chatCore): extrai storeSemanticCacheResponse (cache-store no…
diegosouzapw Jun 23, 2026
867e904
refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers …
diegosouzapw Jun 23, 2026
c69bd6a
refactor(chatCore): extrai maybeConvertJsonBodyToSse (#3089 JSON→SSE …
diegosouzapw Jun 23, 2026
e87d35c
refactor(chatCore): extrai assembleStreamingResponseHeaders (headers …
diegosouzapw Jun 23, 2026
2cd5609
refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache…
diegosouzapw Jun 23, 2026
5bffefb
refactor(chatCore): extrai assembleStreamingPipeline (chain de transf…
diegosouzapw Jun 23, 2026
7f5b1e4
ci(quality): shift heavy validations to the PR→release fast-path (rel…
diegosouzapw Jun 23, 2026
c922b21
fix(quota): cota exclusiva lista qtSd/ no /v1/models (#4806) + limite…
diegosouzapw Jun 23, 2026
502f43c
feat(sse): add Google Flow video-generation provider (#4569) (#4769)
diegosouzapw Jun 23, 2026
fcf162d
fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL…
diegosouzapw Jun 23, 2026
fc2fdc7
fix(translator): strip top-level client_metadata on the OpenAI passth…
diegosouzapw Jun 24, 2026
ea406b2
fix(translator): normalize `developer` role to `system` for OpenAI-fo…
diegosouzapw Jun 24, 2026
2a90a9e
fix(translator): emit </think> close marker for Anthropic thinking bl…
diegosouzapw Jun 24, 2026
a9368af
fix(translator): normalize tools to Anthropic-native shape for non-An…
diegosouzapw Jun 24, 2026
35a3962
fix(gemini): preserve `pattern` in antigravity tool schema sanitizer …
diegosouzapw Jun 24, 2026
f4fa983
fix(perplexity): validate API keys via /v1/models endpoint (#4654)
diegosouzapw Jun 24, 2026
d2aa67a
fix(image): prevent compatible nodes from shadowing provider aliases …
diegosouzapw Jun 24, 2026
1ad6c46
fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool se…
diegosouzapw Jun 24, 2026
983e152
fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5…
diegosouzapw Jun 24, 2026
e176774
fix(cli): harden the systray2 tray runtime (port of 9router#1080) (#4…
diegosouzapw Jun 24, 2026
32b2df9
fix(test): validate anthropic-compatible connections via POST /v1/mes…
diegosouzapw Jun 24, 2026
607ad12
fix(executors): strip params unsupported by the target provider/model…
diegosouzapw Jun 24, 2026
be2ab9e
fix(claude-oauth): respect 429 backoff on usage endpoint to reduce sp…
diegosouzapw Jun 24, 2026
69703ee
feat(api/v1): include alias-backed models in /v1/models listing (#4630)
diegosouzapw Jun 24, 2026
306863d
chore(quality): rebaseline catalog.ts 1574->1577 (#4630 aliases sobre…
diegosouzapw Jun 24, 2026
ec1c5df
feat(compression): Kiro/CodeWhisperer tool-result compression engine …
diegosouzapw Jun 24, 2026
486f017
fix(security): don't trust loopback socket as local when behind rever…
diegosouzapw Jun 24, 2026
b92f045
fix(opencode): preserve DeepSeek reasoning content in streamed respon…
diegosouzapw Jun 24, 2026
57de29a
fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Inval…
diegosouzapw Jun 24, 2026
c02aa7b
fix(dashboard): show custom vision models in LLM selector (#4653)
diegosouzapw Jun 24, 2026
6fe21e5
fix(claude): omit adaptive thinking + output_config.effort for haiku …
diegosouzapw Jun 24, 2026
2d09f72
feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (#4664)
diegosouzapw Jun 24, 2026
122f6d3
feat(combo): Fusion strategy — parallel panel + judge synthesis (16th…
diegosouzapw Jun 24, 2026
396a9a7
feat(proxy-pool): Deno Deploy relays + group action buttons (#4643)
diegosouzapw Jun 24, 2026
9244d93
fix(security): pin image fetch DNS resolution to prevent SSRF rebindi…
diegosouzapw Jun 24, 2026
cc8e1be
fix(github): route Copilot Codex models to /responses (port from 9rou…
diegosouzapw Jun 24, 2026
b599577
fix(copilot): never route Gemini/Claude variants to /responses (chat-…
diegosouzapw Jun 24, 2026
dad55fe
docs(ops): add canonical incident response runbook (#4868)
KooshaPari Jun 24, 2026
21aa561
docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (#4867)
KooshaPari Jun 24, 2026
9a5627a
fix(proxy): fan out direct dispatcher streams (#4803)
makcimbx Jun 24, 2026
805519b
fix(antigravity): exclude standard Gemini rate limit message from quo…
Chewji9875 Jun 24, 2026
e1ffc8e
fix(sse): skip third-party tool-name cloak for Anthropic server tools…
NomenAK Jun 24, 2026
604654c
fix(install): make transformers optional for CUDA-host installs (#4807)
megamen32 Jun 24, 2026
e99e288
fix(combo): propagate selected connection ID to fallback error respon…
Chewji9875 Jun 24, 2026
459ffcf
fix db storage tuning settings (#4834)
rdself Jun 24, 2026
108e93e
fix(sse): drop ccp pin when pinned provider is durably unhealthy (fai…
costaeder Jun 24, 2026
86b14ad
fix(claude): skip mcp__ tool-name cloak + guard missing connectionId …
costaeder Jun 24, 2026
4d61198
chore(quality): reconcile env-doc + file-size base-reds in release/v3…
diegosouzapw Jun 24, 2026
eb175db
fix(codex): drop non-standard codex.* events that break responses.str…
jeffer1312 Jun 24, 2026
2a7f2c8
feat(routing): honor X-Route-Model header to override body.model (#4863)
costaeder Jun 24, 2026
c522454
feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (…
KooshaPari Jun 24, 2026
2039095
chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.18…
diegosouzapw Jun 24, 2026
5c0cda9
fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno…
diegosouzapw Jun 24, 2026
27c994f
feat(quota): recuperação proativa de conexões em cooldown (cron heal)…
diegosouzapw Jun 24, 2026
4305ef8
fix(quota): policy inválida não vaza allow + guard connectionIds vazi…
diegosouzapw Jun 24, 2026
70afa2b
feat(quota): saturação real do Claude no fair-share via /api/oauth/us…
diegosouzapw Jun 24, 2026
f9ccf34
chore(dashboard): rename Qoder display label from "Qoder AI" to "Qode…
diegosouzapw Jun 24, 2026
9b07e0e
fix(ci): include coverage/lcov.info in coverage-report artifact for S…
diegosouzapw Jun 24, 2026
95e26a0
fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (#4685)
diegosouzapw Jun 24, 2026
ec0572d
docs: clarify Kiro is ~50 credits/month per account, not unlimited (#…
diegosouzapw Jun 24, 2026
db192ce
docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model …
diegosouzapw Jun 24, 2026
413d1d3
docs(ops): document the release-green family (green-prs, check:releas…
diegosouzapw Jun 24, 2026
7a6f432
fix(translator): replay reasoning_content on plain Xiaomi MiMo turns …
diegosouzapw Jun 24, 2026
8251e7b
feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with o…
diegosouzapw Jun 24, 2026
1a1a51c
feat(db): track API endpoint dimension on usage_history (#4676)
diegosouzapw Jun 24, 2026
078785c
fix(cli): SIGKILL systray child PID before IPC close to avoid macOS N…
diegosouzapw Jun 24, 2026
8080800
feat(proxy-pool): Cloudflare Workers proxy deployer + pool integratio…
diegosouzapw Jun 24, 2026
5d9ecf6
chore(quality): conserta base-red de release/v3.8.36 (gates + 7 teste…
diegosouzapw Jun 24, 2026
9d59541
feat(quota): saturação proativa por headers de tokens (universal) [Fa…
diegosouzapw Jun 24, 2026
118875e
feat(quota): estratégia de combo "headroom" — seleção por folga de co…
diegosouzapw Jun 24, 2026
9829616
feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase …
diegosouzapw Jun 24, 2026
0811a15
feat(quota): session stickiness p/ integridade de prompt-cache [Fase …
diegosouzapw Jun 24, 2026
15ee83b
feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase…
diegosouzapw Jun 24, 2026
b8e3dc9
refactor(providers): decompõe catálogo providers.ts em módulos de dad…
diegosouzapw Jun 24, 2026
c872b67
refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRIC…
diegosouzapw Jun 24, 2026
21ce487
refactor(api): extrai camada-folha pura de validation.ts (URL/headers…
diegosouzapw Jun 24, 2026
1cb2462
refactor(api): extrai validators web-cookie + Meta AI de validation.t…
diegosouzapw Jun 24, 2026
6035fd8
refactor(api): extrai validators enterprise-cloud + probe compartilha…
diegosouzapw Jun 24, 2026
833adce
refactor(api): extrai validators áudio/speech + misc apikey de valida…
diegosouzapw Jun 24, 2026
9708288
feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight …
diegosouzapw Jun 24, 2026
537e5b5
refactor(api): extrai validators search + embedding/rerank de validat…
diegosouzapw Jun 24, 2026
419a90f
refactor(api): extrai format-validators (OpenAI/Anthropic) de validat…
diegosouzapw Jun 24, 2026
f158980
refactor(db): extrai model-permission matching de db/apiKeys.ts (#4936)
diegosouzapw Jun 24, 2026
ca0fddd
refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys…
diegosouzapw Jun 24, 2026
5073aff
refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (#4947)
diegosouzapw Jun 24, 2026
ca72de7
refactor(db): extrai schema-column reconciliation de db/core.ts (#4948)
diegosouzapw Jun 24, 2026
565b771
refactor(sse): extrai scalar/format helpers de services/usage.ts (#4949)
diegosouzapw Jun 24, 2026
de19b3b
refactor(sse): extrai quota-core (UsageQuota + builders) de services/…
diegosouzapw Jun 24, 2026
b1b3069
fix(translator): regroup parallel tool results adjacent to their assi…
diegosouzapw Jun 24, 2026
cc8557c
fix(qoder): exchange PAT for jt-* job token before Cosy chat (#4683) …
diegosouzapw Jun 24, 2026
6e28889
refactor(sse): dedup fallback tool_call id helper (#4736)
diegosouzapw Jun 24, 2026
4a1ae86
refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (#…
diegosouzapw Jun 24, 2026
950fc6e
fix(compression): eliminate ReDoS in math_inline preservation pattern…
diegosouzapw Jun 24, 2026
7c75b48
fix(combo): fetch models dynamically from custom provider endpoints (…
diegosouzapw Jun 24, 2026
d65050a
feat(providers): update volcengine-ark model list with DeepSeek V4 (#…
diegosouzapw Jun 24, 2026
6137d4e
fix(translator): provider thinking compatibility (DeepSeek/Gemini) (#…
diegosouzapw Jun 24, 2026
07b385d
feat(combo): task-aware routing strategy (#4945)
diegosouzapw Jun 24, 2026
8a7cf50
refactor(sse): extrai a família MiniMax de services/usage.ts (#4952)
diegosouzapw Jun 24, 2026
cca71a5
refactor(sse): extrai a família GLM de services/usage.ts (#4953)
diegosouzapw Jun 24, 2026
d575691
refactor(sse): extrai a família Antigravity de services/usage.ts (#4956)
diegosouzapw Jun 24, 2026
3d37242
fix(dashboard): show custom provider given-name instead of internal i…
diegosouzapw Jun 24, 2026
d4c2e4d
fix(api): evict stale in-memory rate-limit windows to stop slow heap …
diegosouzapw Jun 24, 2026
cd27701
fix(api): parse /v1/responses body once instead of 3-4x on the hot pa…
diegosouzapw Jun 24, 2026
0720940
fix(translator): preserve legitimate empty-string tool arguments in o…
diegosouzapw Jun 24, 2026
678cbcf
chore(quality): reconcile file-size baseline for #4960 provider-displ…
diegosouzapw Jun 24, 2026
b03134e
fix(dashboard): restore home provider-topology card hidden by #4596 d…
diegosouzapw Jun 24, 2026
d3e02e6
fix(build): drop @omniroute/open-sse from optimizePackageImports (bui…
diegosouzapw Jun 24, 2026
a58183a
fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd…
diegosouzapw Jun 24, 2026
195e40f
feat(quota): respeita max_concurrent por conexão no roteamento (#4965)
diegosouzapw Jun 24, 2026
a9ddef1
feat(quota): combo quota-share espera cooldown curto e re-despacha (V…
diegosouzapw Jun 24, 2026
4fdf68e
fix(quota): enforce.ts não fail-open em limite 0/negativo/não-finito …
Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
64 changes: 61 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,16 @@ PROVIDER_LIMITS_SYNC_SPACING_MS=1500
# heuristic in instrumentation-node.ts. Default: unset (tests skip background).
#OMNIROUTE_ENABLE_RUNTIME_BACKGROUND_TASKS=1

# Proactive connection-cooldown recovery (#8): re-validates connections whose
# transient `rate_limited_until` window has elapsed OUTSIDE the request hot path,
# so the first request after a cooldown does not pay the probe latency. Lazy
# recovery in getProviderCredentials still applies regardless. Used by:
# src/lib/quota/connectionRecovery.ts.
# Tick cadence (ms). Default 60000, floor 5000.
# OMNIROUTE_CONNECTION_RECOVERY_INTERVAL_MS=60000
# Disable the proactive recovery scheduler entirely (default: false).
# OMNIROUTE_DISABLE_CONNECTION_RECOVERY=false

# Background job interval for budget reset checks (ms). Default: 600000 (10m).
# Used by: src/lib/jobs/budgetResetJob.ts. Floor: 10000.
#OMNIROUTE_BUDGET_RESET_JOB_INTERVAL_MS=600000
Expand Down Expand Up @@ -598,6 +608,11 @@ PROVIDER_LIMITS_SYNC_SPACING_MS=1500
# Used by: scripts/postinstall.mjs.
#OMNIROUTE_SKIP_POSTINSTALL=0

# Operator-supplied JSON credentials for the offline compression-eval CLI
# (parsed with JSON.parse; leave unset for a dry run). Developer tooling only.
# Used by: scripts/compression-eval/index.ts. Default: {} (empty).
#OMNIROUTE_EVAL_CREDENTIALS={}

# Skip the DB healthcheck entirely on startup (useful for short-lived tasks / tests).
# Used by: src/lib/db/core.ts, src/lib/db/healthCheck.ts. Set to 1 to disable. Default: 0.
#OMNIROUTE_SKIP_DB_HEALTHCHECK=0
Expand Down Expand Up @@ -792,7 +807,7 @@ GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98
# Used by: open-sse/executors/base.ts — buildHeaders() dynamic lookup.
# Update these when providers release new CLI versions to avoid blocks.

CLAUDE_USER_AGENT="claude-cli/2.1.158 (external, cli)"
CLAUDE_USER_AGENT="claude-cli/2.1.187 (external, cli)"

# Disable the deterministic tool-name cloak applied on both Anthropic-bound paths
# (executors/base.ts native OAuth + executors/cliproxyapi.ts CLIProxyAPI) —
Expand All @@ -801,7 +816,7 @@ CLAUDE_USER_AGENT="claude-cli/2.1.158 (external, cli)"
# stream with a misleading 400 out-of-extra-usage placeholder. Set to true to
# forward the original names verbatim (debugging only).
# CLAUDE_DISABLE_TOOL_NAME_CLOAK=false
CODEX_USER_AGENT="codex-cli/0.132.0 (Windows 10.0.26200; x64)"
CODEX_USER_AGENT="codex-cli/0.142.0 (Windows 10.0.26200; x64)"
GITHUB_USER_AGENT="GitHubCopilotChat/0.45.1"
ANTIGRAVITY_USER_AGENT="antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0"
KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0"
Expand All @@ -823,7 +838,13 @@ GEMINI_CLI_USER_AGENT="google-api-nodejs-client/10.3.0"

# Override Codex client version sent in headers independently of the
# CODEX_USER_AGENT string. Used by: open-sse/config/codexClient.ts.
# CODEX_CLIENT_VERSION=0.132.0
# CODEX_CLIENT_VERSION=0.142.0

# Kill-switch to strip non-standard `codex.*` SSE events (e.g. codex.rate_limits)
# from the Codex Responses stream. These frames break the OpenAI SDK's
# responses.stream() with a 502 "Controller is already closed". Off by default;
# set to true/1/yes to enable. Used by: open-sse/executors/codex.ts.
# OMNIROUTE_CODEX_DROP_NONSTANDARD_EVENTS=true

# ═══════════════════════════════════════════════════════════════════════════════
# 13. CLI FINGERPRINT COMPATIBILITY (Anti-Detection)
Expand Down Expand Up @@ -950,6 +971,15 @@ GEMINI_CLI_USER_AGENT="google-api-nodejs-client/10.3.0"
# OMNIROUTE_CIRCUIT_BREAKER_LOCAL_THRESHOLD=2
# OMNIROUTE_CIRCUIT_BREAKER_LOCAL_RESET_MS=15000

# ── Context-cache pin health gate ──
# Used by: open-sse/services/combo.ts. When a context-cache pin points at a
# provider that is durably unhealthy, the pin is dropped to allow failover.
# PIN_DROP_BACKOFF_LEVEL gates how deep a connection's backoff must be before the
# pin is considered durably unhealthy; PIN_DROP_GRACE_MS is the anti-flap window
# that tolerates brief transient cooldowns before dropping the pin.
# PIN_DROP_BACKOFF_LEVEL=2
# PIN_DROP_GRACE_MS=20000

# ── Stream idle detection ──
# STREAM_IDLE_TIMEOUT_MS=600000 # Max silence between SSE chunks (default: 600000)
# # Extended-thinking models rarely pause >90s.
Expand Down Expand Up @@ -1200,6 +1230,34 @@ APP_LOG_TO_FILE=true
# Used by: open-sse/executors/cloudflare-ai.ts
# CLOUDFLARE_ACCOUNT_ID=

# ── Deno Deploy proxy relay (#4643 / 9router#1437) ──
# Override the Deno Deploy REST API base used by the proxy-pool relay deployer.
# Default: https://api.deno.com/v2 (omit unless mocking).
# Used by: src/app/api/settings/proxy/deno-deploy/route.ts
# DENO_DEPLOY_API_BASE=https://api.deno.com/v2

# Default Deno Deploy app name suggested in the "Deploy Relay" modal.
# Used by: src/app/(dashboard)/dashboard/settings/components/proxy/DenoRelayModal.tsx
# NEXT_PUBLIC_DENO_RELAY_DEFAULT_PROJECT=omniroute-deno-relay

# Set to "false" to hide the Deno Deploy relay option from the Proxy Pool tab.
# Used by: src/app/(dashboard)/dashboard/settings/components/proxy/ProxyPoolTab.tsx
# NEXT_PUBLIC_DENO_RELAY_ENABLED=true

# ── Cloudflare Workers proxy relay (#4640 / 9router#1360) ──
# Override the Cloudflare REST API base used by the proxy-pool relay deployer.
# Default: https://api.cloudflare.com/client/v4 (omit unless mocking).
# Used by: src/app/api/settings/proxy/cloudflare-deploy/route.ts
# CLOUDFLARE_API_BASE=https://api.cloudflare.com/client/v4

# Default worker project name suggested in the "Deploy Relay" modal.
# Used by: src/app/(dashboard)/dashboard/settings/components/proxy/CloudflareRelayModal.tsx
# NEXT_PUBLIC_CLOUDFLARE_RELAY_DEFAULT_PROJECT=omniroute-relay

# Set to "false" to hide the Cloudflare Workers relay option from the Proxy Pool tab.
# Used by: src/app/(dashboard)/dashboard/settings/components/proxy/ProxyPoolTab.tsx
# NEXT_PUBLIC_CLOUDFLARE_RELAY_ENABLED=true

# ── Cloudflare Tunnel (cloudflared) ──
# Custom path to cloudflared binary for tunnel management.
# Used by: src/lib/cloudflaredTunnel.ts
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,7 @@ jobs:
path: |
coverage/coverage-summary.json
coverage/coverage-report.md
coverage/lcov.info
if-no-files-found: warn

sonarqube:
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ jobs:
- run: npm run check:fetch-targets
- run: npm run check:openapi-routes
- run: npm run check:docs-symbols
- name: Docs accuracy (fabricated-docs + i18n mirrors, strict)
run: npm run check:docs-all
- run: npm run check:deps
- run: npm run check:file-size
- run: npm run check:error-helper
Expand All @@ -49,6 +51,7 @@ jobs:
- run: npm run check:known-symbols
- run: npm run check:route-guard-membership
- run: npm run check:test-discovery
- run: npm run check:test-runner-api
- run: npm run check:any-budget:t11
- name: Typecheck (core)
run: npm run typecheck:core
Expand Down Expand Up @@ -82,3 +85,48 @@ jobs:
echo "Running impacted tests:"; echo "$SEL"
mapfile -t FILES <<< "$SEL"
node --import tsx --import ./open-sse/utils/setupPolyfill.ts --import ./tests/_setup/isolateDataDir.ts --test --test-force-exit --test-concurrency=4 "${FILES[@]}"

fast-vitest:
name: Vitest (fast-path)
runs-on: ubuntu-latest
env:
JWT_SECRET: ci-lint-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-lint-api-key-secret-long
DISABLE_SQLITE_AUTO_BACKUP: "true"
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run test:vitest

fast-unit:
name: Unit Tests fast-path (${{ matrix.shard }}/2)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2]
env:
JWT_SECRET: ci-lint-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-lint-api-key-secret-long
DISABLE_SQLITE_AUTO_BACKUP: "true"
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- run: >
node --max-old-space-size=4096 --import tsx
--import ./tests/_setup/isolateDataDir.ts
--test --test-force-exit --test-concurrency=4 --test-shard=${{ matrix.shard }}/2
tests/unit/*.test.ts
"tests/unit/{api,auth,authz,build,cli,cli-helper,combo,compression,correctness,cors,dashboard,db,db-adapters,docs,gamification,guardrails,lib,mcp,runtime,security,services,settings,shared,ui}/**/*.test.ts"
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

---

## [3.8.36] — TBD

_In development — bullets added per PR; finalized at release._

- **feat(providers):** update volcengine-ark model list, adding DeepSeek-V4-Flash and DeepSeek-V4-Pro. (thanks @kenlin8827)

### 🔧 Bug Fixes

- **fix(dashboard):** show custom provider given-name instead of internal id across dashboard pages — cache, combo health, compression analytics, cost overview, health/autopilot, provider stats, route explainability, provider utilization, runtime. Adds shared `resolveProviderName` resolver and `useProviderNodeMap` hook. (#4603)

---

## [3.8.35] — 2026-06-23

### ✨ New Features
Expand All @@ -19,6 +31,7 @@
- **Dashboard**: remove the dead, unconditional `useLiveRequests()` call from `HomePageClient.tsx` — it crashed the `/home` page in production builds with `ReferenceError: useLiveRequests is not defined` (#4759, #4745) and opened the live-dashboard WebSocket even when Provider Topology was hidden (#4596). The live feed remains owned by the settings-gated `HomeProviderTopologySection` ([#4761](https://github.com/diegosouzapw/OmniRoute/pull/4761) — thanks @diegosouzapw).
- **Providers dashboard**: dedupe provider nodes by id when adding a compatible provider (`upsertProviderNodeById`) so the same provider can no longer appear twice and no-op adds don't invalidate the compatible-provider memo ([#4768](https://github.com/diegosouzapw/OmniRoute/pull/4768) — closes #4746, thanks @diegosouzapw).
- **Storage VACUUM**: the scheduled VACUUM job now follows the Storage page settings (`scheduledVacuum` / `vacuumHour`) as the single source of truth; the legacy env-flag control path was removed ([#4726](https://github.com/diegosouzapw/OmniRoute/pull/4726) — thanks @rdself).
- **Storage SQLite tuning**: `Cache Size` is now a positive KiB setting (for example, `16384`) that applies to SQLite as `PRAGMA cache_size = -16384`; Page Size and Cache Size changes are applied to the live database instead of being persisted only in the settings table.
- **Tiers**: no-auth providers are now counted as free, and the free-tier filter returns an empty set instead of falling through to every provider ([#4753](https://github.com/diegosouzapw/OmniRoute/pull/4753) — thanks @megamen32 / @diegosouzapw).
- **Combos**: auto-promote `zeroLatencyOptimizationsEnabled` so legacy configs (pre-3.8.33 `fallbackCompressionMode="lite"`) round-trip cleanly on the first GUI edit ([#4774](https://github.com/diegosouzapw/OmniRoute/pull/4774) — thanks @KooshaPari / @diegosouzapw).

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ Dashboard at `http://localhost:20128` · API at `http://localhost:20128/v1`.

**2) Connect a FREE provider (no signup)**

Dashboard → **Providers** → connect **Kiro AI** (free Claude unlimited) or **OpenCode Free** (no auth) → done.
Dashboard → **Providers** → connect **Kiro AI** (free Claude, ~50 credits/month per account) or **OpenCode Free** (no auth) → done.

**3) Point your coding tool**

Expand Down Expand Up @@ -743,7 +743,7 @@ podman compose --profile base up -d
**$0 forever:**

```
1. kr/claude-sonnet-4.5 (Kiro — unlimited)
1. kr/claude-sonnet-4.5 (Kiro — ~50 credits/mo per acct)
2. if/kimi-k2-thinking (Qoder — unlimited)
3. pol/gpt-5 (Pollinations — no key)
4. lc/longcat-flash-lite (50M tok/day backup)
Expand Down Expand Up @@ -800,7 +800,7 @@ Compression: aggressive (~50%) → double your free quota · Cost: $0/mo
| `DATA_DIR` | `~/.omniroute` | Database & config storage |

**Will I be charged by OmniRoute?** No — it's free, open-source software on your machine. You only pay paid providers directly. OmniRoute has no billing system.
**Are FREE providers really unlimited?** Yes — Kiro, Qoder, Pollinations, LongCat, Cloudflare. No catch.
**Are FREE providers really unlimited?** Mostly — Qoder, Pollinations, LongCat, and Cloudflare are free with no per-account credit cap. Kiro is free too but capped at ~50 credits/month per account. Stack multiple free providers in a combo and auto-fallback keeps you serving for $0.
**Will compression hurt quality?** No — it only compresses the **input**; code, URLs, JSON are always protected.
**Does it work where AI is blocked?** Yes — 3-level proxy + 1proxy marketplace reach all 231 providers.

Expand Down
70 changes: 70 additions & 0 deletions bin/_ops-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# bin/_ops-common.sh — shared helpers for the OmniRoute ops runbook scripts.
#
# Sourced (not executed) by rollback.sh / snapshot-data.sh / restore-data.sh /
# restore-policies.sh / cold-start-bench.sh. The runbook context lives in
# docs/INCIDENT_RESPONSE.md and docs/PERF_BUDGETS.md.
#
# Path resolution mirrors the app (src/lib/db/core.ts): the SQLite store is
# $DATA_DIR/storage.sqlite and managed backups go to $DATA_DIR/db_backups
# (overridable via DB_BACKUPS_DIR), so snapshots created here are interchangeable
# with the ones the server writes on migrations.

# Recompute the data-dir-derived paths. Called once on source, and again by
# scripts that accept a --data-dir override.
ops_set_data_dir() {
OMNIROUTE_DATA_DIR="$1"
OMNIROUTE_SQLITE="${OMNIROUTE_DATA_DIR}/storage.sqlite"
OMNIROUTE_BACKUPS_DIR="${DB_BACKUPS_DIR:-${OMNIROUTE_DATA_DIR}/db_backups}"
}
ops_set_data_dir "${DATA_DIR:-$HOME/.omniroute}"

ops_log() { printf '[%s] %s\n' "${SCRIPT_NAME:-ops}" "$*" >&2; }
ops_die() {
printf '[%s] ERROR: %s\n' "${SCRIPT_NAME:-ops}" "$*" >&2
exit 1
}

ops_require_cmd() {
command -v "$1" >/dev/null 2>&1 || ops_die "required command not found: $1"
}

# ops_confirm "<prompt>" — return 0 to proceed. Honors ASSUME_YES=1 (set by the
# --yes flag) and REFUSES a destructive action on a non-interactive stdin unless
# ASSUME_YES is set, so an unattended/CI invocation can never silently destroy data.
ops_confirm() {
local prompt="$1" reply
if [ "${ASSUME_YES:-0}" = "1" ]; then return 0; fi
if [ ! -t 0 ]; then
ops_die "refusing a destructive action without a TTY; pass --yes to proceed non-interactively"
fi
read -r -p "$prompt [y/N] " reply
case "$reply" in
[yY] | [yY][eE][sS]) return 0 ;;
*) return 1 ;;
esac
}

# ops_find_snapshot <id> — resolve a snapshot identifier (a snapshot dir name,
# a bare timestamp/sha, or an explicit path) to a directory containing
# storage.sqlite. Echoes the resolved dir or dies.
ops_find_snapshot() {
local id="$1" cand
[ -n "$id" ] || ops_die "snapshot id required (a timestamp/sha, dir name, or path)"
for cand in \
"$id" \
"$id/" \
"$OMNIROUTE_BACKUPS_DIR/$id" \
"$OMNIROUTE_BACKUPS_DIR/snapshot_$id"; do
if [ -f "${cand%/}/storage.sqlite" ]; then
printf '%s\n' "${cand%/}"
return 0
fi
done
# Fall back to a prefix match against snapshot_* dirs (e.g. a short sha/date).
if [ -d "$OMNIROUTE_BACKUPS_DIR" ]; then
for cand in "$OMNIROUTE_BACKUPS_DIR"/snapshot_*"$id"*; do
[ -f "$cand/storage.sqlite" ] && { printf '%s\n' "$cand"; return 0; }
done
fi
ops_die "no snapshot matching '$id' under $OMNIROUTE_BACKUPS_DIR (run bin/snapshot-data.sh first)"
}
2 changes: 1 addition & 1 deletion bin/cli/runtime/nativeDeps.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { spawnSync } from "node:child_process";
import { platform } from "node:os";
import { resolveDataDir } from "../data-dir.mjs";

const BETTER_SQLITE3_VERSION = "12.9.0";
const BETTER_SQLITE3_VERSION = "12.10.1";

function runtimeDir() {
return join(resolveDataDir(), "runtime");
Expand Down
2 changes: 1 addition & 1 deletion bin/cli/runtime/sqliteRuntime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { pathToFileURL } from "node:url";
import { validateBinaryMagic, platformBinaryLabel } from "./magicBytes.mjs";

const RUNTIME_DIR = join(homedir(), ".omniroute", "runtime");
const BETTER_SQLITE3_VERSION = "better-sqlite3@^12.6.2";
const BETTER_SQLITE3_VERSION = "better-sqlite3@^12.10.1";

let resolvedCached = null;

Expand Down
Loading
Loading