Parent: #257 — Layer 4 (Optimization)
What
Two responsibilities, split across layers:
Counting (in dispatch, Layer 0)
Every dispatch() call increments the counter for the backend used:
const UsageTracker = struct {
claude_calls_5h: u32 = 0,
codex_calls_5h: u32 = 0,
window_start_ns: i128,
pub fn record(self: *UsageTracker, backend: Backend) void { ... }
};
Load balancing (in resolve, Layer 1)
resolve() checks usage before picking a provider. If the resolved provider is near its quota limit (warn_at_percent from config), resolve() switches to the other provider:
// Inside resolve():
if (resolved.backend == .claude and usage.claudeNearLimit(providers.config)) {
resolved.backend = .codex;
resolved.model = mapToCodexEquivalent(resolved.model);
}
This only activates when both providers are available. Single-provider setups just warn.
Depends on
Parent: #257 — Layer 4 (Optimization)
What
Two responsibilities, split across layers:
Counting (in dispatch, Layer 0)
Every
dispatch()call increments the counter for the backend used:Load balancing (in resolve, Layer 1)
resolve()checks usage before picking a provider. If the resolved provider is near its quota limit (warn_at_percentfrom config), resolve() switches to the other provider:This only activates when both providers are available. Single-provider setups just warn.
Depends on