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
|
@@ -3,25 +3,16 @@
|
|
|
3
3
|
selected_agents = params[:agent_types].present? ? (params[:agent_types].is_a?(Array) ? params[:agent_types] : params[:agent_types].split(",")) : []
|
|
4
4
|
selected_statuses = params[:statuses].present? ? (params[:statuses].is_a?(Array) ? params[:statuses] : params[:statuses].split(",")) : []
|
|
5
5
|
selected_models = params[:model_ids].present? ? (params[:model_ids].is_a?(Array) ? params[:model_ids] : params[:model_ids].split(",")) : []
|
|
6
|
-
selected_execution_type = params[:execution_type].presence
|
|
7
6
|
|
|
8
|
-
has_filters = selected_agents.any? || selected_statuses.any? || params[:days].present? || selected_models.any? || params[:tenant_id].present?
|
|
7
|
+
has_filters = selected_agents.any? || selected_statuses.any? || params[:days].present? || selected_models.any? || params[:tenant_id].present?
|
|
9
8
|
active_filter_count = [
|
|
10
9
|
selected_agents.any? ? 1 : 0,
|
|
11
10
|
selected_statuses.any? ? 1 : 0,
|
|
12
11
|
params[:days].present? ? 1 : 0,
|
|
13
12
|
selected_models.any? ? 1 : 0,
|
|
14
|
-
params[:tenant_id].present? ? 1 : 0
|
|
15
|
-
selected_execution_type.present? ? 1 : 0
|
|
13
|
+
params[:tenant_id].present? ? 1 : 0
|
|
16
14
|
].sum
|
|
17
15
|
|
|
18
|
-
# Execution type options (replaces the old tabs)
|
|
19
|
-
execution_type_options = [
|
|
20
|
-
{ value: "", label: "All Executions" },
|
|
21
|
-
{ value: "agents", label: "Agents Only" },
|
|
22
|
-
{ value: "workflows", label: "Workflows" }
|
|
23
|
-
]
|
|
24
|
-
|
|
25
16
|
status_options = [
|
|
26
17
|
{ value: "success", label: "Success", color: "bg-green-500" },
|
|
27
18
|
{ value: "error", label: "Error", color: "bg-red-500" },
|
|
@@ -44,7 +35,7 @@
|
|
|
44
35
|
{ value: m, label: short_name }
|
|
45
36
|
end || []
|
|
46
37
|
%>
|
|
47
|
-
<div id="filters-container" class="
|
|
38
|
+
<div id="filters-container" class="mb-6"
|
|
48
39
|
x-data="{ mobileOpen: false }">
|
|
49
40
|
<%= form_with url: ruby_llm_agents.executions_path, method: :get,
|
|
50
41
|
local: true,
|
|
@@ -79,18 +70,6 @@
|
|
|
79
70
|
|
|
80
71
|
<%# Responsive flex: column on mobile, row on desktop %>
|
|
81
72
|
<div class="flex flex-col md:flex-row md:items-center gap-2">
|
|
82
|
-
<%# Execution Type Filter (replaces tabs) %>
|
|
83
|
-
<div class="md:w-auto">
|
|
84
|
-
<%= render "ruby_llm/agents/shared/select_dropdown",
|
|
85
|
-
name: "execution_type",
|
|
86
|
-
filter_id: "execution_type",
|
|
87
|
-
options: execution_type_options,
|
|
88
|
-
selected: selected_execution_type,
|
|
89
|
-
icon: "M4 6h16M4 10h16M4 14h16M4 18h16",
|
|
90
|
-
width: "w-44",
|
|
91
|
-
full_width: true %>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
73
|
<%# Status Filter %>
|
|
95
74
|
<div class="md:w-auto">
|
|
96
75
|
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
@@ -194,7 +173,7 @@
|
|
|
194
173
|
<span class="md:hidden">Clear</span>
|
|
195
174
|
<% end %>
|
|
196
175
|
<% end %>
|
|
197
|
-
<%= link_to ruby_llm_agents.export_executions_path(agent_types: selected_agents.presence, statuses: selected_statuses.presence, days: params[:days].presence, model_ids: selected_models.presence, tenant_id: params[:tenant_id].presence
|
|
176
|
+
<%= link_to ruby_llm_agents.export_executions_path(agent_types: selected_agents.presence, statuses: selected_statuses.presence, days: params[:days].presence, model_ids: selected_models.presence, tenant_id: params[:tenant_id].presence),
|
|
198
177
|
class: "flex-1 md:flex-initial flex items-center justify-center gap-2 px-3 py-2 md:p-2 text-sm md:text-base text-gray-600 md:text-gray-400 dark:text-gray-300 md:dark:text-gray-400 bg-gray-50 md:bg-transparent dark:bg-gray-700 md:dark:bg-transparent hover:text-gray-600 md:hover:text-gray-600 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600 md:dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
199
178
|
title: "Export CSV" do %>
|
|
200
179
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -1,185 +1,144 @@
|
|
|
1
|
-
|
|
1
|
+
<%# Show tenant column when multi-tenancy is enabled and no specific tenant is selected %>
|
|
2
|
+
<% show_tenant_column = tenant_filter_enabled? && current_tenant_id.blank? %>
|
|
3
|
+
|
|
4
|
+
<%
|
|
5
|
+
# Inline sort helper
|
|
6
|
+
sort_column = @sort_params[:column]
|
|
7
|
+
sort_direction = @sort_params[:direction]
|
|
8
|
+
|
|
9
|
+
sort_link = ->(column, label, align: "left", extra_class: "") {
|
|
10
|
+
is_active = column == sort_column
|
|
11
|
+
next_dir = is_active && sort_direction == "asc" ? "desc" : "asc"
|
|
12
|
+
url = url_for(request.query_parameters.merge(sort: column, direction: next_dir, page: 1))
|
|
13
|
+
|
|
14
|
+
arrow = if is_active && sort_direction == "asc"
|
|
15
|
+
raw('<svg class="w-2.5 h-2.5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"/></svg>')
|
|
16
|
+
elsif is_active
|
|
17
|
+
raw('<svg class="w-2.5 h-2.5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>')
|
|
18
|
+
else
|
|
19
|
+
""
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
active_class = is_active ? "text-gray-700 dark:text-gray-300" : ""
|
|
23
|
+
|
|
24
|
+
raw(%(<a href="#{url}" class="group inline-flex items-center gap-0.5 hover:text-gray-700 dark:hover:text-gray-300 #{active_class} #{extra_class}"><span>#{label}</span><span class="#{is_active ? 'opacity-100' : 'opacity-0 group-hover:opacity-50'} transition-opacity">#{arrow}</span></a>))
|
|
25
|
+
}
|
|
26
|
+
%>
|
|
27
|
+
|
|
28
|
+
<div id="executions-list">
|
|
2
29
|
<% if executions.empty? %>
|
|
3
|
-
<div class="
|
|
4
|
-
<p class="text-lg">No executions found</p>
|
|
5
|
-
<p class="text-sm mt-1">Try adjusting your filters</p>
|
|
6
|
-
</div>
|
|
30
|
+
<div class="font-mono text-xs text-gray-400 dark:text-gray-600 py-4 px-2">no executions found</div>
|
|
7
31
|
<% else %>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
column: "model_id", label: "Model",
|
|
22
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
23
|
-
|
|
24
|
-
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
25
|
-
column: "agent_version", label: "Version",
|
|
26
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
27
|
-
|
|
28
|
-
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
29
|
-
column: "total_tokens", label: "Tokens",
|
|
30
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
31
|
-
|
|
32
|
-
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
33
|
-
column: "total_cost", label: "Cost",
|
|
34
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
35
|
-
|
|
36
|
-
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
37
|
-
column: "duration_ms", label: "Duration",
|
|
38
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
39
|
-
|
|
40
|
-
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
41
|
-
column: "created_at", label: "Time",
|
|
42
|
-
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
43
|
-
</tr>
|
|
44
|
-
</thead>
|
|
45
|
-
|
|
46
|
-
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-100/50 dark:divide-gray-700/50">
|
|
47
|
-
<% executions.each_with_index do |execution, index| %>
|
|
48
|
-
<% attempts_count = (execution.respond_to?(:attempts_count) && execution.attempts_count) || (execution.respond_to?(:attempts) && execution.attempts&.size) || 1 %>
|
|
49
|
-
<% row_bg = index.even? ? '' : 'bg-gray-50/50 dark:bg-gray-900/30' %>
|
|
50
|
-
<tr
|
|
51
|
-
class="<%= row_bg %> hover:bg-blue-50/50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer"
|
|
52
|
-
id="execution-row-<%= execution.id %>"
|
|
53
|
-
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'"
|
|
54
|
-
>
|
|
55
|
-
<td class="px-4 py-3 whitespace-nowrap">
|
|
56
|
-
<div class="flex items-center gap-2">
|
|
57
|
-
<% if execution.respond_to?(:workflow_type) && execution.workflow_type.present? %>
|
|
58
|
-
<%= render "ruby_llm/agents/shared/workflow_type_badge", workflow_type: execution.workflow_type, size: :xs, show_label: false %>
|
|
59
|
-
<% end %>
|
|
60
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
61
|
-
<%= execution.agent_type.gsub(/Agent$|Workflow$|Pipeline$|Parallel$|Router$/, '') %>
|
|
62
|
-
</span>
|
|
63
|
-
</div>
|
|
64
|
-
<% if execution.respond_to?(:parent_execution_id) && execution.parent_execution_id.present? %>
|
|
65
|
-
<span class="text-xs text-gray-400 dark:text-gray-500 ml-5 block">
|
|
66
|
-
child of #<%= execution.parent_execution_id %>
|
|
67
|
-
</span>
|
|
68
|
-
<% end %>
|
|
69
|
-
</td>
|
|
70
|
-
|
|
71
|
-
<td class="px-4 py-3 whitespace-nowrap">
|
|
72
|
-
<div>
|
|
73
|
-
<%= render "ruby_llm/agents/shared/status_badge", status: execution.status, attempts_count: attempts_count %>
|
|
74
|
-
</div>
|
|
75
|
-
<% if execution.status_error? && execution.error_class.present? %>
|
|
76
|
-
<span class="text-xs text-red-500 dark:text-red-400 block mt-0.5">
|
|
77
|
-
<%= execution.error_class.split("::").last %>
|
|
78
|
-
</span>
|
|
79
|
-
<% end %>
|
|
80
|
-
</td>
|
|
81
|
-
|
|
82
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
|
83
|
-
<span title="<%= execution.model_id %>">
|
|
84
|
-
<%= execution.model_id&.split("/")&.last || execution.model_id || "-" %>
|
|
85
|
-
</span>
|
|
86
|
-
</td>
|
|
87
|
-
|
|
88
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
|
89
|
-
v<%= execution.agent_version %>
|
|
90
|
-
</td>
|
|
91
|
-
|
|
92
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
93
|
-
<%= number_to_human_short(execution.total_tokens || 0) %>
|
|
94
|
-
</td>
|
|
95
|
-
|
|
96
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
97
|
-
<%= number_to_human_short(execution.total_cost || 0, prefix: "$", precision: 2) %>
|
|
98
|
-
</td>
|
|
99
|
-
|
|
100
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
101
|
-
<%= number_with_delimiter(execution.duration_ms || 0) %>ms
|
|
102
|
-
</td>
|
|
32
|
+
<!-- Column headers -->
|
|
33
|
+
<div class="flex items-center gap-3 px-2 -mx-2 font-mono text-[10px] text-gray-400 dark:text-gray-600 uppercase tracking-wider mb-1">
|
|
34
|
+
<span class="flex-1 min-w-0"><%= sort_link.call("agent_type", "agent") %></span>
|
|
35
|
+
<span class="w-20 flex-shrink-0"><%= sort_link.call("status", "status") %></span>
|
|
36
|
+
<% if show_tenant_column %>
|
|
37
|
+
<span class="flex-1 min-w-0 hidden sm:block">tenant</span>
|
|
38
|
+
<% end %>
|
|
39
|
+
<span class="flex-1 min-w-0 hidden lg:block"><%= sort_link.call("model_id", "model") %></span>
|
|
40
|
+
<span class="w-16 flex-shrink-0 text-right"><%= sort_link.call("duration_ms", "duration", extra_class: "justify-end w-full") %></span>
|
|
41
|
+
<span class="w-16 flex-shrink-0 text-right hidden md:block"><%= sort_link.call("total_tokens", "tokens", extra_class: "justify-end w-full") %></span>
|
|
42
|
+
<span class="w-16 flex-shrink-0 text-right hidden md:block"><%= sort_link.call("total_cost", "cost", extra_class: "justify-end w-full") %></span>
|
|
43
|
+
<span class="w-24 flex-shrink-0 text-right"><%= sort_link.call("created_at", "time", extra_class: "justify-end w-full") %></span>
|
|
44
|
+
</div>
|
|
103
45
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
46
|
+
<!-- Rows -->
|
|
47
|
+
<div class="font-mono text-xs space-y-px">
|
|
48
|
+
<% executions.each do |execution| %>
|
|
49
|
+
<% attempts_count = (execution.respond_to?(:attempts_count) && execution.attempts_count) || (execution.respond_to?(:attempts) && execution.attempts&.size) || 1 %>
|
|
50
|
+
<%
|
|
51
|
+
status_badge_class = case execution.status.to_s
|
|
52
|
+
when "running" then "badge-running"
|
|
53
|
+
when "success" then "badge-success"
|
|
54
|
+
when "error" then "badge-error"
|
|
55
|
+
when "timeout" then "badge-timeout"
|
|
56
|
+
else "badge-timeout"
|
|
57
|
+
end
|
|
58
|
+
%>
|
|
59
|
+
<div class="group flex items-center gap-3 py-1.5 px-2 -mx-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800/50 cursor-pointer"
|
|
60
|
+
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'">
|
|
61
|
+
<span class="flex-1 min-w-0 truncate">
|
|
62
|
+
<%= link_to execution.agent_type.gsub(/Agent$/, ""),
|
|
63
|
+
ruby_llm_agents.agent_path(execution.agent_type),
|
|
64
|
+
class: "text-gray-900 dark:text-gray-200 hover:underline",
|
|
65
|
+
onclick: "event.stopPropagation()" %>
|
|
66
|
+
</span>
|
|
67
|
+
<span class="w-20 flex-shrink-0">
|
|
68
|
+
<span class="badge badge-sm <%= status_badge_class %>"><%= execution.status %></span>
|
|
69
|
+
</span>
|
|
70
|
+
<% if show_tenant_column %>
|
|
71
|
+
<span class="flex-1 min-w-0 truncate text-gray-400 dark:text-gray-600 hidden sm:inline"><%= execution.tenant_id.present? ? truncate(execution.tenant_id, length: 30) : "—" %></span>
|
|
108
72
|
<% end %>
|
|
109
|
-
|
|
110
|
-
|
|
73
|
+
<span class="flex-1 min-w-0 truncate text-gray-400 dark:text-gray-600 hidden lg:inline" title="<%= execution.model_id %>"><%= execution.model_id %></span>
|
|
74
|
+
<span class="w-16 flex-shrink-0 text-right text-gray-500 dark:text-gray-400">
|
|
75
|
+
<% if execution.status_running? %>
|
|
76
|
+
<span class="text-blue-500 animate-pulse">...</span>
|
|
77
|
+
<% else %>
|
|
78
|
+
<%= execution.duration_ms ? format_duration_ms(execution.duration_ms) : "—" %>
|
|
79
|
+
<% end %>
|
|
80
|
+
</span>
|
|
81
|
+
<span class="w-16 flex-shrink-0 text-right text-gray-500 dark:text-gray-400 hidden md:inline"><%= number_with_delimiter(execution.total_tokens || 0) %></span>
|
|
82
|
+
<span class="w-16 flex-shrink-0 text-right text-gray-500 dark:text-gray-400 hidden md:inline">$<%= number_with_precision(execution.total_cost || 0, precision: 4) %></span>
|
|
83
|
+
<span class="w-24 flex-shrink-0 text-gray-400 dark:text-gray-600 text-right whitespace-nowrap"><%= time_ago_in_words(execution.created_at) %></span>
|
|
84
|
+
</div>
|
|
85
|
+
<% if execution.status_error? && execution.error_class.present? %>
|
|
86
|
+
<div class="flex items-center gap-1 pl-5 py-0.5 text-red-400 dark:text-red-500/70 text-xs font-mono">
|
|
87
|
+
<span class="text-gray-300 dark:text-gray-700">└</span>
|
|
88
|
+
<span class="truncate"><%= execution.error_class.split("::").last %><%= execution.error_message.present? ? ": #{truncate(execution.error_message, length: 100)}" : "" %></span>
|
|
89
|
+
</div>
|
|
90
|
+
<% end %>
|
|
91
|
+
<% end %>
|
|
111
92
|
</div>
|
|
93
|
+
|
|
94
|
+
<%# Pagination %>
|
|
112
95
|
<% if pagination && pagination[:total_pages] > 1 %>
|
|
113
|
-
<%
|
|
96
|
+
<%
|
|
97
|
+
current_page = pagination[:current_page]
|
|
114
98
|
total_pages = pagination[:total_pages]
|
|
115
99
|
total_count = pagination[:total_count]
|
|
116
100
|
per_page = pagination[:per_page]
|
|
117
|
-
|
|
118
101
|
from_record = ((current_page - 1) * per_page) + 1
|
|
119
|
-
to_record = [current_page * per_page, total_count].min
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</p>
|
|
125
|
-
|
|
126
|
-
<nav class="flex items-center space-x-1">
|
|
102
|
+
to_record = [current_page * per_page, total_count].min
|
|
103
|
+
%>
|
|
104
|
+
<div class="flex items-center justify-between font-mono text-xs mt-4 pt-4 border-t border-gray-200 dark:border-gray-800">
|
|
105
|
+
<span class="text-gray-400 dark:text-gray-600"><%= from_record %>-<%= to_record %> of <%= number_with_delimiter(total_count) %></span>
|
|
106
|
+
<nav class="flex items-center gap-1">
|
|
127
107
|
<% if current_page > 1 %>
|
|
128
|
-
<%= link_to "
|
|
108
|
+
<%= link_to "prev", url_for(request.query_parameters.merge(page: current_page - 1)),
|
|
109
|
+
class: "px-2 py-0.5 text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300" %>
|
|
129
110
|
<% else %>
|
|
130
|
-
<span
|
|
131
|
-
class="
|
|
132
|
-
px-3 py-1.5 text-sm font-medium text-gray-400 dark:text-gray-500 bg-gray-100 dark:bg-gray-800
|
|
133
|
-
border border-gray-200 dark:border-gray-700 rounded-md cursor-not-allowed
|
|
134
|
-
"
|
|
135
|
-
>
|
|
136
|
-
Previous
|
|
137
|
-
</span>
|
|
111
|
+
<span class="px-2 py-0.5 text-gray-300 dark:text-gray-700">prev</span>
|
|
138
112
|
<% end %>
|
|
139
113
|
|
|
140
|
-
<%
|
|
141
|
-
|
|
142
|
-
right_edge = 1
|
|
143
|
-
|
|
114
|
+
<%
|
|
115
|
+
window = 2
|
|
144
116
|
pages_to_show = []
|
|
145
117
|
(1..total_pages).each do |page|
|
|
146
|
-
if page <=
|
|
147
|
-
page > total_pages - right_edge ||
|
|
148
|
-
(page >= current_page - window && page <= current_page + window)
|
|
118
|
+
if page <= 1 || page >= total_pages || (page >= current_page - window && page <= current_page + window)
|
|
149
119
|
pages_to_show << page
|
|
150
120
|
elsif pages_to_show.last != :gap
|
|
151
121
|
pages_to_show << :gap
|
|
152
122
|
end
|
|
153
|
-
end
|
|
123
|
+
end
|
|
124
|
+
%>
|
|
154
125
|
|
|
155
126
|
<% pages_to_show.each do |page| %>
|
|
156
127
|
<% if page == :gap %>
|
|
157
|
-
<span class="px-
|
|
128
|
+
<span class="px-1 text-gray-400 dark:text-gray-600">...</span>
|
|
158
129
|
<% elsif page == current_page %>
|
|
159
|
-
<span
|
|
160
|
-
class="
|
|
161
|
-
px-3 py-1.5 text-sm font-medium text-white bg-blue-600
|
|
162
|
-
border border-blue-600 rounded-md
|
|
163
|
-
"
|
|
164
|
-
>
|
|
165
|
-
<%= page %>
|
|
166
|
-
</span>
|
|
130
|
+
<span class="px-2 py-0.5 text-gray-900 dark:text-gray-100"><%= page %></span>
|
|
167
131
|
<% else %>
|
|
168
|
-
<%= link_to page, url_for(request.query_parameters.merge(page: page)),
|
|
132
|
+
<%= link_to page, url_for(request.query_parameters.merge(page: page)),
|
|
133
|
+
class: "px-2 py-0.5 text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300" %>
|
|
169
134
|
<% end %>
|
|
170
135
|
<% end %>
|
|
171
136
|
|
|
172
137
|
<% if current_page < total_pages %>
|
|
173
|
-
<%= link_to "
|
|
138
|
+
<%= link_to "next", url_for(request.query_parameters.merge(page: current_page + 1)),
|
|
139
|
+
class: "px-2 py-0.5 text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300" %>
|
|
174
140
|
<% else %>
|
|
175
|
-
<span
|
|
176
|
-
class="
|
|
177
|
-
px-3 py-1.5 text-sm font-medium text-gray-400 dark:text-gray-500 bg-gray-100 dark:bg-gray-800
|
|
178
|
-
border border-gray-200 dark:border-gray-700 rounded-md cursor-not-allowed
|
|
179
|
-
"
|
|
180
|
-
>
|
|
181
|
-
Next
|
|
182
|
-
</span>
|
|
141
|
+
<span class="px-2 py-0.5 text-gray-300 dark:text-gray-700">next</span>
|
|
183
142
|
<% end %>
|
|
184
143
|
</nav>
|
|
185
144
|
</div>
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
<div class="mb-6">
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
</div>
|
|
6
|
-
<p class="text-gray-500 dark:text-gray-400 mt-1">All agent and workflow execution history</p>
|
|
1
|
+
<div class="flex items-center gap-3 mb-6">
|
|
2
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">executions</span>
|
|
3
|
+
<%= render "ruby_llm/agents/shared/doc_link" %>
|
|
4
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
7
5
|
</div>
|
|
8
6
|
|
|
9
7
|
<div id="executions_content">
|
|
10
|
-
<%= render partial: "ruby_llm/agents/executions/filters", locals: { agent_types: @agent_types, model_ids: @model_ids,
|
|
8
|
+
<%= render partial: "ruby_llm/agents/executions/filters", locals: { agent_types: @agent_types, model_ids: @model_ids, filter_stats: @filter_stats } %>
|
|
11
9
|
<%= render partial: "ruby_llm/agents/executions/list", locals: { executions: @executions, pagination: @pagination, filter_stats: @filter_stats } %>
|
|
12
10
|
</div>
|