Module: Silas::Budget
- Defined in:
- lib/silas/budget.rb
Overview
Per-turn budget caps beyond max_steps: cumulative input tokens, cost, and wall-clock. Checked between steps in the framework-owned loop (never inside a continuation step), so a breach fails the turn cleanly with a limit reason.
Token/cost checks are deterministic (persisted step data). The timeout check reads the wall clock — benign non-determinism: a cap firing later on resume is correct (the turn genuinely ran too long across the crash).
Class Method Summary collapse
-
.exceeded_reason(turn, agent: Silas.agent) ⇒ Object
Returns a failure reason string if a cap is exceeded, else nil.
- .over_cost?(turn, agent) ⇒ Boolean
- .over_time?(turn, agent) ⇒ Boolean
- .over_tokens?(turn, agent) ⇒ Boolean
Class Method Details
.exceeded_reason(turn, agent: Silas.agent) ⇒ Object
Returns a failure reason string if a cap is exceeded, else nil.
13 14 15 16 17 18 19 |
# File 'lib/silas/budget.rb', line 13 def exceeded_reason(turn, agent: Silas.agent) return "max_input_tokens" if over_tokens?(turn, agent) return "max_cost" if over_cost?(turn, agent) return "timeout" if over_time?(turn, agent) nil end |
.over_cost?(turn, agent) ⇒ Boolean
27 28 29 30 31 32 33 |
# File 'lib/silas/budget.rb', line 27 def over_cost?(turn, agent) limit = agent.max_cost or return false spent = Silas::Inbox::Cost.for_turn(turn) # Only enforce on priced tokens; unpriced models can't be cost-capped. spent[:microcents] > (limit.to_f * 1_000_000) end |
.over_time?(turn, agent) ⇒ Boolean
35 36 37 38 39 40 |
# File 'lib/silas/budget.rb', line 35 def over_time?(turn, agent) limit = agent.timeout or return false return false unless turn.started_at (Time.current - turn.started_at) > limit end |