Module: RubyLLM::Agents::Budget::SpendRecorder Private

Extended by:
CacheHelper
Defined in:
lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Records spend and token usage, and handles soft cap alerting

Constant Summary

Constants included from CacheHelper

CacheHelper::NAMESPACE

Class Method Summary collapse

Methods included from CacheHelper

cache_delete, cache_exist?, cache_increment, cache_key, cache_read, cache_store, cache_write

Class Method Details

.alert_cache_key(alert_type, scope, tenant_id) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates an alert cache key

Parameters:

  • alert_type (String)

    Type of alert (e.g., “budget_alert”, “token_alert”)

  • scope (Symbol)

    Alert scope

  • tenant_id (String, nil)

    The tenant identifier

Returns:

  • (String)

    Cache key



114
115
116
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 114

def alert_cache_key(alert_type, scope, tenant_id)
  SpendRecorder.cache_key(alert_type, tenant_key_part(tenant_id), scope, Date.current.to_s)
end

.budget_cache_key(scope, period, agent_type: nil, tenant_id: nil) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates a cache key for budget tracking

Parameters:

  • scope (Symbol)

    :global or :agent

  • period (Symbol)

    :daily or :monthly

  • agent_type (String, nil) (defaults to: nil)

    Required when scope is :agent

  • tenant_id (String, nil) (defaults to: nil)

    The tenant identifier

Returns:

  • (String)

    Cache key



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 125

def budget_cache_key(scope, period, agent_type: nil, tenant_id: nil)
  date_part = date_key_part(period)
  tenant_part = tenant_key_part(tenant_id)

  case scope
  when :global
    SpendRecorder.cache_key("budget", tenant_part, date_part)
  when :agent
    SpendRecorder.cache_key("budget", tenant_part, "agent", agent_type, date_part)
  else
    raise ArgumentError, "Unknown scope: #{scope}"
  end
end

.date_key_part(period) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the date key part for cache keys based on period

Parameters:

  • period (Symbol)

    :daily or :monthly

Returns:

  • (String)

    Date string



104
105
106
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 104

def date_key_part(period)
  (period == :daily) ? Date.current.to_s : Date.current.strftime("%Y-%m")
end

.increment_spend(scope, period, amount, agent_type: nil, tenant_id: nil) ⇒ Float

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Increments the spend counter for a scope and period

Parameters:

  • scope (Symbol)

    :global or :agent

  • period (Symbol)

    :daily or :monthly

  • amount (Float)

    Amount to add

  • agent_type (String, nil) (defaults to: nil)

    Required when scope is :agent

  • tenant_id (String, nil) (defaults to: nil)

    The tenant identifier

Returns:

  • (Float)

    New total



62
63
64
65
66
67
68
69
70
71
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 62

def increment_spend(scope, period, amount, agent_type: nil, tenant_id: nil)
  key = budget_cache_key(scope, period, agent_type: agent_type, tenant_id: tenant_id)
  ttl = (period == :daily) ? 1.day : 31.days

  # Read-modify-write for float values (cache increment is for integers)
  current = (SpendRecorder.cache_read(key) || 0).to_f
  new_total = current + amount
  SpendRecorder.cache_write(key, new_total, expires_in: ttl)
  new_total
end

.increment_tokens(scope, period, tokens, agent_type: nil, tenant_id: nil) ⇒ Integer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Increments the token counter for a period

Parameters:

  • scope (Symbol)

    :global (only global supported for tokens)

  • period (Symbol)

    :daily or :monthly

  • tokens (Integer)

    Tokens to add

  • agent_type (String, nil) (defaults to: nil)

    Not used for tokens

  • tenant_id (String, nil) (defaults to: nil)

    The tenant identifier

Returns:

  • (Integer)

    New total



81
82
83
84
85
86
87
88
89
90
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 81

def increment_tokens(scope, period, tokens, agent_type: nil, tenant_id: nil)
  # For now, we only track global token usage (not per-agent)
  key = token_cache_key(period, tenant_id: tenant_id)
  ttl = (period == :daily) ? 1.day : 31.days

  current = (SpendRecorder.cache_read(key) || 0).to_i
  new_total = current + tokens
  SpendRecorder.cache_write(key, new_total, expires_in: ttl)
  new_total
end

.record_spend!(agent_type, amount, tenant_id:, budget_config:) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Records spend and checks for soft cap alerts

Parameters:

  • agent_type (String)

    The agent class name

  • amount (Float)

    The amount spent in USD

  • tenant_id (String, nil)

    The tenant identifier

  • budget_config (Hash)

    Budget configuration



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 22

def record_spend!(agent_type, amount, tenant_id:, budget_config:)
  return if amount.nil? || amount <= 0

  # Increment all relevant counters
  increment_spend(:global, :daily, amount, tenant_id: tenant_id)
  increment_spend(:global, :monthly, amount, tenant_id: tenant_id)
  increment_spend(:agent, :daily, amount, agent_type: agent_type, tenant_id: tenant_id)
  increment_spend(:agent, :monthly, amount, agent_type: agent_type, tenant_id: tenant_id)

  # Check for soft cap alerts
  check_soft_cap_alerts(agent_type, tenant_id, budget_config) if budget_config[:enabled]
end

.record_tokens!(agent_type, tokens, tenant_id:, budget_config:) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Records token usage and checks for soft cap alerts

Parameters:

  • agent_type (String)

    The agent class name

  • tokens (Integer)

    The number of tokens used

  • tenant_id (String, nil)

    The tenant identifier

  • budget_config (Hash)

    Budget configuration



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 42

def record_tokens!(agent_type, tokens, tenant_id:, budget_config:)
  return if tokens.nil? || tokens <= 0

  # Increment global token counters (daily and monthly)
  # Note: We only track global token usage, not per-agent (scope is ignored in increment_tokens)
  increment_tokens(:global, :daily, tokens, tenant_id: tenant_id)
  increment_tokens(:global, :monthly, tokens, tenant_id: tenant_id)

  # Check for soft cap alerts
  check_soft_token_alerts(agent_type, tenant_id, budget_config) if budget_config[:enabled]
end

.tenant_key_part(tenant_id) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the tenant key part for cache keys

Parameters:

  • tenant_id (String, nil)

    The tenant identifier

Returns:

  • (String)

    “tenant:id” or “global”



96
97
98
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 96

def tenant_key_part(tenant_id)
  tenant_id.present? ? "tenant:#{tenant_id}" : "global"
end

.token_cache_key(period, tenant_id: nil) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates a cache key for token tracking

Parameters:

  • period (Symbol)

    :daily or :monthly

  • tenant_id (String, nil) (defaults to: nil)

    The tenant identifier

Returns:

  • (String)

    Cache key



144
145
146
# File 'lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb', line 144

def token_cache_key(period, tenant_id: nil)
  SpendRecorder.cache_key("tokens", tenant_key_part(tenant_id), date_key_part(period))
end