ruby_llm-agents 1.0.0.beta.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/ruby_llm/agents/paginatable.rb +9 -3
- data/app/controllers/concerns/ruby_llm/agents/sortable.rb +58 -0
- data/app/controllers/ruby_llm/agents/agents_controller.rb +59 -16
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +144 -20
- data/app/controllers/ruby_llm/agents/executions_controller.rb +13 -16
- data/app/controllers/ruby_llm/agents/workflows_controller.rb +279 -90
- data/app/helpers/ruby_llm/agents/application_helper.rb +100 -0
- data/app/mailers/ruby_llm/agents/alert_mailer.rb +84 -0
- data/app/mailers/ruby_llm/agents/application_mailer.rb +28 -0
- data/app/models/ruby_llm/agents/execution/analytics.rb +170 -20
- data/app/models/ruby_llm/agents/execution/scopes.rb +0 -31
- data/app/models/ruby_llm/agents/execution/workflow.rb +0 -129
- data/app/models/ruby_llm/agents/execution.rb +50 -14
- data/app/services/ruby_llm/agents/agent_registry.rb +18 -12
- data/app/views/layouts/ruby_llm/agents/application.html.erb +72 -76
- data/app/views/ruby_llm/agents/agents/_agent.html.erb +0 -12
- data/app/views/ruby_llm/agents/agents/_sortable_header.html.erb +56 -0
- data/app/views/ruby_llm/agents/agents/_workflow.html.erb +5 -15
- data/app/views/ruby_llm/agents/agents/index.html.erb +271 -100
- data/app/views/ruby_llm/agents/agents/show.html.erb +1 -0
- data/app/views/ruby_llm/agents/alert_mailer/alert_notification.html.erb +107 -0
- data/app/views/ruby_llm/agents/alert_mailer/alert_notification.text.erb +18 -0
- data/app/views/ruby_llm/agents/api_configurations/show.html.erb +4 -1
- data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +66 -359
- data/app/views/ruby_llm/agents/dashboard/_model_comparison.html.erb +56 -0
- data/app/views/ruby_llm/agents/dashboard/_model_cost_breakdown.html.erb +115 -0
- data/app/views/ruby_llm/agents/dashboard/_now_strip.html.erb +35 -60
- data/app/views/ruby_llm/agents/dashboard/_top_errors.html.erb +17 -6
- data/app/views/ruby_llm/agents/dashboard/index.html.erb +373 -72
- data/app/views/ruby_llm/agents/executions/_execution.html.erb +0 -1
- data/app/views/ruby_llm/agents/executions/_filters.html.erb +51 -39
- data/app/views/ruby_llm/agents/executions/_list.html.erb +53 -195
- data/app/views/ruby_llm/agents/executions/_workflow_summary.html.erb +5 -20
- data/app/views/ruby_llm/agents/executions/index.html.erb +7 -83
- data/app/views/ruby_llm/agents/executions/show.html.erb +10 -20
- data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +2 -1
- data/app/views/ruby_llm/agents/shared/_doc_link.html.erb +12 -0
- data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +3 -15
- data/app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_select_dropdown.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_sortable_header.html.erb +53 -0
- data/app/views/ruby_llm/agents/shared/_status_badge.html.erb +7 -0
- data/app/views/ruby_llm/agents/shared/_status_dot.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb +9 -35
- data/app/views/ruby_llm/agents/system_config/show.html.erb +4 -1
- data/app/views/ruby_llm/agents/tenants/index.html.erb +4 -1
- data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +7 -15
- data/app/views/ruby_llm/agents/workflows/_structure_dsl.html.erb +539 -0
- data/app/views/ruby_llm/agents/workflows/_workflow_diagram.html.erb +920 -0
- data/app/views/ruby_llm/agents/workflows/index.html.erb +179 -0
- data/app/views/ruby_llm/agents/workflows/show.html.erb +164 -139
- data/config/routes.rb +1 -1
- data/lib/generators/ruby_llm_agents/agent_generator.rb +6 -36
- data/lib/generators/ruby_llm_agents/background_remover_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/embedder_generator.rb +5 -38
- data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/image_editor_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/image_generator_generator.rb +8 -41
- data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +18 -46
- data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/image_variator_generator.rb +7 -37
- data/lib/generators/ruby_llm_agents/install_generator.rb +33 -56
- data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +480 -0
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +2 -2
- data/lib/generators/ruby_llm_agents/speaker_generator.rb +8 -39
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +5 -8
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +40 -42
- data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +20 -22
- data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +24 -26
- data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +20 -22
- data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +19 -17
- data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +31 -33
- data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +125 -127
- data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +20 -18
- data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +19 -17
- data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +19 -17
- data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +38 -40
- data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +42 -44
- data/lib/generators/ruby_llm_agents/templates/application_workflow.rb.tt +48 -0
- data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +19 -21
- data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +19 -21
- data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +20 -22
- data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +15 -17
- data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +25 -27
- data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +19 -21
- data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +20 -22
- data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +17 -19
- data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +15 -17
- data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +87 -24
- data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +21 -27
- data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +46 -54
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +31 -39
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +22 -28
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +53 -63
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +46 -56
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +23 -31
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +22 -30
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +23 -31
- data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +38 -46
- data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +7 -7
- data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +59 -71
- data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +274 -23
- data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +29 -31
- data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +28 -30
- data/lib/generators/ruby_llm_agents/transcriber_generator.rb +10 -43
- data/lib/ruby_llm/agents/core/configuration.rb +55 -43
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +26 -0
- data/lib/ruby_llm/agents/pipeline.rb +69 -0
- data/lib/ruby_llm/agents/workflow/approval.rb +205 -0
- data/lib/ruby_llm/agents/workflow/approval_store.rb +179 -0
- data/lib/ruby_llm/agents/workflow/dsl/executor.rb +467 -0
- data/lib/ruby_llm/agents/workflow/dsl/input_schema.rb +244 -0
- data/lib/ruby_llm/agents/workflow/dsl/iteration_executor.rb +289 -0
- data/lib/ruby_llm/agents/workflow/dsl/parallel_group.rb +107 -0
- data/lib/ruby_llm/agents/workflow/dsl/route_builder.rb +150 -0
- data/lib/ruby_llm/agents/workflow/dsl/schedule_helpers.rb +187 -0
- data/lib/ruby_llm/agents/workflow/dsl/step_config.rb +352 -0
- data/lib/ruby_llm/agents/workflow/dsl/step_executor.rb +415 -0
- data/lib/ruby_llm/agents/workflow/dsl/wait_config.rb +257 -0
- data/lib/ruby_llm/agents/workflow/dsl/wait_executor.rb +317 -0
- data/lib/ruby_llm/agents/workflow/dsl.rb +576 -0
- data/lib/ruby_llm/agents/workflow/instrumentation.rb +2 -7
- data/lib/ruby_llm/agents/workflow/notifiers/base.rb +117 -0
- data/lib/ruby_llm/agents/workflow/notifiers/email.rb +117 -0
- data/lib/ruby_llm/agents/workflow/notifiers/slack.rb +180 -0
- data/lib/ruby_llm/agents/workflow/notifiers/webhook.rb +121 -0
- data/lib/ruby_llm/agents/workflow/notifiers.rb +70 -0
- data/lib/ruby_llm/agents/workflow/orchestrator.rb +190 -23
- data/lib/ruby_llm/agents/workflow/result.rb +202 -0
- data/lib/ruby_llm/agents/workflow/throttle_manager.rb +206 -0
- data/lib/ruby_llm/agents/workflow/wait_result.rb +213 -0
- metadata +37 -6
- data/app/views/ruby_llm/agents/dashboard/_execution_item.html.erb +0 -66
- data/lib/ruby_llm/agents/workflow/parallel.rb +0 -299
- data/lib/ruby_llm/agents/workflow/pipeline.rb +0 -306
- data/lib/ruby_llm/agents/workflow/router.rb +0 -429
|
@@ -3,17 +3,25 @@
|
|
|
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
|
-
|
|
6
|
+
selected_execution_type = params[:execution_type].presence
|
|
7
7
|
|
|
8
|
-
has_filters = selected_agents.any? || selected_statuses.any? || params[:days].present? || selected_models.any? ||
|
|
8
|
+
has_filters = selected_agents.any? || selected_statuses.any? || params[:days].present? || selected_models.any? || params[:tenant_id].present? || selected_execution_type.present?
|
|
9
9
|
active_filter_count = [
|
|
10
10
|
selected_agents.any? ? 1 : 0,
|
|
11
11
|
selected_statuses.any? ? 1 : 0,
|
|
12
12
|
params[:days].present? ? 1 : 0,
|
|
13
13
|
selected_models.any? ? 1 : 0,
|
|
14
|
-
|
|
14
|
+
params[:tenant_id].present? ? 1 : 0,
|
|
15
|
+
selected_execution_type.present? ? 1 : 0
|
|
15
16
|
].sum
|
|
16
17
|
|
|
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
|
+
|
|
17
25
|
status_options = [
|
|
18
26
|
{ value: "success", label: "Success", color: "bg-green-500" },
|
|
19
27
|
{ value: "error", label: "Error", color: "bg-red-500" },
|
|
@@ -35,20 +43,8 @@
|
|
|
35
43
|
short_name = m.split("/").last.split(":").first # Handle "provider/model:version" format
|
|
36
44
|
{ value: m, label: short_name }
|
|
37
45
|
end || []
|
|
38
|
-
|
|
39
|
-
# Build workflow type options with icons
|
|
40
|
-
workflow_type_labels = {
|
|
41
|
-
"pipeline" => { label: "Pipeline", icon: "→" },
|
|
42
|
-
"parallel" => { label: "Parallel", icon: "⫴" },
|
|
43
|
-
"router" => { label: "Router", icon: "⑂" }
|
|
44
|
-
}
|
|
45
|
-
workflow_options = [{ value: "single", label: "Single Agent" }]
|
|
46
|
-
workflow_options += (local_assigns[:workflow_types] || []).map do |wt|
|
|
47
|
-
info = workflow_type_labels[wt] || { label: wt.titleize, icon: "" }
|
|
48
|
-
{ value: wt, label: "#{info[:icon]} #{info[:label]}".strip }
|
|
49
|
-
end
|
|
50
46
|
%>
|
|
51
|
-
<div id="filters-container" class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-
|
|
47
|
+
<div id="filters-container" class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-3 mb-6"
|
|
52
48
|
x-data="{ mobileOpen: false }">
|
|
53
49
|
<%= form_with url: ruby_llm_agents.executions_path, method: :get,
|
|
54
50
|
local: true,
|
|
@@ -82,7 +78,19 @@
|
|
|
82
78
|
:class="{ 'hidden md:block': !mobileOpen, 'block': mobileOpen }">
|
|
83
79
|
|
|
84
80
|
<%# Responsive flex: column on mobile, row on desktop %>
|
|
85
|
-
<div class="flex flex-col md:flex-row md:items-center gap-
|
|
81
|
+
<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
|
+
|
|
86
94
|
<%# Status Filter %>
|
|
87
95
|
<div class="md:w-auto">
|
|
88
96
|
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
@@ -96,6 +104,23 @@
|
|
|
96
104
|
full_width: true %>
|
|
97
105
|
</div>
|
|
98
106
|
|
|
107
|
+
<%# Visual separator between filter groups %>
|
|
108
|
+
<div class="hidden md:block w-px h-6 bg-gray-200 dark:bg-gray-700 mx-1"></div>
|
|
109
|
+
|
|
110
|
+
<%# Tenant Filter %>
|
|
111
|
+
<% if tenant_filter_enabled? && available_tenants.any? %>
|
|
112
|
+
<div class="md:w-auto">
|
|
113
|
+
<%= render "ruby_llm/agents/shared/select_dropdown",
|
|
114
|
+
name: "tenant_id",
|
|
115
|
+
filter_id: "tenant_id",
|
|
116
|
+
options: [{ value: "", label: "All Tenants" }] + available_tenants.map { |t| { value: t, label: t.truncate(15) } },
|
|
117
|
+
selected: params[:tenant_id],
|
|
118
|
+
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
|
119
|
+
width: "w-40",
|
|
120
|
+
full_width: true %>
|
|
121
|
+
</div>
|
|
122
|
+
<% end %>
|
|
123
|
+
|
|
99
124
|
<%# Time Range Filter %>
|
|
100
125
|
<div class="md:w-auto">
|
|
101
126
|
<%= render "ruby_llm/agents/shared/select_dropdown",
|
|
@@ -108,6 +133,9 @@
|
|
|
108
133
|
full_width: true %>
|
|
109
134
|
</div>
|
|
110
135
|
|
|
136
|
+
<%# Visual separator between filter groups %>
|
|
137
|
+
<div class="hidden md:block w-px h-6 bg-gray-200 dark:bg-gray-700 mx-1"></div>
|
|
138
|
+
|
|
111
139
|
<%# Model Filter %>
|
|
112
140
|
<% if model_options.any? %>
|
|
113
141
|
<div class="md:w-auto">
|
|
@@ -139,33 +167,17 @@
|
|
|
139
167
|
</div>
|
|
140
168
|
<% end %>
|
|
141
169
|
|
|
142
|
-
<%# Workflow Type Filter %>
|
|
143
|
-
<% if workflow_options.length > 1 %>
|
|
144
|
-
<div class="md:w-auto">
|
|
145
|
-
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
146
|
-
name: "workflow_types[]",
|
|
147
|
-
filter_id: "workflow_types",
|
|
148
|
-
label: "Type",
|
|
149
|
-
all_label: "All Types",
|
|
150
|
-
options: workflow_options,
|
|
151
|
-
selected: selected_workflows,
|
|
152
|
-
icon: "M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zm0 8a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zm12 0a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z",
|
|
153
|
-
width: "w-44",
|
|
154
|
-
full_width: true %>
|
|
155
|
-
</div>
|
|
156
|
-
<% end %>
|
|
157
|
-
|
|
158
170
|
<%# Spacer (desktop only) %>
|
|
159
171
|
<div class="hidden md:block flex-1"></div>
|
|
160
172
|
|
|
161
173
|
<%# Stats %>
|
|
162
|
-
<div id="filter-stats" class="flex items-center justify-between md:justify-end gap-
|
|
163
|
-
<span class="text-xs text-gray-
|
|
164
|
-
<div class="flex items-center gap-
|
|
174
|
+
<div id="filter-stats" class="flex items-center justify-between md:justify-end gap-2 py-2 px-3 md:p-0 bg-gray-50 md:bg-transparent dark:bg-gray-700/50 md:dark:bg-transparent rounded-lg md:rounded-none">
|
|
175
|
+
<span class="text-xs text-gray-400 dark:text-gray-500 md:hidden">Results</span>
|
|
176
|
+
<div class="flex items-center gap-2 text-xs text-gray-400 dark:text-gray-500">
|
|
165
177
|
<span class="tabular-nums"><%= number_to_human_short(filter_stats[:total_count]) %><span class="md:hidden"> executions</span></span>
|
|
166
|
-
<span class="text-gray-300 dark:text-gray-600"
|
|
178
|
+
<span class="text-gray-300 dark:text-gray-600">/</span>
|
|
167
179
|
<span class="tabular-nums"><%= number_to_human_short(filter_stats[:total_cost], prefix: "$", precision: 2) %></span>
|
|
168
|
-
<span class="hidden md:inline text-gray-300 dark:text-gray-600"
|
|
180
|
+
<span class="hidden md:inline text-gray-300 dark:text-gray-600">/</span>
|
|
169
181
|
<span class="hidden md:inline tabular-nums"><%= number_to_human_short(filter_stats[:total_tokens]) %>t</span>
|
|
170
182
|
</div>
|
|
171
183
|
</div>
|
|
@@ -182,7 +194,7 @@
|
|
|
182
194
|
<span class="md:hidden">Clear</span>
|
|
183
195
|
<% end %>
|
|
184
196
|
<% end %>
|
|
185
|
-
<%= 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,
|
|
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, execution_type: selected_execution_type),
|
|
186
198
|
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",
|
|
187
199
|
title: "Export CSV" do %>
|
|
188
200
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -9,115 +9,50 @@
|
|
|
9
9
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
10
10
|
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
11
11
|
<tr>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class="
|
|
16
|
-
px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400
|
|
17
|
-
uppercase tracking-wider
|
|
18
|
-
"
|
|
19
|
-
>
|
|
20
|
-
Agent
|
|
21
|
-
</th>
|
|
12
|
+
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
13
|
+
column: "agent_type", label: "Agent",
|
|
14
|
+
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400
|
|
27
|
-
uppercase tracking-wider
|
|
28
|
-
"
|
|
29
|
-
>
|
|
30
|
-
Status
|
|
31
|
-
</th>
|
|
16
|
+
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
17
|
+
column: "status", label: "Status",
|
|
18
|
+
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
32
19
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400
|
|
37
|
-
uppercase tracking-wider
|
|
38
|
-
"
|
|
39
|
-
>
|
|
40
|
-
Version
|
|
41
|
-
</th>
|
|
20
|
+
<%= render "ruby_llm/agents/shared/sortable_header",
|
|
21
|
+
column: "model_id", label: "Model",
|
|
22
|
+
current_sort: @sort_params[:column], current_direction: @sort_params[:direction] %>
|
|
42
23
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
px-4 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400
|
|
47
|
-
uppercase tracking-wider
|
|
48
|
-
"
|
|
49
|
-
>
|
|
50
|
-
Attempts
|
|
51
|
-
</th>
|
|
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] %>
|
|
52
27
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400
|
|
57
|
-
uppercase tracking-wider
|
|
58
|
-
"
|
|
59
|
-
>
|
|
60
|
-
Tokens
|
|
61
|
-
</th>
|
|
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] %>
|
|
62
31
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400
|
|
67
|
-
uppercase tracking-wider
|
|
68
|
-
"
|
|
69
|
-
>
|
|
70
|
-
Cost
|
|
71
|
-
</th>
|
|
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] %>
|
|
72
35
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400
|
|
77
|
-
uppercase tracking-wider
|
|
78
|
-
"
|
|
79
|
-
>
|
|
80
|
-
Duration
|
|
81
|
-
</th>
|
|
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] %>
|
|
82
39
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400
|
|
87
|
-
uppercase tracking-wider
|
|
88
|
-
"
|
|
89
|
-
>
|
|
90
|
-
Time
|
|
91
|
-
</th>
|
|
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] %>
|
|
92
43
|
</tr>
|
|
93
44
|
</thead>
|
|
94
45
|
|
|
95
|
-
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-100 dark:divide-gray-700">
|
|
96
|
-
<% executions.
|
|
97
|
-
<%
|
|
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' %>
|
|
98
50
|
<tr
|
|
99
|
-
class="hover:bg-
|
|
51
|
+
class="<%= row_bg %> hover:bg-blue-50/50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer"
|
|
100
52
|
id="execution-row-<%= execution.id %>"
|
|
53
|
+
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'"
|
|
101
54
|
>
|
|
102
|
-
|
|
103
|
-
<td class="px-2 py-3 whitespace-nowrap">
|
|
104
|
-
<% if has_attempts %>
|
|
105
|
-
<button
|
|
106
|
-
type="button"
|
|
107
|
-
onclick="toggleAttempts(<%= execution.id %>); event.stopPropagation();"
|
|
108
|
-
class="expand-btn p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
|
|
109
|
-
data-execution-id="<%= execution.id %>"
|
|
110
|
-
aria-expanded="false"
|
|
111
|
-
aria-label="Toggle attempts"
|
|
112
|
-
>
|
|
113
|
-
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
114
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
115
|
-
</svg>
|
|
116
|
-
</button>
|
|
117
|
-
<% end %>
|
|
118
|
-
</td>
|
|
119
|
-
|
|
120
|
-
<td class="px-4 py-3 whitespace-nowrap cursor-pointer" onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'">
|
|
55
|
+
<td class="px-4 py-3 whitespace-nowrap">
|
|
121
56
|
<div class="flex items-center gap-2">
|
|
122
57
|
<% if execution.respond_to?(:workflow_type) && execution.workflow_type.present? %>
|
|
123
58
|
<%= render "ruby_llm/agents/shared/workflow_type_badge", workflow_type: execution.workflow_type, size: :xs, show_label: false %>
|
|
@@ -133,120 +68,43 @@
|
|
|
133
68
|
<% end %>
|
|
134
69
|
</td>
|
|
135
70
|
|
|
136
|
-
<td class="px-4 py-3 whitespace-nowrap
|
|
137
|
-
|
|
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 %>
|
|
138
80
|
</td>
|
|
139
81
|
|
|
140
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400
|
|
141
|
-
|
|
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>
|
|
142
86
|
</td>
|
|
143
87
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
<% attempts_count = (execution.respond_to?(:attempts_count) && execution.attempts_count) || (execution.respond_to?(:attempts) && execution.attempts&.size) || 1 %>
|
|
147
|
-
<% if attempts_count > 1 %>
|
|
148
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200">
|
|
149
|
-
<%= attempts_count %> attempts
|
|
150
|
-
</span>
|
|
151
|
-
<% else %>
|
|
152
|
-
<span class="text-gray-400 dark:text-gray-500">1</span>
|
|
153
|
-
<% end %>
|
|
88
|
+
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
|
89
|
+
v<%= execution.agent_version %>
|
|
154
90
|
</td>
|
|
155
91
|
|
|
156
|
-
<td
|
|
157
|
-
class="
|
|
158
|
-
px-4 py-3 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100
|
|
159
|
-
text-right font-medium cursor-pointer
|
|
160
|
-
"
|
|
161
|
-
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'"
|
|
162
|
-
>
|
|
92
|
+
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
163
93
|
<%= number_to_human_short(execution.total_tokens || 0) %>
|
|
164
94
|
</td>
|
|
165
95
|
|
|
166
|
-
<td
|
|
167
|
-
class="
|
|
168
|
-
px-4 py-3 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100
|
|
169
|
-
text-right font-medium cursor-pointer
|
|
170
|
-
"
|
|
171
|
-
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'"
|
|
172
|
-
>
|
|
96
|
+
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
173
97
|
<%= number_to_human_short(execution.total_cost || 0, prefix: "$", precision: 2) %>
|
|
174
98
|
</td>
|
|
175
99
|
|
|
176
|
-
<td
|
|
177
|
-
class="
|
|
178
|
-
px-4 py-3 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100
|
|
179
|
-
text-right font-medium cursor-pointer
|
|
180
|
-
"
|
|
181
|
-
onclick="window.location='<%= ruby_llm_agents.execution_path(execution) %>'"
|
|
182
|
-
>
|
|
100
|
+
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-mono">
|
|
183
101
|
<%= number_with_delimiter(execution.duration_ms || 0) %>ms
|
|
184
102
|
</td>
|
|
185
103
|
|
|
186
|
-
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400
|
|
104
|
+
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
|
187
105
|
<%= time_ago_in_words(execution.created_at) %> ago
|
|
188
106
|
</td>
|
|
189
107
|
</tr>
|
|
190
|
-
|
|
191
|
-
<!-- Inline Attempts Expansion Row (hidden by default) -->
|
|
192
|
-
<% if has_attempts %>
|
|
193
|
-
<tr id="attempts-row-<%= execution.id %>" class="hidden bg-gray-50 dark:bg-gray-900">
|
|
194
|
-
<td colspan="9" class="px-4 py-3">
|
|
195
|
-
<div class="ml-6">
|
|
196
|
-
<h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase mb-2">Attempts Timeline</h4>
|
|
197
|
-
<div class="space-y-2">
|
|
198
|
-
<% execution.attempts.each_with_index do |attempt, idx| %>
|
|
199
|
-
<% is_successful = attempt["error_class"].nil? && !attempt["short_circuited"] %>
|
|
200
|
-
<% is_short_circuited = attempt["short_circuited"] %>
|
|
201
|
-
<div class="flex items-center gap-3 text-sm <%= is_successful ? 'bg-green-50 dark:bg-green-900/20 border-l-2 border-green-500' : is_short_circuited ? 'bg-gray-100 dark:bg-gray-800 border-l-2 border-gray-400' : 'bg-red-50 dark:bg-red-900/20 border-l-2 border-red-500' %> px-3 py-2 rounded-r">
|
|
202
|
-
<span class="font-medium text-gray-700 dark:text-gray-300 w-6">#<%= idx + 1 %></span>
|
|
203
|
-
<span class="text-gray-600 dark:text-gray-400 w-32 truncate" title="<%= attempt["model_id"] %>">
|
|
204
|
-
<%= attempt["model_id"]&.split("/")&.last || "unknown" %>
|
|
205
|
-
</span>
|
|
206
|
-
<% if is_successful %>
|
|
207
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-200">
|
|
208
|
-
Success
|
|
209
|
-
</span>
|
|
210
|
-
<% elsif is_short_circuited %>
|
|
211
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-400">
|
|
212
|
-
Skipped (breaker)
|
|
213
|
-
</span>
|
|
214
|
-
<% else %>
|
|
215
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-200" title="<%= attempt["error_message"] %>">
|
|
216
|
-
<%= attempt["error_class"]&.split("::")&.last || "Error" %>
|
|
217
|
-
</span>
|
|
218
|
-
<% end %>
|
|
219
|
-
<% if attempt["duration_ms"] %>
|
|
220
|
-
<span class="text-gray-500 dark:text-gray-400 text-xs">
|
|
221
|
-
<%= number_with_delimiter(attempt["duration_ms"].to_i) %>ms
|
|
222
|
-
</span>
|
|
223
|
-
<% end %>
|
|
224
|
-
<% if attempt["input_tokens"] || attempt["output_tokens"] %>
|
|
225
|
-
<span class="text-gray-500 dark:text-gray-400 text-xs">
|
|
226
|
-
<%= number_to_human_short((attempt["input_tokens"] || 0) + (attempt["output_tokens"] || 0)) %> tokens
|
|
227
|
-
</span>
|
|
228
|
-
<% end %>
|
|
229
|
-
</div>
|
|
230
|
-
<% end %>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
</td>
|
|
234
|
-
</tr>
|
|
235
|
-
<% end %>
|
|
236
|
-
|
|
237
|
-
<% if execution.status_error? && execution.error_message.present? %>
|
|
238
|
-
<tr class="bg-red-50 dark:bg-red-900/30">
|
|
239
|
-
<td colspan="9" class="px-4 py-2">
|
|
240
|
-
<p class="text-xs text-red-600 dark:text-red-400 ml-8">
|
|
241
|
-
<span class="font-medium">
|
|
242
|
-
<%= execution.error_class %>:
|
|
243
|
-
</span>
|
|
244
|
-
|
|
245
|
-
<%= truncate(execution.error_message, length: 150) %>
|
|
246
|
-
</p>
|
|
247
|
-
</td>
|
|
248
|
-
</tr>
|
|
249
|
-
<% end %>
|
|
250
108
|
<% end %>
|
|
251
109
|
</tbody>
|
|
252
110
|
</table>
|
|
@@ -267,7 +125,7 @@
|
|
|
267
125
|
|
|
268
126
|
<nav class="flex items-center space-x-1">
|
|
269
127
|
<% if current_page > 1 %>
|
|
270
|
-
<%= link_to "Previous", url_for(page: current_page - 1), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
128
|
+
<%= link_to "Previous", url_for(request.query_parameters.merge(page: current_page - 1)), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
271
129
|
<% else %>
|
|
272
130
|
<span
|
|
273
131
|
class="
|
|
@@ -307,12 +165,12 @@
|
|
|
307
165
|
<%= page %>
|
|
308
166
|
</span>
|
|
309
167
|
<% else %>
|
|
310
|
-
<%= link_to page, url_for(page: page), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
168
|
+
<%= link_to page, url_for(request.query_parameters.merge(page: page)), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
311
169
|
<% end %>
|
|
312
170
|
<% end %>
|
|
313
171
|
|
|
314
172
|
<% if current_page < total_pages %>
|
|
315
|
-
<%= link_to "Next", url_for(page: current_page + 1), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
173
|
+
<%= link_to "Next", url_for(request.query_parameters.merge(page: current_page + 1)), class: "px-3 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700" %>
|
|
316
174
|
<% else %>
|
|
317
175
|
<span
|
|
318
176
|
class="
|
|
@@ -9,20 +9,9 @@
|
|
|
9
9
|
<!-- Header -->
|
|
10
10
|
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
|
11
11
|
<div class="flex items-center gap-2">
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<span class="font-medium text-gray-900 dark:text-gray-100">Pipeline</span>
|
|
16
|
-
<span class="text-gray-500 dark:text-gray-400">· <%= stats[:steps_count] %> steps</span>
|
|
17
|
-
<% when "parallel" %>
|
|
18
|
-
<span class="text-cyan-600 dark:text-cyan-400">⫴</span>
|
|
19
|
-
<span class="font-medium text-gray-900 dark:text-gray-100">Parallel</span>
|
|
20
|
-
<span class="text-gray-500 dark:text-gray-400">· <%= stats[:steps_count] %> branches</span>
|
|
21
|
-
<% when "router" %>
|
|
22
|
-
<span class="text-amber-600 dark:text-amber-400">⑂</span>
|
|
23
|
-
<span class="font-medium text-gray-900 dark:text-gray-100">Router</span>
|
|
24
|
-
<span class="text-gray-500 dark:text-gray-400">→ <%= execution.routed_to %></span>
|
|
25
|
-
<% end %>
|
|
12
|
+
<span class="text-emerald-600 dark:text-emerald-400">◈</span>
|
|
13
|
+
<span class="font-medium text-gray-900 dark:text-gray-100">Workflow</span>
|
|
14
|
+
<span class="text-gray-500 dark:text-gray-400">· <%= stats[:steps_count] %> steps</span>
|
|
26
15
|
</div>
|
|
27
16
|
|
|
28
17
|
<% overall_status = execution.workflow_overall_status %>
|
|
@@ -34,9 +23,7 @@
|
|
|
34
23
|
<table class="min-w-full text-sm">
|
|
35
24
|
<thead class="bg-gray-50 dark:bg-gray-900/50">
|
|
36
25
|
<tr>
|
|
37
|
-
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">
|
|
38
|
-
<%= execution.pipeline_workflow? ? "Step" : execution.parallel_workflow? ? "Branch" : "Route" %>
|
|
39
|
-
</th>
|
|
26
|
+
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Step</th>
|
|
40
27
|
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Status</th>
|
|
41
28
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Duration</th>
|
|
42
29
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Tokens</th>
|
|
@@ -48,9 +35,7 @@
|
|
|
48
35
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800/50">
|
|
49
36
|
<td class="px-4 py-2">
|
|
50
37
|
<%= link_to ruby_llm_agents.execution_path(step.id), class: "text-blue-600 dark:text-blue-400 hover:underline" do %>
|
|
51
|
-
|
|
52
|
-
<span class="text-gray-400 dark:text-gray-500"><%= index + 1 %>.</span>
|
|
53
|
-
<% end %>
|
|
38
|
+
<span class="text-gray-400 dark:text-gray-500"><%= index + 1 %>.</span>
|
|
54
39
|
<%= step.workflow_step || step.agent_type.gsub(/Agent$/, "") %>
|
|
55
40
|
<% end %>
|
|
56
41
|
</td>
|
|
@@ -1,88 +1,12 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
<div class="border-b border-gray-200 dark:border-gray-700 mb-4">
|
|
6
|
-
<nav class="-mb-px flex space-x-6" aria-label="Execution Types">
|
|
7
|
-
<button type="button" @click="activeTab = 'all'; activeWorkflowType = ''; submitFilters()"
|
|
8
|
-
:class="activeTab === 'all' ? 'border-blue-500 text-blue-600 dark:text-blue-400' : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'"
|
|
9
|
-
class="whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors">
|
|
10
|
-
All
|
|
11
|
-
</button>
|
|
12
|
-
<button type="button" @click="activeTab = 'agents'; activeWorkflowType = ''; submitFilters()"
|
|
13
|
-
:class="activeTab === 'agents' ? 'border-blue-500 text-blue-600 dark:text-blue-400' : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'"
|
|
14
|
-
class="whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors">
|
|
15
|
-
Agents Only
|
|
16
|
-
</button>
|
|
17
|
-
<button type="button" @click="activeTab = 'workflows'; activeWorkflowType = ''; submitFilters()"
|
|
18
|
-
:class="activeTab === 'workflows' ? 'border-blue-500 text-blue-600 dark:text-blue-400' : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'"
|
|
19
|
-
class="whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors">
|
|
20
|
-
Workflows
|
|
21
|
-
</button>
|
|
22
|
-
</nav>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<!-- Workflow Sub-tabs -->
|
|
26
|
-
<div x-show="activeTab === 'workflows'" x-cloak class="mb-4">
|
|
27
|
-
<div class="flex flex-wrap gap-2">
|
|
28
|
-
<button type="button" @click="activeWorkflowType = ''; submitFilters()"
|
|
29
|
-
:class="activeWorkflowType === '' ? 'bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-900' : 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'"
|
|
30
|
-
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors">
|
|
31
|
-
All Workflows
|
|
32
|
-
</button>
|
|
33
|
-
<button type="button" @click="activeWorkflowType = 'pipeline'; submitFilters()"
|
|
34
|
-
:class="activeWorkflowType === 'pipeline' ? 'bg-indigo-600 text-white' : 'bg-indigo-100 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 hover:bg-indigo-200 dark:hover:bg-indigo-800'"
|
|
35
|
-
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors inline-flex items-center gap-1.5">
|
|
36
|
-
<span aria-hidden="true">-></span> Pipeline
|
|
37
|
-
</button>
|
|
38
|
-
<button type="button" @click="activeWorkflowType = 'parallel'; submitFilters()"
|
|
39
|
-
:class="activeWorkflowType === 'parallel' ? 'bg-cyan-600 text-white' : 'bg-cyan-100 dark:bg-cyan-900/50 text-cyan-700 dark:text-cyan-300 hover:bg-cyan-200 dark:hover:bg-cyan-800'"
|
|
40
|
-
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors inline-flex items-center gap-1.5">
|
|
41
|
-
<span aria-hidden="true">//</span> Parallel
|
|
42
|
-
</button>
|
|
43
|
-
<button type="button" @click="activeWorkflowType = 'router'; submitFilters()"
|
|
44
|
-
:class="activeWorkflowType === 'router' ? 'bg-amber-600 text-white' : 'bg-amber-100 dark:bg-amber-900/50 text-amber-700 dark:text-amber-300 hover:bg-amber-200 dark:hover:bg-amber-800'"
|
|
45
|
-
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors inline-flex items-center gap-1.5">
|
|
46
|
-
<span aria-hidden="true"><></span> Router
|
|
47
|
-
</button>
|
|
48
|
-
</div>
|
|
1
|
+
<div class="mb-6">
|
|
2
|
+
<div class="flex items-center gap-2">
|
|
3
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Executions</h1>
|
|
4
|
+
<%= render "ruby_llm/agents/shared/doc_link" %>
|
|
49
5
|
</div>
|
|
6
|
+
<p class="text-gray-500 dark:text-gray-400 mt-1">All agent and workflow execution history</p>
|
|
7
|
+
</div>
|
|
50
8
|
|
|
51
|
-
|
|
52
|
-
<input type="hidden" id="execution-type-filter" name="execution_type" x-model="activeTab" form="filters-form">
|
|
53
|
-
<input type="hidden" id="workflow-type-tab-filter" name="workflow_type_tab" x-model="activeWorkflowType" form="filters-form">
|
|
54
|
-
|
|
9
|
+
<div id="executions_content">
|
|
55
10
|
<%= render partial: "ruby_llm/agents/executions/filters", locals: { agent_types: @agent_types, model_ids: @model_ids, workflow_types: @workflow_types, filter_stats: @filter_stats } %>
|
|
56
11
|
<%= render partial: "ruby_llm/agents/executions/list", locals: { executions: @executions, pagination: @pagination, filter_stats: @filter_stats } %>
|
|
57
12
|
</div>
|
|
58
|
-
|
|
59
|
-
<script>
|
|
60
|
-
// Toggle attempts expansion (used by executions list)
|
|
61
|
-
function toggleAttempts(executionId) {
|
|
62
|
-
const attemptsRow = document.getElementById('attempts-row-' + executionId);
|
|
63
|
-
const expandBtn = document.querySelector(`button[data-execution-id="${executionId}"]`);
|
|
64
|
-
|
|
65
|
-
if (attemptsRow) {
|
|
66
|
-
const isHidden = attemptsRow.classList.contains('hidden');
|
|
67
|
-
attemptsRow.classList.toggle('hidden');
|
|
68
|
-
|
|
69
|
-
// Rotate the chevron
|
|
70
|
-
if (expandBtn) {
|
|
71
|
-
const svg = expandBtn.querySelector('svg');
|
|
72
|
-
if (svg) {
|
|
73
|
-
svg.classList.toggle('rotate-90', isHidden);
|
|
74
|
-
}
|
|
75
|
-
expandBtn.setAttribute('aria-expanded', isHidden ? 'true' : 'false');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Submit filters when tabs change
|
|
81
|
-
function submitFilters() {
|
|
82
|
-
// Delay to allow Alpine to update x-model values
|
|
83
|
-
setTimeout(function() {
|
|
84
|
-
const form = document.getElementById('filters-form');
|
|
85
|
-
if (form) form.requestSubmit();
|
|
86
|
-
}, 50);
|
|
87
|
-
}
|
|
88
|
-
</script>
|