Module: RubyLLM::Agents::Budget::BudgetQuery Private

Extended by:
CacheHelper
Defined in:
lib/ruby_llm/agents/infrastructure/budget/budget_query.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.

Query methods for current spend, remaining budget, and status

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

.budget_status(scope, period, limit, agent_type: nil, tenant_id: nil) ⇒ Hash?

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 budget status for a scope/period

Parameters:

  • scope (Symbol)

    :global or :agent

  • period (Symbol)

    :daily or :monthly

  • limit (Float, nil)

    The budget limit

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

    Required when scope is :agent

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

    The tenant identifier

Returns:

  • (Hash, nil)

    Status hash or nil if no limit



176
177
178
179
180
181
182
183
184
185
186
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 176

def budget_status(scope, period, limit, agent_type: nil, tenant_id: nil)
  return nil unless limit

  current = current_spend(scope, period, agent_type: agent_type, tenant_id: tenant_id)
  {
    limit: limit,
    current: current.round(6),
    remaining: [limit - current, 0].max.round(6),
    percentage_used: ((current / limit) * 100).round(2)
  }
end

.current_global_spend(period) ⇒ 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.

Rebuilds global spend from executions table on cache miss

Parameters:

  • period (Symbol)

    :daily or :monthly

Returns:

  • (Float)

    Total spend in USD



59
60
61
62
63
64
65
66
67
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 59

def current_global_spend(period)
  total = RubyLLM::Agents::Execution
    .where("created_at >= ?", period_start(period))
    .where(tenant_id: nil)
    .sum(:total_cost)
  key = SpendRecorder.budget_cache_key(:global, period)
  BudgetQuery.cache_write(key, total, expires_in: period_ttl(period))
  total
end

.current_global_tokens(period) ⇒ 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.

Rebuilds global token usage from executions table on cache miss

Parameters:

  • period (Symbol)

    :daily or :monthly

Returns:

  • (Integer)

    Total tokens used



73
74
75
76
77
78
79
80
81
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 73

def current_global_tokens(period)
  total = RubyLLM::Agents::Execution
    .where("created_at >= ?", period_start(period))
    .where(tenant_id: nil)
    .sum(:total_tokens)
  key = SpendRecorder.token_cache_key(period)
  BudgetQuery.cache_write(key, total, expires_in: period_ttl(period))
  total
end

.current_spend(scope, period, 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.

Returns the current spend for a scope and period

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:

  • (Float)

    Current spend in USD



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

def current_spend(scope, period, agent_type: nil, tenant_id: nil)
  key = SpendRecorder.budget_cache_key(scope, period, agent_type: agent_type, tenant_id: tenant_id)
  cached = BudgetQuery.cache_read(key)
  return cached.to_f if cached.present?

  # Cache miss — rebuild from executions table for global scope
  if scope == :global && tenant_id.nil?
    total = current_global_spend(period)
    return total.to_f
  end

  0.to_f
end

.current_tokens(period, 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.

Returns the current token usage for a period (global only)

Parameters:

  • period (Symbol)

    :daily or :monthly

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

    The tenant identifier

Returns:

  • (Integer)

    Current token usage



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

def current_tokens(period, tenant_id: nil)
  key = SpendRecorder.token_cache_key(period, tenant_id: tenant_id)
  cached = BudgetQuery.cache_read(key)
  return cached.to_i if cached.present?

  # Cache miss — rebuild from executions table
  if tenant_id.nil?
    total = current_global_tokens(period)
    return total.to_i
  end

  0
end

.remaining_budget(scope, period, budget_config:, 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.

Returns the remaining budget for a scope and period

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

  • budget_config (Hash)

    Budget configuration

Returns:

  • (Float, nil)

    Remaining budget in USD, or nil if no limit configured



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 109

def remaining_budget(scope, period, budget_config:, agent_type: nil, tenant_id: nil)
  limit = case [scope, period]
  when [:global, :daily]
    budget_config[:global_daily]
  when [:global, :monthly]
    budget_config[:global_monthly]
  when [:agent, :daily]
    budget_config[:per_agent_daily]&.dig(agent_type)
  when [:agent, :monthly]
    budget_config[:per_agent_monthly]&.dig(agent_type)
  end

  return nil unless limit

  [limit - current_spend(scope, period, agent_type: agent_type, tenant_id: tenant_id), 0].max
end

.remaining_token_budget(period, budget_config:, 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.

Returns the remaining token budget for a period (global only)

Parameters:

  • period (Symbol)

    :daily or :monthly

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

    The tenant identifier

  • budget_config (Hash)

    Budget configuration

Returns:

  • (Integer, nil)

    Remaining token budget, or nil if no limit configured



132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 132

def remaining_token_budget(period, budget_config:, tenant_id: nil)
  limit = case period
  when :daily
    budget_config[:global_daily_tokens]
  when :monthly
    budget_config[:global_monthly_tokens]
  end

  return nil unless limit

  [limit - current_tokens(period, tenant_id: tenant_id), 0].max
end

.status(budget_config:, agent_type: nil, tenant_id: nil) ⇒ Hash

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 a summary of all budget statuses

Parameters:

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

    Optional agent type for per-agent budgets

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

    The tenant identifier

  • budget_config (Hash)

    Budget configuration

Returns:

  • (Hash)

    Budget status information



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 151

def status(budget_config:, agent_type: nil, tenant_id: nil)
  {
    tenant_id: tenant_id,
    enabled: budget_config[:enabled],
    enforcement: budget_config[:enforcement],
    # Cost budgets
    global_daily: budget_status(:global, :daily, budget_config[:global_daily], tenant_id: tenant_id),
    global_monthly: budget_status(:global, :monthly, budget_config[:global_monthly], tenant_id: tenant_id),
    per_agent_daily: agent_type ? budget_status(:agent, :daily, budget_config[:per_agent_daily]&.dig(agent_type), agent_type: agent_type, tenant_id: tenant_id) : nil,
    per_agent_monthly: agent_type ? budget_status(:agent, :monthly, budget_config[:per_agent_monthly]&.dig(agent_type), agent_type: agent_type, tenant_id: tenant_id) : nil,
    # Token budgets (global only)
    global_daily_tokens: token_status(:daily, budget_config[:global_daily_tokens], tenant_id: tenant_id),
    global_monthly_tokens: token_status(:monthly, budget_config[:global_monthly_tokens], tenant_id: tenant_id),
    forecast: Forecaster.calculate_forecast(tenant_id: tenant_id, budget_config: budget_config)
  }.compact
end

.token_status(period, limit, tenant_id: nil) ⇒ Hash?

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 token status for a period

Parameters:

  • period (Symbol)

    :daily or :monthly

  • limit (Integer, nil)

    The token limit

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

    The tenant identifier

Returns:

  • (Hash, nil)

    Status hash or nil if no limit



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/ruby_llm/agents/infrastructure/budget/budget_query.rb', line 194

def token_status(period, limit, tenant_id: nil)
  return nil unless limit

  current = current_tokens(period, tenant_id: tenant_id)
  {
    limit: limit,
    current: current,
    remaining: [limit - current, 0].max,
    percentage_used: ((current.to_f / limit) * 100).round(2)
  }
end