feat: spend budgets - #8
Conversation
What it actually doesPer-secret (Anthropic/OpenAI) spend caps, enforced in the Rust gateway with real metering.
Why it existsCost control for org/project-owned LLM credentials proxied through the gateway — cap spend on a secret so a runaway agent or leaked key can't rack up unbounded provider bills. Reading order
Low risk, skim: What to scrutiniseThe flush-lag race is larger than the code's comments suggest. WebSocket-tunnelled usage is never metered. The 402 gate does run on WS upgrades, so an already-over budget correctly blocks a new connection. But once a tunnel is established, Best-effort substring parsing is spoofable in principle.
Error paths look defensible — verify the state machine. Retries are not double-counting. A retried request is a genuinely new upstream call with its own Design decisions worth questioning
Test coverage reality
Zero tests for
Untested paths worth naming: the 402 body's shape under load; concurrent-request overshoot; Forward-looking: upstream v1.45.0 inserts a Reviewer orientation guide — produced by analysing this PR's diff and surrounding code, not the commit messages. Claims about line numbers and behaviour are worth spot-checking as you read; where it says something is untested or risky, that was verified against the tree rather than inferred. |
Reconciliation Stage I (final). Per-secret monthly cost caps: the gateway meters anthropic/openai token usage post-response (bounded stream tee, no byte corruption, Accept-Encoding: identity so usage parses, prompt-cache tokens priced), keeps a nano-dollar running total in the cache counter, and enforces a pre-request 402 when over. Fail-OPEN on any metering or read error (a cost control, not a security gate) while an over-budget org is still blocked; the budget gate runs after the security decision so it can never turn a Block into an allow. Org-scoped budget CRUD on the eeRoutes seam + a Budgets tab. The reconciliation preserved every hook site, so forward.rs needed no edits. +21 gateway / +12 api tests, no agent-group, no migration.
36aebad to
caaf574
Compare
Per-agent and per-project spend budgets with metered enforcement in the gateway. 20 files, +2,523/−35 — ~1,960 lines of code plus ~560 of tests.
This PR is the tail of the split: it was the original 381-file open-edition PR, now reduced to just its last two commits (
741a45cspend budgets,36aebadgitignore). Everything else moved into the stack below.gateway/hooks.rsgains the real budget implementation —prepare_requestforcesAccept-Encoding: identityfor metered hosts so responses can be measured. Worth knowing for the next upstream bump: upstream v1.45.0 inserts arefuse_empty_scopehook at exactly the same anchor (see #9's review doc — it's an adjacent-insertion conflict, keep both).Stack
Split out of the original 381-file #8. Upstream catch-up (v1.42.0 → v1.44.0) already landed as #10, so
mainis now v1.44.0 and everything below is our own code.Review and merge in order, top to bottom. Roughly half of each diff is tests.