Module: LlmCostTracker::Budget
- Defined in:
- lib/llm_cost_tracker/budget.rb,
lib/llm_cost_tracker/budget/per_tag.rb
Defined Under Namespace
Modules: PerTag
Constant Summary collapse
- BUDGET_TYPE_TO_PERIOD =
{ monthly: :month, daily: :day }.freeze
Class Method Summary collapse
- .check!(event, behavior_override: nil) ⇒ Object
- .check_persisted!(events, behavior_override: nil) ⇒ Object
- .enforce!(provider: nil, model: nil, request: nil, estimate: nil, tags: nil, force: false) ⇒ Object
- .notify_persisted_safely!(events) ⇒ Object
Class Method Details
.check!(event, behavior_override: nil) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/llm_cost_tracker/budget.rb', line 36 def check!(event, behavior_override: nil) config = LlmCostTracker.configuration return unless event.total_cost check_per_call_budget(event, config, behavior_override) check_windowed({ daily: config.budgets.daily, monthly: config.budgets.monthly }.compact, time: event.tracked_at) do |budget_type, total, budget| handle_exceeded(budget_type: budget_type, total: total, budget: budget, previous_total: total - event.total_cost, last_event: event, behavior: behavior_override) end end |
.check_persisted!(events, behavior_override: nil) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/llm_cost_tracker/budget.rb', line 52 def check_persisted!(events, behavior_override: nil) by_rule = PerTag.rules_for_events(events.select(&:total_cost)) by_rule = by_rule.reject { |rule, _| rule.on_exceeded.nil? } if behavior_override == :notify window_buckets(by_rule).each do |(key, window, bucket), scored| totals = PerTag.spend_by_value(key, scored.keys.map(&:value), window, bucket) scored.each do |rule, recorded| total = totals.fetch(rule.value, 0).to_d limit = rule.windows.fetch(window) next if total < limit handle_exceeded( budget_type: window, total: total, budget: limit, previous_total: total - recorded.sum(&:total_cost), last_event: recorded.last, scope: scope_for(rule), behavior: behavior_override || rule.behavior, on_exceeded: rule.on_exceeded ) end end end |
.enforce!(provider: nil, model: nil, request: nil, estimate: nil, tags: nil, force: false) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/llm_cost_tracker/budget.rb', line 15 def enforce!(provider: nil, model: nil, request: nil, estimate: nil, tags: nil, force: false) config = LlmCostTracker.configuration return unless config.enabled globally = force || config.budgets.exceeded_behavior == :block_requests per_tag = force || PerTag.blocking? return unless globally || per_tag estimate ||= estimate_cost(provider: provider, model: model, request: request) now = Time.now.utc enforce_globally(config, estimate: estimate, time: now) if globally return unless per_tag check_per_tag( || Tags::Context., time: now, estimate: estimate, blocking_only: !force) do |rule, window, total, limit| raise_pre_send(budget_type: window, total: total, budget: limit, scope: scope_for(rule)) end end |
.notify_persisted_safely!(events) ⇒ Object
76 77 78 79 80 |
# File 'lib/llm_cost_tracker/budget.rb', line 76 def notify_persisted_safely!(events) check_persisted!(events, behavior_override: :notify) rescue StandardError => e Logging.warn("Per-tag budget check failed after ingest: #{e.class}: #{e.}") end |