Skip to content

\ feat: operator-configurable account rotation\ - #6763

Merged
diegosouzapw merged 8 commits into
diegosouzapw:release/v3.8.47from
artickc:feat/configurable-account-rotation
Jul 11, 2026
Merged

diegosouzapw merged 8 commits into
diegosouzapw:release/v3.8.47from
artickc:feat/configurable-account-rotation

Conversation

@artickc

@artickc artickc commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes OmniRoute's account-fallback rotation operator-configurable at runtime, instead of the fully hardcoded COOLDOWN_MS / BACKOFF_CONFIG / ERROR_RULES behavior.

This is useful when a supervising front-end/orchestrator (e.g. a desktop app) manages the same set of accounts and wants the backend to rotate according to the operator's own rules — per-HTTP-status enable, per-status error threshold/window, and the rate-limit cooldown — without forking the engine.

New module open-sse/services/rotationConfig.ts reads the config from environment variables, with an optional per-connection override taken from a connection's providerSpecificData.rotationOverrides. All defaults preserve the current engine behavior, so this is a no-op unless an operator sets the env vars.

Config surface (all optional)

Env var Default Effect
OMNIROUTE_ROTATION_ENABLED true Master switch for the gated classes
OMNIROUTE_ROTATION_RATE_LIMIT_RESET_SECONDS 0 (engine default) 429 cooldown when no upstream Retry-After hint
OMNIROUTE_ROTATE_ON_429 / _500 / _502 / _400 true/true/true/false Per-status account-fallback enable
OMNIROUTE_ROTATE_{status}_THRESHOLD 1 (immediate) Errors within the window before rotating
OMNIROUTE_ROTATE_{status}_WINDOW_SECONDS 120 Sliding window for the threshold

Per-connection overrides (same keys, camelCase: rotateOn429, error429Threshold, error429WindowSeconds, rateLimitResetSeconds, …) can be supplied via providerSpecificData.rotationOverrides.

Wiring (checkFallbackError)

  • 429 / 500 / 502 are restrictively gated — when disabled, the error returns to the client instead of rotating. 502 is tracked as its own class (separate window/count from generic 5xx).
  • 400 is additive / opt-in (off by default): a plain 400 still does not rotate, and a 400 carrying rate-limit text still falls over exactly as before — [BUG] MiMo-auto fails to fallback on 400 Rate Limits from free providers, causing 502 Fetch Failed in Cline #4976 preserved.
  • A per-class sliding-window threshold holds off rotation until N errors occur within the window (default threshold 1 ⇒ rotate immediately, unchanged).
  • The rate-limit cooldown override applies to 429 only when there is no upstream Retry-After hint; 5xx/capacity keep their scaled exponential backoff.

Everything is pure functions + a small in-memory counter — no DB/IO on the hot path.

Tests

tests/unit/rotation-config-omniroute.test.ts — 12 cases (env parse, per-connection override merge, restrictive/additive gate semantics, sliding-window threshold, and checkFallbackError integration incl. the #4976 regression). Existing account-fallback suites stay green.

✔ 12 pass / 0 fail  (rotation-config-omniroute.test.ts)
✔ 19 pass / 0 fail  (accountfallback-ratelimit-400-4976 + retry-after-json + persist-429-cooldown + route-restriction-403)

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants