github diegosouzapw/OmniRoute v3.8.18

4 hours ago

✨ New Features

  • feat(ui): unified Active + Finished requests into a single view — the dashboard now shows in-flight and completed requests in one list with deep-linking, live streaming detail, and a dedicated /api/logs/[id] detail route; pending requests are tracked per connection and finalized as they complete. (#3401 — thanks @hartmark / @diegosouzapw)
  • feat(plugins): plugin lifecycle hooks + theme-manager example — adds onInstall/onActivate/onDeactivate/onUninstall lifecycle events dispatched by the plugin manager, thins index.ts to a backward-compatible re-export shim over hooks.ts, and ships theme-manager + request-logger example plugins. (#3473 — thanks @oyi77 / @diegosouzapw)
  • feat(browserPool): Playwright proxy resolved from the proxy registry — browser-backed providers (claude-web/gemini-web) now route through the configured per-provider/global proxy instead of connecting directly, matching how OAuth/token-refresh already honor resolveProxyForProvider (closes the VPS IP-rate-limit gap for the browser path). Fully additive with graceful degradation. (#3492 — thanks @borodulin)

🔧 Bug Fixes

  • fix(executor): Llama / OpenAI-compat base URL normalization — a baseURL without a path (e.g. llama.example.foo) or with a non-/v1 path (e.g. bar.example.com/foo) now correctly gets /v1/chat/completions appended, fixing the 404 on message sends while GET /model still worked. (#3519 — thanks @hartmark)
  • fix(sse): empty-choices chunks without usage are dropped instead of injecting retry text — a streamed chunk carrying an empty choices array and no usage is now silently skipped rather than emitting placeholder retry text into the stream, eliminating spurious content for clients that send such keepalive-style frames. (#3513 — thanks @diegosouzapw)
  • fix(types): restored a clean typecheck:core — typed getPendingRequests() to its real shape (Record<string, Record<string, number>>) so the unified-requests view (#3401) no longer treats pending counts as unknown, cast the streamChunks log payload to its declared type, and aligned preScreenTargets (#3169) to the canonical IsModelAvailable signature (sync-or-async, normalized via Promise.resolve). (thanks @diegosouzapw)
  • fix(opencode-plugin): repaired the corrupted index.ts that broke the npm publish-opencode-plugin build (introduced by the #3435 branch) — removed two duplicated code blocks (apiFormat + debug-logging), dropped the local normaliseFreeLabel superseded by the naming.ts extraction, fixed an undefined sdkBaseURL reference, declared the missing startupDebug / logLevel feature-schema fields, and fixed shortProviderLabel dropping the prefix on a long displayName with no alias. Plugin now builds (DTS clean) with all 254 tests green. (#3435 — thanks @diegosouzapw)
  • fix(catalog): Codex CLI model-catalog refresh no longer errors — GET /v1/models now returns a top-level models: [] array for Codex clients (detected via the originator / user-agent = codex_* headers it sends on GET /v1/models?client_version=...), so codex_models_manager stops failing to decode the OpenAI-standard response and no longer logs failed to refresh available models on every startup. The array is intentionally empty: Codex replaces its built-in per-model agent prompt (base_instructions, ~21k chars) with whatever a populated entry carries for the selected model, so emitting our catalog would break Codex's agent behaviour — an empty list keeps Codex on its built-in model info (same inference as before, minus the error). Non-Codex OpenAI clients receive the unchanged {object,data} response. (#3481 — thanks @diegosouzapw)
  • fix(provider): Cursor's Responses-API-shaped bodies on /chat/completions are detected and handled — a body with input but no messages is now classified as openai-responses (instead of forcing openai and building from undefined messages → upstream 400); standard OpenAI clients are unaffected by the messages===undefined guard. (#3490 — thanks @borodulin)
  • fix(sse): numeric provider IDs normalized to strings across 4 more surfaces — extends #3427 to the Responses-API SSE passthrough (response_id/item_id/call_id), the buffered/flush path in stream.ts, the dedup-key builders, and sseParser.ts, preventing undefined lookups when IDs arrive as numbers. (#3451 — thanks @disafronov)
  • fix(theoldllm): X-Request-Token generated server-side, dropping the Playwright dependency — replicates the site's client rie() token (djb2 hash + oldllm-client-2026 seed + UA prefix + 8-hex crypto.randomUUID suffix) directly, so The Old LLM no longer needs a headless browser to mint tokens. (#3491 — thanks @borodulin / @diegosouzapw)
  • fix(combo): parallel pre-screen + circuit-breaker fast-exit for priority combos — provider profiles and model availability for all targets are pre-screened concurrently (max 5), and targets whose circuit breaker is OPEN are skipped immediately, reducing first-token latency on multi-target priority combos. (#3169 — thanks @pizzav-xyz)
  • fix(authz): URL-tokenized client endpoints (/api/v1/vscode/<key>/...) authenticate again when the caller sends its own non-OmniRoute Authorization header — a non-Bearer <token> header (e.g. VS Code Copilot's own, or an empty Bearer ) no longer short-circuits auth; it falls through to the path-scoped URL token (still validated downstream), instead of 401'ing under REQUIRE_API_KEY=true. (#3504 — thanks @zhiru / @diegosouzapw)
  • fix(playground): the dashboard provider Test playground works under REQUIRE_API_KEY=true — it previously sent the masked key (sk-xxxx****yyyy) as a bearer (always invalid → 401). It now authenticates via the dashboard session and sends only the key id (x-omniroute-playground-key-id); the gateway resolves the secret server-side, honored only for an authenticated session and never putting the key secret on the wire. (#3503 — thanks @zhiru / @diegosouzapw)

📝 Maintenance

  • feat(docs): doc-accuracy gate — new npm run check:fabricated-docs (scripts/check/check-fabricated-docs.mjs) indexes the codebase (api routes, env vars, CLI commands) and flags API-path/env-var/CLI/hook/file-ref claims in docs/** + AGENTS.md that don't exist in source (soft-fail by default, --strict for CI; wired into check:docs-all). Also refreshes the AGENTS.md live counts against source. (#3510 — thanks @oyi77)
  • chore: ignore local quality reports and prompt artifacts (quality-metrics.json, PLANO-/RELATORIO-QUALITY-GATES.md, stray prompt .txt files) so they no longer surface in git status. (thanks @diegosouzapw)

🔒 Security

  • fix(opencode-plugin): bounded the regex quantifiers in normaliseFreeLabel to close a polynomial-ReDoS (CodeQL js/polynomial-redos) — an unbounded \s* before an anchored \s*$ allowed O(n²) backtracking on attacker-influenced provider/model display names; bounded to {0,8}/{1,8}. (thanks @diegosouzapw)

What's Changed

Full Changelog: v3.8.17...v3.8.18

Don't miss a new OmniRoute release

NewReleases is sending notifications on new releases.