feat: per-model routing with configurable routes#86
Merged
Conversation
Route requests by model family so an account is gated and ranked on the quota bucket that actually governs each request, not a blanket max across all buckets. A spent Fable/Sonnet weekly bucket now bars only that family; the account keeps serving Opus/Sonnet, and selection spends the account whose governing weekly resets soonest. - account-manager: model-aware _isNearQuota/_maxUtilization/reset ranking (governing bucket per family); replaces the Fable-only special case. - Configurable routes: a `routes` table pins model globs to an exclusive set of accounts (with optional quota-bucket override). First match wins; no match falls back to the legacy per-account `models` claim. Applied live on config reload. Manage via `teamclaude route list|add|rm` or the TUI settings screen (g -> Manage routing; a/e/d). - Show the request model live: peek the top-level `model` from the request stream during buffering and surface it on the in-flight TUI rows (base and MITM paths). - Console: status + TUI show a routing table (configured + auto-detected routes) and a per-account per-model eligibility line. - Tests for glob matching, exclusive/bucket-override routing, reload, streaming model peek, status rendering, and the TUI routes editor. - README: Model routes section, config row, and command. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adding/editing a route flashed back to the main dashboard because the render dispatch only special-cased 'settings'/'routes'; in 'input' mode it fell through to the main body. Render the screen the prompt was launched from (inputReturn) so routes/settings stay visible with the prompt in the footer. Co-Authored-By: Claude Opus 4.8 <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.
What
Turns model routing from a single implicit pipe into per-model routing over one shared account pool, and makes the model categories configurable. Addresses #85 (per-model routing) and the "show the request model immediately" gap.
Behavior (works with zero config)
Selection used to gate/rank every request on the shared
unified5h/unified7dbuckets, so an account whose Fable bucket was spent looked busy for everything. Now each request is gated and ranked on the bucket that governs its family:fable → unified7dFable,sonnet → unified7dSonnet,opus/other → unified7d, all still under the shared 5h.This generalizes (and removes) the old Fable-only special case, and Sonnet is now consulted the same way.
Configurable routes
A
routestable pins model globs to an exclusive set of accounts (first match wins), with an optional quota-bucket override:modelsclaim, so existing configs keep working (routes supersede it).teamclaude route list|add|rm, or the TUI settings screen (g→ Manage routing;a/e/d).Show the request model live
The model now streams into the TUI in-flight rows the instant the top-level
modelfield is peeked from the request body (via the existing streaming finder), on both the base and MITM paths — previously it only appeared once the request finished.Console
statusand the TUI show a Routing table (configured routes + auto-detected family routes tagged(auto), derived live and never persisted) plus a per-account per-model eligibility line (Models Opus ✓ Fable ✗ 2d/⊘ Fable).Tests
+17 tests: glob matching, exclusive routing + index match + bucket override + legacy fallback + reload, streaming model peek, status routing/eligibility rendering, and the TUI routes editor (add/edit/delete). Full suite green (217), lint clean.
Notes
master(1.1.5), which already merged WIP Fix: recover from network drops without restarting #73/feat: add third-party backend account support (upstream, modelMap, models) #74/Feature request: start idle accounts’ 5h timers with a minimal request #76/Fix: revalidate throttled accounts so a stale 429 hold cannot require a restart #77.🤖 Generated with Claude Code