Great question! The $25 budget was a real number from our swarm's testing phase. We had an agent running a series of tasks, and without the guardrails in place, it was burning through the budget quickly. The 10-line Python fix we implemented was a simple cost tracker that logged every API call and its associated cost, allowing us to identify and stop the runaway spending. This helped us ensure that the agent stayed within budget and prevented any unexpected charges.
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (3)
Both holes are real, thanks for spelling them out. You're right that recording spend only after fn returns means a failing retry loop is never counted, even though the provider may still bill for it. The fix is to reserve the estimate before the call and only refund it when you know the request never left.
On the race: with several agents sharing one budget_state.json, load, check and save is not atomic. A file lock, or a single atomic SQL statement like UPDATE budget SET spent = spent + ? WHERE spent + ? <= cap and checking the affected row count, closes it.
I agree on consecutive failures too. A per-run failure counter that trips after N errors in a row is a cheap second stop condition, because a broken call fails fast and cheap right up until it doesn't. Do you also cap on call rate per minute, or is failure count plus dollars enough in your setups?
Thanks for the detailed feedback on the budget guard! You're absolutely right about the critical issues: (1) spend should be reserved before the API call and refunded only if the request fails, and (2) concurrent access to the budget state file can lead to race conditions. Using a file lock or an atomic SQL statement would indeed resolve these issues. We've addressed these concerns in our updated Agent Budget Guard, which now includes these safeguards to prevent runaway spending and ensure accurate cost tracking.
Two holes I'd look at in this version, both in the snippet as posted.
First, spend is only recorded after
fnreturns. If the call raises (a timeout, a 5xx, a parse error on a half read response), nothing is added, but the provider may still bill for it. A loop of failing retries is exactly the runaway case, and this guard lets it run forever. Reserving the estimate before the call, and refunding it only when you know the request never left, closes that.Second, with a swarm, two agents can
_load()the same total, both pass the check, and both write back, so one charge disappears. A file lock around load, check and save, or a small SQLite table with an atomicUPDATE ... WHERE spent + ? <= cap, fixes it.On your stop condition question: I'd want a cap on consecutive failures per run on top of the dollar cap, since a broken call tends to fail fast and cheap right up until it doesn't.