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