ruby_llm-agents 0.4.0 → 1.0.0.beta.1

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +225 -34
  3. data/app/controllers/ruby_llm/agents/agents_controller.rb +136 -16
  4. data/app/controllers/ruby_llm/agents/api_configurations_controller.rb +214 -0
  5. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +29 -9
  6. data/app/controllers/ruby_llm/agents/{settings_controller.rb → system_config_controller.rb} +3 -3
  7. data/app/controllers/ruby_llm/agents/tenants_controller.rb +109 -0
  8. data/app/controllers/ruby_llm/agents/workflows_controller.rb +355 -0
  9. data/app/helpers/ruby_llm/agents/application_helper.rb +25 -0
  10. data/app/models/ruby_llm/agents/api_configuration.rb +386 -0
  11. data/app/models/ruby_llm/agents/execution.rb +3 -0
  12. data/app/models/ruby_llm/agents/tenant_budget.rb +112 -14
  13. data/app/services/ruby_llm/agents/agent_registry.rb +51 -12
  14. data/app/views/layouts/ruby_llm/agents/application.html.erb +5 -30
  15. data/app/views/ruby_llm/agents/agents/_agent.html.erb +13 -1
  16. data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +235 -0
  17. data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +70 -0
  18. data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +152 -0
  19. data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +63 -0
  20. data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +108 -0
  21. data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +91 -0
  22. data/app/views/ruby_llm/agents/agents/_workflow.html.erb +1 -1
  23. data/app/views/ruby_llm/agents/agents/index.html.erb +74 -9
  24. data/app/views/ruby_llm/agents/agents/show.html.erb +18 -378
  25. data/app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb +34 -0
  26. data/app/views/ruby_llm/agents/api_configurations/_form.html.erb +288 -0
  27. data/app/views/ruby_llm/agents/api_configurations/edit.html.erb +95 -0
  28. data/app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb +97 -0
  29. data/app/views/ruby_llm/agents/api_configurations/show.html.erb +211 -0
  30. data/app/views/ruby_llm/agents/api_configurations/tenant.html.erb +179 -0
  31. data/app/views/ruby_llm/agents/dashboard/_action_center.html.erb +1 -1
  32. data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +269 -15
  33. data/app/views/ruby_llm/agents/executions/show.html.erb +98 -0
  34. data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +93 -0
  35. data/app/views/ruby_llm/agents/{settings → system_config}/show.html.erb +1 -1
  36. data/app/views/ruby_llm/agents/tenants/_form.html.erb +150 -0
  37. data/app/views/ruby_llm/agents/tenants/edit.html.erb +13 -0
  38. data/app/views/ruby_llm/agents/tenants/index.html.erb +129 -0
  39. data/app/views/ruby_llm/agents/tenants/show.html.erb +374 -0
  40. data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +236 -0
  41. data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +76 -0
  42. data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +74 -0
  43. data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +108 -0
  44. data/app/views/ruby_llm/agents/workflows/show.html.erb +442 -0
  45. data/config/routes.rb +13 -1
  46. data/lib/generators/ruby_llm_agents/agent_generator.rb +56 -7
  47. data/lib/generators/ruby_llm_agents/api_configuration_generator.rb +100 -0
  48. data/lib/generators/ruby_llm_agents/background_remover_generator.rb +110 -0
  49. data/lib/generators/ruby_llm_agents/embedder_generator.rb +107 -0
  50. data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +115 -0
  51. data/lib/generators/ruby_llm_agents/image_editor_generator.rb +108 -0
  52. data/lib/generators/ruby_llm_agents/image_generator_generator.rb +116 -0
  53. data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +178 -0
  54. data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +109 -0
  55. data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +103 -0
  56. data/lib/generators/ruby_llm_agents/image_variator_generator.rb +102 -0
  57. data/lib/generators/ruby_llm_agents/install_generator.rb +76 -4
  58. data/lib/generators/ruby_llm_agents/restructure_generator.rb +292 -0
  59. data/lib/generators/ruby_llm_agents/speaker_generator.rb +121 -0
  60. data/lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt +8 -0
  61. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +99 -84
  62. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +42 -40
  63. data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +26 -0
  64. data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +50 -0
  65. data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +26 -0
  66. data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +20 -0
  67. data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +38 -0
  68. data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +139 -0
  69. data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +21 -0
  70. data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +20 -0
  71. data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +20 -0
  72. data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +49 -0
  73. data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +53 -0
  74. data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +44 -0
  75. data/lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt +90 -0
  76. data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +41 -0
  77. data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +45 -0
  78. data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +35 -0
  79. data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +47 -0
  80. data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +50 -0
  81. data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +44 -0
  82. data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +38 -0
  83. data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +33 -0
  84. data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +228 -0
  85. data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +131 -0
  86. data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +255 -0
  87. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +120 -0
  88. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +102 -0
  89. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +282 -0
  90. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +228 -0
  91. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +120 -0
  92. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +110 -0
  93. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +120 -0
  94. data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +212 -0
  95. data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +227 -0
  96. data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +251 -0
  97. data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +300 -0
  98. data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +56 -0
  99. data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +51 -0
  100. data/lib/generators/ruby_llm_agents/transcriber_generator.rb +107 -0
  101. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +152 -1
  102. data/lib/ruby_llm/agents/audio/speaker.rb +553 -0
  103. data/lib/ruby_llm/agents/audio/transcriber.rb +669 -0
  104. data/lib/ruby_llm/agents/base_agent.rb +675 -0
  105. data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +181 -0
  106. data/lib/ruby_llm/agents/core/base/moderation_execution.rb +274 -0
  107. data/lib/ruby_llm/agents/core/base.rb +135 -0
  108. data/lib/ruby_llm/agents/core/configuration.rb +981 -0
  109. data/lib/ruby_llm/agents/core/errors.rb +150 -0
  110. data/lib/ruby_llm/agents/{instrumentation.rb → core/instrumentation.rb} +93 -4
  111. data/lib/ruby_llm/agents/core/llm_tenant.rb +358 -0
  112. data/lib/ruby_llm/agents/core/resolved_config.rb +348 -0
  113. data/lib/ruby_llm/agents/{version.rb → core/version.rb} +1 -1
  114. data/lib/ruby_llm/agents/dsl/base.rb +110 -0
  115. data/lib/ruby_llm/agents/dsl/caching.rb +142 -0
  116. data/lib/ruby_llm/agents/dsl/reliability.rb +307 -0
  117. data/lib/ruby_llm/agents/dsl.rb +41 -0
  118. data/lib/ruby_llm/agents/image/analyzer/dsl.rb +130 -0
  119. data/lib/ruby_llm/agents/image/analyzer/execution.rb +402 -0
  120. data/lib/ruby_llm/agents/image/analyzer.rb +90 -0
  121. data/lib/ruby_llm/agents/image/background_remover/dsl.rb +154 -0
  122. data/lib/ruby_llm/agents/image/background_remover/execution.rb +240 -0
  123. data/lib/ruby_llm/agents/image/background_remover.rb +89 -0
  124. data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +91 -0
  125. data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +165 -0
  126. data/lib/ruby_llm/agents/image/editor/dsl.rb +56 -0
  127. data/lib/ruby_llm/agents/image/editor/execution.rb +207 -0
  128. data/lib/ruby_llm/agents/image/editor.rb +92 -0
  129. data/lib/ruby_llm/agents/image/generator/active_storage_support.rb +127 -0
  130. data/lib/ruby_llm/agents/image/generator/content_policy.rb +95 -0
  131. data/lib/ruby_llm/agents/image/generator/pricing.rb +353 -0
  132. data/lib/ruby_llm/agents/image/generator/templates.rb +124 -0
  133. data/lib/ruby_llm/agents/image/generator.rb +455 -0
  134. data/lib/ruby_llm/agents/image/pipeline/dsl.rb +213 -0
  135. data/lib/ruby_llm/agents/image/pipeline/execution.rb +382 -0
  136. data/lib/ruby_llm/agents/image/pipeline.rb +97 -0
  137. data/lib/ruby_llm/agents/image/transformer/dsl.rb +148 -0
  138. data/lib/ruby_llm/agents/image/transformer/execution.rb +223 -0
  139. data/lib/ruby_llm/agents/image/transformer.rb +95 -0
  140. data/lib/ruby_llm/agents/image/upscaler/dsl.rb +83 -0
  141. data/lib/ruby_llm/agents/image/upscaler/execution.rb +219 -0
  142. data/lib/ruby_llm/agents/image/upscaler.rb +81 -0
  143. data/lib/ruby_llm/agents/image/variator/dsl.rb +62 -0
  144. data/lib/ruby_llm/agents/image/variator/execution.rb +189 -0
  145. data/lib/ruby_llm/agents/image/variator.rb +80 -0
  146. data/lib/ruby_llm/agents/{alert_manager.rb → infrastructure/alert_manager.rb} +17 -22
  147. data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +145 -0
  148. data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +149 -0
  149. data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +68 -0
  150. data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +279 -0
  151. data/lib/ruby_llm/agents/infrastructure/budget_tracker.rb +275 -0
  152. data/lib/ruby_llm/agents/{execution_logger_job.rb → infrastructure/execution_logger_job.rb} +17 -1
  153. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/executor.rb +2 -1
  154. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/retry_strategy.rb +9 -3
  155. data/lib/ruby_llm/agents/{reliability.rb → infrastructure/reliability.rb} +11 -21
  156. data/lib/ruby_llm/agents/pipeline/builder.rb +215 -0
  157. data/lib/ruby_llm/agents/pipeline/context.rb +255 -0
  158. data/lib/ruby_llm/agents/pipeline/executor.rb +86 -0
  159. data/lib/ruby_llm/agents/pipeline/middleware/base.rb +124 -0
  160. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +95 -0
  161. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +171 -0
  162. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +415 -0
  163. data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +276 -0
  164. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +196 -0
  165. data/lib/ruby_llm/agents/pipeline.rb +68 -0
  166. data/lib/ruby_llm/agents/{engine.rb → rails/engine.rb} +79 -10
  167. data/lib/ruby_llm/agents/results/background_removal_result.rb +286 -0
  168. data/lib/ruby_llm/agents/{result.rb → results/base.rb} +73 -1
  169. data/lib/ruby_llm/agents/results/embedding_result.rb +243 -0
  170. data/lib/ruby_llm/agents/results/image_analysis_result.rb +314 -0
  171. data/lib/ruby_llm/agents/results/image_edit_result.rb +250 -0
  172. data/lib/ruby_llm/agents/results/image_generation_result.rb +346 -0
  173. data/lib/ruby_llm/agents/results/image_pipeline_result.rb +399 -0
  174. data/lib/ruby_llm/agents/results/image_transform_result.rb +251 -0
  175. data/lib/ruby_llm/agents/results/image_upscale_result.rb +255 -0
  176. data/lib/ruby_llm/agents/results/image_variation_result.rb +237 -0
  177. data/lib/ruby_llm/agents/results/moderation_result.rb +158 -0
  178. data/lib/ruby_llm/agents/results/speech_result.rb +338 -0
  179. data/lib/ruby_llm/agents/results/transcription_result.rb +408 -0
  180. data/lib/ruby_llm/agents/text/embedder.rb +444 -0
  181. data/lib/ruby_llm/agents/text/moderator.rb +237 -0
  182. data/lib/ruby_llm/agents/workflow/async.rb +220 -0
  183. data/lib/ruby_llm/agents/workflow/async_executor.rb +156 -0
  184. data/lib/ruby_llm/agents/{workflow.rb → workflow/orchestrator.rb} +6 -5
  185. data/lib/ruby_llm/agents/workflow/parallel.rb +34 -17
  186. data/lib/ruby_llm/agents/workflow/thread_pool.rb +185 -0
  187. data/lib/ruby_llm/agents.rb +86 -20
  188. metadata +189 -35
  189. data/lib/ruby_llm/agents/base/caching.rb +0 -40
  190. data/lib/ruby_llm/agents/base/cost_calculation.rb +0 -105
  191. data/lib/ruby_llm/agents/base/dsl.rb +0 -324
  192. data/lib/ruby_llm/agents/base/execution.rb +0 -283
  193. data/lib/ruby_llm/agents/base/reliability_dsl.rb +0 -82
  194. data/lib/ruby_llm/agents/base/reliability_execution.rb +0 -136
  195. data/lib/ruby_llm/agents/base/response_building.rb +0 -86
  196. data/lib/ruby_llm/agents/base/tool_tracking.rb +0 -57
  197. data/lib/ruby_llm/agents/base.rb +0 -209
  198. data/lib/ruby_llm/agents/budget_tracker.rb +0 -471
  199. data/lib/ruby_llm/agents/configuration.rb +0 -357
  200. /data/lib/ruby_llm/agents/{deprecations.rb → core/deprecations.rb} +0 -0
  201. /data/lib/ruby_llm/agents/{inflections.rb → core/inflections.rb} +0 -0
  202. /data/lib/ruby_llm/agents/{attempt_tracker.rb → infrastructure/attempt_tracker.rb} +0 -0
  203. /data/lib/ruby_llm/agents/{cache_helper.rb → infrastructure/cache_helper.rb} +0 -0
  204. /data/lib/ruby_llm/agents/{circuit_breaker.rb → infrastructure/circuit_breaker.rb} +0 -0
  205. /data/lib/ruby_llm/agents/{redactor.rb → infrastructure/redactor.rb} +0 -0
  206. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/breaker_manager.rb +0 -0
  207. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/execution_constraints.rb +0 -0
  208. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/fallback_routing.rb +0 -0
@@ -1,6 +1,6 @@
1
1
  <%= render "ruby_llm/agents/shared/breadcrumbs", items: [
2
2
  { label: "Dashboard", path: ruby_llm_agents.root_path },
3
- { label: "Agents", path: ruby_llm_agents.agents_path },
3
+ { label: "Agents", path: ruby_llm_agents.agents_path(tab: params[:tab], subtab: params[:subtab]) },
4
4
  { label: @agent_type.gsub(/Agent$/, '') }
5
5
  ] %>
6
6
 
@@ -42,8 +42,19 @@
42
42
 
43
43
  <% if @config %>
44
44
  <p class="text-gray-500 dark:text-gray-400 mt-1">
45
- <%= @config[:model] %> &middot; temp <%= @config[:temperature] %>
46
- &middot; timeout <%= @config[:timeout] %>s
45
+ <%= @config[:model] %>
46
+ <% if @config[:temperature] %>
47
+ &middot; temp <%= @config[:temperature] %>
48
+ <% end %>
49
+ <% if @config[:timeout] %>
50
+ &middot; timeout <%= @config[:timeout] %>s
51
+ <% end %>
52
+ <% if @config[:dimensions] %>
53
+ &middot; <%= @config[:dimensions] %> dims
54
+ <% end %>
55
+ <% if @config[:voice] %>
56
+ &middot; voice: <%= @config[:voice] %>
57
+ <% end %>
47
58
  </p>
48
59
  <% if @config[:description].present? %>
49
60
  <p class="text-gray-600 dark:text-gray-300 mt-2">
@@ -80,8 +91,8 @@
80
91
  </div>
81
92
  </div>
82
93
 
83
- <!-- Circuit Breaker Status (if reliability enabled) -->
84
- <% if @config && @circuit_breaker_status.present? %>
94
+ <!-- Circuit Breaker Status (only for base agents with reliability enabled) -->
95
+ <% if @config && @agent_type_kind == "agent" && @circuit_breaker_status.present? %>
85
96
  <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4 mb-6">
86
97
  <div class="flex items-center justify-between mb-3">
87
98
  <h3
@@ -292,379 +303,8 @@
292
303
  <%= render partial: "ruby_llm/agents/agents/version_comparison",
293
304
  locals: { versions: @versions, version_comparison: @version_comparison } %>
294
305
 
295
- <% if @config %>
296
- <!-- Configuration -->
297
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-6">
298
- <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
299
- Configuration
300
- </h3>
301
-
302
- <!-- Basic Configuration -->
303
- <p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">
304
- Basic
305
- </p>
306
-
307
- <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
308
- <div>
309
- <p class="text-sm text-gray-500 dark:text-gray-400">Model</p>
310
-
311
- <p class="font-medium text-gray-900 dark:text-gray-100">
312
- <%= @config[:model] %>
313
- </p>
314
- </div>
315
-
316
- <div>
317
- <p class="text-sm text-gray-500 dark:text-gray-400">Temperature</p>
318
-
319
- <p class="font-medium text-gray-900 dark:text-gray-100">
320
- <%= @config[:temperature] %>
321
- </p>
322
- </div>
323
-
324
- <div>
325
- <p class="text-sm text-gray-500 dark:text-gray-400">Timeout</p>
326
-
327
- <p class="font-medium text-gray-900 dark:text-gray-100">
328
- <%= @config[:timeout] %> seconds
329
- </p>
330
- </div>
331
-
332
- <div>
333
- <p class="text-sm text-gray-500 dark:text-gray-400">Cache</p>
334
-
335
- <p class="font-medium text-gray-900 dark:text-gray-100">
336
- <% if @config[:cache_enabled] %>
337
- Enabled (
338
- <%= @config[:cache_ttl].inspect %>
339
- )
340
- <% else %>
341
- <span class="text-gray-400 dark:text-gray-500">Disabled</span>
342
- <% end %>
343
- </p>
344
- </div>
345
- </div>
346
-
347
- <!-- Reliability Configuration -->
348
- <% retries_config = @config[:retries] || {}
349
- fallback_models = Array(@config[:fallback_models]).compact
350
- has_retries = (retries_config[:max] || 0) > 0
351
- has_fallbacks = fallback_models.any?
352
- has_total_timeout = @config[:total_timeout].present?
353
- has_circuit_breaker = @config[:circuit_breaker].present?
354
- has_any_reliability = has_retries || has_fallbacks || has_total_timeout || has_circuit_breaker %>
355
-
356
- <div class="border-t border-gray-100 dark:border-gray-700 pt-4 mb-6">
357
- <p
358
- class="
359
- text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider
360
- mb-3
361
- "
362
- >
363
- Reliability
364
- </p>
365
-
366
- <% if has_any_reliability %>
367
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
368
- <!-- Retries -->
369
- <div class="flex items-start gap-3 p-3 rounded-lg <%= has_retries ? 'bg-green-50 dark:bg-green-900/20' : 'bg-gray-50 dark:bg-gray-700/50' %>">
370
- <div class="flex-shrink-0 mt-0.5">
371
- <% if has_retries %>
372
- <svg
373
- class="w-5 h-5 text-green-500"
374
- fill="currentColor"
375
- viewBox="0 0 20 20"
376
- >
377
- <path
378
- fill-rule="evenodd"
379
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
380
- clip-rule="evenodd"
381
- />
382
- </svg>
383
- <% else %>
384
- <svg
385
- class="w-5 h-5 text-gray-400"
386
- fill="currentColor"
387
- viewBox="0 0 20 20"
388
- >
389
- <path
390
- fill-rule="evenodd"
391
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
392
- clip-rule="evenodd"
393
- />
394
- </svg>
395
- <% end %>
396
- </div>
397
-
398
- <div>
399
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">
400
- Retries
401
- </p>
402
-
403
- <% if has_retries %>
404
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
405
- Max: <%= retries_config[:max] %> &middot; Backoff:
406
- <%= retries_config[:backoff] %> &middot; Base:
407
- <%= retries_config[:base] %>s &middot; Max delay:
408
- <%= retries_config[:max_delay] %>s
409
- </p>
410
- <% else %>
411
- <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
412
- Not configured
413
- </p>
414
- <% end %>
415
- </div>
416
- </div>
417
-
418
- <!-- Fallback Models -->
419
- <div class="flex items-start gap-3 p-3 rounded-lg <%= has_fallbacks ? 'bg-green-50 dark:bg-green-900/20' : 'bg-gray-50 dark:bg-gray-700/50' %>">
420
- <div class="flex-shrink-0 mt-0.5">
421
- <% if has_fallbacks %>
422
- <svg
423
- class="w-5 h-5 text-green-500"
424
- fill="currentColor"
425
- viewBox="0 0 20 20"
426
- >
427
- <path
428
- fill-rule="evenodd"
429
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
430
- clip-rule="evenodd"
431
- />
432
- </svg>
433
- <% else %>
434
- <svg
435
- class="w-5 h-5 text-gray-400"
436
- fill="currentColor"
437
- viewBox="0 0 20 20"
438
- >
439
- <path
440
- fill-rule="evenodd"
441
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
442
- clip-rule="evenodd"
443
- />
444
- </svg>
445
- <% end %>
446
- </div>
447
-
448
- <div>
449
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">
450
- Fallback Models
451
- </p>
452
-
453
- <% if has_fallbacks %>
454
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
455
- <%= fallback_models.join(" → ") %>
456
- </p>
457
- <% else %>
458
- <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
459
- Not configured
460
- </p>
461
- <% end %>
462
- </div>
463
- </div>
464
-
465
- <!-- Total Timeout -->
466
- <div class="flex items-start gap-3 p-3 rounded-lg <%= has_total_timeout ? 'bg-green-50 dark:bg-green-900/20' : 'bg-gray-50 dark:bg-gray-700/50' %>">
467
- <div class="flex-shrink-0 mt-0.5">
468
- <% if has_total_timeout %>
469
- <svg
470
- class="w-5 h-5 text-green-500"
471
- fill="currentColor"
472
- viewBox="0 0 20 20"
473
- >
474
- <path
475
- fill-rule="evenodd"
476
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
477
- clip-rule="evenodd"
478
- />
479
- </svg>
480
- <% else %>
481
- <svg
482
- class="w-5 h-5 text-gray-400"
483
- fill="currentColor"
484
- viewBox="0 0 20 20"
485
- >
486
- <path
487
- fill-rule="evenodd"
488
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
489
- clip-rule="evenodd"
490
- />
491
- </svg>
492
- <% end %>
493
- </div>
494
-
495
- <div>
496
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">
497
- Total Timeout
498
- </p>
499
-
500
- <% if has_total_timeout %>
501
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
502
- <%= @config[:total_timeout] %> seconds across all attempts
503
- </p>
504
- <% else %>
505
- <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
506
- Not configured
507
- </p>
508
- <% end %>
509
- </div>
510
- </div>
511
-
512
- <!-- Circuit Breaker -->
513
- <div class="flex items-start gap-3 p-3 rounded-lg <%= has_circuit_breaker ? 'bg-green-50 dark:bg-green-900/20' : 'bg-gray-50 dark:bg-gray-700/50' %>">
514
- <div class="flex-shrink-0 mt-0.5">
515
- <% if has_circuit_breaker %>
516
- <svg
517
- class="w-5 h-5 text-green-500"
518
- fill="currentColor"
519
- viewBox="0 0 20 20"
520
- >
521
- <path
522
- fill-rule="evenodd"
523
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
524
- clip-rule="evenodd"
525
- />
526
- </svg>
527
- <% else %>
528
- <svg
529
- class="w-5 h-5 text-gray-400"
530
- fill="currentColor"
531
- viewBox="0 0 20 20"
532
- >
533
- <path
534
- fill-rule="evenodd"
535
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
536
- clip-rule="evenodd"
537
- />
538
- </svg>
539
- <% end %>
540
- </div>
541
-
542
- <div>
543
- <p class="text-sm font-medium text-gray-900 dark:text-gray-100">
544
- Circuit Breaker
545
- </p>
546
-
547
- <% if has_circuit_breaker %>
548
- <% cb = @config[:circuit_breaker] %>
549
- <p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
550
- Opens after <%= cb[:errors] %> errors within
551
- <%= cb[:within] %>s &middot; Cooldown: <%= cb[:cooldown] %>s
552
- </p>
553
- <% else %>
554
- <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
555
- Not configured
556
- </p>
557
- <% end %>
558
- </div>
559
- </div>
560
- </div>
561
- <% else %>
562
- <p class="text-sm text-gray-400 dark:text-gray-500">
563
- No reliability features configured
564
- </p>
565
- <% end %>
566
- </div>
567
-
568
- <!-- Parameters -->
569
- <% if @config[:params].present? && @config[:params].any? %>
570
- <div class="border-t border-gray-100 dark:border-gray-700 pt-4">
571
- <p
572
- class="
573
- text-xs text-gray-500 dark:text-gray-400 uppercase
574
- tracking-wider mb-3
575
- "
576
- >
577
- Parameters
578
- </p>
579
-
580
- <div class="space-y-2">
581
- <% @config[:params].each do |name, opts| %>
582
- <div class="flex items-center text-sm">
583
- <code
584
- class="
585
- bg-gray-100 dark:bg-gray-700 dark:text-gray-200 px-2
586
- py-0.5 rounded font-mono
587
- "
588
- >
589
- <%= name %>
590
- </code>
591
-
592
- <% if opts[:required] %>
593
- <span class="ml-2 text-xs text-red-500 dark:text-red-400 font-medium">
594
- required
595
- </span>
596
- <% elsif opts[:default].present? %>
597
- <span class="ml-2 text-xs text-gray-400 dark:text-gray-500">
598
- default: <%= opts[:default].inspect %>
599
- </span>
600
- <% else %>
601
- <span class="ml-2 text-xs text-gray-400 dark:text-gray-500">
602
- optional
603
- </span>
604
- <% end %>
605
- </div>
606
- <% end %>
607
- </div>
608
- </div>
609
- <% end %>
610
-
611
- <!-- Available Tools -->
612
- <%
613
- class_tools = @agent_class.respond_to?(:tools) ? (@agent_class.tools || []) : []
614
- has_dynamic_tools = @agent_class.instance_methods(false).include?(:tools)
615
- %>
616
- <div class="border-t border-gray-100 dark:border-gray-700 pt-4">
617
- <p
618
- class="
619
- text-xs text-gray-500 dark:text-gray-400 uppercase
620
- tracking-wider mb-3
621
- "
622
- >
623
- Available Tools
624
- <% if class_tools.any? %>
625
- <span class="inline-flex items-center ml-2 px-1.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 dark:bg-blue-900/50 text-blue-800 dark:text-blue-300">
626
- <%= class_tools.size %>
627
- </span>
628
- <% elsif has_dynamic_tools %>
629
- <span class="inline-flex items-center ml-2 px-1.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-900/50 text-purple-800 dark:text-purple-300">
630
- Dynamic
631
- </span>
632
- <% else %>
633
- <span class="inline-flex items-center ml-2 px-1.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400">
634
- 0
635
- </span>
636
- <% end %>
637
- </p>
638
-
639
- <% if class_tools.any? %>
640
- <div class="space-y-2">
641
- <% class_tools.each do |tool_class| %>
642
- <div class="flex items-center text-sm">
643
- <code
644
- class="
645
- bg-gray-100 dark:bg-gray-700 dark:text-gray-200 px-2
646
- py-0.5 rounded font-mono
647
- "
648
- >
649
- <%= tool_class.respond_to?(:tool_name) ? tool_class.tool_name : tool_class.name.demodulize %>
650
- </code>
651
- </div>
652
- <% end %>
653
- </div>
654
- <% elsif has_dynamic_tools %>
655
- <p class="text-sm text-purple-600 dark:text-purple-400">
656
- This agent configures tools dynamically at runtime based on context.
657
- </p>
658
- <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
659
- Tools vary per execution based on feature flags and configuration.
660
- </p>
661
- <% else %>
662
- <p class="text-sm text-gray-400 dark:text-gray-500 italic">
663
- No tools configured for this agent.
664
- </p>
665
- <% end %>
666
- </div>
667
- </div>
306
+ <% if @config && @agent_type_kind %>
307
+ <%= render "ruby_llm/agents/agents/config_#{@agent_type_kind}", config: @config %>
668
308
  <% end %>
669
309
 
670
310
  <!-- Executions -->
@@ -0,0 +1,34 @@
1
+ <% # Partial for API key input field %>
2
+ <% # Local variables: f (form builder), config (ApiConfiguration), resolved (ResolvedConfig, optional), attr (symbol), label (string), placeholder (string, optional), hint (string, optional) %>
3
+ <% resolved = local_assigns[:resolved] %>
4
+ <% config_value = resolved&.ruby_llm_value_for(attr) %>
5
+ <% db_value = config.send(attr) %>
6
+
7
+ <div>
8
+ <%= f.label attr, label, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %>
9
+ <div class="mt-1 relative rounded-md shadow-sm">
10
+ <%= f.password_field attr,
11
+ class: "block w-full px-3 py-2 rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm pr-10",
12
+ placeholder: config.has_value?(attr) ? "[Key set - leave blank to keep]" : (local_assigns[:placeholder] || "Enter API key..."),
13
+ autocomplete: "off",
14
+ value: db_value,
15
+ data: { key_field: attr, config_value: config_value, db_value: db_value } %>
16
+ <% if config.has_value?(attr) %>
17
+ <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
18
+ <svg class="h-5 w-5 text-green-500" fill="currentColor" viewBox="0 0 20 20">
19
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
20
+ </svg>
21
+ </div>
22
+ <% end %>
23
+ </div>
24
+ <% if local_assigns[:hint] %>
25
+ <p class="mt-1 text-xs text-gray-500 dark:text-gray-400"><%= hint %></p>
26
+ <% end %>
27
+ <% if config_value.present? %>
28
+ <p class="mt-1 text-xs text-gray-500 dark:text-gray-400 config-value-hint"
29
+ data-full-value="<%= config_value %>"
30
+ data-masked-value="<%= resolved.mask_string(config_value) %>">
31
+ From config: <code class="bg-gray-100 dark:bg-gray-700 px-1 rounded config-value-display"><%= resolved.mask_string(config_value) %></code>
32
+ </p>
33
+ <% end %>
34
+ </div>