Commit Graph

2644 Commits

Author SHA1 Message Date
Brandon Bennett
8d78e3dfd3 fix: per-connection virtual admission lanes (#9654) (#9940)
* fix: add per-connection virtual admission lanes (#9654)

Worst-day-ever analysis to harden AdaptiveAdmissionController:

- Guard expireEntry() against null entry (CRITICAL null deref)
- Add deleteLane() to drain+reject on LRU eviction (HIGH orphaned promises)
- Fix Map mutation during evictIdleLanes iteration (MEDIUM safety)
- Add ADMISSION_LANE_EVICTED reject code (MEDIUM clarity)
- Pass sessionId to admitChatRequest in route.ts
- virtualLanes defaults to false in validateConfig
- 7 new controller tests + 14 new byte-level admission tests
- Assertions tightened from >= to === (Matt Pocock methodology)

Debunked 2 false positives: concurrency race (single-threaded JS)
and memory amplification (FairCostQueue bounds per-lane).

Fixes #9654

* fix(admission): restore bounded queue-wait on per-connection lanes (#9654)

The per-connection lane refactor dropped the bounded queue-wait
(acquireHeavyWithin / #waiters / queueMs). #9654's acceptance criteria and
#9608 section C prefer server-side wait/pacing up to defaultMaxWaitMs over
an instant retryable 503.

- ChatAdmissionController: re-add #waiters FIFO + acquireHeavyWithin(timeoutMs);
  queueMs: 0 preserves the instant-503 path
- admitChatStructure and admitChatRequest.reserve are async again and take queueMs
- route: pass CHAT_ADMISSION_QUEUE_MAX_MS and await the admission calls
- per-connection lane tests await the async admitChatStructure

Admission suite: 114/114 pass (bun test, 7 files).

* chore: re-trigger CI after dast-smoke infra cancellation (#9654)

* feat(admission): cancel queue-wait on client abort (#9654)

U2 from KC plan 2026-08-09-001. Thread the request AbortSignal through
acquireHeavyWithin so a disconnected client stops parking in the FIFO
for the full queueMs.

- acquireHeavyWithin(timeoutMs, signal?): on abort the waiter is removed
  from the FIFO immediately and the promise resolves null early;
  pre-aborted signals never park; the deadline timer is cleared when
  abort/release wins the race
- admitChatRequest reserve() passes request.signal; admitChatStructure
  gains options.signal; the route threads request.signal
- 5 exact-assertion tests (settle-early, pre-aborted, byte-heavy,
  structural, FIFO-preservation): 119/119 across the 7-file suite

* fix(admission): bound queued bytes for the queue-wait heap valve (#9654)

U3 from KC plan 2026-08-09-001. The restored queue-wait parks fully-buffered
bodies; without a cap, several large coding-agent bodies (~750 KB) waiting at
once recreates the #4380 heap amplification this module was built to stop.

- acquireHeavyWithin(timeoutMs, signal?, queuedBytes): each parked waiter is
  charged its buffered size against CHAT_ADMISSION_MAX_QUEUED_BYTES (default
  4 MB); over-budget waits reject immediately with a retryable 503 and never
  park. The charge is released on wake, abort, or timeout.
- Real sizes threaded from admitChatRequest (declared length / sniffed bytes);
  structural waits charge the conservative 256 KB weight.
- Lower default OMNIROUTE_CHAT_ADMISSION_QUEUE_MS to 2000ms (was 5000ms).
- Env vars documented in .env.example; 6 exact-assertion tests: 125/125 across
  the 7-file admission suite (was 119).

* docs: map the two admission-lane systems for operators (#9654)

U5 from KC plan 2026-08-09-001. Verifies lane metrics are exposed by the health
payload (GET /api/monitoring/health -> adaptiveAdmission -> lane* fields) and
records which lane system reports where: byte-level per-connection lanes (always
on, memory scope) vs adaptive virtual lanes (opt-in via OMNIROUTE_CHAT_VIRTUAL_LANES,
dispatch scope) plus the explicit opt-in ops note.

* docs: add required frontmatter to admission-lanes doc (dast-smoke build fix)

* docs: sync env vars with .env.example and ENVIRONMENT.md (docs gate fix)

* fix(admission): complete REJECT_MAP, literal lane env read, split oversized test file

Three CI-gate fixes surfaced by the post-merge check run (head 3de77166e):

1. open-sse-typecheck (TS2741): REJECT_MAP was missing the ADMISSION_LANE_EVICTED
   entry that controller.ts:662 emits on lane eviction. Add the 503 mapping so the
   Record<AdmissionRejectCode, RejectHttpMapping> is total.
2. Docs Gates fabricated-claim: OMNIROUTE_CHAT_VIRTUAL_LANES was read dynamically
   via ENV_KEYS.virtualLanes (env[key]), invisible to the literal env.X scanner.
   Read it literally — behavior-identical, doc claim now verifiable.
3. check:file-size: chat-body-admission.test.ts (1307 lines) exceeded the 1000-line
   new-file cap. Split the queue-wait/abort/heap-valve section into
   chat-body-admission-queue.test.ts (818 + 513 lines, both under cap).

Suite: 125/125 across 8 files. All three checkers pass locally.

* refactor(admission): drop dead ENV_KEYS.virtualLanes entry + lock lane-evicted mapping test

Code-review follow-up on 50c93d266:

1. ENV_KEYS.virtualLanes is now unreferenced since the literal env read landed;
   remove it so the config map only lists keys actually read through the map.
2. Add an exact-assertion runtime test for the ADMISSION_LANE_EVICTED mapping:
   a queued lane waiter evicted by the 60s idle TTL rejects with 503 /
   admission_lane_evicted / Retry-After 1 / sanitized body (no raw tenant key).
   Proves the REJECT_MAP entry end-to-end through buildAdmissionRejectResponse.

Suite: 126/126 (17 in runtime file, 125 in the 8-file admission suite).

---------

Co-authored-by: Brandon Bennett <brandonbennett@macbookair.myfiosgateway.com>
2026-08-10 03:25:13 -03:00
Vasily Larin
40f9709071 fix(executors): preserve non-strict Codex tool semantics (#9931)
* fix(executors): preserve non-strict Codex tool semantics

* docs(changelog): add Codex strict semantics fix
2026-08-10 03:25:07 -03:00
SB Yoon
e4a7da7526 feat(usage): add Command Code quota tracking (#9921)
Wire Bearer /alpha billing credits and 5h/weekly windows into Provider
Limits and genericQuotaFetcher so dashboard and preflight see live CC quotas.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 03:25:02 -03:00
agisota
b80afbb74f fix(proxy): isolate TLS sessions by account (#9837)
Co-authored-by: Antigravity Agent (via Agisota) <agisota@users.noreply.github.com>
2026-08-10 03:24:51 -03:00
Xiangzhe
2e6c151902 fix(providers): support data URL icons for compatible nodes (#9555)
Co-authored-by: xz-dev <xz-dev@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-10 03:22:59 -03:00
Aman
ee0073dc4a fix(db): invalidate stale LKGP pins on connection delete (#9936) 2026-08-10 02:54:59 -03:00
Bob.Hou
4fc04a5604 fix(combo): classify Cloudflare 1010 fingerprint rejection as non-auth (#9929)
opencode.ai/zen/v1 rejects non-browser clients (urllib) with 403
error_code 1010 while curl on the same key succeeds. The 403 was
treated as an auth-level failure and two of them crystallized a
misleading ALL_ACCOUNTS_INACTIVE on the free pool.

- errorClassifier: new FINGERPRINT_REJECTION type; a 403 carrying
  error_code 1010 / browser_signature_banned is the CDN refusing the
  client TLS/UA signature, not the account credentials.
- combo/targetExhaustion: fingerprint rejections skip auth-level
  exhaustion so remaining targets stay eligible.
- auth: resolveTerminalConnectionStatus no longer treats the
  fingerprint rejection as a terminal banned account state.

UA passthrough is deliberately untouched: #5997/#5720 make the
forward-only behavior load-bearing.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
2026-08-10 00:30:10 -03:00
rinseaid
a93f64ed5f fix(video): support Fal-hosted Grok Imagine Video (#9969)
Co-authored-by: rinseaid <rinseaid@rinseaid.net>
2026-08-10 00:30:04 -03:00
Aman
9bcb48a2d2 fix(db): avoid skipping pending job registry migration 146 (#9965) 2026-08-10 00:30:00 -03:00
backryun
7ad091be11 fix(types): complete responses stream failure contract (#9979) 2026-08-10 00:28:47 -03:00
backryun
cc3aa05c34 fix(stream): collect all synthesized response tool events (#9978) 2026-08-10 00:28:43 -03:00
backryun
160fd55a6d fix(types): normalize stream usage before cost calculation (#9977) 2026-08-10 00:28:37 -03:00
AgnesRiber
4cd9c8e39c fix(i18n): escape angle brackets in denoRelayOrgDomainHint across all 43 locales (#9976)
Replace literal <app-name> and <org-slug> with HTML entities (&lt; &gt;)
in the denoRelayOrgDomainHint translation key for all 43 locale files.

The React Flight (RSC) protocol parser interprets unclosed angle-bracket
tokens as HTML tags, causing INVALID_MESSAGE: UNCLOSED_TAG errors when
rendering the DenoRelayModal component on /dashboard/system/proxy.

Add regression test suite (tests/unit/i18n-deno-relay-unclosed-tag.test.ts)
covering four axes: valid JSON (no BOM), key existence, no raw angle brackets,
and correct HTML entities in all locales.
2026-08-10 00:28:31 -03:00
backryun
578bd379a9 chore(types): remove orphan combo manifest metrics (#9975) 2026-08-10 00:28:26 -03:00
backryun
a13107731f fix(types): type Copilot WebSocket construction (#9974) 2026-08-10 00:28:21 -03:00
backryun
6285cfd26e fix(types): align Claude message contracts (#9973) 2026-08-10 00:28:16 -03:00
backryun
987b03c334 fix(types): narrow combo model collections (#9972) 2026-08-10 00:28:11 -03:00
backryun
de2679f6d1 fix(types): stabilize skill token extraction (#9920) 2026-08-10 00:28:07 -03:00
Donald Thompson
f390327c88 fix(cleanup): prune mcp_tool_audit/a2a_task_events by created_at column (#9963)
Both tables (002_mcp_a2a_tables.sql) store their row timestamp in
created_at; the cleanup queries used WHERE timestamp < ? which does not
exist, so every boot-time cleanup logged:
  Error cleaning mcp_tool_audit: SqliteError: no such column: timestamp
  Error cleaning a2a_task_events: SqliteError: no such column: timestamp
and retention pruning for these two tables never ran. Fix the DELETE
columns and align the log labels/doc comments with the real table names.

Adds source-level invariant tests (cleanup-column-fix.test.mjs) asserting
the created_at column for both tables.
2026-08-10 00:28:02 -03:00
Sahil Singh
d0e15a8c0b fix(backend): retain streaming usage for providers with choices:[{delta:{}}] final chunk (#9938) 2026-08-10 00:27:52 -03:00
Rakibul Hasan
4938a435ea fix(memory): env-configurable strict system-message-first providers (#9924)
* fix(memory): allow OMNIROUTE_STRICT_SYSTEM_PROVIDERS to extend the system-first provider list

PROVIDERS_SYSTEM_MUST_BE_FIRST (added in #6225 for #6135) gates both the
memory-injection placement fix and the #7293 hoistLeadingSystemMessage
translator fix, but was hardcoded to xiaomi-mimo/mimo only. Self-hosted
deployments routing other strict backends (e.g. a custom OpenAI-compatible
connection in front of a self-hosted Qwen3.5+/3.6 model, whose chat template
rejects any non-leading system message the same way) had no way to opt in
without forking and rebuilding the image.

Adds OMNIROUTE_STRICT_SYSTEM_PROVIDERS (comma-separated, case-insensitive
provider ids) to extend the built-in set at read time, mirroring the
injectable-env pattern already used in src/lib/memory/typedDecay.ts. No
behavior change for anyone who doesn't set it.

* chore: fix changelog fragment PR number
2026-08-10 00:27:47 -03:00
Diego Rodrigues de Sa e Souza
6553ba31f2 feat(dashboard): Modality Bridge settings page (vision tabs, model selector, stats, test button) (#9782)
* feat(i18n): modality bridge page strings (en + synced locales)

* feat(dashboard): ModalityBridgeVisionTab + stats row + test button

* feat(dashboard): Modality Bridge settings page with vision/audio/video tabs + sidebar entry

* feat(dashboard): relocate vision bridge card to link + media-providers shortcuts

* docs(guardrails): document Modality Bridge dashboard

* chore: preserve upstream formatting after base merge

* fix(modality-bridge): satisfy i18n quality gates

* fix(i18n): preserve canonical Chinese glossary terms

* fix(modality-bridge): clear dashboard quality regressions

* fix(settings): use catalog-only modality labels

* fix(i18n): isolate modality bridge availability copy

* chore(i18n): prepare conflict-free Modality Bridge base sync

* docs(modality-bridge): align migration note with dead-code decision

* fix(i18n): sync capability filter locales after release merge

* fix(i18n): restore canonical Traditional Chinese glossary

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-08-10 00:16:06 -03:00
Diego Rodrigues de Sa e Souza
06a691f8fe Merge pull request #9424 from diegosouzapw/feat/5696-layer-a-capability-filter
feat(core): add Layer A capability filter at router (#5696)
2026-08-09 20:51:28 -03:00
SB Yoon
40e1562850 fix(i18n): re-escape CC discovery-alias angle brackets for next-intl (#9917)
* fix(i18n): re-escape CC discovery-alias angle brackets for next-intl

Restore #8747 HTML-entity escaping for claude/<provider>/<model> in the
three CC discovery-alias message keys so next-intl stops logging
INVALID_MESSAGE: UNCLOSED_TAG on provider detail pages after the bulk
entity-unescape regression.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(i18n): align conflict context with release

* fix(i18n): cover localized CC alias placeholders

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
2026-08-09 20:27:18 -03:00
diegosouzapw
63bf4b909d Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9424
# Conflicts:
#	config/quality/file-size-baseline.json
2026-08-09 20:02:17 -03:00
Diego Rodrigues de Sa e Souza
fade1cbab3 Merge pull request #9341 from diegosouzapw/feat/9268-gemini-schema-recursive-type-empty-choices
feat(gemini): recursive schema type:object + empty choices interceptor (#9268)
2026-08-09 20:01:44 -03:00
Diego Rodrigues de Sa e Souza
3aa0a7306f Merge pull request #9337 from diegosouzapw/feat/9322-nanogpt-endpoint-surface
feat: expose full NanoGPT endpoint surface (#9322)
2026-08-09 20:01:41 -03:00
diegosouzapw
9747123f00 test(flags): account for capability filter flag 2026-08-09 19:41:17 -03:00
Diego Rodrigues de Sa e Souza
ab8f3e83b7 fix(ci): allow test-masking to finish in release preflight (#9964)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-08-09 19:41:03 -03:00
diegosouzapw
e53ca645f3 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9424 2026-08-09 19:23:58 -03:00
diegosouzapw
cf0f416da3 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9424 2026-08-09 18:57:50 -03:00
diegosouzapw
2c8cb81fc0 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9341 2026-08-09 18:57:46 -03:00
diegosouzapw
1287a4f2ec Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9337 2026-08-09 18:57:00 -03:00
diegosouzapw
99781e000d Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave2b-9784 2026-08-09 18:56:19 -03:00
diegosouzapw
493cae2ed9 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9424
# Conflicts:
#	config/quality/file-size-baseline.json
#	src/i18n/messages/en.json
#	src/i18n/messages/pt-BR.json
#	src/shared/constants/featureFlagDefinitions.ts
#	stryker.conf.json
2026-08-09 18:25:44 -03:00
diegosouzapw
a6f095c583 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9341
# Conflicts:
#	config/quality/file-size-baseline.json
2026-08-09 18:25:42 -03:00
diegosouzapw
26daeabcf2 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave3b-9337
# Conflicts:
#	open-sse/config/providers/registry/nanogpt/index.ts
2026-08-09 18:25:16 -03:00
diegosouzapw
c6de098630 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave2b-9784 2026-08-09 18:21:12 -03:00
diegosouzapw
792626c3c4 Merge remote-tracking branch 'origin/release/v3.8.50' into codex/wave2b-9749 2026-08-09 18:20:53 -03:00
diegosouzapw
181828625b fix: clear release unit and quality regressions 2026-08-09 17:54:23 -03:00
diegosouzapw
b7bad4006b fix(release): clear remaining Adobe and typecheck gates 2026-08-09 17:02:47 -03:00
Diego Rodrigues de Sa e Souza
c6195cec62 fix(security): harden Adobe credential parsing gates 2026-08-09 16:31:24 -03:00
diegosouzapw
8c009f55e9 Merge commit 'refs/codex/pr-9619-head' into merge-prs-base-9945 2026-08-09 16:23:20 -03:00
benzntech
14b6183693 test(providers): cover web session fast path
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-09 16:20:54 -03:00
benzntech
0bb3bc093c fix(logging): cover opt-in diagnostics
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-09 16:20:54 -03:00
Will Gordon
326a975084 fix(combo): restore hard capability filtering
Restore the shared media detector and the hard-reason set lost by the maintainer cherry-pick. Re-document the two live low-memory controls and cover nested case-insensitive image indicators.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-09 15:39:22 -03:00
diegosouzapw
0d36801f20 Merge remote-tracking branch 'origin/release/v3.8.50' into fix/release-v3.8.50-post-sweep-base-red
# Conflicts:
#	src/i18n/messages/vi.json
2026-08-09 15:21:37 -03:00
diegosouzapw
754ba0fa86 fix(release): repair post-sweep base regressions 2026-08-09 15:16:55 -03:00
rinseaid
240b9b5bc4 fix(image): return fal defaults as base64 (#9932)
Co-authored-by: rinseaid <rinseaid@rinseaid.net>
2026-08-09 14:19:22 -03:00
Diego Rodrigues de Sa e Souza
382449d593 maint: follow-up cherry-pick fix-in-place #9711 (conflict-resolved fallback) (#9891)
* fix(sse): grace period before finalizing a client disconnect as 499 (#9653)

A client that closes its connection right after reading a fully-completed
SSE stream can race OmniRoute's own completion bookkeeping: the bytes
already reached the client, but the transform stream's own completion
callback (onStreamComplete, which flips streamCompletionRecorded) hasn't
finished bubbling up when the disconnect handler fires, so the request gets
persisted as a false 499 with zero token usage even though it delivered its
full response.

Confirmed live on real traffic before this fix: a request whose server log
showed "disconnect: request_signal_aborted" at 18236ms was persisted with
status 200 and full token usage (82814/1292) once the grace period let the
real completion win the race, matching what the client actually received.

createClientDisconnectGraceHandler (new leaf in
streamFailureFinalization.ts) polls isStreamCompletionRecorded() for up to
STREAM_DISCONNECT_GRACE_PERIOD_MS (default 10s, env-configurable, 0
disables) before finalizing as a failure. If a real completion lands within
the window, handleStreamFailure's own guard is a no-op and the genuine 200
stands.

Covered by tests/unit/stream-disconnect-grace-period-9653.test.ts (fake-timer
driven: already-recorded completion short-circuits, disabled-grace-period
finalizes immediately, a completion landing mid-window skips finalize
entirely, and no completion ever landing finalizes once the deadline
passes).

(cherry picked from commit 5d0fe28c42)

* chore(quality): rebaseline chatCore.ts for the disconnect grace-period fix

Own growth from the disconnect grace-period fix: 5030->5039 (+9, the
createClientDisconnectGraceHandler wiring at the existing
onClientDisconnectFinalize call site).

---------

Co-authored-by: Markus Hartung <mail@hartmark.se>
2026-08-09 10:08:25 -03:00