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,61 +1,38 @@
|
|
|
1
1
|
<% if critical_alerts.any? %>
|
|
2
|
-
<div id="action-center" class="mb-6
|
|
3
|
-
<div class="flex items-center mb-3">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<h3 class="font-semibold text-red-800 dark:text-red-200">Action Required</h3>
|
|
2
|
+
<div id="action-center" class="mb-6">
|
|
3
|
+
<div class="flex items-center gap-3 mb-3">
|
|
4
|
+
<span class="text-[10px] font-medium text-red-500 dark:text-red-400 uppercase tracking-widest font-mono">action required</span>
|
|
5
|
+
<span class="font-mono text-xs text-red-400 dark:text-red-500"><%= critical_alerts.size %></span>
|
|
6
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
8
7
|
</div>
|
|
9
8
|
|
|
10
|
-
<div class="space-y-
|
|
9
|
+
<div class="font-mono text-xs space-y-1">
|
|
11
10
|
<% critical_alerts.each do |alert| %>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</p>
|
|
21
|
-
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
22
|
-
<%= alert[:data][:model_id] %> · <%= alert[:data][:failure_count] %>/<%= alert[:data][:threshold] %> failures
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
<span class="text-xs text-orange-600 dark:text-orange-400 font-medium ml-5 sm:ml-0">
|
|
27
|
-
<%= alert[:data][:cooldown_remaining] %>s remaining
|
|
28
|
-
</span>
|
|
11
|
+
<% case alert[:type] %>
|
|
12
|
+
<% when :breaker %>
|
|
13
|
+
<div class="flex items-center gap-3 py-1.5 px-2 -mx-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800/50">
|
|
14
|
+
<span class="w-1.5 h-1.5 bg-orange-500 rounded-full flex-shrink-0"></span>
|
|
15
|
+
<span class="text-gray-900 dark:text-gray-100">circuit breaker open: <span class="text-gray-500 dark:text-gray-400"><%= alert[:data][:agent_type].gsub(/Agent$/, '') %></span></span>
|
|
16
|
+
<span class="text-gray-400 dark:text-gray-600"><%= alert[:data][:model_id] %> · <%= alert[:data][:failure_count] %>/<%= alert[:data][:threshold] %> failures</span>
|
|
17
|
+
<span class="ml-auto text-orange-600 dark:text-orange-400"><%= alert[:data][:cooldown_remaining] %>s remaining</span>
|
|
18
|
+
</div>
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
38
|
-
$<%= number_with_precision(alert[:data][:current], precision: 2) %> / $<%= number_with_precision(alert[:data][:limit], precision: 2) %>
|
|
39
|
-
</p>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
<%= link_to "Adjust", ruby_llm_agents.system_config_path, class: "text-xs text-red-600 dark:text-red-400 hover:underline font-medium ml-5 sm:ml-0" %>
|
|
20
|
+
<% when :budget_breach %>
|
|
21
|
+
<div class="flex items-center gap-3 py-1.5 px-2 -mx-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800/50">
|
|
22
|
+
<span class="w-1.5 h-1.5 bg-red-500 rounded-full flex-shrink-0"></span>
|
|
23
|
+
<span class="text-gray-900 dark:text-gray-100"><%= alert[:data][:period].to_s.capitalize %> budget exceeded</span>
|
|
24
|
+
<span class="text-gray-400 dark:text-gray-600">$<%= number_with_precision(alert[:data][:current], precision: 2) %> / $<%= number_with_precision(alert[:data][:limit], precision: 2) %></span>
|
|
25
|
+
<%= link_to "adjust", ruby_llm_agents.system_config_path, class: "ml-auto text-red-600 dark:text-red-400 hover:underline" %>
|
|
26
|
+
</div>
|
|
43
27
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<%= alert[:data][:count] %> errors in last 15 minutes
|
|
53
|
-
</p>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
<%= link_to "View failures", ruby_llm_agents.executions_path(status: "error"), class: "text-xs text-red-600 dark:text-red-400 hover:underline font-medium ml-5 sm:ml-0" %>
|
|
57
|
-
<% end %>
|
|
58
|
-
</div>
|
|
28
|
+
<% when :error_spike %>
|
|
29
|
+
<div class="flex items-center gap-3 py-1.5 px-2 -mx-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800/50">
|
|
30
|
+
<span class="w-1.5 h-1.5 bg-red-500 rounded-full flex-shrink-0 animate-pulse"></span>
|
|
31
|
+
<span class="text-gray-900 dark:text-gray-100">error spike detected</span>
|
|
32
|
+
<span class="text-gray-400 dark:text-gray-600"><%= alert[:data][:count] %> errors in last 15 minutes</span>
|
|
33
|
+
<%= link_to "view failures", ruby_llm_agents.executions_path(status: "error"), class: "ml-auto text-red-600 dark:text-red-400 hover:underline" %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
59
36
|
<% end %>
|
|
60
37
|
</div>
|
|
61
38
|
</div>
|
|
@@ -2,114 +2,88 @@
|
|
|
2
2
|
<%# @param tenant_budget [Hash] Budget data from controller %>
|
|
3
3
|
|
|
4
4
|
<% if tenant_budget.present? %>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
when "soft" then "bg-yellow-100 dark:bg-yellow-900/50 text-yellow-700 dark:text-yellow-300"
|
|
21
|
-
else "bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400"
|
|
22
|
-
end %>
|
|
23
|
-
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium <%= badge_class %>">
|
|
24
|
-
<%= enforcement.capitalize %> Enforcement
|
|
25
|
-
</span>
|
|
26
|
-
</div>
|
|
5
|
+
<%
|
|
6
|
+
enforcement = tenant_budget[:enforcement].to_s
|
|
7
|
+
enforcement_badge = case enforcement
|
|
8
|
+
when "hard" then "badge-error"
|
|
9
|
+
when "soft" then "badge-timeout"
|
|
10
|
+
else ""
|
|
11
|
+
end
|
|
12
|
+
%>
|
|
13
|
+
<div class="mb-6">
|
|
14
|
+
<div class="flex items-center gap-3 mb-3">
|
|
15
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">tenant budget: <%= tenant_budget[:tenant_id] %></span>
|
|
16
|
+
<% if enforcement_badge.present? %>
|
|
17
|
+
<span class="badge <%= enforcement_badge %> badge-sm"><%= enforcement %></span>
|
|
18
|
+
<% end %>
|
|
19
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
27
20
|
</div>
|
|
28
21
|
|
|
29
|
-
<div class="
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
<div class="font-mono text-xs space-y-2">
|
|
23
|
+
<%# Daily Budget %>
|
|
24
|
+
<% if tenant_budget[:daily_limit] %>
|
|
25
|
+
<%
|
|
26
|
+
daily_pct = [tenant_budget[:daily_percentage], 100].min
|
|
27
|
+
bar_color = if daily_pct >= 100 then "bg-red-500"
|
|
28
|
+
elsif daily_pct >= 80 then "bg-yellow-500"
|
|
29
|
+
else "bg-green-500"
|
|
30
|
+
end
|
|
31
|
+
%>
|
|
32
|
+
<div class="flex items-center gap-3">
|
|
33
|
+
<span class="w-28 flex-shrink-0 text-gray-500 dark:text-gray-400">daily</span>
|
|
34
|
+
<span class="w-44 flex-shrink-0 text-gray-800 dark:text-gray-200">$<%= number_with_precision(tenant_budget[:daily_spend], precision: 2) %> <span class="text-gray-400 dark:text-gray-600">/ $<%= number_with_precision(tenant_budget[:daily_limit], precision: 2) %></span></span>
|
|
35
|
+
<span class="w-12 flex-shrink-0 text-right text-gray-400 dark:text-gray-600"><%= tenant_budget[:daily_percentage] %>%</span>
|
|
36
|
+
<div class="flex-1 bg-gray-200 dark:bg-gray-800 rounded-full h-1">
|
|
37
|
+
<div class="<%= bar_color %> h-1 rounded-full transition-all" style="width: <%= daily_pct %>%"></div>
|
|
43
38
|
</div>
|
|
44
|
-
<% if tenant_budget[:daily_limit] %>
|
|
45
|
-
<% daily_pct = [tenant_budget[:daily_percentage], 100].min %>
|
|
46
|
-
<% bar_color = if daily_pct >= 100
|
|
47
|
-
"bg-red-500"
|
|
48
|
-
elsif daily_pct >= 80
|
|
49
|
-
"bg-yellow-500"
|
|
50
|
-
else
|
|
51
|
-
"bg-green-500"
|
|
52
|
-
end %>
|
|
53
|
-
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5">
|
|
54
|
-
<div class="<%= bar_color %> h-2.5 rounded-full transition-all duration-300" style="width: <%= daily_pct %>%"></div>
|
|
55
|
-
</div>
|
|
56
|
-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1"><%= tenant_budget[:daily_percentage] %>% used</p>
|
|
57
|
-
<% else %>
|
|
58
|
-
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5">
|
|
59
|
-
<div class="bg-gray-400 h-2.5 rounded-full" style="width: 0%"></div>
|
|
60
|
-
</div>
|
|
61
|
-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">No daily limit configured</p>
|
|
62
|
-
<% end %>
|
|
63
39
|
</div>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
<span class="text-sm text-gray-500 dark:text-gray-400">
|
|
70
|
-
$<%= number_with_precision(tenant_budget[:monthly_spend], precision: 2) %>
|
|
71
|
-
<% if tenant_budget[:monthly_limit] %>
|
|
72
|
-
/ $<%= number_with_precision(tenant_budget[:monthly_limit], precision: 2) %>
|
|
73
|
-
<% else %>
|
|
74
|
-
(no limit)
|
|
75
|
-
<% end %>
|
|
76
|
-
</span>
|
|
77
|
-
</div>
|
|
78
|
-
<% if tenant_budget[:monthly_limit] %>
|
|
79
|
-
<% monthly_pct = [tenant_budget[:monthly_percentage], 100].min %>
|
|
80
|
-
<% bar_color = if monthly_pct >= 100
|
|
81
|
-
"bg-red-500"
|
|
82
|
-
elsif monthly_pct >= 80
|
|
83
|
-
"bg-yellow-500"
|
|
84
|
-
else
|
|
85
|
-
"bg-blue-500"
|
|
86
|
-
end %>
|
|
87
|
-
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5">
|
|
88
|
-
<div class="<%= bar_color %> h-2.5 rounded-full transition-all duration-300" style="width: <%= monthly_pct %>%"></div>
|
|
89
|
-
</div>
|
|
90
|
-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1"><%= tenant_budget[:monthly_percentage] %>% used</p>
|
|
91
|
-
<% else %>
|
|
92
|
-
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5">
|
|
93
|
-
<div class="bg-gray-400 h-2.5 rounded-full" style="width: 0%"></div>
|
|
94
|
-
</div>
|
|
95
|
-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">No monthly limit configured</p>
|
|
96
|
-
<% end %>
|
|
40
|
+
<% else %>
|
|
41
|
+
<div class="flex items-center gap-3">
|
|
42
|
+
<span class="w-28 flex-shrink-0 text-gray-500 dark:text-gray-400">daily</span>
|
|
43
|
+
<span class="text-gray-800 dark:text-gray-200">$<%= number_with_precision(tenant_budget[:daily_spend], precision: 2) %></span>
|
|
44
|
+
<span class="text-gray-400 dark:text-gray-600">(no limit)</span>
|
|
97
45
|
</div>
|
|
98
|
-
|
|
46
|
+
<% end %>
|
|
99
47
|
|
|
100
|
-
<%#
|
|
101
|
-
<% if tenant_budget[:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
48
|
+
<%# Monthly Budget %>
|
|
49
|
+
<% if tenant_budget[:monthly_limit] %>
|
|
50
|
+
<%
|
|
51
|
+
monthly_pct = [tenant_budget[:monthly_percentage], 100].min
|
|
52
|
+
bar_color = if monthly_pct >= 100 then "bg-red-500"
|
|
53
|
+
elsif monthly_pct >= 80 then "bg-yellow-500"
|
|
54
|
+
else "bg-blue-500"
|
|
55
|
+
end
|
|
56
|
+
%>
|
|
57
|
+
<div class="flex items-center gap-3">
|
|
58
|
+
<span class="w-28 flex-shrink-0 text-gray-500 dark:text-gray-400">monthly</span>
|
|
59
|
+
<span class="w-44 flex-shrink-0 text-gray-800 dark:text-gray-200">$<%= number_with_precision(tenant_budget[:monthly_spend], precision: 2) %> <span class="text-gray-400 dark:text-gray-600">/ $<%= number_with_precision(tenant_budget[:monthly_limit], precision: 2) %></span></span>
|
|
60
|
+
<span class="w-12 flex-shrink-0 text-right text-gray-400 dark:text-gray-600"><%= tenant_budget[:monthly_percentage] %>%</span>
|
|
61
|
+
<div class="flex-1 bg-gray-200 dark:bg-gray-800 rounded-full h-1">
|
|
62
|
+
<div class="<%= bar_color %> h-1 rounded-full transition-all" style="width: <%= monthly_pct %>%"></div>
|
|
110
63
|
</div>
|
|
111
64
|
</div>
|
|
65
|
+
<% else %>
|
|
66
|
+
<div class="flex items-center gap-3">
|
|
67
|
+
<span class="w-28 flex-shrink-0 text-gray-500 dark:text-gray-400">monthly</span>
|
|
68
|
+
<span class="text-gray-800 dark:text-gray-200">$<%= number_with_precision(tenant_budget[:monthly_spend], precision: 2) %></span>
|
|
69
|
+
<span class="text-gray-400 dark:text-gray-600">(no limit)</span>
|
|
70
|
+
</div>
|
|
112
71
|
<% end %>
|
|
113
72
|
</div>
|
|
73
|
+
|
|
74
|
+
<%# Per-agent limits if configured %>
|
|
75
|
+
<% if tenant_budget[:per_agent_daily].present? %>
|
|
76
|
+
<div class="mt-3 font-mono text-xs">
|
|
77
|
+
<span class="text-gray-400 dark:text-gray-600">per-agent daily:</span>
|
|
78
|
+
<div class="mt-1 space-y-0.5 pl-2">
|
|
79
|
+
<% tenant_budget[:per_agent_daily].each do |agent, limit| %>
|
|
80
|
+
<div class="flex items-center gap-2">
|
|
81
|
+
<span class="text-gray-900 dark:text-gray-200"><%= agent.to_s.gsub(/Agent$/, "") %></span>
|
|
82
|
+
<span class="text-gray-400 dark:text-gray-600">$<%= number_with_precision(limit, precision: 2) %></span>
|
|
83
|
+
</div>
|
|
84
|
+
<% end %>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<% end %>
|
|
114
88
|
</div>
|
|
115
89
|
<% end %>
|