feat: opt-in keep-warm for idle accounts + per-account pin endpoint (#76)#80
Merged
Merged
Conversation
) Idle accounts' rolling 5h session window only starts on real usage, so a cold account's timer begins exactly when rotation reaches it — right when its full headroom is needed. Keep-warm starts that timer ahead of time. - src/warmer.js: opt-in Warmer (mirrors Prober). On an interval it warms each eligible idle account by spawning a minimal one-shot `claude -p --bare --model haiku "hi"` pointed at this proxy, pinned to that account. Warms only healthy, idle, Anthropic OAuth accounts whose 5h window is NOT already running (skips disabled/throttled/errored and third-party backends), to keep the quota cost minimal. Injectable spawnFn for tests; per-account status via getStatus(). - src/server.js: account-pin routing. A request to `/tc-acct/<name-or-index>` (e.g. ANTHROPIC_BASE_URL=.../tc-acct/deepseek) is forced onto that one account with no rotation and no failover; the prefix is stripped before forwarding. resolveAccountPin() exported for tests. - src/index.js: wire the Warmer (start/stop/reschedule/status), gated on config.warmupSeconds (default 0 = off); `teamclaude warmup <off|secs>` CLI. - src/prober.js: note there are now two sanctioned active features. Unlike the passive quota probe (a zero-spend usage read), keep-warm sends a real message and therefore spends a little quota — hence strictly opt-in and window-aware. Requires the `claude` CLI on PATH. Tests: account-pin (resolver + end-to-end routing, prefix strip, 404, rotation override) and warmer (eligibility, spawn spec, status, error paths, scheduling). 180 tests pass, lint clean. Closes #76 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #76: keep idle accounts' 5-hour session timers running so the next account isn't cold when rotation reaches it.
Why
The rolling 5h window only starts on real usage. So when the active account runs out and rotation moves to a cold account, that account's 5h window starts then — right when you need its full headroom. Keep-warm starts the timer ahead of time.
What
src/warmer.js— opt-inWarmer(mirrorsProber). On an interval, for each eligible idle account it spawns a minimal one-shotclaude -p --bare --model haiku "hi"pointed at this proxy, pinned to that account. Warms only healthy, idle, Anthropic OAuth accounts whose 5h window is not already running (skips disabled/throttled/errored + third-party backends) and uses the cheapest model, to keep the cost minimal. InjectablespawnFnfor tests; per-account status viagetStatus().src/server.js— account-pin routing. A request to/tc-acct/<name-or-index>/...is forced onto that one account, no rotation and no failover; the prefix is stripped before forwarding.resolveAccountPin()exported for tests. This is what the warmer uses, and it doubles as a manual way to target one account.src/index.js— wire the Warmer (start/stop/reschedule/status), gated onconfig.warmupSeconds(default0= off);teamclaude warmup <off|secs>CLI, live-reschedulable.The quota probe is a zero-spend usage read. Keep-warm is different: the 5h timer cannot be started by a read-only call, so it sends a real (minimal) message and therefore spends a little quota (a few tokens + a slice of the 5h/weekly buckets per account per window). That's why it's strictly opt-in, window-aware, and cheapest-model.
prober.js's "one sanctioned active feature" note is updated to reflect there are now two.Manual test
Tests
account-pin.test.js(resolver + end-to-end routing, prefix strip, 404, rotation override) andwarmer.test.js(eligibility, spawn spec, status, error paths, scheduling). 180 tests pass, lint clean.Note for review
Unit/integration tests fully cover the pin routing and the warmer's decision/spawn logic, but CI can't exercise the real
claude --baresubprocess end-to-end (no live accounts). I verified the CLI flags exist (--bare,-p,--model,--output-format); a live smoke test against a running server is worth doing before relying on it.Closes #76
🤖 Generated with Claude Code