ruby_llm-agents 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/ruby_llm/agents/tenant/budgetable.rb +277 -0
- data/app/models/ruby_llm/agents/tenant/configurable.rb +135 -0
- data/app/models/ruby_llm/agents/tenant/trackable.rb +310 -0
- data/app/models/ruby_llm/agents/tenant.rb +146 -0
- data/app/models/ruby_llm/agents/tenant_budget.rb +12 -253
- data/lib/generators/ruby_llm_agents/multi_tenancy_generator.rb +42 -22
- data/lib/generators/ruby_llm_agents/templates/add_tenant_to_executions_migration.rb.tt +13 -2
- data/lib/generators/ruby_llm_agents/templates/create_tenant_budgets_migration.rb.tt +11 -0
- data/lib/generators/ruby_llm_agents/templates/create_tenants_migration.rb.tt +72 -0
- data/lib/generators/ruby_llm_agents/templates/rename_tenant_budgets_to_tenants_migration.rb.tt +34 -0
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +26 -0
- data/lib/ruby_llm/agents/core/llm_tenant.rb +60 -60
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +4 -2
- metadata +7 -1
|
@@ -12,21 +12,25 @@ module RubyLLM
|
|
|
12
12
|
#
|
|
13
13
|
# @example Basic usage
|
|
14
14
|
# class Organization < ApplicationRecord
|
|
15
|
+
# include RubyLLM::Agents::LLMTenant
|
|
15
16
|
# llm_tenant
|
|
16
17
|
# end
|
|
17
18
|
#
|
|
18
19
|
# @example With custom ID method
|
|
19
20
|
# class Organization < ApplicationRecord
|
|
21
|
+
# include RubyLLM::Agents::LLMTenant
|
|
20
22
|
# llm_tenant id: :slug
|
|
21
23
|
# end
|
|
22
24
|
#
|
|
23
25
|
# @example With auto-created budget
|
|
24
26
|
# class Organization < ApplicationRecord
|
|
27
|
+
# include RubyLLM::Agents::LLMTenant
|
|
25
28
|
# llm_tenant id: :slug, budget: true
|
|
26
29
|
# end
|
|
27
30
|
#
|
|
28
31
|
# @example With limits (auto-creates budget)
|
|
29
32
|
# class Organization < ApplicationRecord
|
|
33
|
+
# include RubyLLM::Agents::LLMTenant
|
|
30
34
|
# llm_tenant(
|
|
31
35
|
# id: :slug,
|
|
32
36
|
# name: :company_name,
|
|
@@ -41,6 +45,7 @@ module RubyLLM
|
|
|
41
45
|
#
|
|
42
46
|
# @example With API keys from model columns/methods
|
|
43
47
|
# class Organization < ApplicationRecord
|
|
48
|
+
# include RubyLLM::Agents::LLMTenant
|
|
44
49
|
# encrypts :openai_api_key, :anthropic_api_key # Rails 7+ encryption
|
|
45
50
|
#
|
|
46
51
|
# llm_tenant(
|
|
@@ -57,7 +62,7 @@ module RubyLLM
|
|
|
57
62
|
# end
|
|
58
63
|
# end
|
|
59
64
|
#
|
|
60
|
-
# @see RubyLLM::Agents::
|
|
65
|
+
# @see RubyLLM::Agents::Tenant
|
|
61
66
|
# @api public
|
|
62
67
|
module LLMTenant
|
|
63
68
|
extend ActiveSupport::Concern
|
|
@@ -69,12 +74,16 @@ module RubyLLM
|
|
|
69
74
|
as: :tenant_record,
|
|
70
75
|
dependent: :nullify
|
|
71
76
|
|
|
72
|
-
#
|
|
73
|
-
has_one :
|
|
74
|
-
class_name: "RubyLLM::Agents::
|
|
77
|
+
# Link to gem's Tenant model (new name)
|
|
78
|
+
has_one :llm_tenant_record,
|
|
79
|
+
class_name: "RubyLLM::Agents::Tenant",
|
|
75
80
|
as: :tenant_record,
|
|
76
81
|
dependent: :destroy
|
|
77
82
|
|
|
83
|
+
# Backward compatible alias (llm_budget points to same Tenant record)
|
|
84
|
+
# @deprecated Use llm_tenant_record instead
|
|
85
|
+
alias_method :llm_budget_association, :llm_tenant_record
|
|
86
|
+
|
|
78
87
|
# Store options at class level
|
|
79
88
|
class_attribute :llm_tenant_options, default: {}
|
|
80
89
|
end
|
|
@@ -84,7 +93,7 @@ module RubyLLM
|
|
|
84
93
|
#
|
|
85
94
|
# @param id [Symbol] Method to call for tenant_id string (default: :id)
|
|
86
95
|
# @param name [Symbol] Method for budget display name (default: :to_s)
|
|
87
|
-
# @param budget [Boolean] Auto-create
|
|
96
|
+
# @param budget [Boolean] Auto-create Tenant record on model creation (default: false)
|
|
88
97
|
# @param limits [Hash] Default budget limits (implies budget: true)
|
|
89
98
|
# @param enforcement [Symbol] Budget enforcement mode (:none, :soft, :hard)
|
|
90
99
|
# @param inherit_global [Boolean] Inherit from global config (default: true)
|
|
@@ -101,8 +110,8 @@ module RubyLLM
|
|
|
101
110
|
api_keys: api_keys
|
|
102
111
|
}
|
|
103
112
|
|
|
104
|
-
# Auto-create
|
|
105
|
-
after_create :
|
|
113
|
+
# Auto-create tenant record callback
|
|
114
|
+
after_create :create_default_llm_tenant if llm_tenant_options[:budget]
|
|
106
115
|
end
|
|
107
116
|
|
|
108
117
|
private
|
|
@@ -152,13 +161,42 @@ module RubyLLM
|
|
|
152
161
|
end.compact
|
|
153
162
|
end
|
|
154
163
|
|
|
164
|
+
# Returns or builds the associated Tenant record
|
|
165
|
+
#
|
|
166
|
+
# @return [Tenant] The tenant record
|
|
167
|
+
def llm_tenant
|
|
168
|
+
llm_tenant_record || build_llm_tenant_record(tenant_id: llm_tenant_id)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Backward compatible alias for llm_tenant
|
|
172
|
+
# @deprecated Use llm_tenant instead
|
|
173
|
+
alias_method :llm_budget, :llm_tenant
|
|
174
|
+
|
|
175
|
+
# Configure tenant with a block
|
|
176
|
+
#
|
|
177
|
+
# @yield [tenant] The tenant to configure
|
|
178
|
+
# @return [Tenant] The saved tenant
|
|
179
|
+
def llm_configure(&block)
|
|
180
|
+
tenant = llm_tenant
|
|
181
|
+
yield(tenant) if block_given?
|
|
182
|
+
tenant.save!
|
|
183
|
+
tenant
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Backward compatible alias
|
|
187
|
+
# @deprecated Use llm_configure instead
|
|
188
|
+
alias_method :llm_configure_budget, :llm_configure
|
|
189
|
+
|
|
190
|
+
# Tracking methods using llm_executions association
|
|
191
|
+
# These query executions via the polymorphic tenant_record association
|
|
192
|
+
|
|
155
193
|
# Returns cost for a given period
|
|
156
194
|
#
|
|
157
195
|
# @param period [Symbol, Range, nil] Time period (:today, :this_month, etc.)
|
|
158
196
|
# @return [BigDecimal] Total cost
|
|
159
197
|
def llm_cost(period: nil)
|
|
160
198
|
scope = llm_executions
|
|
161
|
-
scope =
|
|
199
|
+
scope = apply_llm_period_scope(scope, period) if period
|
|
162
200
|
scope.sum(:total_cost) || 0
|
|
163
201
|
end
|
|
164
202
|
|
|
@@ -182,7 +220,7 @@ module RubyLLM
|
|
|
182
220
|
# @return [Integer] Total tokens
|
|
183
221
|
def llm_tokens(period: nil)
|
|
184
222
|
scope = llm_executions
|
|
185
|
-
scope =
|
|
223
|
+
scope = apply_llm_period_scope(scope, period) if period
|
|
186
224
|
scope.sum(:total_tokens) || 0
|
|
187
225
|
end
|
|
188
226
|
|
|
@@ -206,7 +244,7 @@ module RubyLLM
|
|
|
206
244
|
# @return [Integer] Execution count
|
|
207
245
|
def llm_execution_count(period: nil)
|
|
208
246
|
scope = llm_executions
|
|
209
|
-
scope =
|
|
247
|
+
scope = apply_llm_period_scope(scope, period) if period
|
|
210
248
|
scope.count
|
|
211
249
|
end
|
|
212
250
|
|
|
@@ -237,29 +275,13 @@ module RubyLLM
|
|
|
237
275
|
}
|
|
238
276
|
end
|
|
239
277
|
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
-
# @return [TenantBudget] The budget record
|
|
243
|
-
def llm_budget
|
|
244
|
-
super || build_llm_budget(tenant_id: llm_tenant_id)
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
# Configure budget with a block
|
|
248
|
-
#
|
|
249
|
-
# @yield [budget] The budget to configure
|
|
250
|
-
# @return [TenantBudget] The saved budget
|
|
251
|
-
def llm_configure_budget
|
|
252
|
-
budget = llm_budget
|
|
253
|
-
yield(budget) if block_given?
|
|
254
|
-
budget.save!
|
|
255
|
-
budget
|
|
256
|
-
end
|
|
278
|
+
# Delegate budget methods to the Tenant record
|
|
257
279
|
|
|
258
280
|
# Returns the budget status from BudgetTracker
|
|
259
281
|
#
|
|
260
282
|
# @return [Hash] Budget status
|
|
261
283
|
def llm_budget_status
|
|
262
|
-
|
|
284
|
+
llm_tenant.budget_status
|
|
263
285
|
end
|
|
264
286
|
|
|
265
287
|
# Checks if within budget for a given limit type
|
|
@@ -267,11 +289,7 @@ module RubyLLM
|
|
|
267
289
|
# @param type [Symbol] Limit type (:daily_cost, :monthly_cost, :daily_tokens, etc.)
|
|
268
290
|
# @return [Boolean] true if within budget
|
|
269
291
|
def llm_within_budget?(type: :daily_cost)
|
|
270
|
-
|
|
271
|
-
return true unless status[:enabled]
|
|
272
|
-
|
|
273
|
-
key = budget_status_key(type)
|
|
274
|
-
status.dig(key, :percentage_used).to_f < 100
|
|
292
|
+
llm_tenant.within_budget?(type: type)
|
|
275
293
|
end
|
|
276
294
|
|
|
277
295
|
# Returns remaining budget for a given limit type
|
|
@@ -279,9 +297,7 @@ module RubyLLM
|
|
|
279
297
|
# @param type [Symbol] Limit type
|
|
280
298
|
# @return [Numeric, nil] Remaining amount
|
|
281
299
|
def llm_remaining_budget(type: :daily_cost)
|
|
282
|
-
|
|
283
|
-
key = budget_status_key(type)
|
|
284
|
-
status.dig(key, :remaining)
|
|
300
|
+
llm_tenant.remaining_budget(type: type)
|
|
285
301
|
end
|
|
286
302
|
|
|
287
303
|
# Raises an error if over budget
|
|
@@ -289,7 +305,7 @@ module RubyLLM
|
|
|
289
305
|
# @raise [BudgetExceededError] if budget is exceeded
|
|
290
306
|
# @return [void]
|
|
291
307
|
def llm_check_budget!
|
|
292
|
-
|
|
308
|
+
llm_tenant.check_budget!(self.class.name)
|
|
293
309
|
end
|
|
294
310
|
|
|
295
311
|
private
|
|
@@ -299,7 +315,7 @@ module RubyLLM
|
|
|
299
315
|
# @param scope [ActiveRecord::Relation] The query scope
|
|
300
316
|
# @param period [Symbol, Range] The period to filter by
|
|
301
317
|
# @return [ActiveRecord::Relation] Filtered scope
|
|
302
|
-
def
|
|
318
|
+
def apply_llm_period_scope(scope, period)
|
|
303
319
|
case period
|
|
304
320
|
when :today then scope.where(created_at: Time.current.all_day)
|
|
305
321
|
when :yesterday then scope.where(created_at: 1.day.ago.all_day)
|
|
@@ -310,34 +326,18 @@ module RubyLLM
|
|
|
310
326
|
end
|
|
311
327
|
end
|
|
312
328
|
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
# @param type [Symbol] User-friendly type
|
|
316
|
-
# @return [Symbol] Status key
|
|
317
|
-
def budget_status_key(type)
|
|
318
|
-
case type
|
|
319
|
-
when :daily_cost then :global_daily
|
|
320
|
-
when :monthly_cost then :global_monthly
|
|
321
|
-
when :daily_tokens then :global_daily_tokens
|
|
322
|
-
when :monthly_tokens then :global_monthly_tokens
|
|
323
|
-
when :daily_executions then :global_daily_executions
|
|
324
|
-
when :monthly_executions then :global_monthly_executions
|
|
325
|
-
else :global_daily
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
# Creates the default budget on model creation
|
|
329
|
+
# Creates the default tenant record on model creation
|
|
330
330
|
#
|
|
331
331
|
# @return [void]
|
|
332
|
-
def
|
|
332
|
+
def create_default_llm_tenant
|
|
333
333
|
return if self.class.llm_tenant_options.blank?
|
|
334
|
-
return if
|
|
334
|
+
return if llm_tenant_record&.persisted?
|
|
335
335
|
|
|
336
336
|
options = self.class.llm_tenant_options
|
|
337
337
|
limits = options[:limits] || {}
|
|
338
338
|
name_method = options[:name] || :to_s
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
tenant = build_llm_tenant_record(
|
|
341
341
|
tenant_id: llm_tenant_id,
|
|
342
342
|
name: send(name_method).to_s,
|
|
343
343
|
daily_limit: limits[:daily_cost],
|
|
@@ -350,8 +350,8 @@ module RubyLLM
|
|
|
350
350
|
inherit_global_defaults: options.fetch(:inherit_global, true)
|
|
351
351
|
)
|
|
352
352
|
|
|
353
|
-
|
|
354
|
-
|
|
353
|
+
tenant.tenant_record = self
|
|
354
|
+
tenant.save!
|
|
355
355
|
end
|
|
356
356
|
end
|
|
357
357
|
end
|
|
@@ -125,13 +125,15 @@ module RubyLLM
|
|
|
125
125
|
nil
|
|
126
126
|
end
|
|
127
127
|
|
|
128
|
-
# Checks if the
|
|
128
|
+
# Checks if the tenants table exists (supports old and new table names)
|
|
129
129
|
#
|
|
130
130
|
# @return [Boolean] true if table exists
|
|
131
131
|
def tenant_budget_table_exists?
|
|
132
132
|
return @tenant_budget_table_exists if defined?(@tenant_budget_table_exists)
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
# Check for new table name (tenants) or old table name (tenant_budgets) for backward compatibility
|
|
135
|
+
@tenant_budget_table_exists = ::ActiveRecord::Base.connection.table_exists?(:ruby_llm_agents_tenants) ||
|
|
136
|
+
::ActiveRecord::Base.connection.table_exists?(:ruby_llm_agents_tenant_budgets)
|
|
135
137
|
rescue StandardError
|
|
136
138
|
@tenant_budget_table_exists = false
|
|
137
139
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_llm-agents
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- adham90
|
|
@@ -95,6 +95,10 @@ files:
|
|
|
95
95
|
- app/models/ruby_llm/agents/execution/metrics.rb
|
|
96
96
|
- app/models/ruby_llm/agents/execution/scopes.rb
|
|
97
97
|
- app/models/ruby_llm/agents/execution/workflow.rb
|
|
98
|
+
- app/models/ruby_llm/agents/tenant.rb
|
|
99
|
+
- app/models/ruby_llm/agents/tenant/budgetable.rb
|
|
100
|
+
- app/models/ruby_llm/agents/tenant/configurable.rb
|
|
101
|
+
- app/models/ruby_llm/agents/tenant/trackable.rb
|
|
98
102
|
- app/models/ruby_llm/agents/tenant_budget.rb
|
|
99
103
|
- app/services/ruby_llm/agents/agent_registry.rb
|
|
100
104
|
- app/views/layouts/ruby_llm/agents/application.html.erb
|
|
@@ -208,6 +212,7 @@ files:
|
|
|
208
212
|
- lib/generators/ruby_llm_agents/templates/background_remover.rb.tt
|
|
209
213
|
- lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt
|
|
210
214
|
- lib/generators/ruby_llm_agents/templates/create_tenant_budgets_migration.rb.tt
|
|
215
|
+
- lib/generators/ruby_llm_agents/templates/create_tenants_migration.rb.tt
|
|
211
216
|
- lib/generators/ruby_llm_agents/templates/embedder.rb.tt
|
|
212
217
|
- lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt
|
|
213
218
|
- lib/generators/ruby_llm_agents/templates/image_editor.rb.tt
|
|
@@ -218,6 +223,7 @@ files:
|
|
|
218
223
|
- lib/generators/ruby_llm_agents/templates/image_variator.rb.tt
|
|
219
224
|
- lib/generators/ruby_llm_agents/templates/initializer.rb.tt
|
|
220
225
|
- lib/generators/ruby_llm_agents/templates/migration.rb.tt
|
|
226
|
+
- lib/generators/ruby_llm_agents/templates/rename_tenant_budgets_to_tenants_migration.rb.tt
|
|
221
227
|
- lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt
|
|
222
228
|
- lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt
|
|
223
229
|
- lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt
|