Skip to content

feat: per-model routing with configurable routes#86

Merged
MagicalTux merged 3 commits into
masterfrom
feat/per-model-routing
Jul 7, 2026
Merged

feat: per-model routing with configurable routes#86
MagicalTux merged 3 commits into
masterfrom
feat/per-model-routing

Conversation

@MagicalTux

Copy link
Copy Markdown
Member

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/unified7d buckets, 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.
  • A spent Fable/Sonnet weekly bucket bars only that family; the account keeps serving the others.
  • Selection spends the account whose governing weekly resets soonest, preserving accounts that reset later for other families.
  • Falls back to the shared weekly when a family bucket isn't reported, so nothing sails past an overall cap.

This generalizes (and removes) the old Fable-only special case, and Sonnet is now consulted the same way.

Configurable routes

A routes table pins model globs to an exclusive set of accounts (first match wins), with an optional quota-bucket override:

"routes": [
  { "name": "fable", "match": ["*fable*"], "accounts": ["personal-max"] },
  { "name": "bulk",  "match": ["*opus*","*sonnet*"], "accounts": ["corp-1","corp-2"], "bucket": "unified7d" }
]

Show the request model live

The model now streams into the TUI in-flight rows the instant the top-level model field 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

status and 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

🤖 Generated with Claude Code

MagicalTux and others added 3 commits July 7, 2026 20:42
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>
@MagicalTux MagicalTux merged commit 4408888 into master Jul 7, 2026
5 checks passed
@MagicalTux MagicalTux deleted the feat/per-model-routing branch July 7, 2026 12:19
@MagicalTux MagicalTux mentioned this pull request Jul 7, 2026
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.

1 participant