ruby_llm-agents 3.8.0 → 3.9.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/README.md +30 -10
- data/app/controllers/ruby_llm/agents/requests_controller.rb +117 -0
- data/app/views/layouts/ruby_llm/agents/application.html.erb +4 -2
- data/app/views/ruby_llm/agents/requests/index.html.erb +153 -0
- data/app/views/ruby_llm/agents/requests/show.html.erb +136 -0
- data/config/routes.rb +2 -0
- data/lib/generators/ruby_llm_agents/agent_generator.rb +2 -2
- data/lib/generators/ruby_llm_agents/demo_generator.rb +102 -0
- data/lib/generators/ruby_llm_agents/doctor_generator.rb +196 -0
- data/lib/generators/ruby_llm_agents/install_generator.rb +7 -19
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +27 -80
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +18 -51
- data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +19 -17
- data/lib/ruby_llm/agents/base_agent.rb +68 -7
- data/lib/ruby_llm/agents/core/base.rb +4 -0
- data/lib/ruby_llm/agents/core/configuration.rb +10 -0
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/pipeline/context.rb +26 -0
- data/lib/ruby_llm/agents/pipeline/middleware/base.rb +58 -4
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +17 -15
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +34 -22
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +105 -50
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +7 -5
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +6 -4
- data/lib/ruby_llm/agents/rails/engine.rb +11 -0
- data/lib/ruby_llm/agents/results/background_removal_result.rb +7 -1
- data/lib/ruby_llm/agents/results/base.rb +24 -2
- data/lib/ruby_llm/agents/results/embedding_result.rb +4 -0
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_edit_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_generation_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_transform_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_variation_result.rb +7 -1
- data/lib/ruby_llm/agents/results/speech_result.rb +6 -0
- data/lib/ruby_llm/agents/results/trackable.rb +25 -0
- data/lib/ruby_llm/agents/results/transcription_result.rb +6 -0
- data/lib/ruby_llm/agents/text/embedder.rb +7 -4
- data/lib/ruby_llm/agents/track_report.rb +127 -0
- data/lib/ruby_llm/agents/tracker.rb +32 -0
- data/lib/ruby_llm/agents.rb +208 -0
- data/lib/tasks/ruby_llm_agents.rake +6 -0
- metadata +10 -2
data/lib/ruby_llm/agents.rb
CHANGED
|
@@ -37,7 +37,12 @@ require_relative "agents/infrastructure/budget/config_resolver"
|
|
|
37
37
|
require_relative "agents/infrastructure/budget/forecaster"
|
|
38
38
|
require_relative "agents/infrastructure/budget/spend_recorder"
|
|
39
39
|
|
|
40
|
+
# Tracking
|
|
41
|
+
require_relative "agents/tracker"
|
|
42
|
+
require_relative "agents/track_report"
|
|
43
|
+
|
|
40
44
|
# Results
|
|
45
|
+
require_relative "agents/results/trackable"
|
|
41
46
|
require_relative "agents/results/base"
|
|
42
47
|
require_relative "agents/results/embedding_result"
|
|
43
48
|
require_relative "agents/results/transcription_result"
|
|
@@ -119,6 +124,69 @@ module RubyLLM
|
|
|
119
124
|
# @see RubyLLM::Agents::Configuration
|
|
120
125
|
module Agents
|
|
121
126
|
class << self
|
|
127
|
+
# Wraps a block of agent calls, collecting all Results and
|
|
128
|
+
# returning an aggregated TrackReport.
|
|
129
|
+
#
|
|
130
|
+
# Shared options (tenant, tags, request_id) are injected into
|
|
131
|
+
# every agent instantiated inside the block unless overridden.
|
|
132
|
+
#
|
|
133
|
+
# @param tenant [Hash, Object, nil] Shared tenant for all calls
|
|
134
|
+
# @param request_id [String, nil] Shared request ID (auto-generated if nil)
|
|
135
|
+
# @param tags [Hash] Tags merged into each execution's metadata
|
|
136
|
+
# @param defaults [Hash] Additional shared options for agents
|
|
137
|
+
# @yield Block containing agent calls to track
|
|
138
|
+
# @return [TrackReport] Aggregated report of all calls
|
|
139
|
+
#
|
|
140
|
+
# @example Basic usage
|
|
141
|
+
# report = RubyLLM::Agents.track do
|
|
142
|
+
# ChatAgent.call(query: "hello")
|
|
143
|
+
# SummaryAgent.call(text: "...")
|
|
144
|
+
# end
|
|
145
|
+
# report.total_cost # => 0.015
|
|
146
|
+
#
|
|
147
|
+
# @example With shared tenant
|
|
148
|
+
# report = RubyLLM::Agents.track(tenant: current_user) do
|
|
149
|
+
# AgentA.call(query: "test")
|
|
150
|
+
# end
|
|
151
|
+
def track(tenant: nil, request_id: nil, tags: {}, **defaults)
|
|
152
|
+
defaults[:tenant] = tenant if tenant
|
|
153
|
+
tracker = Tracker.new(defaults: defaults, request_id: request_id, tags: tags)
|
|
154
|
+
|
|
155
|
+
# Stack trackers for nesting support
|
|
156
|
+
previous_tracker = Thread.current[:ruby_llm_agents_tracker]
|
|
157
|
+
Thread.current[:ruby_llm_agents_tracker] = tracker
|
|
158
|
+
|
|
159
|
+
started_at = Time.current
|
|
160
|
+
value = nil
|
|
161
|
+
error = nil
|
|
162
|
+
|
|
163
|
+
begin
|
|
164
|
+
value = yield
|
|
165
|
+
rescue => e
|
|
166
|
+
error = e
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
completed_at = Time.current
|
|
170
|
+
|
|
171
|
+
report = TrackReport.new(
|
|
172
|
+
value: value,
|
|
173
|
+
error: error,
|
|
174
|
+
results: tracker.results,
|
|
175
|
+
request_id: tracker.request_id,
|
|
176
|
+
started_at: started_at,
|
|
177
|
+
completed_at: completed_at
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Bubble results up to parent tracker if nested
|
|
181
|
+
if previous_tracker
|
|
182
|
+
tracker.results.each { |r| previous_tracker << r }
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
report
|
|
186
|
+
ensure
|
|
187
|
+
Thread.current[:ruby_llm_agents_tracker] = previous_tracker
|
|
188
|
+
end
|
|
189
|
+
|
|
122
190
|
# Returns the global configuration instance
|
|
123
191
|
#
|
|
124
192
|
# @return [Configuration] The configuration object
|
|
@@ -148,6 +216,146 @@ module RubyLLM
|
|
|
148
216
|
@configuration = Configuration.new
|
|
149
217
|
end
|
|
150
218
|
|
|
219
|
+
# ============================================================
|
|
220
|
+
# Convenience Query API
|
|
221
|
+
# ============================================================
|
|
222
|
+
# These methods provide quick access to execution data without
|
|
223
|
+
# needing to reference model classes directly.
|
|
224
|
+
|
|
225
|
+
# Returns a chainable scope of all executions.
|
|
226
|
+
#
|
|
227
|
+
# @return [ActiveRecord::Relation] All executions
|
|
228
|
+
#
|
|
229
|
+
# @example Recent successful executions
|
|
230
|
+
# RubyLLM::Agents.executions.successful.recent(10)
|
|
231
|
+
#
|
|
232
|
+
# @example Filter by agent
|
|
233
|
+
# RubyLLM::Agents.executions.by_agent("ChatAgent").today
|
|
234
|
+
def executions
|
|
235
|
+
Execution.all
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Returns a usage summary for a given period.
|
|
239
|
+
#
|
|
240
|
+
# @param period [Symbol, Range] :today, :yesterday, :this_week, :this_month,
|
|
241
|
+
# :last_7_days, :last_30_days, or a custom Time range
|
|
242
|
+
# @param agent [String, Class, nil] Optional agent class or name to filter by
|
|
243
|
+
# @param tenant [String, Object, nil] Optional tenant ID or object to filter by
|
|
244
|
+
# @return [Hash] Usage summary with keys:
|
|
245
|
+
# :executions, :successful, :failed, :success_rate,
|
|
246
|
+
# :total_cost, :total_tokens, :avg_duration_ms, :avg_cost
|
|
247
|
+
#
|
|
248
|
+
# @example Global usage today
|
|
249
|
+
# RubyLLM::Agents.usage(period: :today)
|
|
250
|
+
#
|
|
251
|
+
# @example Per-agent usage
|
|
252
|
+
# RubyLLM::Agents.usage(period: :this_month, agent: "ChatAgent")
|
|
253
|
+
#
|
|
254
|
+
# @example Per-tenant usage
|
|
255
|
+
# RubyLLM::Agents.usage(period: :this_week, tenant: current_user)
|
|
256
|
+
def usage(period: :today, agent: nil, tenant: nil)
|
|
257
|
+
scope = scope_for_period(Execution, period)
|
|
258
|
+
scope = scope.by_agent(agent_name_for(agent)) if agent
|
|
259
|
+
scope = scope_for_tenant(scope, tenant) if tenant
|
|
260
|
+
|
|
261
|
+
total = scope.count
|
|
262
|
+
successful = scope.successful.count
|
|
263
|
+
|
|
264
|
+
{
|
|
265
|
+
executions: total,
|
|
266
|
+
successful: successful,
|
|
267
|
+
failed: scope.failed.count,
|
|
268
|
+
success_rate: total.zero? ? 0.0 : (successful.to_f / total * 100).round(1),
|
|
269
|
+
total_cost: scope.sum(:total_cost),
|
|
270
|
+
total_tokens: scope.sum(:total_tokens),
|
|
271
|
+
avg_duration_ms: scope.average(:duration_ms)&.round,
|
|
272
|
+
avg_cost: total.zero? ? 0 : (scope.sum(:total_cost).to_f / total).round(6)
|
|
273
|
+
}
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Returns cost breakdown by agent for a period.
|
|
277
|
+
#
|
|
278
|
+
# @param period [Symbol, Range] Time period (see #usage)
|
|
279
|
+
# @param tenant [String, Object, nil] Optional tenant filter
|
|
280
|
+
# @return [Hash{String => Hash}] Agent name => { cost:, count:, avg_cost: }
|
|
281
|
+
#
|
|
282
|
+
# @example
|
|
283
|
+
# RubyLLM::Agents.costs(period: :this_month)
|
|
284
|
+
# # => { "ChatAgent" => { cost: 12.50, count: 1000, avg_cost: 0.0125 } }
|
|
285
|
+
def costs(period: :today, tenant: nil)
|
|
286
|
+
scope = scope_for_period(Execution, period)
|
|
287
|
+
scope = scope_for_tenant(scope, tenant) if tenant
|
|
288
|
+
|
|
289
|
+
scope.group(:agent_type).pluck(
|
|
290
|
+
:agent_type,
|
|
291
|
+
Arel.sql("COUNT(*)"),
|
|
292
|
+
Arel.sql("SUM(total_cost)"),
|
|
293
|
+
Arel.sql("AVG(total_cost)")
|
|
294
|
+
).each_with_object({}) do |(agent, count, total, avg), hash|
|
|
295
|
+
hash[agent] = {
|
|
296
|
+
cost: total&.to_f&.round(6) || 0,
|
|
297
|
+
count: count,
|
|
298
|
+
avg_cost: avg&.to_f&.round(6) || 0
|
|
299
|
+
}
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Returns all registered agents with their stats.
|
|
304
|
+
#
|
|
305
|
+
# @return [Array<Hash>] Agent info with name, model, stats, etc.
|
|
306
|
+
#
|
|
307
|
+
# @example
|
|
308
|
+
# RubyLLM::Agents.agents
|
|
309
|
+
# # => [{ name: "ChatAgent", active: true, model: "gpt-4o", ... }]
|
|
310
|
+
def agents
|
|
311
|
+
AgentRegistry.all_with_details
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Returns a tenant's usage data.
|
|
315
|
+
#
|
|
316
|
+
# @param tenant [String, Object] Tenant ID or object with llm_tenant_id
|
|
317
|
+
# @return [RubyLLM::Agents::Tenant, nil] The tenant record
|
|
318
|
+
#
|
|
319
|
+
# @example
|
|
320
|
+
# tenant = RubyLLM::Agents.tenant_for(current_user)
|
|
321
|
+
# tenant.cost_today # => 0.42
|
|
322
|
+
# tenant.budget_status # => { enabled: true, enforcement: :soft, ... }
|
|
323
|
+
def tenant_for(tenant)
|
|
324
|
+
Tenant.for(tenant)
|
|
325
|
+
rescue
|
|
326
|
+
nil
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
private
|
|
330
|
+
|
|
331
|
+
def scope_for_period(model, period)
|
|
332
|
+
case period
|
|
333
|
+
when :today then model.today
|
|
334
|
+
when :yesterday then model.yesterday
|
|
335
|
+
when :this_week then model.this_week
|
|
336
|
+
when :this_month then model.this_month
|
|
337
|
+
when :last_7_days then model.last_n_days(7)
|
|
338
|
+
when :last_30_days then model.last_n_days(30)
|
|
339
|
+
when Range then model.where(created_at: period)
|
|
340
|
+
else model.all
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def scope_for_tenant(scope, tenant)
|
|
345
|
+
tenant_id = case tenant
|
|
346
|
+
when String then tenant
|
|
347
|
+
else
|
|
348
|
+
tenant.try(:llm_tenant_id) || tenant.try(:tenant_id) || tenant.try(:id)&.to_s
|
|
349
|
+
end
|
|
350
|
+
scope.by_tenant(tenant_id)
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def agent_name_for(agent)
|
|
354
|
+
agent.is_a?(String) ? agent : agent.name
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
public
|
|
358
|
+
|
|
151
359
|
# Renames an agent in the database, updating execution records and
|
|
152
360
|
# tenant budget configuration keys
|
|
153
361
|
#
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
namespace :ruby_llm_agents do
|
|
4
|
+
desc "Validate your RubyLLM::Agents setup (API keys, migrations, routes, jobs)"
|
|
5
|
+
task doctor: :environment do
|
|
6
|
+
require "generators/ruby_llm_agents/doctor_generator"
|
|
7
|
+
RubyLlmAgents::DoctorGenerator.start([])
|
|
8
|
+
end
|
|
9
|
+
|
|
4
10
|
desc "Rename an agent type in execution records. Usage: rake ruby_llm_agents:rename_agent FROM=OldName TO=NewName [DRY_RUN=1]"
|
|
5
11
|
task rename_agent: :environment do
|
|
6
12
|
from = ENV["FROM"]
|
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: 3.
|
|
4
|
+
version: 3.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- adham90
|
|
@@ -82,6 +82,7 @@ files:
|
|
|
82
82
|
- app/controllers/ruby_llm/agents/agents_controller.rb
|
|
83
83
|
- app/controllers/ruby_llm/agents/dashboard_controller.rb
|
|
84
84
|
- app/controllers/ruby_llm/agents/executions_controller.rb
|
|
85
|
+
- app/controllers/ruby_llm/agents/requests_controller.rb
|
|
85
86
|
- app/controllers/ruby_llm/agents/system_config_controller.rb
|
|
86
87
|
- app/controllers/ruby_llm/agents/tenants_controller.rb
|
|
87
88
|
- app/helpers/ruby_llm/agents/application_helper.rb
|
|
@@ -120,6 +121,8 @@ files:
|
|
|
120
121
|
- app/views/ruby_llm/agents/executions/_list.html.erb
|
|
121
122
|
- app/views/ruby_llm/agents/executions/index.html.erb
|
|
122
123
|
- app/views/ruby_llm/agents/executions/show.html.erb
|
|
124
|
+
- app/views/ruby_llm/agents/requests/index.html.erb
|
|
125
|
+
- app/views/ruby_llm/agents/requests/show.html.erb
|
|
123
126
|
- app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb
|
|
124
127
|
- app/views/ruby_llm/agents/shared/_doc_link.html.erb
|
|
125
128
|
- app/views/ruby_llm/agents/shared/_executions_table.html.erb
|
|
@@ -137,6 +140,8 @@ files:
|
|
|
137
140
|
- config/routes.rb
|
|
138
141
|
- lib/generators/ruby_llm_agents/agent_generator.rb
|
|
139
142
|
- lib/generators/ruby_llm_agents/background_remover_generator.rb
|
|
143
|
+
- lib/generators/ruby_llm_agents/demo_generator.rb
|
|
144
|
+
- lib/generators/ruby_llm_agents/doctor_generator.rb
|
|
140
145
|
- lib/generators/ruby_llm_agents/embedder_generator.rb
|
|
141
146
|
- lib/generators/ruby_llm_agents/image_analyzer_generator.rb
|
|
142
147
|
- lib/generators/ruby_llm_agents/image_editor_generator.rb
|
|
@@ -315,11 +320,14 @@ files:
|
|
|
315
320
|
- lib/ruby_llm/agents/results/image_upscale_result.rb
|
|
316
321
|
- lib/ruby_llm/agents/results/image_variation_result.rb
|
|
317
322
|
- lib/ruby_llm/agents/results/speech_result.rb
|
|
323
|
+
- lib/ruby_llm/agents/results/trackable.rb
|
|
318
324
|
- lib/ruby_llm/agents/results/transcription_result.rb
|
|
319
325
|
- lib/ruby_llm/agents/routing.rb
|
|
320
326
|
- lib/ruby_llm/agents/routing/class_methods.rb
|
|
321
327
|
- lib/ruby_llm/agents/routing/result.rb
|
|
322
328
|
- lib/ruby_llm/agents/text/embedder.rb
|
|
329
|
+
- lib/ruby_llm/agents/track_report.rb
|
|
330
|
+
- lib/ruby_llm/agents/tracker.rb
|
|
323
331
|
- lib/tasks/ruby_llm_agents.rake
|
|
324
332
|
homepage: https://github.com/adham90/ruby_llm-agents
|
|
325
333
|
licenses:
|
|
@@ -342,7 +350,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
342
350
|
- !ruby/object:Gem::Version
|
|
343
351
|
version: '0'
|
|
344
352
|
requirements: []
|
|
345
|
-
rubygems_version: 4.0.
|
|
353
|
+
rubygems_version: 4.0.7
|
|
346
354
|
specification_version: 4
|
|
347
355
|
summary: Agent framework for building LLM-powered agents with RubyLLM
|
|
348
356
|
test_files: []
|