mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 04:12:17 +03:00
`PipelineStateHooks` declares `recordRateLimitHeaders`/`recordRateLimitBody`
and chatCore injects both at its two call sites, but neither was ever invoked:
grep -rn "recordRateLimitBody(" open-sse/ --include=*.ts -> no callers
grep -rn "recordRateLimitHeaders(" open-sse/ --include=*.ts -> no callers
The consequence only bites the non-streaming leg. chatCore's own
updateFromHeaders/updateFromResponseBody pair lives inside the labeled
`providerFailure:` block, which the streaming leg still reaches after the
pipeline returns an error outcome — but the non-streaming leg returns
`legResult` straight to the caller before ever getting there. So an upstream
429 on a non-streaming request never informed the limiter, by header or by
the retry-after embedded in the JSON body: the Bottleneck reservoir stayed
full and the account kept getting hammered.
Invoke both hooks right after the 2xx early-return and before any recovery
branch, so the 429 is attributed to the connection that actually took it
(codex rotation moves on to another account). Order matters and mirrors the
chatCore path: headers first — a 429 evicts the cached limiter on purpose —
then the body, which materializes a fresh one and drains its reservoir.
The error body is read through `attempt.response.clone()`, never the original
stream: this is a shared streaming path and consuming it would silently break
passthrough and SSE. `toOutcome`, the antigravity 422 rotation and the
signature-recovery block already drain the same Response the same way.
Second defect in the same function, proven by the file's other test: when the
upstream error body is not JSON, `toOutcome` swallowed it and fell back to
statusText ("upstream error"). parseUpstreamError — the pre-pipeline path this
replaced — surfaces the raw text. Restore that; buildErrorBody/
sanitizeErrorMessage still sanitize it before it reaches any response body.
Both were pre-existing base-reds on release/v3.8.51.