Skip to content

Route across logins and keys with CPA's strategies, retries and cooldowns - #24

Merged
playgrndlabs-bot merged 3 commits into
mainfrom
claude/project-thread-foif0l
Oct 28, 2026
Merged

playgrndlabs-bot merged 3 commits into
mainfrom
claude/project-thread-foif0l

Conversation

@playgrndlabs-bot

Copy link
Copy Markdown
Contributor

Requested by PlaygrndLabs · project thread

What this does

Item 4 of the plan (routing polish) for the Workers-only install, following CPA's auth conductor (sdk/cliproxy/auth) and its v8 config.

  • Each login is its own candidate. Before, several Claude or ChatGPT logins shared one cached token, so a retry after a 429 went back to the same account. Now a rate-limited or failing login is skipped for the next one, like API keys. Logins read priority, weight, prefix, disable_cooling and request_retry from their auth file, as CPA does.
  • Strategies (routing.strategy): round-robin (default), weighted-round-robin and fill-first, within the highest priority, with lower priorities as fallbacks.
  • Retry rounds (routing.retry.request-retry, max-retry-credentials, max-retry-interval), with per-key and per-login request-retry overrides. A later round waits for the soonest cooldown only if it ends within max-retry-interval.
  • Cooldowns (new free/src/routing.ts), with CPA's durations: 429 waits for the provider's stated reset (Retry-After, Anthropic's rejected unified window, Codex usage_limit_reached, Gemini RetryInfo), with a 10 s floor, or else CPA's 1 s → 30 min backoff. 401/402/403 on a key rest it for 30 min, 404 rests that model for 12 h, and transient errors rest it for 60 s (cooldown.transient-error-cooldown-seconds). disable-cooling works globally, per key and per login. If every credential is cooling, the client gets a 429 with Retry-After and no upstream call is made.
  • Shared across isolates. Cooldowns are reported to the Durable Object in the same batched flush as usage, and come back in the routing table (cached up to 60 s).
  • Dashboard. Auth Files shows cooldowns, unavailable, next_retry_after and status in CPA's shape (checked against the latest panel's parser), and POST /v8/management/routing/cooldown/reset really clears them now.

Behaviour changes to note

  • Under the default round-robin, key weights no longer skew turns: CPA only uses weights under weighted-round-robin. Weight 0 now takes a key out of weighted rotation, as in CPA.
  • With two or more Claude logins, Claude Code bodies are read once so they can be sent again on failover. That costs about 1.9 ms of CPU for 600 KB (new CPU test). With a single login and nothing else, requests still stream through unread.
  • A 401 on a login refreshes its token and rests it only for the transient window, not 30 min, since the refresh usually fixes it.
  • A success clears all of that credential's cooldowns, including other models' 404s. That's simpler than CPA's per-model clear.

Limits

At most 10 upstream attempts and 2 minutes of waiting per request, to stay inside the Free plan's 50 subrequests.

Security pass

  • The reset endpoint goes through the existing sign-in cookie + management key check, like every /v8/management route.
  • Cooldown views hold only reason codes, model names, status codes and times. They never include upstream bodies, keys or tokens. API-key cooldowns are keyed by config position, and every config edit clears them.
  • cool() is reachable only over the Worker→DO binding. It is still bounded: 200 events, length caps, at most 24 h, backoff level capped.
  • Bodies are read for wait hints only on 429 and only up to 64 KB.
  • An error for a removed or disabled login no longer names the login file, which contains an email.
  • Nothing new is forwarded upstream, and no cloaking.

Tests

npm run verify: typecheck, lint and 178 tests pass. New tests cover login failover, cooldown sharing, all-cooling 429, the last error returned whole, no failover on 400, retry rounds with a wait, max-retry-interval, priority and disable-cooling, prefix logins, ChatGPT login failover, reset, the DO's routing state and the management views.


Generated by Claude Code

…owns

Each Claude and ChatGPT login is now a candidate of its own, so a request
moves on to the next login when one is rate limited or failing, as it
already did for API keys. The new free/src/routing.ts follows CPA's auth
conductor: round-robin, weighted-round-robin and fill-first strategies,
request-retry rounds with max-retry-credentials and max-retry-interval,
and cooldowns (Retry-After and provider reset hints, the 1 s to 30 min
quota backoff, 30 min for 401/402/403 keys, 12 h for 404, 60 s for
transient errors), with disable-cooling and request-retry overrides per
key and per login. Isolates share cooldowns through the Durable Object,
the Auth Files list shows them in CPA's shape, and the dashboard's reset
button clears them.
@playgrndlabs-bot playgrndlabs-bot self-assigned this Oct 28, 2026
…-foif0l

# Conflicts:
#	free/README.md
#	free/src/account.ts
#	free/src/app.ts
#	free/src/management.ts
#	free/src/providers.ts
#	free/test/management.test.ts
…-foif0l

# Conflicts:
#	free/README.md
#	free/src/account.ts
#	free/src/app.ts
#	free/test/app.test.ts
@playgrndlabs-bot
playgrndlabs-bot merged commit 289e570 into main Oct 28, 2026
4 checks passed
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