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.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +112 -336
  3. data/app/controllers/concerns/ruby_llm/agents/sortable.rb +0 -1
  4. data/app/controllers/ruby_llm/agents/agents_controller.rb +5 -56
  5. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +22 -106
  6. data/app/controllers/ruby_llm/agents/executions_controller.rb +4 -114
  7. data/app/controllers/ruby_llm/agents/tenants_controller.rb +30 -2
  8. data/app/helpers/ruby_llm/agents/application_helper.rb +19 -53
  9. data/app/models/ruby_llm/agents/execution/analytics.rb +13 -54
  10. data/app/models/ruby_llm/agents/execution/scopes.rb +61 -14
  11. data/app/models/ruby_llm/agents/execution.rb +52 -12
  12. data/app/models/ruby_llm/agents/execution_detail.rb +18 -0
  13. data/app/models/ruby_llm/agents/tenant/budgetable.rb +132 -24
  14. data/app/models/ruby_llm/agents/tenant/incrementable.rb +117 -0
  15. data/app/models/ruby_llm/agents/tenant/resettable.rb +128 -0
  16. data/app/models/ruby_llm/agents/tenant/trackable.rb +46 -12
  17. data/app/models/ruby_llm/agents/tenant.rb +2 -3
  18. data/app/models/ruby_llm/agents/tenant_budget.rb +6 -3
  19. data/app/services/ruby_llm/agents/agent_registry.rb +6 -112
  20. data/app/views/layouts/ruby_llm/agents/application.html.erb +89 -252
  21. data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +71 -218
  22. data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +20 -63
  23. data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +44 -131
  24. data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +16 -57
  25. data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +39 -104
  26. data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +29 -82
  27. data/app/views/ruby_llm/agents/agents/_empty_state.html.erb +4 -14
  28. data/app/views/ruby_llm/agents/agents/index.html.erb +105 -274
  29. data/app/views/ruby_llm/agents/agents/show.html.erb +248 -378
  30. data/app/views/ruby_llm/agents/dashboard/_action_center.html.erb +29 -52
  31. data/app/views/ruby_llm/agents/dashboard/_tenant_budget.html.erb +73 -99
  32. data/app/views/ruby_llm/agents/dashboard/index.html.erb +228 -433
  33. data/app/views/ruby_llm/agents/executions/_execution.html.erb +1 -1
  34. data/app/views/ruby_llm/agents/executions/_filters.html.erb +4 -25
  35. data/app/views/ruby_llm/agents/executions/_list.html.erb +111 -152
  36. data/app/views/ruby_llm/agents/executions/index.html.erb +5 -7
  37. data/app/views/ruby_llm/agents/executions/show.html.erb +526 -1037
  38. data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +5 -21
  39. data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +70 -191
  40. data/app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb +16 -44
  41. data/app/views/ruby_llm/agents/shared/_select_dropdown.html.erb +12 -41
  42. data/app/views/ruby_llm/agents/shared/_status_badge.html.erb +11 -65
  43. data/app/views/ruby_llm/agents/shared/_tenant_filter.html.erb +6 -5
  44. data/app/views/ruby_llm/agents/system_config/show.html.erb +240 -351
  45. data/app/views/ruby_llm/agents/tenants/_form.html.erb +67 -77
  46. data/app/views/ruby_llm/agents/tenants/edit.html.erb +7 -9
  47. data/app/views/ruby_llm/agents/tenants/index.html.erb +100 -122
  48. data/app/views/ruby_llm/agents/tenants/show.html.erb +146 -336
  49. data/config/routes.rb +0 -13
  50. data/lib/generators/ruby_llm_agents/install_generator.rb +13 -17
  51. data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +2 -12
  52. data/lib/generators/ruby_llm_agents/restructure_generator.rb +0 -2
  53. data/lib/generators/ruby_llm_agents/templates/add_usage_counters_to_tenants_migration.rb.tt +37 -0
  54. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +1 -2
  55. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +1 -1
  56. data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +0 -1
  57. data/lib/generators/ruby_llm_agents/templates/create_execution_details_migration.rb.tt +27 -0
  58. data/lib/generators/ruby_llm_agents/templates/create_tenants_migration.rb.tt +25 -0
  59. data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +0 -1
  60. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +33 -12
  61. data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +40 -71
  62. data/lib/generators/ruby_llm_agents/templates/remove_agent_version_migration.rb.tt +13 -0
  63. data/lib/generators/ruby_llm_agents/templates/remove_workflow_columns_migration.rb.tt +19 -0
  64. data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +2 -4
  65. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +0 -1
  66. data/lib/generators/ruby_llm_agents/templates/split_execution_details_migration.rb.tt +232 -0
  67. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +77 -259
  68. data/lib/ruby_llm/agents/audio/speaker.rb +0 -1
  69. data/lib/ruby_llm/agents/audio/transcriber.rb +0 -1
  70. data/lib/ruby_llm/agents/base_agent.rb +54 -23
  71. data/lib/ruby_llm/agents/core/base/callbacks.rb +142 -0
  72. data/lib/ruby_llm/agents/core/base.rb +23 -55
  73. data/lib/ruby_llm/agents/core/configuration.rb +97 -117
  74. data/lib/ruby_llm/agents/core/errors.rb +0 -58
  75. data/lib/ruby_llm/agents/core/instrumentation.rb +157 -110
  76. data/lib/ruby_llm/agents/core/llm_tenant.rb +8 -7
  77. data/lib/ruby_llm/agents/core/version.rb +1 -1
  78. data/lib/ruby_llm/agents/dsl/base.rb +157 -17
  79. data/lib/ruby_llm/agents/dsl/caching.rb +33 -2
  80. data/lib/ruby_llm/agents/dsl/reliability.rb +148 -0
  81. data/lib/ruby_llm/agents/dsl.rb +1 -2
  82. data/lib/ruby_llm/agents/image/analyzer/execution.rb +1 -2
  83. data/lib/ruby_llm/agents/image/background_remover/execution.rb +1 -2
  84. data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +1 -13
  85. data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +2 -2
  86. data/lib/ruby_llm/agents/image/editor/dsl.rb +0 -14
  87. data/lib/ruby_llm/agents/image/editor/execution.rb +1 -10
  88. data/lib/ruby_llm/agents/image/editor.rb +0 -1
  89. data/lib/ruby_llm/agents/image/generator.rb +0 -21
  90. data/lib/ruby_llm/agents/image/pipeline/dsl.rb +0 -13
  91. data/lib/ruby_llm/agents/image/pipeline/execution.rb +0 -1
  92. data/lib/ruby_llm/agents/image/transformer/dsl.rb +0 -13
  93. data/lib/ruby_llm/agents/image/transformer/execution.rb +1 -10
  94. data/lib/ruby_llm/agents/image/transformer.rb +0 -1
  95. data/lib/ruby_llm/agents/image/upscaler/execution.rb +1 -2
  96. data/lib/ruby_llm/agents/image/variator/execution.rb +1 -2
  97. data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +78 -173
  98. data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +66 -2
  99. data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +0 -12
  100. data/lib/ruby_llm/agents/infrastructure/circuit_breaker.rb +10 -13
  101. data/lib/ruby_llm/agents/infrastructure/execution_logger_job.rb +8 -0
  102. data/lib/ruby_llm/agents/pipeline/context.rb +0 -1
  103. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +28 -4
  104. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +3 -10
  105. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +88 -55
  106. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +5 -41
  107. data/lib/ruby_llm/agents/rails/engine.rb +6 -6
  108. data/lib/ruby_llm/agents/results/base.rb +1 -49
  109. data/lib/ruby_llm/agents/text/embedder.rb +0 -1
  110. data/lib/ruby_llm/agents.rb +1 -9
  111. data/lib/tasks/ruby_llm_agents.rake +34 -0
  112. metadata +14 -83
  113. data/app/controllers/ruby_llm/agents/api_configurations_controller.rb +0 -214
  114. data/app/controllers/ruby_llm/agents/workflows_controller.rb +0 -544
  115. data/app/mailers/ruby_llm/agents/alert_mailer.rb +0 -84
  116. data/app/mailers/ruby_llm/agents/application_mailer.rb +0 -28
  117. data/app/models/ruby_llm/agents/api_configuration.rb +0 -386
  118. data/app/models/ruby_llm/agents/execution/workflow.rb +0 -170
  119. data/app/models/ruby_llm/agents/tenant/configurable.rb +0 -135
  120. data/app/views/ruby_llm/agents/agents/_agent.html.erb +0 -98
  121. data/app/views/ruby_llm/agents/agents/_version_comparison.html.erb +0 -186
  122. data/app/views/ruby_llm/agents/agents/_workflow.html.erb +0 -126
  123. data/app/views/ruby_llm/agents/alert_mailer/alert_notification.html.erb +0 -107
  124. data/app/views/ruby_llm/agents/alert_mailer/alert_notification.text.erb +0 -18
  125. data/app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb +0 -34
  126. data/app/views/ruby_llm/agents/api_configurations/_form.html.erb +0 -288
  127. data/app/views/ruby_llm/agents/api_configurations/edit.html.erb +0 -95
  128. data/app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb +0 -97
  129. data/app/views/ruby_llm/agents/api_configurations/show.html.erb +0 -214
  130. data/app/views/ruby_llm/agents/api_configurations/tenant.html.erb +0 -179
  131. data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +0 -73
  132. data/app/views/ruby_llm/agents/dashboard/_alerts_feed.html.erb +0 -62
  133. data/app/views/ruby_llm/agents/dashboard/_breaker_strip.html.erb +0 -47
  134. data/app/views/ruby_llm/agents/dashboard/_budgets_bar.html.erb +0 -75
  135. data/app/views/ruby_llm/agents/dashboard/_model_comparison.html.erb +0 -56
  136. data/app/views/ruby_llm/agents/dashboard/_model_cost_breakdown.html.erb +0 -115
  137. data/app/views/ruby_llm/agents/dashboard/_now_strip.html.erb +0 -59
  138. data/app/views/ruby_llm/agents/dashboard/_top_errors.html.erb +0 -60
  139. data/app/views/ruby_llm/agents/executions/_workflow_summary.html.erb +0 -86
  140. data/app/views/ruby_llm/agents/executions/dry_run.html.erb +0 -149
  141. data/app/views/ruby_llm/agents/shared/_breadcrumbs.html.erb +0 -48
  142. data/app/views/ruby_llm/agents/shared/_nav_link.html.erb +0 -27
  143. data/app/views/ruby_llm/agents/shared/_stat_card.html.erb +0 -14
  144. data/app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb +0 -35
  145. data/app/views/ruby_llm/agents/workflows/_empty_state.html.erb +0 -22
  146. data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +0 -228
  147. data/app/views/ruby_llm/agents/workflows/_structure_dsl.html.erb +0 -539
  148. data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +0 -76
  149. data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +0 -74
  150. data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +0 -108
  151. data/app/views/ruby_llm/agents/workflows/_workflow_diagram.html.erb +0 -920
  152. data/app/views/ruby_llm/agents/workflows/index.html.erb +0 -179
  153. data/app/views/ruby_llm/agents/workflows/show.html.erb +0 -467
  154. data/lib/generators/ruby_llm_agents/api_configuration_generator.rb +0 -100
  155. data/lib/generators/ruby_llm_agents/templates/add_workflow_migration.rb.tt +0 -38
  156. data/lib/generators/ruby_llm_agents/templates/application_workflow.rb.tt +0 -48
  157. data/lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt +0 -90
  158. data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +0 -551
  159. data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +0 -181
  160. data/lib/ruby_llm/agents/core/base/moderation_execution.rb +0 -274
  161. data/lib/ruby_llm/agents/core/resolved_config.rb +0 -348
  162. data/lib/ruby_llm/agents/image/generator/content_policy.rb +0 -95
  163. data/lib/ruby_llm/agents/infrastructure/redactor.rb +0 -130
  164. data/lib/ruby_llm/agents/results/moderation_result.rb +0 -158
  165. data/lib/ruby_llm/agents/text/moderator.rb +0 -237
  166. data/lib/ruby_llm/agents/workflow/approval.rb +0 -205
  167. data/lib/ruby_llm/agents/workflow/approval_store.rb +0 -179
  168. data/lib/ruby_llm/agents/workflow/async.rb +0 -220
  169. data/lib/ruby_llm/agents/workflow/async_executor.rb +0 -156
  170. data/lib/ruby_llm/agents/workflow/dsl/executor.rb +0 -467
  171. data/lib/ruby_llm/agents/workflow/dsl/input_schema.rb +0 -244
  172. data/lib/ruby_llm/agents/workflow/dsl/iteration_executor.rb +0 -289
  173. data/lib/ruby_llm/agents/workflow/dsl/parallel_group.rb +0 -107
  174. data/lib/ruby_llm/agents/workflow/dsl/route_builder.rb +0 -150
  175. data/lib/ruby_llm/agents/workflow/dsl/schedule_helpers.rb +0 -187
  176. data/lib/ruby_llm/agents/workflow/dsl/step_config.rb +0 -352
  177. data/lib/ruby_llm/agents/workflow/dsl/step_executor.rb +0 -415
  178. data/lib/ruby_llm/agents/workflow/dsl/wait_config.rb +0 -257
  179. data/lib/ruby_llm/agents/workflow/dsl/wait_executor.rb +0 -317
  180. data/lib/ruby_llm/agents/workflow/dsl.rb +0 -576
  181. data/lib/ruby_llm/agents/workflow/instrumentation.rb +0 -249
  182. data/lib/ruby_llm/agents/workflow/notifiers/base.rb +0 -117
  183. data/lib/ruby_llm/agents/workflow/notifiers/email.rb +0 -117
  184. data/lib/ruby_llm/agents/workflow/notifiers/slack.rb +0 -180
  185. data/lib/ruby_llm/agents/workflow/notifiers/webhook.rb +0 -121
  186. data/lib/ruby_llm/agents/workflow/notifiers.rb +0 -70
  187. data/lib/ruby_llm/agents/workflow/orchestrator.rb +0 -416
  188. data/lib/ruby_llm/agents/workflow/result.rb +0 -592
  189. data/lib/ruby_llm/agents/workflow/thread_pool.rb +0 -185
  190. data/lib/ruby_llm/agents/workflow/throttle_manager.rb +0 -206
  191. data/lib/ruby_llm/agents/workflow/wait_result.rb +0 -213
@@ -1,372 +1,261 @@
1
- <div class="space-y-6">
2
- <!-- Header -->
3
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
4
- <div class="flex items-center space-x-3">
5
- <svg class="w-8 h-8 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
6
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
7
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
8
- </svg>
9
- <div>
10
- <div class="flex items-center gap-2">
11
- <h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">System Configuration</h1>
12
- <%= render "ruby_llm/agents/shared/doc_link" %>
13
- </div>
14
- <p class="text-sm text-gray-500 dark:text-gray-400">Settings configured in <code class="bg-gray-100 dark:bg-gray-700 px-1 rounded">config/initializers/ruby_llm_agents.rb</code></p>
15
- </div>
16
- </div>
17
- </div>
18
-
19
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
20
- <!-- Model Defaults -->
21
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
22
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Model Defaults</h3>
23
- <div class="space-y-4">
24
- <div class="flex justify-between items-center">
25
- <div>
26
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Model</p>
27
- <p class="text-xs text-gray-500 dark:text-gray-400">Used when agents don't specify a model</p>
28
- </div>
29
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.default_model %></code>
30
- </div>
31
- <div class="flex justify-between items-center">
32
- <div>
33
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Temperature</p>
34
- <p class="text-xs text-gray-500 dark:text-gray-400">0.0 = deterministic, 2.0 = creative</p>
35
- </div>
36
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.default_temperature %></code>
37
- </div>
38
- <div class="flex justify-between items-center">
39
- <div>
40
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Timeout</p>
41
- <p class="text-xs text-gray-500 dark:text-gray-400">Per-request timeout in seconds</p>
42
- </div>
43
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.default_timeout %>s</code>
44
- </div>
45
- </div>
46
- </div>
1
+ <%
2
+ retries = @config.default_retries || {}
3
+ has_retries = (retries[:max] || 0) > 0
4
+ has_fallbacks = @config.default_fallback_models.present? && @config.default_fallback_models.any?
5
+ has_total_timeout = @config.default_total_timeout.present?
6
+ budgets = @config.budgets || {}
7
+ budgets_enabled = @config.budgets_enabled?
8
+ alerts_enabled = @config.on_alert.respond_to?(:call)
9
+ redaction = @config.redaction || {}
10
+ redaction_enabled = redaction.present?
11
+ %>
47
12
 
48
- <!-- Execution Logging -->
49
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
50
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Execution Logging</h3>
51
- <div class="space-y-4">
52
- <div class="flex justify-between items-center">
53
- <div>
54
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Async Logging</p>
55
- <p class="text-xs text-gray-500 dark:text-gray-400">Log executions via background job</p>
56
- </div>
57
- <%= render_enabled_badge(@config.async_logging) %>
58
- </div>
59
- <div class="flex justify-between items-center">
60
- <div>
61
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Retention Period</p>
62
- <p class="text-xs text-gray-500 dark:text-gray-400">How long to keep execution records</p>
63
- </div>
64
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.retention_period.inspect %></code>
65
- </div>
66
- <div class="flex justify-between items-center">
67
- <div>
68
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Job Retry Attempts</p>
69
- <p class="text-xs text-gray-500 dark:text-gray-400">Retries for async logging job</p>
70
- </div>
71
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.job_retry_attempts %></code>
72
- </div>
73
- </div>
74
- </div>
13
+ <!-- ── system config ──────────────── -->
14
+ <div class="flex items-center gap-3 mb-1.5">
15
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">system configuration</span>
16
+ <div class="font-mono text-xs text-gray-400 dark:text-gray-500 flex items-center gap-1.5">
17
+ <%= render "ruby_llm/agents/shared/doc_link" %>
18
+ </div>
19
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
20
+ </div>
21
+ <div class="font-mono text-xs text-gray-400 dark:text-gray-600 mb-6">
22
+ configured in <span class="text-gray-500 dark:text-gray-400">config/initializers/ruby_llm_agents.rb</span>
23
+ </div>
75
24
 
76
- <!-- Caching -->
77
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
78
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Caching</h3>
79
- <div class="space-y-4">
80
- <div class="flex justify-between items-center">
81
- <div>
82
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Cache Store</p>
83
- <p class="text-xs text-gray-500 dark:text-gray-400">Used for response caching</p>
84
- </div>
85
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.cache_store.class.name %></code>
86
- </div>
87
- </div>
88
- </div>
25
+ <!-- ── model defaults ──────────────── -->
26
+ <div class="flex items-center gap-3 mt-6 mb-3">
27
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">model defaults</span>
28
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
29
+ </div>
30
+ <div class="font-mono text-xs space-y-1.5">
31
+ <div class="flex items-center gap-3 py-0.5">
32
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">default model</span>
33
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.default_model %></span>
34
+ </div>
35
+ <div class="flex items-center gap-3 py-0.5">
36
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">temperature</span>
37
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.default_temperature %></span>
38
+ </div>
39
+ <div class="flex items-center gap-3 py-0.5">
40
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">timeout</span>
41
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.default_timeout %>s</span>
42
+ </div>
43
+ </div>
89
44
 
90
- <!-- Anomaly Detection -->
91
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
92
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Anomaly Detection</h3>
93
- <div class="space-y-4">
94
- <div class="flex justify-between items-center">
95
- <div>
96
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Cost Threshold</p>
97
- <p class="text-xs text-gray-500 dark:text-gray-400">Executions above this trigger warnings</p>
98
- </div>
99
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm">$<%= @config.anomaly_cost_threshold %></code>
100
- </div>
101
- <div class="flex justify-between items-center">
102
- <div>
103
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Duration Threshold</p>
104
- <p class="text-xs text-gray-500 dark:text-gray-400">Executions above this trigger warnings</p>
105
- </div>
106
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= number_with_delimiter(@config.anomaly_duration_threshold) %>ms</code>
107
- </div>
108
- </div>
109
- </div>
45
+ <!-- ── execution logging ──────────────── -->
46
+ <div class="flex items-center gap-3 mt-6 mb-3">
47
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">execution logging</span>
48
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
49
+ </div>
50
+ <div class="font-mono text-xs space-y-1.5">
51
+ <div class="flex items-center gap-3 py-0.5">
52
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">async logging</span>
53
+ <span class="badge badge-sm <%= @config.async_logging ? 'badge-success' : 'badge-timeout' %>"><%= @config.async_logging ? 'on' : 'off' %></span>
54
+ </div>
55
+ <div class="flex items-center gap-3 py-0.5">
56
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">retention</span>
57
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.retention_period.inspect %></span>
58
+ </div>
59
+ <div class="flex items-center gap-3 py-0.5">
60
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">job retries</span>
61
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.job_retry_attempts %></span>
62
+ </div>
63
+ </div>
110
64
 
111
- <!-- Dashboard Settings -->
112
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
113
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Dashboard Settings</h3>
114
- <div class="space-y-4">
115
- <div class="flex justify-between items-center">
116
- <div>
117
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Records Per Page</p>
118
- <p class="text-xs text-gray-500 dark:text-gray-400">Pagination limit for listings</p>
119
- </div>
120
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.per_page %></code>
121
- </div>
122
- <div class="flex justify-between items-center">
123
- <div>
124
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Recent Executions Limit</p>
125
- <p class="text-xs text-gray-500 dark:text-gray-400">Shown on dashboard home</p>
126
- </div>
127
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.recent_executions_limit %></code>
128
- </div>
129
- <div class="flex justify-between items-center">
130
- <div>
131
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Parent Controller</p>
132
- <p class="text-xs text-gray-500 dark:text-gray-400">Dashboard inherits from this</p>
133
- </div>
134
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-xs"><%= @config.dashboard_parent_controller %></code>
135
- </div>
136
- <div class="flex justify-between items-center">
137
- <div>
138
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">HTTP Basic Auth</p>
139
- <p class="text-xs text-gray-500 dark:text-gray-400">Username/password protection</p>
140
- </div>
141
- <%= render_configured_badge(@config.basic_auth_username.present? && @config.basic_auth_password.present?) %>
142
- </div>
143
- <div class="flex justify-between items-center">
144
- <div>
145
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Custom Auth</p>
146
- <p class="text-xs text-gray-500 dark:text-gray-400">Lambda-based authentication</p>
147
- </div>
148
- <%= render_configured_badge(@config.dashboard_auth.present?) %>
149
- </div>
150
- </div>
151
- </div>
65
+ <!-- ── caching ──────────────── -->
66
+ <div class="flex items-center gap-3 mt-6 mb-3">
67
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">caching</span>
68
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
69
+ </div>
70
+ <div class="font-mono text-xs space-y-1.5">
71
+ <div class="flex items-center gap-3 py-0.5">
72
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">cache store</span>
73
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.cache_store.class.name %></span>
74
+ </div>
75
+ </div>
152
76
 
153
- <!-- Reliability Defaults -->
154
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
155
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Reliability Defaults</h3>
156
- <% retries = @config.default_retries || {} %>
157
- <% has_retries = (retries[:max] || 0) > 0 %>
158
- <% has_fallbacks = @config.default_fallback_models.present? && @config.default_fallback_models.any? %>
159
- <% has_total_timeout = @config.default_total_timeout.present? %>
77
+ <!-- ── anomaly detection ──────────────── -->
78
+ <div class="flex items-center gap-3 mt-6 mb-3">
79
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">anomaly detection</span>
80
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
81
+ </div>
82
+ <div class="font-mono text-xs space-y-1.5">
83
+ <div class="flex items-center gap-3 py-0.5">
84
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">cost threshold</span>
85
+ <span class="text-gray-900 dark:text-gray-200">$<%= @config.anomaly_cost_threshold %></span>
86
+ </div>
87
+ <div class="flex items-center gap-3 py-0.5">
88
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">duration threshold</span>
89
+ <span class="text-gray-900 dark:text-gray-200"><%= number_with_delimiter(@config.anomaly_duration_threshold) %>ms</span>
90
+ </div>
91
+ </div>
160
92
 
161
- <div class="space-y-4">
162
- <div>
163
- <div class="flex justify-between items-center">
164
- <div>
165
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Retries</p>
166
- <p class="text-xs text-gray-500 dark:text-gray-400">Applied to agents without retry config</p>
167
- </div>
168
- <%= render_enabled_badge(has_retries) %>
169
- </div>
170
- <% if has_retries %>
171
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-2 ml-4">
172
- Max: <%= retries[:max] %> &middot;
173
- Backoff: <%= retries[:backoff] %> &middot;
174
- Base: <%= retries[:base] %>s &middot;
175
- Max delay: <%= retries[:max_delay] %>s
176
- </p>
177
- <% end %>
178
- </div>
93
+ <!-- ── dashboard settings ──────────────── -->
94
+ <div class="flex items-center gap-3 mt-6 mb-3">
95
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">dashboard</span>
96
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
97
+ </div>
98
+ <div class="font-mono text-xs space-y-1.5">
99
+ <div class="flex items-center gap-3 py-0.5">
100
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">per page</span>
101
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.per_page %></span>
102
+ </div>
103
+ <div class="flex items-center gap-3 py-0.5">
104
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">recent limit</span>
105
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.recent_executions_limit %></span>
106
+ </div>
107
+ <div class="flex items-center gap-3 py-0.5">
108
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">parent controller</span>
109
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.dashboard_parent_controller %></span>
110
+ </div>
111
+ <div class="flex items-center gap-3 py-0.5">
112
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">basic auth</span>
113
+ <% if @config.basic_auth_username.present? && @config.basic_auth_password.present? %>
114
+ <span class="badge badge-sm badge-success">configured</span>
115
+ <% else %>
116
+ <span class="text-gray-300 dark:text-gray-700">—</span>
117
+ <% end %>
118
+ </div>
119
+ <div class="flex items-center gap-3 py-0.5">
120
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">custom auth</span>
121
+ <% if @config.dashboard_auth.present? %>
122
+ <span class="badge badge-sm badge-success">configured</span>
123
+ <% else %>
124
+ <span class="text-gray-300 dark:text-gray-700">—</span>
125
+ <% end %>
126
+ </div>
127
+ </div>
179
128
 
180
- <div>
181
- <div class="flex justify-between items-center">
182
- <div>
183
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Fallback Models</p>
184
- <p class="text-xs text-gray-500 dark:text-gray-400">Tried when primary model fails</p>
185
- </div>
186
- <%= render_enabled_badge(has_fallbacks) %>
187
- </div>
188
- <% if has_fallbacks %>
189
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-2 ml-4">
190
- <%= @config.default_fallback_models.join(" ") %>
191
- </p>
192
- <% end %>
193
- </div>
129
+ <!-- ── reliability ──────────────── -->
130
+ <div class="flex items-center gap-3 mt-6 mb-3">
131
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">reliability defaults</span>
132
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
133
+ </div>
134
+ <div class="font-mono text-xs space-y-1.5">
135
+ <div class="flex items-center gap-3 py-0.5">
136
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">retries</span>
137
+ <% if has_retries %>
138
+ <span class="text-gray-900 dark:text-gray-200"><%= retries[:max] %> max</span>
139
+ <span class="text-gray-300 dark:text-gray-700">&middot;</span>
140
+ <span class="text-gray-400 dark:text-gray-600"><%= retries[:backoff] %> backoff</span>
141
+ <span class="text-gray-300 dark:text-gray-700">&middot;</span>
142
+ <span class="text-gray-400 dark:text-gray-600"><%= retries[:base] %>s base</span>
143
+ <span class="text-gray-300 dark:text-gray-700">&middot;</span>
144
+ <span class="text-gray-400 dark:text-gray-600"><%= retries[:max_delay] %>s max</span>
145
+ <% else %>
146
+ <span class="text-gray-300 dark:text-gray-700">—</span>
147
+ <% end %>
148
+ </div>
149
+ <div class="flex items-center gap-3 py-0.5">
150
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">fallback models</span>
151
+ <% if has_fallbacks %>
152
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.default_fallback_models.join(" → ") %></span>
153
+ <% else %>
154
+ <span class="text-gray-300 dark:text-gray-700">—</span>
155
+ <% end %>
156
+ </div>
157
+ <div class="flex items-center gap-3 py-0.5">
158
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">total timeout</span>
159
+ <% if has_total_timeout %>
160
+ <span class="text-gray-900 dark:text-gray-200"><%= @config.default_total_timeout %>s</span>
161
+ <% else %>
162
+ <span class="text-gray-300 dark:text-gray-700">—</span>
163
+ <% end %>
164
+ </div>
165
+ </div>
194
166
 
195
- <div class="flex justify-between items-center">
196
- <div>
197
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Default Total Timeout</p>
198
- <p class="text-xs text-gray-500 dark:text-gray-400">Across all retry/fallback attempts</p>
199
- </div>
200
- <% if has_total_timeout %>
201
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm"><%= @config.default_total_timeout %>s</code>
202
- <% else %>
203
- <span class="text-xs text-gray-400 dark:text-gray-500">Not configured</span>
204
- <% end %>
205
- </div>
167
+ <!-- ── governance ──────────────── -->
168
+ <div class="flex items-center gap-3 mt-6 mb-3">
169
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">governance</span>
170
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
171
+ </div>
172
+ <div class="font-mono text-xs space-y-1.5">
173
+ <div class="flex items-center gap-3 py-0.5">
174
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">budget enforcement</span>
175
+ <% if budgets_enabled %>
176
+ <%
177
+ enforcement_badge = @config.budget_enforcement == :hard ? "badge-error" : "badge-timeout"
178
+ %>
179
+ <span class="badge badge-sm <%= enforcement_badge %>"><%= @config.budget_enforcement %></span>
180
+ <% else %>
181
+ <span class="text-gray-300 dark:text-gray-700">—</span>
182
+ <% end %>
183
+ </div>
184
+ <% if budgets_enabled %>
185
+ <% if budgets[:global_daily] %>
186
+ <div class="flex items-center gap-3 py-0.5 pl-4">
187
+ <span class="w-32 flex-shrink-0 text-gray-400 dark:text-gray-600">global daily</span>
188
+ <span class="text-gray-900 dark:text-gray-200">$<%= budgets[:global_daily] %></span>
206
189
  </div>
207
- </div>
208
-
209
- <!-- Governance - Budgets -->
210
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
211
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Governance - Budgets</h3>
212
- <% budgets = @config.budgets || {} %>
213
- <% budgets_enabled = @config.budgets_enabled? %>
214
-
215
- <div class="space-y-4">
216
- <div class="flex justify-between items-center">
217
- <div>
218
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Budget Enforcement</p>
219
- <p class="text-xs text-gray-500 dark:text-gray-400">Cost limits for agents</p>
190
+ <% end %>
191
+ <% if budgets[:global_monthly] %>
192
+ <div class="flex items-center gap-3 py-0.5 pl-4">
193
+ <span class="w-32 flex-shrink-0 text-gray-400 dark:text-gray-600">global monthly</span>
194
+ <span class="text-gray-900 dark:text-gray-200">$<%= budgets[:global_monthly] %></span>
195
+ </div>
196
+ <% end %>
197
+ <% if budgets[:per_agent_daily].present? %>
198
+ <div class="py-0.5 pl-4">
199
+ <span class="text-gray-400 dark:text-gray-600">per-agent daily:</span>
200
+ <% budgets[:per_agent_daily].each do |agent, limit| %>
201
+ <div class="flex items-center gap-2 pl-2 py-0.5">
202
+ <span class="text-gray-900 dark:text-gray-200"><%= agent %></span>
203
+ <span class="text-gray-400 dark:text-gray-600">$<%= limit %></span>
220
204
  </div>
221
- <% if budgets_enabled %>
222
- <span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium <%= @config.budget_enforcement == :hard ? 'bg-red-100 dark:bg-red-900/50 text-red-700 dark:text-red-300' : 'bg-yellow-100 dark:bg-yellow-900/50 text-yellow-700 dark:text-yellow-300' %>">
223
- <%= @config.budget_enforcement.to_s.titleize %>
224
- </span>
225
- <% else %>
226
- <span class="text-xs text-gray-400 dark:text-gray-500">Disabled</span>
227
- <% end %>
228
- </div>
229
-
230
- <% if budgets_enabled %>
231
- <% if budgets[:global_daily] %>
232
- <div class="flex justify-between items-center ml-4">
233
- <p class="text-sm text-gray-600 dark:text-gray-400">Global Daily Limit</p>
234
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm">$<%= budgets[:global_daily] %></code>
235
- </div>
236
- <% end %>
237
- <% if budgets[:global_monthly] %>
238
- <div class="flex justify-between items-center ml-4">
239
- <p class="text-sm text-gray-600 dark:text-gray-400">Global Monthly Limit</p>
240
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-2 py-1 rounded text-sm">$<%= budgets[:global_monthly] %></code>
241
- </div>
242
- <% end %>
243
- <% if budgets[:per_agent_daily].present? %>
244
- <div class="ml-4">
245
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-1">Per-Agent Daily Limits</p>
246
- <% budgets[:per_agent_daily].each do |agent, limit| %>
247
- <div class="flex justify-between items-center ml-4 text-xs">
248
- <span class="text-gray-500 dark:text-gray-400"><%= agent %></span>
249
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-1 rounded">$<%= limit %></code>
250
- </div>
251
- <% end %>
252
- </div>
253
- <% end %>
254
- <% if budgets[:per_agent_monthly].present? %>
255
- <div class="ml-4">
256
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-1">Per-Agent Monthly Limits</p>
257
- <% budgets[:per_agent_monthly].each do |agent, limit| %>
258
- <div class="flex justify-between items-center ml-4 text-xs">
259
- <span class="text-gray-500 dark:text-gray-400"><%= agent %></span>
260
- <code class="bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 px-1 rounded">$<%= limit %></code>
261
- </div>
262
- <% end %>
263
- </div>
264
- <% end %>
265
205
  <% end %>
266
206
  </div>
267
- </div>
268
-
269
- <!-- Governance - Alerts -->
270
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
271
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Governance - Alerts</h3>
272
- <% alerts = @config.alerts || {} %>
273
- <% alerts_enabled = @config.alerts_enabled? %>
274
-
275
- <div class="space-y-4">
276
- <div class="flex justify-between items-center">
277
- <div>
278
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Alerts</p>
279
- <p class="text-xs text-gray-500 dark:text-gray-400">Notifications for important events</p>
207
+ <% end %>
208
+ <% if budgets[:per_agent_monthly].present? %>
209
+ <div class="py-0.5 pl-4">
210
+ <span class="text-gray-400 dark:text-gray-600">per-agent monthly:</span>
211
+ <% budgets[:per_agent_monthly].each do |agent, limit| %>
212
+ <div class="flex items-center gap-2 pl-2 py-0.5">
213
+ <span class="text-gray-900 dark:text-gray-200"><%= agent %></span>
214
+ <span class="text-gray-400 dark:text-gray-600">$<%= limit %></span>
280
215
  </div>
281
- <%= render_enabled_badge(alerts_enabled) %>
282
- </div>
283
-
284
- <% if alerts_enabled %>
285
- <div class="flex justify-between items-center ml-4">
286
- <p class="text-sm text-gray-600 dark:text-gray-400">Slack Webhook</p>
287
- <%= render_configured_badge(alerts[:slack_webhook_url].present?) %>
288
- </div>
289
- <div class="flex justify-between items-center ml-4">
290
- <p class="text-sm text-gray-600 dark:text-gray-400">Generic Webhook</p>
291
- <%= render_configured_badge(alerts[:webhook_url].present?) %>
292
- </div>
293
- <div class="flex justify-between items-center ml-4">
294
- <p class="text-sm text-gray-600 dark:text-gray-400">Custom Handler</p>
295
- <%= render_configured_badge(alerts[:custom].present?) %>
296
- </div>
297
- <% if @config.alert_events.any? %>
298
- <div class="ml-4">
299
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-2">Events</p>
300
- <div class="flex flex-wrap gap-1">
301
- <% @config.alert_events.each do |event| %>
302
- <span class="inline-flex items-center px-2 py-0.5 rounded text-xs bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300">
303
- <%= event %>
304
- </span>
305
- <% end %>
306
- </div>
307
- </div>
308
- <% end %>
309
216
  <% end %>
310
217
  </div>
311
- </div>
312
-
313
- <!-- Data Handling -->
314
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
315
- <h3 class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">Data Handling</h3>
316
- <div class="space-y-4">
317
- <div class="flex justify-between items-center">
318
- <div>
319
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Persist Prompts</p>
320
- <p class="text-xs text-gray-500 dark:text-gray-400">Store system/user prompts in executions</p>
321
- </div>
322
- <%= render_enabled_badge(@config.persist_prompts) %>
323
- </div>
324
- <div class="flex justify-between items-center">
325
- <div>
326
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">Persist Responses</p>
327
- <p class="text-xs text-gray-500 dark:text-gray-400">Store LLM responses in executions</p>
328
- </div>
329
- <%= render_enabled_badge(@config.persist_responses) %>
330
- </div>
218
+ <% end %>
219
+ <% end %>
331
220
 
332
- <% redaction = @config.redaction || {} %>
333
- <% redaction_enabled = redaction.present? %>
334
- <div>
335
- <div class="flex justify-between items-center">
336
- <div>
337
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">PII Redaction</p>
338
- <p class="text-xs text-gray-500 dark:text-gray-400">Sanitize sensitive data before storing</p>
339
- </div>
340
- <%= render_enabled_badge(redaction_enabled) %>
341
- </div>
342
- <% if redaction_enabled %>
343
- <div class="mt-2 ml-4 text-xs text-gray-600 dark:text-gray-400 space-y-1">
344
- <p>Fields: <%= @config.redaction_fields.count %> patterns</p>
345
- <p>Regex patterns: <%= @config.redaction_patterns.count %></p>
346
- <p>Placeholder: <code class="bg-gray-100 dark:bg-gray-700 px-1 rounded"><%= @config.redaction_placeholder %></code></p>
347
- <% if @config.redaction_max_value_length %>
348
- <p>Max value length: <%= number_with_delimiter(@config.redaction_max_value_length) %> chars</p>
349
- <% end %>
350
- </div>
351
- <% end %>
352
- </div>
353
- </div>
354
- </div>
221
+ <div class="flex items-center gap-3 py-0.5">
222
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">alert handler</span>
223
+ <% if alerts_enabled %>
224
+ <span class="badge badge-sm badge-success">configured</span>
225
+ <% else %>
226
+ <span class="text-gray-300 dark:text-gray-700">—</span>
227
+ <% end %>
355
228
  </div>
229
+ </div>
356
230
 
357
- <!-- Info Box -->
358
- <div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
359
- <div class="flex">
360
- <svg class="w-5 h-5 text-blue-400 mr-3 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
361
- <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
362
- </svg>
363
- <div>
364
- <p class="text-sm text-blue-700 dark:text-blue-300">
365
- These settings are configured in your Rails initializer and cannot be changed at runtime.
366
- To modify, edit <code class="bg-blue-100 dark:bg-blue-800 px-1 rounded">config/initializers/ruby_llm_agents.rb</code> and restart your application.
367
- </p>
368
- </div>
369
- </div>
231
+ <!-- ── data handling ──────────────── -->
232
+ <div class="flex items-center gap-3 mt-6 mb-3">
233
+ <span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">data handling</span>
234
+ <div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
235
+ </div>
236
+ <div class="font-mono text-xs space-y-1.5">
237
+ <div class="flex items-center gap-3 py-0.5">
238
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">persist prompts</span>
239
+ <span class="badge badge-sm <%= @config.persist_prompts ? 'badge-success' : 'badge-timeout' %>"><%= @config.persist_prompts ? 'on' : 'off' %></span>
240
+ </div>
241
+ <div class="flex items-center gap-3 py-0.5">
242
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">persist responses</span>
243
+ <span class="badge badge-sm <%= @config.persist_responses ? 'badge-success' : 'badge-timeout' %>"><%= @config.persist_responses ? 'on' : 'off' %></span>
244
+ </div>
245
+ <div class="flex items-center gap-3 py-0.5">
246
+ <span class="w-36 flex-shrink-0 text-gray-500 dark:text-gray-400">pii redaction</span>
247
+ <% if redaction_enabled %>
248
+ <span class="badge badge-sm badge-success">on</span>
249
+ <span class="text-gray-400 dark:text-gray-600"><%= @config.redaction_fields.count %> fields</span>
250
+ <span class="text-gray-300 dark:text-gray-700">&middot;</span>
251
+ <span class="text-gray-400 dark:text-gray-600"><%= @config.redaction_patterns.count %> patterns</span>
252
+ <% else %>
253
+ <span class="text-gray-300 dark:text-gray-700">—</span>
254
+ <% end %>
370
255
  </div>
371
256
  </div>
372
257
 
258
+ <!-- Footer note -->
259
+ <div class="mt-8 font-mono text-[10px] text-gray-400 dark:text-gray-600">
260
+ these settings are read-only — edit <span class="text-gray-500 dark:text-gray-400">config/initializers/ruby_llm_agents.rb</span> and restart to change
261
+ </div>