ruby_llm-agents 1.3.4 → 2.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/README.md +112 -336
- 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 +52 -12
- 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 +89 -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 +526 -1037
- 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 +13 -17
- 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 +33 -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 +77 -259
- 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 +54 -23
- 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 +97 -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/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/execution_logger_job.rb +8 -0
- 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 +14 -83
- 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
|
@@ -1,421 +1,291 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<div class="
|
|
10
|
-
<div>
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</h1>
|
|
15
|
-
<%= render "ruby_llm/agents/shared/doc_link" %>
|
|
16
|
-
|
|
17
|
-
<% if @agent_active %>
|
|
18
|
-
<span
|
|
19
|
-
class="
|
|
20
|
-
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs
|
|
21
|
-
font-medium bg-green-100 dark:bg-green-900/50 text-green-800 dark:text-green-300
|
|
22
|
-
"
|
|
23
|
-
>
|
|
24
|
-
Active
|
|
25
|
-
</span>
|
|
26
|
-
<% else %>
|
|
27
|
-
<span
|
|
28
|
-
class="
|
|
29
|
-
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs
|
|
30
|
-
font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400
|
|
31
|
-
"
|
|
32
|
-
>
|
|
33
|
-
Deleted
|
|
34
|
-
</span>
|
|
35
|
-
<% end %>
|
|
36
|
-
|
|
1
|
+
<!-- Back link -->
|
|
2
|
+
<nav class="font-mono text-xs mb-6">
|
|
3
|
+
<%= link_to "← agents", ruby_llm_agents.agents_path(subtab: params[:subtab]), class: "text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300" %>
|
|
4
|
+
</nav>
|
|
5
|
+
|
|
6
|
+
<!-- ── agent header ──────────────── -->
|
|
7
|
+
<div class="flex items-start justify-between gap-8 mb-2">
|
|
8
|
+
<!-- Left: identity -->
|
|
9
|
+
<div class="min-w-0">
|
|
10
|
+
<div class="flex items-center gap-3 mb-1.5">
|
|
11
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono"><%= @agent_type.gsub(/Agent$/, '') %></span>
|
|
12
|
+
<div class="font-mono text-xs text-gray-400 dark:text-gray-500 flex items-center gap-1.5">
|
|
13
|
+
<span class="badge badge-sm <%= @agent_active ? 'badge-success' : 'badge-error' %>"><%= @agent_active ? 'active' : 'inactive' %></span>
|
|
37
14
|
<% if @config %>
|
|
38
|
-
<span class="text-
|
|
39
|
-
v<%= @config[:version] %>
|
|
40
|
-
</span>
|
|
41
|
-
<% end %>
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<% if @config %>
|
|
45
|
-
<p class="text-gray-500 dark:text-gray-400 mt-1">
|
|
46
|
-
<%= @config[:model] %>
|
|
15
|
+
<span class="text-gray-800 dark:text-gray-200"><%= @config[:model] %></span>
|
|
47
16
|
<% if @config[:temperature] %>
|
|
48
|
-
|
|
17
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
18
|
+
<span>temp <%= @config[:temperature] %></span>
|
|
49
19
|
<% end %>
|
|
50
20
|
<% if @config[:timeout] %>
|
|
51
|
-
|
|
21
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
22
|
+
<span><%= @config[:timeout] %>s</span>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% if @config[:cache_enabled] %>
|
|
25
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
26
|
+
<%
|
|
27
|
+
ttl = @config[:cache_ttl]
|
|
28
|
+
cache_label = if ttl.is_a?(ActiveSupport::Duration)
|
|
29
|
+
secs = ttl.to_i
|
|
30
|
+
if secs >= 3600 then "#{secs / 3600}h"
|
|
31
|
+
elsif secs >= 60 then "#{secs / 60}m"
|
|
32
|
+
else "#{secs}s"
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
ttl.to_s
|
|
36
|
+
end
|
|
37
|
+
%>
|
|
38
|
+
<span>cache <%= cache_label %></span>
|
|
52
39
|
<% end %>
|
|
53
40
|
<% if @config[:dimensions] %>
|
|
54
|
-
|
|
41
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
42
|
+
<span><%= @config[:dimensions] %> dims</span>
|
|
55
43
|
<% end %>
|
|
56
44
|
<% if @config[:voice] %>
|
|
57
|
-
|
|
45
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
46
|
+
<span>voice: <%= @config[:voice] %></span>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% if @streaming_rate && @streaming_rate > 0 %>
|
|
49
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
50
|
+
<span>streaming</span>
|
|
58
51
|
<% end %>
|
|
59
|
-
</p>
|
|
60
|
-
<% if @config[:description].present? %>
|
|
61
|
-
<p class="text-gray-600 dark:text-gray-300 mt-2">
|
|
62
|
-
<%= @config[:description] %>
|
|
63
|
-
</p>
|
|
64
|
-
<% end %>
|
|
65
|
-
<% end %>
|
|
66
|
-
</div>
|
|
67
|
-
|
|
68
|
-
<div class="text-right">
|
|
69
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
70
|
-
<%= number_with_delimiter(@stats[:count]) %> total executions
|
|
71
|
-
</p>
|
|
72
|
-
|
|
73
|
-
<div class="flex items-center justify-end gap-3 mt-1">
|
|
74
|
-
<% status_colors = {
|
|
75
|
-
"success" => "bg-green-500",
|
|
76
|
-
"error" => "bg-red-500",
|
|
77
|
-
"timeout" => "bg-yellow-500",
|
|
78
|
-
"running" => "bg-blue-500"
|
|
79
|
-
} %>
|
|
80
|
-
|
|
81
|
-
<% @status_distribution.each do |status, count| %>
|
|
82
|
-
<div class="flex items-center gap-1">
|
|
83
|
-
<span class="w-2 h-2 rounded-full <%= status_colors[status] || 'bg-gray-400' %> <%= status == 'running' ? 'animate-pulse' : '' %>"></span>
|
|
84
|
-
|
|
85
|
-
<span class="text-xs text-gray-600 dark:text-gray-400">
|
|
86
|
-
<%= number_with_delimiter(count) %>
|
|
87
|
-
</span>
|
|
88
|
-
</div>
|
|
89
52
|
<% end %>
|
|
90
53
|
</div>
|
|
54
|
+
<%= render "ruby_llm/agents/shared/doc_link" %>
|
|
91
55
|
</div>
|
|
56
|
+
<% if @config && @config[:description].present? %>
|
|
57
|
+
<p class="font-mono text-xs text-gray-500 dark:text-gray-400"><%= @config[:description] %></p>
|
|
58
|
+
<% end %>
|
|
92
59
|
</div>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
<!-- Circuit Breaker Status (only for base agents with reliability enabled) -->
|
|
96
|
-
<% if @config && @agent_type_kind == "agent" && @circuit_breaker_status.present? %>
|
|
97
|
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4 mb-6">
|
|
98
|
-
<div class="flex items-center justify-between mb-3">
|
|
99
|
-
<h3
|
|
100
|
-
class="
|
|
101
|
-
text-sm font-medium text-gray-700 dark:text-gray-300 uppercase
|
|
102
|
-
tracking-wider
|
|
103
|
-
"
|
|
104
|
-
>
|
|
105
|
-
Circuit Breaker Status
|
|
106
|
-
</h3>
|
|
107
60
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
61
|
+
<!-- Right: stats -->
|
|
62
|
+
<div class="flex-shrink-0 text-right font-mono text-xs text-gray-400 dark:text-gray-500 space-y-1">
|
|
63
|
+
<% success_rate = @stats[:success_rate] || 0 %>
|
|
64
|
+
<div class="flex items-center justify-end gap-x-4">
|
|
65
|
+
<span><span class="text-gray-800 dark:text-gray-200"><%= number_with_delimiter(@stats[:count]) %></span> runs</span>
|
|
66
|
+
<span class="<%= success_rate >= 95 ? 'text-green-500' : success_rate >= 80 ? 'text-yellow-500' : 'text-red-500' %>"><%= success_rate %>% ok</span>
|
|
67
|
+
<span><span class="text-gray-800 dark:text-gray-200">$<%= number_with_precision(@stats[:total_cost] || 0, precision: 4) %></span> cost</span>
|
|
111
68
|
</div>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<!-- Open/Tripped indicator -->
|
|
118
|
-
<span class="relative flex h-3 w-3">
|
|
119
|
-
<span
|
|
120
|
-
class="
|
|
121
|
-
animate-ping absolute inline-flex h-full w-full
|
|
122
|
-
rounded-full bg-red-400 opacity-75
|
|
123
|
-
"
|
|
124
|
-
></span>
|
|
125
|
-
|
|
126
|
-
<span class="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
|
|
127
|
-
</span>
|
|
128
|
-
<span class="text-sm font-medium text-red-700 dark:text-red-300">
|
|
129
|
-
<%= model_id %>
|
|
130
|
-
</span>
|
|
131
|
-
<span class="text-xs text-red-500 dark:text-red-400 ml-1">
|
|
132
|
-
OPEN
|
|
133
|
-
</span>
|
|
134
|
-
<% if status[:cooldown_remaining] %>
|
|
135
|
-
<span class="text-xs text-red-400 dark:text-red-500 ml-1">
|
|
136
|
-
(resets in <%= status[:cooldown_remaining] %>s)
|
|
137
|
-
</span>
|
|
138
|
-
<% end %>
|
|
139
|
-
<% else %>
|
|
140
|
-
<!-- Closed/Healthy indicator -->
|
|
141
|
-
<span class="inline-flex rounded-full h-3 w-3 bg-green-500"></span>
|
|
142
|
-
<span class="text-sm font-medium text-green-700 dark:text-green-300">
|
|
143
|
-
<%= model_id %>
|
|
144
|
-
</span>
|
|
145
|
-
<span class="text-xs text-green-500 dark:text-green-400 ml-1">
|
|
146
|
-
OK
|
|
147
|
-
</span>
|
|
148
|
-
<% if status[:failure_count] && status[:failure_count] > 0 %>
|
|
149
|
-
<span class="text-xs text-yellow-500 dark:text-yellow-400 ml-1">
|
|
150
|
-
(<%= status[:failure_count] %>/<%= status[:threshold] %>
|
|
151
|
-
failures)
|
|
152
|
-
</span>
|
|
153
|
-
<% end %>
|
|
154
|
-
<% end %>
|
|
155
|
-
</div>
|
|
69
|
+
<div class="flex items-center justify-end gap-x-4 text-gray-500 dark:text-gray-600">
|
|
70
|
+
<span><span class="text-gray-600 dark:text-gray-400"><%= number_with_delimiter(@stats[:total_tokens] || 0) %></span> tokens</span>
|
|
71
|
+
<span><span class="text-gray-600 dark:text-gray-400"><%= number_with_delimiter(@stats[:avg_duration_ms] || 0) %></span>ms avg</span>
|
|
72
|
+
<% if (@config && @config[:cache_enabled]) || @cache_hit_rate > 0 %>
|
|
73
|
+
<span><span class="text-gray-600 dark:text-gray-400"><%= @cache_hit_rate %>%</span> cache</span>
|
|
156
74
|
<% end %>
|
|
157
75
|
</div>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
76
|
+
<% if @stats_today[:count] > 0 %>
|
|
77
|
+
<% today_success_rate = @stats_today[:success_rate] || 0 %>
|
|
78
|
+
<div class="flex items-center justify-end gap-x-4 pt-1 border-t border-gray-200 dark:border-gray-800">
|
|
79
|
+
<span class="text-gray-300 dark:text-gray-700">today</span>
|
|
80
|
+
<span><span class="text-gray-800 dark:text-gray-200"><%= number_with_delimiter(@stats_today[:count]) %></span> runs</span>
|
|
81
|
+
<span class="<%= today_success_rate >= 95 ? 'text-green-500' : today_success_rate >= 80 ? 'text-yellow-500' : 'text-red-500' %>"><%= today_success_rate %>% ok</span>
|
|
82
|
+
<span><span class="text-gray-800 dark:text-gray-200">$<%= number_with_precision(@stats_today[:total_cost] || 0, precision: 4) %></span> cost</span>
|
|
83
|
+
<span><span class="text-gray-800 dark:text-gray-200"><%= number_with_delimiter(@stats_today[:avg_duration_ms] || 0) %></span>ms</span>
|
|
84
|
+
</div>
|
|
164
85
|
<% end %>
|
|
165
86
|
</div>
|
|
166
|
-
<% end %>
|
|
167
|
-
|
|
168
|
-
<!-- Stats Grid -->
|
|
169
|
-
<% success_rate = @stats[:success_rate] || 0 %>
|
|
170
|
-
<% success_rate_color = success_rate >= 95 ? 'text-green-600' : success_rate >= 80 ? 'text-yellow-600' : 'text-red-600' %>
|
|
171
|
-
|
|
172
|
-
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 mb-6">
|
|
173
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
174
|
-
title: "Executions",
|
|
175
|
-
value: number_with_delimiter(@stats[:count]),
|
|
176
|
-
subtitle: "Today: #{@stats_today[:count]}",
|
|
177
|
-
icon: "M13 10V3L4 14h7v7l9-11h-7z",
|
|
178
|
-
icon_color: "text-blue-500" %>
|
|
179
|
-
|
|
180
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
181
|
-
title: "Success Rate",
|
|
182
|
-
value: "#{success_rate}%",
|
|
183
|
-
subtitle: "Error rate: #{@stats[:error_rate] || 0}%",
|
|
184
|
-
icon: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
|
|
185
|
-
icon_color: "text-green-500",
|
|
186
|
-
value_color: success_rate_color %>
|
|
187
|
-
|
|
188
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
189
|
-
title: "Total Cost",
|
|
190
|
-
value: "$#{number_with_precision(@stats[:total_cost] || 0, precision: 4)}",
|
|
191
|
-
subtitle: "Avg: $#{number_with_precision(@stats[:avg_cost] || 0, precision: 6)}",
|
|
192
|
-
icon: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z",
|
|
193
|
-
icon_color: "text-amber-500" %>
|
|
194
|
-
|
|
195
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
196
|
-
title: "Total Tokens",
|
|
197
|
-
value: number_with_delimiter(@stats[:total_tokens] || 0),
|
|
198
|
-
subtitle: "Avg: #{number_with_delimiter(@stats[:avg_tokens] || 0)}",
|
|
199
|
-
icon: "M7 20l4-16m2 16l4-16M6 9h14M4 15h14",
|
|
200
|
-
icon_color: "text-indigo-500" %>
|
|
201
|
-
|
|
202
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
203
|
-
title: "Avg Duration",
|
|
204
|
-
value: "#{number_with_delimiter(@stats[:avg_duration_ms] || 0)} ms",
|
|
205
|
-
icon: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z",
|
|
206
|
-
icon_color: "text-purple-500" %>
|
|
207
|
-
|
|
208
|
-
<%= render "ruby_llm/agents/shared/stat_card",
|
|
209
|
-
title: "Cache Hit Rate",
|
|
210
|
-
value: "#{@cache_hit_rate}%",
|
|
211
|
-
icon: "M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4",
|
|
212
|
-
icon_color: "text-purple-500" %>
|
|
213
87
|
</div>
|
|
88
|
+
<div class="border-t border-gray-200 dark:border-gray-800 mb-2"></div>
|
|
214
89
|
|
|
215
|
-
<!--
|
|
216
|
-
<div class="
|
|
217
|
-
|
|
218
|
-
<div class="
|
|
219
|
-
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
220
|
-
Executions (30 days)
|
|
221
|
-
</h3>
|
|
222
|
-
<div id="executions-chart" style="height: 220px;"></div>
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<!-- Cost Over Time -->
|
|
226
|
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 overflow-hidden">
|
|
227
|
-
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
228
|
-
Cost (30 days)
|
|
229
|
-
</h3>
|
|
230
|
-
<div id="cost-chart" style="height: 220px;"></div>
|
|
231
|
-
</div>
|
|
90
|
+
<!-- 30d trend chart -->
|
|
91
|
+
<div class="flex items-center gap-3 mt-6 mb-2">
|
|
92
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">last 30 days</span>
|
|
93
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
232
94
|
</div>
|
|
233
|
-
|
|
95
|
+
<div id="agent-trend-chart" style="width: 100%; height: 160px;"></div>
|
|
234
96
|
<script>
|
|
235
97
|
(function() {
|
|
236
|
-
const trendData = <%= raw @trend_data.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
98
|
+
const trendData = <%= raw @trend_data.map { |d|
|
|
99
|
+
{ date: d[:date] || d["date"], count: d[:count] || d["count"] || 0,
|
|
100
|
+
cost: (d[:total_cost] || d["total_cost"] || 0).to_f.round(6),
|
|
101
|
+
errors: d[:error_count] || d["error_count"] || 0 }
|
|
102
|
+
}.to_json %>;
|
|
103
|
+
|
|
104
|
+
const successData = trendData.map(d => [new Date(d.date).getTime(), d.count - d.errors]);
|
|
105
|
+
const errorData = trendData.map(d => [new Date(d.date).getTime(), d.errors]);
|
|
106
|
+
|
|
107
|
+
Highcharts.chart('agent-trend-chart', {
|
|
108
|
+
chart: { type: 'areaspline', backgroundColor: 'transparent', spacing: [5, 0, 0, 0] },
|
|
109
|
+
title: { text: null },
|
|
110
|
+
xAxis: {
|
|
111
|
+
type: 'datetime',
|
|
112
|
+
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' }, format: '{value:%b %d}' },
|
|
113
|
+
lineColor: 'transparent',
|
|
114
|
+
tickLength: 0,
|
|
115
|
+
gridLineWidth: 0
|
|
116
|
+
},
|
|
117
|
+
yAxis: {
|
|
118
|
+
title: { text: null },
|
|
119
|
+
min: 0,
|
|
120
|
+
allowDecimals: false,
|
|
121
|
+
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' } },
|
|
122
|
+
gridLineColor: 'rgba(107, 114, 128, 0.08)'
|
|
123
|
+
},
|
|
244
124
|
legend: { enabled: false },
|
|
245
|
-
|
|
125
|
+
credits: { enabled: false },
|
|
126
|
+
tooltip: {
|
|
127
|
+
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
128
|
+
borderColor: 'transparent',
|
|
129
|
+
borderRadius: 3,
|
|
130
|
+
style: { color: '#E5E7EB', fontSize: '10px', fontFamily: 'ui-monospace, monospace' },
|
|
131
|
+
shared: true,
|
|
132
|
+
formatter: function() {
|
|
133
|
+
let html = '<span style="color:#9CA3AF">' + Highcharts.dateFormat('%b %d', this.x) + '</span>';
|
|
134
|
+
let cost = trendData.find(d => new Date(d.date).getTime() === this.x);
|
|
135
|
+
this.points.forEach(p => html += '<br/>' + p.series.name + ': <b>' + p.y + '</b>');
|
|
136
|
+
if (cost) html += '<br/>cost: <b>$' + cost.cost.toFixed(4) + '</b>';
|
|
137
|
+
return html;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
plotOptions: {
|
|
141
|
+
areaspline: {
|
|
142
|
+
stacking: 'normal',
|
|
143
|
+
lineWidth: 1.5,
|
|
144
|
+
marker: { enabled: false, states: { hover: { enabled: true, radius: 2 } } }
|
|
145
|
+
}
|
|
146
|
+
},
|
|
246
147
|
series: [
|
|
247
|
-
{
|
|
248
|
-
|
|
148
|
+
{
|
|
149
|
+
name: 'errors',
|
|
150
|
+
data: errorData,
|
|
151
|
+
color: '#EF4444',
|
|
152
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(239, 68, 68, 0.08)'], [1, 'rgba(239, 68, 68, 0)']] }
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'success',
|
|
156
|
+
data: successData,
|
|
157
|
+
color: '#10B981',
|
|
158
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(16, 185, 129, 0.08)'], [1, 'rgba(16, 185, 129, 0)']] }
|
|
159
|
+
}
|
|
249
160
|
]
|
|
250
161
|
});
|
|
251
|
-
|
|
252
|
-
// Cost chart
|
|
253
|
-
Highcharts.chart('cost-chart', {
|
|
254
|
-
chart: { type: 'spline', backgroundColor: 'transparent' },
|
|
255
|
-
xAxis: { categories: categories, labels: { style: { color: '#9CA3AF' } } },
|
|
256
|
-
yAxis: { min: 0, title: { text: null }, labels: { style: { color: '#9CA3AF' }, format: '${value}' } },
|
|
257
|
-
legend: { enabled: false },
|
|
258
|
-
plotOptions: { spline: { marker: { enabled: false } } },
|
|
259
|
-
tooltip: { valuePrefix: '$' },
|
|
260
|
-
series: [{ name: 'Cost', color: '#10B981', data: trendData.map(d => parseFloat(d.total_cost) || 0) }]
|
|
261
|
-
});
|
|
262
162
|
})();
|
|
263
163
|
</script>
|
|
264
164
|
|
|
265
|
-
<!--
|
|
266
|
-
<% if @
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
class="w-2 h-2 rounded-full mr-1.5"
|
|
286
|
-
style="background-color: <%= finish_colors[reason] || '#6B7280' %>"
|
|
287
|
-
></span>
|
|
288
|
-
|
|
289
|
-
<span class="text-sm text-gray-700 dark:text-gray-300">
|
|
290
|
-
<%= reason || 'unknown' %>
|
|
291
|
-
</span>
|
|
165
|
+
<!-- ── tools ──────────────────────── -->
|
|
166
|
+
<% if @config && @agent_type_kind == "agent" %>
|
|
167
|
+
<%
|
|
168
|
+
class_tools = @agent_class.respond_to?(:tools) ? (@agent_class.tools || []) : []
|
|
169
|
+
has_dynamic_tools = @agent_class.instance_methods(false).include?(:tools)
|
|
170
|
+
%>
|
|
171
|
+
<% if class_tools.any? || has_dynamic_tools %>
|
|
172
|
+
<div class="flex items-center gap-3 mt-6 mb-3">
|
|
173
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">tools (<%= class_tools.size %>)</span>
|
|
174
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="flex flex-wrap gap-1.5 font-mono text-xs">
|
|
177
|
+
<% class_tools.each do |tool_class| %>
|
|
178
|
+
<span class="badge badge-cyan"><%= tool_class.respond_to?(:tool_name) ? tool_class.tool_name : tool_class.name.demodulize %></span>
|
|
179
|
+
<% end %>
|
|
180
|
+
<% if has_dynamic_tools %>
|
|
181
|
+
<span class="badge badge-purple">dynamic</span>
|
|
182
|
+
<% end %>
|
|
183
|
+
</div>
|
|
184
|
+
<% end %>
|
|
292
185
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
</div>
|
|
297
|
-
<% end %>
|
|
298
|
-
</div>
|
|
186
|
+
<% if @config[:params].present? && @config[:params].any? %>
|
|
187
|
+
<div class="mt-3">
|
|
188
|
+
<span class="text-[10px] text-gray-400 dark:text-gray-600 uppercase tracking-wider font-mono">parameters</span>
|
|
299
189
|
</div>
|
|
300
|
-
|
|
190
|
+
<div class="grid grid-cols-2 sm:grid-cols-3 gap-x-6 gap-y-0.5 font-mono text-xs mt-1.5">
|
|
191
|
+
<% @config[:params].each do |name, opts| %>
|
|
192
|
+
<div class="flex items-center gap-2 py-0.5">
|
|
193
|
+
<span class="text-gray-900 dark:text-gray-200"><%= name %></span>
|
|
194
|
+
<% if opts[:required] %>
|
|
195
|
+
<span class="text-red-500">required</span>
|
|
196
|
+
<% elsif opts[:default].present? %>
|
|
197
|
+
<span class="text-gray-400 dark:text-gray-600">= <%= opts[:default].inspect %></span>
|
|
198
|
+
<% else %>
|
|
199
|
+
<span class="text-gray-400 dark:text-gray-600">optional</span>
|
|
200
|
+
<% end %>
|
|
201
|
+
</div>
|
|
202
|
+
<% end %>
|
|
203
|
+
</div>
|
|
204
|
+
<% end %>
|
|
301
205
|
<% end %>
|
|
302
206
|
|
|
303
|
-
<!--
|
|
304
|
-
|
|
305
|
-
|
|
207
|
+
<!-- ── model health ──────────────── -->
|
|
208
|
+
<%
|
|
209
|
+
if @config && @agent_type_kind == "agent"
|
|
210
|
+
retries_config = @config[:retries] || {}
|
|
211
|
+
fallback_models = Array(@config[:fallback_models]).compact
|
|
212
|
+
has_retries = (retries_config[:max] || 0) > 0
|
|
213
|
+
has_fallbacks = fallback_models.any?
|
|
214
|
+
has_circuit_breaker = @config[:circuit_breaker].present?
|
|
215
|
+
has_any_reliability = has_retries || has_fallbacks || has_circuit_breaker
|
|
216
|
+
show_model_health = has_any_reliability || @circuit_breaker_status.present?
|
|
217
|
+
end
|
|
218
|
+
%>
|
|
219
|
+
<% if show_model_health %>
|
|
220
|
+
<div class="flex items-center gap-3 mt-6 mb-3">
|
|
221
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">model health</span>
|
|
222
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
223
|
+
</div>
|
|
224
|
+
<% if has_any_reliability %>
|
|
225
|
+
<div class="font-mono text-xs text-gray-400 dark:text-gray-500 mb-2 flex flex-wrap gap-x-1.5 gap-y-0.5">
|
|
226
|
+
<% if has_retries %>
|
|
227
|
+
<span>retries: <%= retries_config[:max] %> max</span>
|
|
228
|
+
<% end %>
|
|
229
|
+
<% if has_retries && (has_fallbacks || has_circuit_breaker) %>
|
|
230
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
231
|
+
<% end %>
|
|
232
|
+
<% if has_fallbacks %>
|
|
233
|
+
<span>fallbacks: <%= fallback_models.join(" → ") %></span>
|
|
234
|
+
<% end %>
|
|
235
|
+
<% if has_fallbacks && has_circuit_breaker %>
|
|
236
|
+
<span class="text-gray-300 dark:text-gray-700">·</span>
|
|
237
|
+
<% end %>
|
|
238
|
+
<% if has_circuit_breaker %>
|
|
239
|
+
<% cb = @config[:circuit_breaker] %>
|
|
240
|
+
<span>pauses after <%= cb[:errors] %> errors in <%= cb[:within] %>s</span>
|
|
241
|
+
<% end %>
|
|
242
|
+
</div>
|
|
243
|
+
<% end %>
|
|
244
|
+
<% if @circuit_breaker_status.present? %>
|
|
245
|
+
<div class="font-mono text-xs">
|
|
246
|
+
<% @circuit_breaker_status.each do |model_id, status| %>
|
|
247
|
+
<div class="flex items-center gap-3 py-1 px-2 -mx-2">
|
|
248
|
+
<span class="w-1.5 h-1.5 rounded-full flex-shrink-0 <%= status[:open] ? 'bg-red-500 animate-pulse' : 'bg-green-500' %>"></span>
|
|
249
|
+
<span class="text-gray-900 dark:text-gray-200"><%= model_id %></span>
|
|
250
|
+
<% if status[:open] %>
|
|
251
|
+
<span class="text-red-500">paused</span>
|
|
252
|
+
<% if status[:cooldown_remaining] %>
|
|
253
|
+
<span class="text-gray-400 dark:text-gray-600">retrying in <%= status[:cooldown_remaining] %>s</span>
|
|
254
|
+
<% end %>
|
|
255
|
+
<% else %>
|
|
256
|
+
<span class="text-green-500">healthy</span>
|
|
257
|
+
<% if status[:failure_count] && status[:failure_count] > 0 %>
|
|
258
|
+
<span class="text-yellow-500"><%= status[:failure_count] %>/<%= status[:threshold] %> failures before pause</span>
|
|
259
|
+
<% end %>
|
|
260
|
+
<% end %>
|
|
261
|
+
</div>
|
|
262
|
+
<% end %>
|
|
263
|
+
</div>
|
|
264
|
+
<% end %>
|
|
265
|
+
<% end %>
|
|
306
266
|
|
|
307
|
-
|
|
267
|
+
<!-- ── config (non-agent types only) ── -->
|
|
268
|
+
<% if @config && @agent_type_kind && @agent_type_kind != "agent" %>
|
|
269
|
+
<div class="flex items-center gap-3 mt-6 mb-3">
|
|
270
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">config</span>
|
|
271
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
272
|
+
</div>
|
|
308
273
|
<%= render "ruby_llm/agents/agents/config_#{@agent_type_kind}", config: @config %>
|
|
309
274
|
<% end %>
|
|
310
275
|
|
|
311
|
-
<!--
|
|
312
|
-
<div class="
|
|
313
|
-
<
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
<div id="executions_table">
|
|
318
|
-
<%
|
|
319
|
-
has_filters = params[:statuses].present? || params[:versions].present? || params[:models].present? || params[:temperatures].present? || params[:days].present?
|
|
320
|
-
selected_statuses = params[:statuses].present? ? (params[:statuses].is_a?(Array) ? params[:statuses] : params[:statuses].split(",")) : []
|
|
321
|
-
selected_versions = params[:versions].present? ? (params[:versions].is_a?(Array) ? params[:versions] : params[:versions].split(",")) : []
|
|
322
|
-
selected_models = params[:models].present? ? (params[:models].is_a?(Array) ? params[:models] : params[:models].split(",")) : []
|
|
323
|
-
selected_temperatures = params[:temperatures].present? ? (params[:temperatures].is_a?(Array) ? params[:temperatures] : params[:temperatures].split(",")).map(&:to_s) : []
|
|
324
|
-
|
|
325
|
-
status_options = [
|
|
326
|
-
{ value: "success", label: "Success", color: "bg-green-500" },
|
|
327
|
-
{ value: "error", label: "Error", color: "bg-red-500" },
|
|
328
|
-
{ value: "running", label: "Running", color: "bg-blue-500" },
|
|
329
|
-
{ value: "timeout", label: "Timeout", color: "bg-yellow-500" }
|
|
330
|
-
]
|
|
331
|
-
version_options = @versions.map { |v| { value: v.to_s, label: "v#{v}" } }
|
|
332
|
-
model_options = @models.map { |m| { value: m, label: m } }
|
|
333
|
-
temperature_options = @temperatures.map { |t| { value: t.to_s, label: t.to_s } }
|
|
334
|
-
days_options = [
|
|
335
|
-
{ value: "", label: "All Time" },
|
|
336
|
-
{ value: "1", label: "Today" },
|
|
337
|
-
{ value: "7", label: "Last 7 Days" },
|
|
338
|
-
{ value: "30", label: "Last 30 Days" }
|
|
339
|
-
]
|
|
340
|
-
%>
|
|
341
|
-
|
|
342
|
-
<%= form_with url: ruby_llm_agents.agent_path(@agent_type), method: :get, local: true do |f| %>
|
|
343
|
-
<div class="flex flex-wrap items-center gap-3 mb-4 pb-4 border-b border-gray-100 dark:border-gray-700">
|
|
344
|
-
<%# Status Filter (Multi-select) %>
|
|
345
|
-
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
346
|
-
name: "statuses[]",
|
|
347
|
-
filter_id: "statuses",
|
|
348
|
-
label: "Status",
|
|
349
|
-
all_label: "All Statuses",
|
|
350
|
-
options: status_options,
|
|
351
|
-
selected: selected_statuses %>
|
|
352
|
-
|
|
353
|
-
<%# Version Filter (Multi-select) %>
|
|
354
|
-
<% if @versions.any? %>
|
|
355
|
-
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
356
|
-
name: "versions[]",
|
|
357
|
-
filter_id: "versions",
|
|
358
|
-
label: "Version",
|
|
359
|
-
all_label: "All Versions",
|
|
360
|
-
options: version_options,
|
|
361
|
-
selected: selected_versions,
|
|
362
|
-
icon: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" %>
|
|
363
|
-
<% end %>
|
|
364
|
-
|
|
365
|
-
<%# Model Filter (Multi-select) %>
|
|
366
|
-
<% if @models.length > 1 %>
|
|
367
|
-
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
368
|
-
name: "models[]",
|
|
369
|
-
filter_id: "models",
|
|
370
|
-
label: "Model",
|
|
371
|
-
all_label: "All Models",
|
|
372
|
-
options: model_options,
|
|
373
|
-
selected: selected_models,
|
|
374
|
-
icon: "M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" %>
|
|
375
|
-
<% end %>
|
|
376
|
-
|
|
377
|
-
<%# Temperature Filter (Multi-select) %>
|
|
378
|
-
<% if @temperatures.length > 1 %>
|
|
379
|
-
<%= render "ruby_llm/agents/shared/filter_dropdown",
|
|
380
|
-
name: "temperatures[]",
|
|
381
|
-
filter_id: "temperatures",
|
|
382
|
-
label: "Temp",
|
|
383
|
-
all_label: "All Temps",
|
|
384
|
-
options: temperature_options,
|
|
385
|
-
selected: selected_temperatures,
|
|
386
|
-
icon: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" %>
|
|
387
|
-
<% end %>
|
|
388
|
-
|
|
389
|
-
<%# Time Range Filter (Single-select) %>
|
|
390
|
-
<%= render "ruby_llm/agents/shared/select_dropdown",
|
|
391
|
-
name: "days",
|
|
392
|
-
filter_id: "days",
|
|
393
|
-
options: days_options,
|
|
394
|
-
selected: params[:days].to_s,
|
|
395
|
-
icon: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" %>
|
|
276
|
+
<!-- ── executions ──────────────────── -->
|
|
277
|
+
<div class="flex items-center gap-3 mt-6 mb-3">
|
|
278
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">recent executions</span>
|
|
279
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
280
|
+
</div>
|
|
396
281
|
|
|
397
|
-
|
|
398
|
-
<% if has_filters %>
|
|
399
|
-
<%= link_to ruby_llm_agents.agent_path(@agent_type),
|
|
400
|
-
class: "flex items-center gap-1 px-3 py-2 text-sm text-red-500 dark:text-red-400 hover:text-red-600 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/30 rounded-lg transition-colors" do %>
|
|
401
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
402
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
403
|
-
</svg>
|
|
404
|
-
Clear
|
|
405
|
-
<% end %>
|
|
406
|
-
<% end %>
|
|
282
|
+
<%= render "ruby_llm/agents/shared/executions_table", executions: @executions, pagination: @pagination, hide_agent_column: true %>
|
|
407
283
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
<span class="text-gray-300 dark:text-gray-600">|</span>
|
|
414
|
-
<span><%= number_with_delimiter(@filter_stats[:total_tokens] || 0) %> tokens</span>
|
|
415
|
-
</div>
|
|
416
|
-
</div>
|
|
284
|
+
<% if @stats[:count] > 0 %>
|
|
285
|
+
<div class="mt-3 font-mono text-xs">
|
|
286
|
+
<%= link_to ruby_llm_agents.executions_path("agent_types[]": @agent_type),
|
|
287
|
+
class: "text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300" do %>
|
|
288
|
+
show all <%= number_with_delimiter(@stats[:count]) %> executions →
|
|
417
289
|
<% end %>
|
|
418
|
-
|
|
419
|
-
<%= render "ruby_llm/agents/shared/executions_table", executions: @executions, pagination: @pagination %>
|
|
420
290
|
</div>
|
|
421
|
-
|
|
291
|
+
<% end %>
|