ruby_llm-agents 1.3.3 → 2.0.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 +101 -334
- data/app/controllers/concerns/ruby_llm/agents/sortable.rb +0 -1
- data/app/controllers/ruby_llm/agents/agents_controller.rb +5 -56
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +22 -106
- data/app/controllers/ruby_llm/agents/executions_controller.rb +4 -114
- data/app/controllers/ruby_llm/agents/tenants_controller.rb +30 -2
- data/app/helpers/ruby_llm/agents/application_helper.rb +19 -53
- data/app/models/ruby_llm/agents/execution/analytics.rb +13 -54
- data/app/models/ruby_llm/agents/execution/scopes.rb +61 -14
- data/app/models/ruby_llm/agents/execution.rb +46 -10
- data/app/models/ruby_llm/agents/execution_detail.rb +18 -0
- data/app/models/ruby_llm/agents/tenant/budgetable.rb +132 -24
- data/app/models/ruby_llm/agents/tenant/incrementable.rb +117 -0
- data/app/models/ruby_llm/agents/tenant/resettable.rb +128 -0
- data/app/models/ruby_llm/agents/tenant/trackable.rb +46 -12
- data/app/models/ruby_llm/agents/tenant.rb +2 -3
- data/app/models/ruby_llm/agents/tenant_budget.rb +6 -3
- data/app/services/ruby_llm/agents/agent_registry.rb +6 -112
- data/app/views/layouts/ruby_llm/agents/application.html.erb +87 -252
- data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +71 -218
- data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +20 -63
- data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +44 -131
- data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +16 -57
- data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +39 -104
- data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +29 -82
- data/app/views/ruby_llm/agents/agents/_empty_state.html.erb +4 -14
- data/app/views/ruby_llm/agents/agents/index.html.erb +105 -274
- data/app/views/ruby_llm/agents/agents/show.html.erb +248 -378
- data/app/views/ruby_llm/agents/dashboard/_action_center.html.erb +29 -52
- data/app/views/ruby_llm/agents/dashboard/_tenant_budget.html.erb +73 -99
- data/app/views/ruby_llm/agents/dashboard/index.html.erb +228 -433
- data/app/views/ruby_llm/agents/executions/_execution.html.erb +1 -1
- data/app/views/ruby_llm/agents/executions/_filters.html.erb +4 -25
- data/app/views/ruby_llm/agents/executions/_list.html.erb +111 -152
- data/app/views/ruby_llm/agents/executions/index.html.erb +5 -7
- data/app/views/ruby_llm/agents/executions/show.html.erb +528 -989
- data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +5 -21
- data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +70 -191
- data/app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb +16 -44
- data/app/views/ruby_llm/agents/shared/_select_dropdown.html.erb +12 -41
- data/app/views/ruby_llm/agents/shared/_status_badge.html.erb +11 -65
- data/app/views/ruby_llm/agents/shared/_tenant_filter.html.erb +6 -5
- data/app/views/ruby_llm/agents/system_config/show.html.erb +240 -351
- data/app/views/ruby_llm/agents/tenants/_form.html.erb +67 -77
- data/app/views/ruby_llm/agents/tenants/edit.html.erb +7 -9
- data/app/views/ruby_llm/agents/tenants/index.html.erb +100 -122
- data/app/views/ruby_llm/agents/tenants/show.html.erb +146 -336
- data/config/routes.rb +0 -13
- data/lib/generators/ruby_llm_agents/install_generator.rb +9 -14
- data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +2 -12
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +0 -2
- data/lib/generators/ruby_llm_agents/templates/add_usage_counters_to_tenants_migration.rb.tt +37 -0
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +1 -2
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +1 -1
- data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +0 -1
- data/lib/generators/ruby_llm_agents/templates/create_execution_details_migration.rb.tt +27 -0
- data/lib/generators/ruby_llm_agents/templates/create_tenants_migration.rb.tt +25 -0
- data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +0 -1
- data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +9 -12
- data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +40 -71
- data/lib/generators/ruby_llm_agents/templates/remove_agent_version_migration.rb.tt +13 -0
- data/lib/generators/ruby_llm_agents/templates/remove_workflow_columns_migration.rb.tt +19 -0
- data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +2 -4
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +0 -1
- data/lib/generators/ruby_llm_agents/templates/split_execution_details_migration.rb.tt +232 -0
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +58 -262
- data/lib/ruby_llm/agents/audio/speaker.rb +0 -1
- data/lib/ruby_llm/agents/audio/transcriber.rb +0 -1
- data/lib/ruby_llm/agents/base_agent.rb +52 -6
- data/lib/ruby_llm/agents/core/base/callbacks.rb +142 -0
- data/lib/ruby_llm/agents/core/base.rb +23 -55
- data/lib/ruby_llm/agents/core/configuration.rb +58 -117
- data/lib/ruby_llm/agents/core/errors.rb +0 -58
- data/lib/ruby_llm/agents/core/instrumentation.rb +157 -110
- data/lib/ruby_llm/agents/core/llm_tenant.rb +8 -7
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/dsl/base.rb +157 -17
- data/lib/ruby_llm/agents/dsl/caching.rb +33 -2
- data/lib/ruby_llm/agents/dsl/reliability.rb +148 -0
- data/lib/ruby_llm/agents/dsl.rb +1 -2
- data/lib/ruby_llm/agents/image/analyzer/execution.rb +1 -2
- data/lib/ruby_llm/agents/image/background_remover/execution.rb +1 -2
- data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +1 -13
- data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +2 -2
- data/lib/ruby_llm/agents/image/editor/dsl.rb +0 -14
- data/lib/ruby_llm/agents/image/editor/execution.rb +1 -10
- data/lib/ruby_llm/agents/image/editor.rb +0 -1
- data/lib/ruby_llm/agents/image/generator.rb +0 -21
- data/lib/ruby_llm/agents/image/pipeline/dsl.rb +0 -13
- data/lib/ruby_llm/agents/image/pipeline/execution.rb +0 -1
- data/lib/ruby_llm/agents/image/transformer/dsl.rb +0 -13
- data/lib/ruby_llm/agents/image/transformer/execution.rb +1 -10
- data/lib/ruby_llm/agents/image/transformer.rb +0 -1
- data/lib/ruby_llm/agents/image/upscaler/execution.rb +1 -2
- data/lib/ruby_llm/agents/image/variator/execution.rb +1 -2
- data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +78 -173
- data/lib/ruby_llm/agents/infrastructure/attempt_tracker.rb +1 -0
- data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +66 -2
- data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +0 -12
- data/lib/ruby_llm/agents/infrastructure/circuit_breaker.rb +10 -13
- data/lib/ruby_llm/agents/infrastructure/reliability.rb +37 -2
- data/lib/ruby_llm/agents/pipeline/context.rb +0 -1
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +28 -4
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +3 -10
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +88 -55
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +5 -41
- data/lib/ruby_llm/agents/rails/engine.rb +6 -6
- data/lib/ruby_llm/agents/results/base.rb +1 -49
- data/lib/ruby_llm/agents/text/embedder.rb +0 -1
- data/lib/ruby_llm/agents.rb +1 -9
- data/lib/tasks/ruby_llm_agents.rake +34 -0
- metadata +12 -81
- data/app/controllers/ruby_llm/agents/api_configurations_controller.rb +0 -214
- data/app/controllers/ruby_llm/agents/workflows_controller.rb +0 -544
- data/app/mailers/ruby_llm/agents/alert_mailer.rb +0 -84
- data/app/mailers/ruby_llm/agents/application_mailer.rb +0 -28
- data/app/models/ruby_llm/agents/api_configuration.rb +0 -386
- data/app/models/ruby_llm/agents/execution/workflow.rb +0 -170
- data/app/models/ruby_llm/agents/tenant/configurable.rb +0 -135
- data/app/views/ruby_llm/agents/agents/_agent.html.erb +0 -98
- data/app/views/ruby_llm/agents/agents/_version_comparison.html.erb +0 -186
- data/app/views/ruby_llm/agents/agents/_workflow.html.erb +0 -126
- data/app/views/ruby_llm/agents/alert_mailer/alert_notification.html.erb +0 -107
- data/app/views/ruby_llm/agents/alert_mailer/alert_notification.text.erb +0 -18
- data/app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb +0 -34
- data/app/views/ruby_llm/agents/api_configurations/_form.html.erb +0 -288
- data/app/views/ruby_llm/agents/api_configurations/edit.html.erb +0 -95
- data/app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb +0 -97
- data/app/views/ruby_llm/agents/api_configurations/show.html.erb +0 -214
- data/app/views/ruby_llm/agents/api_configurations/tenant.html.erb +0 -179
- data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +0 -73
- data/app/views/ruby_llm/agents/dashboard/_alerts_feed.html.erb +0 -62
- data/app/views/ruby_llm/agents/dashboard/_breaker_strip.html.erb +0 -47
- data/app/views/ruby_llm/agents/dashboard/_budgets_bar.html.erb +0 -75
- data/app/views/ruby_llm/agents/dashboard/_model_comparison.html.erb +0 -56
- data/app/views/ruby_llm/agents/dashboard/_model_cost_breakdown.html.erb +0 -115
- data/app/views/ruby_llm/agents/dashboard/_now_strip.html.erb +0 -59
- data/app/views/ruby_llm/agents/dashboard/_top_errors.html.erb +0 -60
- data/app/views/ruby_llm/agents/executions/_workflow_summary.html.erb +0 -86
- data/app/views/ruby_llm/agents/executions/dry_run.html.erb +0 -149
- data/app/views/ruby_llm/agents/shared/_breadcrumbs.html.erb +0 -48
- data/app/views/ruby_llm/agents/shared/_nav_link.html.erb +0 -27
- data/app/views/ruby_llm/agents/shared/_stat_card.html.erb +0 -14
- data/app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb +0 -35
- data/app/views/ruby_llm/agents/workflows/_empty_state.html.erb +0 -22
- data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +0 -228
- data/app/views/ruby_llm/agents/workflows/_structure_dsl.html.erb +0 -539
- data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +0 -76
- data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +0 -74
- data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +0 -108
- data/app/views/ruby_llm/agents/workflows/_workflow_diagram.html.erb +0 -920
- data/app/views/ruby_llm/agents/workflows/index.html.erb +0 -179
- data/app/views/ruby_llm/agents/workflows/show.html.erb +0 -467
- data/lib/generators/ruby_llm_agents/api_configuration_generator.rb +0 -100
- data/lib/generators/ruby_llm_agents/templates/add_workflow_migration.rb.tt +0 -38
- data/lib/generators/ruby_llm_agents/templates/application_workflow.rb.tt +0 -48
- data/lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt +0 -90
- data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +0 -551
- data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +0 -181
- data/lib/ruby_llm/agents/core/base/moderation_execution.rb +0 -274
- data/lib/ruby_llm/agents/core/resolved_config.rb +0 -348
- data/lib/ruby_llm/agents/image/generator/content_policy.rb +0 -95
- data/lib/ruby_llm/agents/infrastructure/redactor.rb +0 -130
- data/lib/ruby_llm/agents/results/moderation_result.rb +0 -158
- data/lib/ruby_llm/agents/text/moderator.rb +0 -237
- data/lib/ruby_llm/agents/workflow/approval.rb +0 -205
- data/lib/ruby_llm/agents/workflow/approval_store.rb +0 -179
- data/lib/ruby_llm/agents/workflow/async.rb +0 -220
- data/lib/ruby_llm/agents/workflow/async_executor.rb +0 -156
- data/lib/ruby_llm/agents/workflow/dsl/executor.rb +0 -467
- data/lib/ruby_llm/agents/workflow/dsl/input_schema.rb +0 -244
- data/lib/ruby_llm/agents/workflow/dsl/iteration_executor.rb +0 -289
- data/lib/ruby_llm/agents/workflow/dsl/parallel_group.rb +0 -107
- data/lib/ruby_llm/agents/workflow/dsl/route_builder.rb +0 -150
- data/lib/ruby_llm/agents/workflow/dsl/schedule_helpers.rb +0 -187
- data/lib/ruby_llm/agents/workflow/dsl/step_config.rb +0 -352
- data/lib/ruby_llm/agents/workflow/dsl/step_executor.rb +0 -415
- data/lib/ruby_llm/agents/workflow/dsl/wait_config.rb +0 -257
- data/lib/ruby_llm/agents/workflow/dsl/wait_executor.rb +0 -317
- data/lib/ruby_llm/agents/workflow/dsl.rb +0 -576
- data/lib/ruby_llm/agents/workflow/instrumentation.rb +0 -249
- data/lib/ruby_llm/agents/workflow/notifiers/base.rb +0 -117
- data/lib/ruby_llm/agents/workflow/notifiers/email.rb +0 -117
- data/lib/ruby_llm/agents/workflow/notifiers/slack.rb +0 -180
- data/lib/ruby_llm/agents/workflow/notifiers/webhook.rb +0 -121
- data/lib/ruby_llm/agents/workflow/notifiers.rb +0 -70
- data/lib/ruby_llm/agents/workflow/orchestrator.rb +0 -416
- data/lib/ruby_llm/agents/workflow/result.rb +0 -592
- data/lib/ruby_llm/agents/workflow/thread_pool.rb +0 -185
- data/lib/ruby_llm/agents/workflow/throttle_manager.rb +0 -206
- data/lib/ruby_llm/agents/workflow/wait_result.rb +0 -213
|
@@ -57,25 +57,51 @@ module RubyLLM
|
|
|
57
57
|
|
|
58
58
|
# Checks budget before execution
|
|
59
59
|
#
|
|
60
|
+
# For tenants, checks budget via counter columns on the tenant model.
|
|
61
|
+
# For non-tenant usage, falls back to BudgetTracker (cache-based).
|
|
62
|
+
#
|
|
60
63
|
# @param context [Context] The execution context
|
|
61
64
|
# @raise [BudgetExceededError] If budget exceeded with hard enforcement
|
|
62
65
|
def check_budget!(context)
|
|
66
|
+
if context.tenant_id.present?
|
|
67
|
+
tenant = RubyLLM::Agents::Tenant.find_by(tenant_id: context.tenant_id)
|
|
68
|
+
if tenant
|
|
69
|
+
tenant.check_budget!(context.agent_class&.name)
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Fallback to cache-based checking (non-tenant or no tenant record)
|
|
63
75
|
BudgetTracker.check_budget!(
|
|
64
76
|
context.agent_class&.name,
|
|
65
77
|
tenant_id: context.tenant_id
|
|
66
78
|
)
|
|
67
79
|
rescue RubyLLM::Agents::Reliability::BudgetExceededError
|
|
68
|
-
# Re-raise budget errors
|
|
69
80
|
raise
|
|
70
81
|
rescue StandardError => e
|
|
71
|
-
# Log but don't fail on budget check errors
|
|
72
82
|
error("Budget check failed: #{e.message}")
|
|
73
83
|
end
|
|
74
84
|
|
|
75
85
|
# Records spend after execution
|
|
76
86
|
#
|
|
87
|
+
# For tenants, uses atomic SQL increment via tenant.record_execution!.
|
|
88
|
+
# For non-tenant usage, falls back to BudgetTracker (cache-based).
|
|
89
|
+
#
|
|
77
90
|
# @param context [Context] The execution context
|
|
78
91
|
def record_spend!(context)
|
|
92
|
+
if context.tenant_id.present?
|
|
93
|
+
tenant = RubyLLM::Agents::Tenant.find_by(tenant_id: context.tenant_id)
|
|
94
|
+
if tenant
|
|
95
|
+
tenant.record_execution!(
|
|
96
|
+
cost: context.total_cost || 0,
|
|
97
|
+
tokens: context.total_tokens || 0,
|
|
98
|
+
error: context.error?
|
|
99
|
+
)
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Fallback for non-tenant usage
|
|
79
105
|
return unless context.total_cost&.positive?
|
|
80
106
|
|
|
81
107
|
BudgetTracker.record_spend!(
|
|
@@ -84,7 +110,6 @@ module RubyLLM
|
|
|
84
110
|
tenant_id: context.tenant_id
|
|
85
111
|
)
|
|
86
112
|
|
|
87
|
-
# Also record tokens if available
|
|
88
113
|
if context.total_tokens&.positive?
|
|
89
114
|
BudgetTracker.record_tokens!(
|
|
90
115
|
context.agent_class&.name,
|
|
@@ -93,7 +118,6 @@ module RubyLLM
|
|
|
93
118
|
)
|
|
94
119
|
end
|
|
95
120
|
rescue StandardError => e
|
|
96
|
-
# Log but don't fail on spend recording errors
|
|
97
121
|
error("Failed to record spend: #{e.message}")
|
|
98
122
|
end
|
|
99
123
|
end
|
|
@@ -23,13 +23,6 @@ module RubyLLM
|
|
|
23
23
|
# cache_for 1.hour
|
|
24
24
|
# end
|
|
25
25
|
#
|
|
26
|
-
# @example Cache versioning
|
|
27
|
-
# class MyEmbedder < RubyLLM::Agents::Embedder
|
|
28
|
-
# model "text-embedding-3-small"
|
|
29
|
-
# version "2.0" # Change to invalidate cache
|
|
30
|
-
# cache_for 1.hour
|
|
31
|
-
# end
|
|
32
|
-
#
|
|
33
26
|
class Cache < Base
|
|
34
27
|
# Process caching
|
|
35
28
|
#
|
|
@@ -91,14 +84,15 @@ module RubyLLM
|
|
|
91
84
|
|
|
92
85
|
# Generates a cache key for the context
|
|
93
86
|
#
|
|
94
|
-
#
|
|
87
|
+
# Cache keys are content-based, including:
|
|
95
88
|
# - Namespace prefix
|
|
96
89
|
# - Agent type
|
|
97
90
|
# - Agent class name
|
|
98
|
-
# - Version (for cache invalidation)
|
|
99
91
|
# - Model
|
|
100
92
|
# - SHA256 hash of input
|
|
101
93
|
#
|
|
94
|
+
# This means caches automatically invalidate when inputs change.
|
|
95
|
+
#
|
|
102
96
|
# @param context [Context] The execution context
|
|
103
97
|
# @return [String] The cache key
|
|
104
98
|
def generate_cache_key(context)
|
|
@@ -106,7 +100,6 @@ module RubyLLM
|
|
|
106
100
|
"ruby_llm_agents",
|
|
107
101
|
context.agent_type,
|
|
108
102
|
context.agent_class&.name,
|
|
109
|
-
config(:version, "1.0"),
|
|
110
103
|
context.model,
|
|
111
104
|
hash_input(context.input)
|
|
112
105
|
].compact
|
|
@@ -18,7 +18,6 @@ module RubyLLM
|
|
|
18
18
|
# Tracking is enabled/disabled per agent type via configuration:
|
|
19
19
|
# - track_executions (conversation agents)
|
|
20
20
|
# - track_embeddings
|
|
21
|
-
# - track_moderations
|
|
22
21
|
# - track_image_generations
|
|
23
22
|
# - track_audio
|
|
24
23
|
#
|
|
@@ -92,7 +91,15 @@ module RubyLLM
|
|
|
92
91
|
return nil if context.cached? && !track_cache_hits?
|
|
93
92
|
|
|
94
93
|
data = build_running_execution_data(context)
|
|
95
|
-
Execution.create!(data)
|
|
94
|
+
execution = Execution.create!(data)
|
|
95
|
+
|
|
96
|
+
# Create detail record with parameters
|
|
97
|
+
params = sanitize_parameters(context)
|
|
98
|
+
if params.present? && params != {}
|
|
99
|
+
execution.create_detail!(parameters: params)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
execution
|
|
96
103
|
rescue StandardError => e
|
|
97
104
|
error("Failed to create running execution record: #{e.message}")
|
|
98
105
|
nil
|
|
@@ -120,14 +127,10 @@ module RubyLLM
|
|
|
120
127
|
end
|
|
121
128
|
|
|
122
129
|
update_data = build_completion_data(context, status)
|
|
130
|
+
execution.update!(update_data)
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
# For now, update synchronously to ensure dashboard shows correct status
|
|
127
|
-
execution.update!(update_data)
|
|
128
|
-
else
|
|
129
|
-
execution.update!(update_data)
|
|
130
|
-
end
|
|
132
|
+
# Save detail data (prompts, responses, tool calls, etc.)
|
|
133
|
+
save_execution_details(execution, context, status)
|
|
131
134
|
rescue StandardError => e
|
|
132
135
|
error("Failed to complete execution record: #{e.message}")
|
|
133
136
|
raise # Re-raise for ensure block to handle via mark_execution_failed!
|
|
@@ -150,11 +153,22 @@ module RubyLLM
|
|
|
150
153
|
update_data = {
|
|
151
154
|
status: "error",
|
|
152
155
|
completed_at: Time.current,
|
|
153
|
-
error_class: error&.class&.name || "UnknownError"
|
|
154
|
-
error_message: error_message
|
|
156
|
+
error_class: error&.class&.name || "UnknownError"
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
execution.class.where(id: execution.id, status: "running").update_all(update_data)
|
|
160
|
+
|
|
161
|
+
# Store error_message in detail table (best-effort)
|
|
162
|
+
begin
|
|
163
|
+
detail_attrs = { error_message: error_message }
|
|
164
|
+
if execution.detail
|
|
165
|
+
execution.detail.update_columns(detail_attrs)
|
|
166
|
+
else
|
|
167
|
+
RubyLLM::Agents::ExecutionDetail.create!(detail_attrs.merge(execution_id: execution.id))
|
|
168
|
+
end
|
|
169
|
+
rescue StandardError
|
|
170
|
+
# Non-critical
|
|
171
|
+
end
|
|
158
172
|
rescue StandardError => e
|
|
159
173
|
error("CRITICAL: Failed emergency status update for execution #{execution&.id}: #{e.message}")
|
|
160
174
|
end
|
|
@@ -174,7 +188,6 @@ module RubyLLM
|
|
|
174
188
|
def build_running_execution_data(context)
|
|
175
189
|
data = {
|
|
176
190
|
agent_type: context.agent_class&.name,
|
|
177
|
-
agent_version: config(:version, "1.0"),
|
|
178
191
|
model_id: context.model,
|
|
179
192
|
status: "running",
|
|
180
193
|
started_at: context.started_at,
|
|
@@ -189,9 +202,6 @@ module RubyLLM
|
|
|
189
202
|
data[:tenant_id] = context.tenant_id
|
|
190
203
|
end
|
|
191
204
|
|
|
192
|
-
# Add sanitized parameters
|
|
193
|
-
data[:parameters] = sanitize_parameters(context)
|
|
194
|
-
|
|
195
205
|
data
|
|
196
206
|
end
|
|
197
207
|
|
|
@@ -212,38 +222,63 @@ module RubyLLM
|
|
|
212
222
|
attempts_count: context.attempts_made
|
|
213
223
|
}
|
|
214
224
|
|
|
215
|
-
#
|
|
225
|
+
# Store niche cache key in metadata
|
|
226
|
+
merged_metadata = context.metadata.dup rescue {}
|
|
216
227
|
if context.cached? && context[:cache_key]
|
|
217
|
-
|
|
228
|
+
merged_metadata["response_cache_key"] = context[:cache_key]
|
|
218
229
|
end
|
|
230
|
+
data[:metadata] = merged_metadata if merged_metadata.any?
|
|
219
231
|
|
|
220
|
-
#
|
|
232
|
+
# Error class on execution (error_message goes to detail)
|
|
221
233
|
if context.error
|
|
222
234
|
data[:error_class] = context.error.class.name
|
|
223
|
-
data[:error_message] = truncate_error_message(context.error.message)
|
|
224
235
|
end
|
|
225
236
|
|
|
226
|
-
#
|
|
227
|
-
data[:metadata] = context.metadata if context.metadata.any?
|
|
228
|
-
|
|
229
|
-
# Add enhanced tool calls if present
|
|
237
|
+
# Tool calls count on execution
|
|
230
238
|
if context[:tool_calls].present?
|
|
231
|
-
data[:tool_calls] = context[:tool_calls]
|
|
232
239
|
data[:tool_calls_count] = context[:tool_calls].size
|
|
233
240
|
end
|
|
234
241
|
|
|
235
|
-
#
|
|
242
|
+
# Attempts count on execution
|
|
236
243
|
if context[:reliability_attempts].present?
|
|
237
|
-
data[:attempts] = context[:reliability_attempts]
|
|
238
244
|
data[:attempts_count] = context[:reliability_attempts].size
|
|
239
245
|
end
|
|
240
246
|
|
|
241
|
-
|
|
247
|
+
data
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Saves detail data to the execution_details table after completion
|
|
251
|
+
def save_execution_details(execution, context, status)
|
|
252
|
+
return unless execution
|
|
253
|
+
|
|
254
|
+
detail_data = {}
|
|
255
|
+
|
|
256
|
+
if context.error
|
|
257
|
+
detail_data[:error_message] = truncate_error_message(context.error.message)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
if context[:tool_calls].present?
|
|
261
|
+
detail_data[:tool_calls] = context[:tool_calls]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
if context[:reliability_attempts].present?
|
|
265
|
+
detail_data[:attempts] = context[:reliability_attempts]
|
|
266
|
+
end
|
|
267
|
+
|
|
242
268
|
if global_config.persist_responses && context.output.respond_to?(:content)
|
|
243
|
-
|
|
269
|
+
detail_data[:response] = serialize_response(context)
|
|
244
270
|
end
|
|
245
271
|
|
|
246
|
-
|
|
272
|
+
has_data = detail_data.values.any? { |v| v.present? && v != {} && v != [] }
|
|
273
|
+
return unless has_data
|
|
274
|
+
|
|
275
|
+
if execution.detail
|
|
276
|
+
execution.detail.update!(detail_data)
|
|
277
|
+
else
|
|
278
|
+
execution.create_detail!(detail_data)
|
|
279
|
+
end
|
|
280
|
+
rescue StandardError => e
|
|
281
|
+
error("Failed to save execution details: #{e.message}")
|
|
247
282
|
end
|
|
248
283
|
|
|
249
284
|
# Persists execution data to database (legacy fallback)
|
|
@@ -272,9 +307,13 @@ module RubyLLM
|
|
|
272
307
|
# @param status [String] "success" or "error"
|
|
273
308
|
# @return [Hash] Execution data
|
|
274
309
|
def build_execution_data(context, status)
|
|
310
|
+
merged_metadata = context.metadata.dup rescue {}
|
|
311
|
+
if context.cached? && context[:cache_key]
|
|
312
|
+
merged_metadata["response_cache_key"] = context[:cache_key]
|
|
313
|
+
end
|
|
314
|
+
|
|
275
315
|
data = {
|
|
276
316
|
agent_type: context.agent_class&.name,
|
|
277
|
-
agent_version: config(:version, "1.0"),
|
|
278
317
|
model_id: context.model,
|
|
279
318
|
status: determine_status(context, status),
|
|
280
319
|
duration_ms: context.duration_ms,
|
|
@@ -284,7 +323,8 @@ module RubyLLM
|
|
|
284
323
|
input_tokens: context.input_tokens || 0,
|
|
285
324
|
output_tokens: context.output_tokens || 0,
|
|
286
325
|
total_cost: context.total_cost || 0,
|
|
287
|
-
attempts_count: context.attempts_made
|
|
326
|
+
attempts_count: context.attempts_made,
|
|
327
|
+
metadata: merged_metadata
|
|
288
328
|
}
|
|
289
329
|
|
|
290
330
|
# Add tenant_id only if multi-tenancy is enabled and tenant is set
|
|
@@ -292,39 +332,30 @@ module RubyLLM
|
|
|
292
332
|
data[:tenant_id] = context.tenant_id
|
|
293
333
|
end
|
|
294
334
|
|
|
295
|
-
#
|
|
296
|
-
if context.cached? && context[:cache_key]
|
|
297
|
-
data[:response_cache_key] = context[:cache_key]
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
# Add error details if present
|
|
335
|
+
# Error class on execution
|
|
301
336
|
if context.error
|
|
302
337
|
data[:error_class] = context.error.class.name
|
|
303
|
-
data[:error_message] = truncate_error_message(context.error.message)
|
|
304
338
|
end
|
|
305
339
|
|
|
306
|
-
#
|
|
307
|
-
data[:metadata] = context.metadata if context.metadata.any?
|
|
308
|
-
|
|
309
|
-
# Add sanitized parameters
|
|
310
|
-
data[:parameters] = sanitize_parameters(context)
|
|
311
|
-
|
|
312
|
-
# Add enhanced tool calls if present
|
|
340
|
+
# Tool calls count on execution
|
|
313
341
|
if context[:tool_calls].present?
|
|
314
|
-
data[:tool_calls] = context[:tool_calls]
|
|
315
342
|
data[:tool_calls_count] = context[:tool_calls].size
|
|
316
343
|
end
|
|
317
344
|
|
|
318
|
-
#
|
|
345
|
+
# Attempts count on execution
|
|
319
346
|
if context[:reliability_attempts].present?
|
|
320
|
-
data[:attempts] = context[:reliability_attempts]
|
|
321
347
|
data[:attempts_count] = context[:reliability_attempts].size
|
|
322
348
|
end
|
|
323
349
|
|
|
324
|
-
#
|
|
350
|
+
# Store detail data for separate creation
|
|
351
|
+
detail_data = { parameters: sanitize_parameters(context) }
|
|
352
|
+
detail_data[:error_message] = truncate_error_message(context.error.message) if context.error
|
|
353
|
+
detail_data[:tool_calls] = context[:tool_calls] if context[:tool_calls].present?
|
|
354
|
+
detail_data[:attempts] = context[:reliability_attempts] if context[:reliability_attempts].present?
|
|
325
355
|
if global_config.persist_responses && context.output.respond_to?(:content)
|
|
326
|
-
|
|
356
|
+
detail_data[:response] = serialize_response(context)
|
|
327
357
|
end
|
|
358
|
+
data[:_detail_data] = detail_data
|
|
328
359
|
|
|
329
360
|
data
|
|
330
361
|
end
|
|
@@ -401,8 +432,7 @@ module RubyLLM
|
|
|
401
432
|
response_data[:input_tokens] = context.input_tokens if context.input_tokens
|
|
402
433
|
response_data[:output_tokens] = context.output_tokens if context.output_tokens
|
|
403
434
|
|
|
404
|
-
|
|
405
|
-
Redactor.redact(response_data)
|
|
435
|
+
response_data
|
|
406
436
|
rescue StandardError => e
|
|
407
437
|
error("Failed to serialize response: #{e.message}")
|
|
408
438
|
nil
|
|
@@ -419,7 +449,12 @@ module RubyLLM
|
|
|
419
449
|
#
|
|
420
450
|
# @param data [Hash] Execution data
|
|
421
451
|
def create_execution_record(data)
|
|
422
|
-
|
|
452
|
+
detail_data = data.delete(:_detail_data)
|
|
453
|
+
execution = Execution.create!(data)
|
|
454
|
+
if detail_data && detail_data.values.any? { |v| v.present? && v != {} && v != [] }
|
|
455
|
+
execution.create_detail!(detail_data)
|
|
456
|
+
end
|
|
457
|
+
execution
|
|
423
458
|
end
|
|
424
459
|
|
|
425
460
|
# Returns whether tracking is enabled for this agent type
|
|
@@ -432,8 +467,6 @@ module RubyLLM
|
|
|
432
467
|
case context.agent_type
|
|
433
468
|
when :embedding
|
|
434
469
|
cfg.track_embeddings
|
|
435
|
-
when :moderation
|
|
436
|
-
cfg.track_moderation
|
|
437
470
|
when :image
|
|
438
471
|
cfg.track_image_generation
|
|
439
472
|
when :audio
|
|
@@ -8,18 +8,16 @@ module RubyLLM
|
|
|
8
8
|
#
|
|
9
9
|
# This middleware extracts tenant information from the context options,
|
|
10
10
|
# sets the tenant_id, tenant_object, and tenant_config on the context,
|
|
11
|
-
# and applies
|
|
11
|
+
# and applies any tenant-specific API keys to RubyLLM.
|
|
12
12
|
#
|
|
13
13
|
# Supports three formats:
|
|
14
14
|
# - Object with llm_tenant_id method (recommended for ActiveRecord models)
|
|
15
15
|
# - Hash with :id key (simple/legacy format)
|
|
16
16
|
# - nil (no tenant - single-tenant mode)
|
|
17
17
|
#
|
|
18
|
-
# API
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# 3. Global database config
|
|
22
|
-
# 4. RubyLLM.configuration (set via initializer or environment)
|
|
18
|
+
# API keys are configured via:
|
|
19
|
+
# - RubyLLM.configuration (set via initializer or environment variables)
|
|
20
|
+
# - Tenant object's llm_api_keys method (for per-tenant overrides)
|
|
23
21
|
#
|
|
24
22
|
# @example With ActiveRecord model
|
|
25
23
|
# # Model uses llm_tenant DSL
|
|
@@ -88,16 +86,10 @@ module RubyLLM
|
|
|
88
86
|
|
|
89
87
|
# Applies API configuration to RubyLLM based on resolved tenant
|
|
90
88
|
#
|
|
91
|
-
# This method resolves API keys from multiple sources and applies
|
|
92
|
-
# them to RubyLLM.config before the agent executes.
|
|
93
|
-
#
|
|
94
89
|
# @param context [Context] The execution context
|
|
95
90
|
def apply_api_configuration!(context)
|
|
96
|
-
#
|
|
91
|
+
# Apply keys from tenant object's llm_api_keys method if present
|
|
97
92
|
apply_tenant_object_api_keys!(context)
|
|
98
|
-
|
|
99
|
-
# Then, apply database configuration (tenant > global > ruby_llm_config)
|
|
100
|
-
apply_database_api_configuration!(context)
|
|
101
93
|
end
|
|
102
94
|
|
|
103
95
|
# Applies API keys from tenant object's llm_api_keys method
|
|
@@ -116,22 +108,6 @@ module RubyLLM
|
|
|
116
108
|
warn_api_key_error("tenant object", e)
|
|
117
109
|
end
|
|
118
110
|
|
|
119
|
-
# Applies API configuration from the database
|
|
120
|
-
#
|
|
121
|
-
# @param context [Context] The execution context
|
|
122
|
-
def apply_database_api_configuration!(context)
|
|
123
|
-
return unless api_configuration_available?
|
|
124
|
-
|
|
125
|
-
resolved = ApiConfiguration.resolve(tenant_id: context.tenant_id)
|
|
126
|
-
resolved.apply_to_ruby_llm!
|
|
127
|
-
|
|
128
|
-
# Store resolved config on context for observability
|
|
129
|
-
context[:resolved_api_config] = resolved
|
|
130
|
-
rescue StandardError => e
|
|
131
|
-
# Log but don't fail if DB lookup fails
|
|
132
|
-
warn_api_key_error("database", e)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
111
|
# Applies a hash of API keys to RubyLLM configuration
|
|
136
112
|
#
|
|
137
113
|
# @param api_keys [Hash] Hash of provider => key mappings
|
|
@@ -154,18 +130,6 @@ module RubyLLM
|
|
|
154
130
|
"#{provider}_api_key="
|
|
155
131
|
end
|
|
156
132
|
|
|
157
|
-
# Checks if ApiConfiguration model is available
|
|
158
|
-
#
|
|
159
|
-
# @return [Boolean]
|
|
160
|
-
def api_configuration_available?
|
|
161
|
-
return false unless defined?(RubyLLM::Agents::ApiConfiguration)
|
|
162
|
-
|
|
163
|
-
# Check if table exists
|
|
164
|
-
ApiConfiguration.table_exists?
|
|
165
|
-
rescue StandardError
|
|
166
|
-
false
|
|
167
|
-
end
|
|
168
|
-
|
|
169
133
|
# Logs a warning about API key resolution failure
|
|
170
134
|
#
|
|
171
135
|
# @param source [String] Source that failed
|
|
@@ -34,9 +34,7 @@ module RubyLLM
|
|
|
34
34
|
config.to_prepare do
|
|
35
35
|
require_relative "../infrastructure/execution_logger_job"
|
|
36
36
|
require_relative "../core/instrumentation"
|
|
37
|
-
require_relative "../core/resolved_config"
|
|
38
37
|
require_relative "../core/base"
|
|
39
|
-
require_relative "../workflow/orchestrator"
|
|
40
38
|
|
|
41
39
|
# Resolve the parent controller class from configuration
|
|
42
40
|
# Default is ActionController::Base, but can be set to inherit from app controllers
|
|
@@ -161,6 +159,12 @@ module RubyLLM
|
|
|
161
159
|
end)
|
|
162
160
|
end
|
|
163
161
|
|
|
162
|
+
# Load rake tasks from lib/tasks
|
|
163
|
+
rake_tasks do
|
|
164
|
+
tasks_path = File.expand_path("../../../tasks", __dir__)
|
|
165
|
+
Dir[File.join(tasks_path, "**", "*.rake")].each { |f| load f }
|
|
166
|
+
end
|
|
167
|
+
|
|
164
168
|
# Configures default generators for the engine
|
|
165
169
|
# Sets up RSpec and FactoryBot for generated specs
|
|
166
170
|
# @api private
|
|
@@ -179,7 +183,6 @@ module RubyLLM
|
|
|
179
183
|
# - app/agents/ (top-level, no namespace)
|
|
180
184
|
# - app/agents/embedders/ -> Embedders namespace
|
|
181
185
|
# - app/agents/images/ -> Images namespace
|
|
182
|
-
# - app/workflows/ (top-level, no namespace)
|
|
183
186
|
#
|
|
184
187
|
# @api private
|
|
185
188
|
initializer "ruby_llm_agents.autoload_agents", before: :set_autoload_paths do |app|
|
|
@@ -219,9 +222,6 @@ module RubyLLM
|
|
|
219
222
|
def self.namespace_for_path(path, config)
|
|
220
223
|
parts = path.split("/")
|
|
221
224
|
|
|
222
|
-
# app/workflows -> no namespace (top-level workflows)
|
|
223
|
-
return nil if parts == ["app", "workflows"]
|
|
224
|
-
|
|
225
225
|
# Need at least app/{root_directory}
|
|
226
226
|
return nil unless parts.length >= 2 && parts[0] == "app"
|
|
227
227
|
return nil unless parts[1] == config.root_directory
|
|
@@ -102,15 +102,6 @@ module RubyLLM
|
|
|
102
102
|
# @return [Integer, nil] Number of tokens used for thinking
|
|
103
103
|
attr_reader :thinking_text, :thinking_signature, :thinking_tokens
|
|
104
104
|
|
|
105
|
-
# @!group Moderation
|
|
106
|
-
# @!attribute [r] status
|
|
107
|
-
# @return [Symbol, nil] Result status (:success, :input_moderation_blocked, :output_moderation_blocked)
|
|
108
|
-
# @!attribute [r] moderation_result
|
|
109
|
-
# @return [Object, nil] The raw moderation result from RubyLLM
|
|
110
|
-
# @!attribute [r] moderation_phase
|
|
111
|
-
# @return [Symbol, nil] The phase where moderation blocked (:input or :output)
|
|
112
|
-
attr_reader :status, :moderation_result, :moderation_phase
|
|
113
|
-
|
|
114
105
|
# Creates a new Result instance
|
|
115
106
|
#
|
|
116
107
|
# @param content [Hash, String] The processed response content
|
|
@@ -160,12 +151,6 @@ module RubyLLM
|
|
|
160
151
|
@thinking_text = options[:thinking_text]
|
|
161
152
|
@thinking_signature = options[:thinking_signature]
|
|
162
153
|
@thinking_tokens = options[:thinking_tokens]
|
|
163
|
-
|
|
164
|
-
# Moderation
|
|
165
|
-
@status = options[:status] || :success
|
|
166
|
-
@moderation_flagged = options[:moderation_flagged] || false
|
|
167
|
-
@moderation_result = options[:moderation_result]
|
|
168
|
-
@moderation_phase = options[:moderation_phase]
|
|
169
154
|
end
|
|
170
155
|
|
|
171
156
|
# Returns total tokens (input + output)
|
|
@@ -224,34 +209,6 @@ module RubyLLM
|
|
|
224
209
|
thinking_text.present?
|
|
225
210
|
end
|
|
226
211
|
|
|
227
|
-
# Returns whether content was flagged by moderation
|
|
228
|
-
#
|
|
229
|
-
# @return [Boolean] true if moderation flagged the content
|
|
230
|
-
def moderation_flagged?
|
|
231
|
-
@moderation_flagged == true
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
# Returns whether content passed moderation
|
|
235
|
-
#
|
|
236
|
-
# @return [Boolean] true if content was not flagged
|
|
237
|
-
def moderation_passed?
|
|
238
|
-
!moderation_flagged?
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
# Returns the categories flagged by moderation
|
|
242
|
-
#
|
|
243
|
-
# @return [Array<String, Symbol>] Flagged category names
|
|
244
|
-
def moderation_categories
|
|
245
|
-
@moderation_result&.flagged_categories || []
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
# Returns the moderation category scores
|
|
249
|
-
#
|
|
250
|
-
# @return [Hash{String, Symbol => Float}] Category to score mapping
|
|
251
|
-
def moderation_scores
|
|
252
|
-
@moderation_result&.category_scores || {}
|
|
253
|
-
end
|
|
254
|
-
|
|
255
212
|
# Converts the result to a hash
|
|
256
213
|
#
|
|
257
214
|
# @return [Hash] All result data as a hash
|
|
@@ -283,12 +240,7 @@ module RubyLLM
|
|
|
283
240
|
tool_calls_count: tool_calls_count,
|
|
284
241
|
thinking_text: thinking_text,
|
|
285
242
|
thinking_signature: thinking_signature,
|
|
286
|
-
thinking_tokens: thinking_tokens
|
|
287
|
-
status: status,
|
|
288
|
-
moderation_flagged: moderation_flagged?,
|
|
289
|
-
moderation_phase: moderation_phase,
|
|
290
|
-
moderation_categories: moderation_categories,
|
|
291
|
-
moderation_scores: moderation_scores
|
|
243
|
+
thinking_tokens: thinking_tokens
|
|
292
244
|
}
|
|
293
245
|
end
|
|
294
246
|
|
data/lib/ruby_llm/agents.rb
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require "csv"
|
|
4
4
|
require "ruby_llm"
|
|
5
|
+
require "ruby_llm/schema"
|
|
5
6
|
|
|
6
7
|
# Core
|
|
7
8
|
require_relative "agents/core/version"
|
|
8
9
|
require_relative "agents/core/configuration"
|
|
9
10
|
require_relative "agents/core/deprecations"
|
|
10
11
|
require_relative "agents/core/errors"
|
|
11
|
-
require_relative "agents/core/resolved_config"
|
|
12
12
|
require_relative "agents/core/llm_tenant"
|
|
13
13
|
|
|
14
14
|
# Infrastructure - Reliability
|
|
@@ -29,7 +29,6 @@ require_relative "agents/dsl"
|
|
|
29
29
|
require_relative "agents/base_agent"
|
|
30
30
|
|
|
31
31
|
# Infrastructure - Budget & Utilities
|
|
32
|
-
require_relative "agents/infrastructure/redactor"
|
|
33
32
|
require_relative "agents/infrastructure/circuit_breaker"
|
|
34
33
|
require_relative "agents/infrastructure/budget_tracker"
|
|
35
34
|
require_relative "agents/infrastructure/alert_manager"
|
|
@@ -43,7 +42,6 @@ require_relative "agents/infrastructure/budget/spend_recorder"
|
|
|
43
42
|
# Results
|
|
44
43
|
require_relative "agents/results/base"
|
|
45
44
|
require_relative "agents/results/embedding_result"
|
|
46
|
-
require_relative "agents/results/moderation_result"
|
|
47
45
|
require_relative "agents/results/transcription_result"
|
|
48
46
|
require_relative "agents/results/speech_result"
|
|
49
47
|
require_relative "agents/results/image_generation_result"
|
|
@@ -61,7 +59,6 @@ require_relative "agents/image/concerns/image_operation_execution"
|
|
|
61
59
|
|
|
62
60
|
# Text agents
|
|
63
61
|
require_relative "agents/text/embedder"
|
|
64
|
-
require_relative "agents/text/moderator"
|
|
65
62
|
|
|
66
63
|
# Audio agents
|
|
67
64
|
require_relative "agents/audio/transcriber"
|
|
@@ -77,11 +74,6 @@ require_relative "agents/image/analyzer"
|
|
|
77
74
|
require_relative "agents/image/background_remover"
|
|
78
75
|
require_relative "agents/image/pipeline"
|
|
79
76
|
|
|
80
|
-
# Workflow
|
|
81
|
-
require_relative "agents/workflow/async"
|
|
82
|
-
require_relative "agents/workflow/orchestrator"
|
|
83
|
-
require_relative "agents/workflow/async_executor"
|
|
84
|
-
|
|
85
77
|
# Rails integration
|
|
86
78
|
if defined?(Rails)
|
|
87
79
|
require_relative "agents/core/inflections"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :ruby_llm_agents do
|
|
4
|
+
namespace :tenants do
|
|
5
|
+
desc "Refresh all tenant counters from executions table"
|
|
6
|
+
task refresh: :environment do
|
|
7
|
+
count = 0
|
|
8
|
+
RubyLLM::Agents::Tenant.find_each do |tenant|
|
|
9
|
+
tenant.refresh_counters!
|
|
10
|
+
count += 1
|
|
11
|
+
end
|
|
12
|
+
puts "Refreshed #{count} tenants"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc "Refresh active tenant counters from executions table"
|
|
16
|
+
task refresh_active: :environment do
|
|
17
|
+
count = 0
|
|
18
|
+
RubyLLM::Agents::Tenant.active.find_each do |tenant|
|
|
19
|
+
tenant.refresh_counters!
|
|
20
|
+
count += 1
|
|
21
|
+
end
|
|
22
|
+
puts "Refreshed #{count} active tenants"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "Refresh a single tenant's counters"
|
|
26
|
+
task :refresh_one, [:tenant_id] => :environment do |_, args|
|
|
27
|
+
abort "Usage: rake ruby_llm_agents:tenants:refresh_one[tenant_id]" unless args[:tenant_id]
|
|
28
|
+
|
|
29
|
+
tenant = RubyLLM::Agents::Tenant.find_by!(tenant_id: args[:tenant_id])
|
|
30
|
+
tenant.refresh_counters!
|
|
31
|
+
puts "Refreshed tenant: #{tenant.tenant_id}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|