Module: RubyLLM::Agents::LLMTenant

Extended by:
ActiveSupport::Concern
Defined in:
lib/ruby_llm/agents/core/llm_tenant.rb

Overview

DSL for declaring Rails models as LLM tenants

Provides automatic budget management and usage tracking when included in ActiveRecord models. Models using this concern can be passed as the ‘tenant:` parameter to agents.

Examples:

Basic usage

class Organization < ApplicationRecord
  include RubyLLM::Agents::LLMTenant
  llm_tenant
end

With custom ID method

class Organization < ApplicationRecord
  include RubyLLM::Agents::LLMTenant
  llm_tenant id: :slug
end

With auto-created budget

class Organization < ApplicationRecord
  include RubyLLM::Agents::LLMTenant
  llm_tenant id: :slug, budget: true
end

With limits (auto-creates budget)

class Organization < ApplicationRecord
  include RubyLLM::Agents::LLMTenant
  llm_tenant(
    id: :slug,
    name: :company_name,
    limits: {
      daily_cost: 100,
      monthly_cost: 1000,
      daily_executions: 500
    },
    enforcement: :hard
  )
end

With API keys from model columns/methods

class Organization < ApplicationRecord
  include RubyLLM::Agents::LLMTenant
  encrypts :openai_api_key, :anthropic_api_key  # Rails 7+ encryption

  llm_tenant(
    id: :slug,
    api_keys: {
      openai: :openai_api_key,        # column name
      anthropic: :anthropic_api_key,  # column name
      gemini: :fetch_gemini_key       # custom method
    }
  )

  def fetch_gemini_key
    Vault.read("secret/#{slug}/gemini")
  end
end

See Also:

Instance Method Summary collapse

Instance Method Details

#llm_api_keysHash

Returns API keys resolved from the DSL configuration

Maps provider names (e.g., :openai, :anthropic) to their resolved values by calling the configured method/column on this model instance.

Examples:

org.llm_api_keys
# => { openai: "sk-abc123", anthropic: "sk-ant-xyz789" }

Returns:

  • (Hash)

    Provider to API key mapping (e.g., { openai: “sk-…” })



155
156
157
158
159
160
161
162
163
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 155

def llm_api_keys
  api_keys_config = self.class.llm_tenant_options[:api_keys]
  return {} if api_keys_config.blank?

  api_keys_config.transform_values do |method_name|
    value = send(method_name)
    value.presence
  end.compact
end

#llm_budget_statusHash

Returns the budget status from BudgetTracker

Returns:

  • (Hash)

    Budget status



284
285
286
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 284

def llm_budget_status
  llm_tenant.budget_status
end

#llm_check_budget!void

This method returns an undefined value.

Raises an error if over budget

Raises:

  • (BudgetExceededError)

    if budget is exceeded



308
309
310
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 308

def llm_check_budget!
  llm_tenant.check_budget!(self.class.name)
end

#llm_configure {|tenant| ... } ⇒ Tenant Also known as: llm_configure_budget

Configure tenant with a block

Yields:

  • (tenant)

    The tenant to configure

Returns:

  • (Tenant)

    The saved tenant



180
181
182
183
184
185
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 180

def llm_configure(&block)
  tenant = llm_tenant
  yield(tenant) if block_given?
  tenant.save!
  tenant
end

#llm_cost(period: nil) ⇒ BigDecimal

Returns cost for a given period

Parameters:

  • period (Symbol, Range, nil) (defaults to: nil)

    Time period (:today, :this_month, etc.)

Returns:

  • (BigDecimal)

    Total cost



198
199
200
201
202
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 198

def llm_cost(period: nil)
  scope = llm_executions
  scope = apply_llm_period_scope(scope, period) if period
  scope.sum(:total_cost) || 0
end

#llm_cost_this_monthBigDecimal

Returns cost for this month

Returns:

  • (BigDecimal)

    This month’s cost



214
215
216
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 214

def llm_cost_this_month
  llm_cost(period: :this_month)
end

#llm_cost_todayBigDecimal

Returns cost for today

Returns:

  • (BigDecimal)

    Today’s cost



207
208
209
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 207

def llm_cost_today
  llm_cost(period: :today)
end

#llm_execution_count(period: nil) ⇒ Integer

Returns execution count for a given period

Parameters:

  • period (Symbol, Range, nil) (defaults to: nil)

    Time period

Returns:

  • (Integer)

    Execution count



246
247
248
249
250
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 246

def llm_execution_count(period: nil)
  scope = llm_executions
  scope = apply_llm_period_scope(scope, period) if period
  scope.count
end

#llm_executions_this_monthInteger

Returns executions for this month

Returns:

  • (Integer)

    This month’s execution count



262
263
264
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 262

def llm_executions_this_month
  llm_execution_count(period: :this_month)
end

#llm_executions_todayInteger

Returns executions for today

Returns:

  • (Integer)

    Today’s execution count



255
256
257
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 255

def llm_executions_today
  llm_execution_count(period: :today)
end

#llm_remaining_budget(type: :daily_cost) ⇒ Numeric?

Returns remaining budget for a given limit type

Parameters:

  • type (Symbol) (defaults to: :daily_cost)

    Limit type

Returns:

  • (Numeric, nil)

    Remaining amount



300
301
302
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 300

def llm_remaining_budget(type: :daily_cost)
  llm_tenant.remaining_budget(type: type)
end

#llm_tenantTenant Also known as: llm_budget

Returns or builds the associated Tenant record

Returns:

  • (Tenant)

    The tenant record



168
169
170
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 168

def llm_tenant
  llm_tenant_record || build_llm_tenant_record(tenant_id: llm_tenant_id)
end

#llm_tenant_idString

Returns the tenant_id string for this model

Returns:

  • (String)

    The tenant identifier



141
142
143
144
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 141

def llm_tenant_id
  id_method = self.class.llm_tenant_options[:id] || :id
  send(id_method).to_s
end

#llm_tokens(period: nil) ⇒ Integer

Returns token count for a given period

Parameters:

  • period (Symbol, Range, nil) (defaults to: nil)

    Time period

Returns:

  • (Integer)

    Total tokens



222
223
224
225
226
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 222

def llm_tokens(period: nil)
  scope = llm_executions
  scope = apply_llm_period_scope(scope, period) if period
  scope.sum(:total_tokens) || 0
end

#llm_tokens_this_monthInteger

Returns tokens for this month

Returns:

  • (Integer)

    This month’s tokens



238
239
240
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 238

def llm_tokens_this_month
  llm_tokens(period: :this_month)
end

#llm_tokens_todayInteger

Returns tokens for today

Returns:

  • (Integer)

    Today’s tokens



231
232
233
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 231

def llm_tokens_today
  llm_tokens(period: :today)
end

#llm_usage_summary(period: :this_month) ⇒ Hash

Returns a usage summary for a given period

Parameters:

  • period (Symbol) (defaults to: :this_month)

    Time period (default: :this_month)

Returns:

  • (Hash)

    Usage summary with cost, tokens, and executions



270
271
272
273
274
275
276
277
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 270

def llm_usage_summary(period: :this_month)
  {
    cost: llm_cost(period: period),
    tokens: llm_tokens(period: period),
    executions: llm_execution_count(period: period),
    period: period
  }
end

#llm_within_budget?(type: :daily_cost) ⇒ Boolean

Checks if within budget for a given limit type

Parameters:

  • type (Symbol) (defaults to: :daily_cost)

    Limit type (:daily_cost, :monthly_cost, :daily_tokens, etc.)

Returns:

  • (Boolean)

    true if within budget



292
293
294
# File 'lib/ruby_llm/agents/core/llm_tenant.rb', line 292

def llm_within_budget?(type: :daily_cost)
  llm_tenant.within_budget?(type: type)
end