ruby_llm-agents 0.5.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 (190) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +189 -31
  3. data/app/controllers/ruby_llm/agents/agents_controller.rb +136 -16
  4. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +29 -9
  5. data/app/controllers/ruby_llm/agents/workflows_controller.rb +355 -0
  6. data/app/helpers/ruby_llm/agents/application_helper.rb +25 -0
  7. data/app/models/ruby_llm/agents/execution.rb +3 -0
  8. data/app/models/ruby_llm/agents/tenant_budget.rb +58 -15
  9. data/app/services/ruby_llm/agents/agent_registry.rb +51 -12
  10. data/app/views/layouts/ruby_llm/agents/application.html.erb +2 -29
  11. data/app/views/ruby_llm/agents/agents/_agent.html.erb +13 -1
  12. data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +235 -0
  13. data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +70 -0
  14. data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +152 -0
  15. data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +63 -0
  16. data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +108 -0
  17. data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +91 -0
  18. data/app/views/ruby_llm/agents/agents/_workflow.html.erb +1 -1
  19. data/app/views/ruby_llm/agents/agents/index.html.erb +74 -9
  20. data/app/views/ruby_llm/agents/agents/show.html.erb +18 -378
  21. data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +269 -15
  22. data/app/views/ruby_llm/agents/executions/show.html.erb +16 -0
  23. data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +93 -0
  24. data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +236 -0
  25. data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +76 -0
  26. data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +74 -0
  27. data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +108 -0
  28. data/app/views/ruby_llm/agents/workflows/show.html.erb +442 -0
  29. data/config/routes.rb +1 -0
  30. data/lib/generators/ruby_llm_agents/agent_generator.rb +56 -7
  31. data/lib/generators/ruby_llm_agents/background_remover_generator.rb +110 -0
  32. data/lib/generators/ruby_llm_agents/embedder_generator.rb +107 -0
  33. data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +115 -0
  34. data/lib/generators/ruby_llm_agents/image_editor_generator.rb +108 -0
  35. data/lib/generators/ruby_llm_agents/image_generator_generator.rb +116 -0
  36. data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +178 -0
  37. data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +109 -0
  38. data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +103 -0
  39. data/lib/generators/ruby_llm_agents/image_variator_generator.rb +102 -0
  40. data/lib/generators/ruby_llm_agents/install_generator.rb +76 -4
  41. data/lib/generators/ruby_llm_agents/restructure_generator.rb +292 -0
  42. data/lib/generators/ruby_llm_agents/speaker_generator.rb +121 -0
  43. data/lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt +8 -0
  44. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +99 -84
  45. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +42 -40
  46. data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +26 -0
  47. data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +50 -0
  48. data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +26 -0
  49. data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +20 -0
  50. data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +38 -0
  51. data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +139 -0
  52. data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +21 -0
  53. data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +20 -0
  54. data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +20 -0
  55. data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +49 -0
  56. data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +53 -0
  57. data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +44 -0
  58. data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +41 -0
  59. data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +45 -0
  60. data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +35 -0
  61. data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +47 -0
  62. data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +50 -0
  63. data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +44 -0
  64. data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +38 -0
  65. data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +33 -0
  66. data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +228 -0
  67. data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +131 -0
  68. data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +255 -0
  69. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +120 -0
  70. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +102 -0
  71. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +282 -0
  72. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +228 -0
  73. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +120 -0
  74. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +110 -0
  75. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +120 -0
  76. data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +212 -0
  77. data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +227 -0
  78. data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +251 -0
  79. data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +300 -0
  80. data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +56 -0
  81. data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +51 -0
  82. data/lib/generators/ruby_llm_agents/transcriber_generator.rb +107 -0
  83. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +152 -1
  84. data/lib/ruby_llm/agents/audio/speaker.rb +553 -0
  85. data/lib/ruby_llm/agents/audio/transcriber.rb +669 -0
  86. data/lib/ruby_llm/agents/base_agent.rb +675 -0
  87. data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +181 -0
  88. data/lib/ruby_llm/agents/core/base/moderation_execution.rb +274 -0
  89. data/lib/ruby_llm/agents/core/base.rb +135 -0
  90. data/lib/ruby_llm/agents/core/configuration.rb +981 -0
  91. data/lib/ruby_llm/agents/core/errors.rb +150 -0
  92. data/lib/ruby_llm/agents/{instrumentation.rb → core/instrumentation.rb} +22 -1
  93. data/lib/ruby_llm/agents/core/llm_tenant.rb +358 -0
  94. data/lib/ruby_llm/agents/{version.rb → core/version.rb} +1 -1
  95. data/lib/ruby_llm/agents/dsl/base.rb +110 -0
  96. data/lib/ruby_llm/agents/dsl/caching.rb +142 -0
  97. data/lib/ruby_llm/agents/dsl/reliability.rb +307 -0
  98. data/lib/ruby_llm/agents/dsl.rb +41 -0
  99. data/lib/ruby_llm/agents/image/analyzer/dsl.rb +130 -0
  100. data/lib/ruby_llm/agents/image/analyzer/execution.rb +402 -0
  101. data/lib/ruby_llm/agents/image/analyzer.rb +90 -0
  102. data/lib/ruby_llm/agents/image/background_remover/dsl.rb +154 -0
  103. data/lib/ruby_llm/agents/image/background_remover/execution.rb +240 -0
  104. data/lib/ruby_llm/agents/image/background_remover.rb +89 -0
  105. data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +91 -0
  106. data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +165 -0
  107. data/lib/ruby_llm/agents/image/editor/dsl.rb +56 -0
  108. data/lib/ruby_llm/agents/image/editor/execution.rb +207 -0
  109. data/lib/ruby_llm/agents/image/editor.rb +92 -0
  110. data/lib/ruby_llm/agents/image/generator/active_storage_support.rb +127 -0
  111. data/lib/ruby_llm/agents/image/generator/content_policy.rb +95 -0
  112. data/lib/ruby_llm/agents/image/generator/pricing.rb +353 -0
  113. data/lib/ruby_llm/agents/image/generator/templates.rb +124 -0
  114. data/lib/ruby_llm/agents/image/generator.rb +455 -0
  115. data/lib/ruby_llm/agents/image/pipeline/dsl.rb +213 -0
  116. data/lib/ruby_llm/agents/image/pipeline/execution.rb +382 -0
  117. data/lib/ruby_llm/agents/image/pipeline.rb +97 -0
  118. data/lib/ruby_llm/agents/image/transformer/dsl.rb +148 -0
  119. data/lib/ruby_llm/agents/image/transformer/execution.rb +223 -0
  120. data/lib/ruby_llm/agents/image/transformer.rb +95 -0
  121. data/lib/ruby_llm/agents/image/upscaler/dsl.rb +83 -0
  122. data/lib/ruby_llm/agents/image/upscaler/execution.rb +219 -0
  123. data/lib/ruby_llm/agents/image/upscaler.rb +81 -0
  124. data/lib/ruby_llm/agents/image/variator/dsl.rb +62 -0
  125. data/lib/ruby_llm/agents/image/variator/execution.rb +189 -0
  126. data/lib/ruby_llm/agents/image/variator.rb +80 -0
  127. data/lib/ruby_llm/agents/{alert_manager.rb → infrastructure/alert_manager.rb} +17 -22
  128. data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +145 -0
  129. data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +149 -0
  130. data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +68 -0
  131. data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +279 -0
  132. data/lib/ruby_llm/agents/infrastructure/budget_tracker.rb +275 -0
  133. data/lib/ruby_llm/agents/{execution_logger_job.rb → infrastructure/execution_logger_job.rb} +17 -1
  134. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/executor.rb +2 -1
  135. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/retry_strategy.rb +9 -3
  136. data/lib/ruby_llm/agents/{reliability.rb → infrastructure/reliability.rb} +11 -21
  137. data/lib/ruby_llm/agents/pipeline/builder.rb +215 -0
  138. data/lib/ruby_llm/agents/pipeline/context.rb +255 -0
  139. data/lib/ruby_llm/agents/pipeline/executor.rb +86 -0
  140. data/lib/ruby_llm/agents/pipeline/middleware/base.rb +124 -0
  141. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +95 -0
  142. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +171 -0
  143. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +415 -0
  144. data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +276 -0
  145. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +196 -0
  146. data/lib/ruby_llm/agents/pipeline.rb +68 -0
  147. data/lib/ruby_llm/agents/{engine.rb → rails/engine.rb} +79 -11
  148. data/lib/ruby_llm/agents/results/background_removal_result.rb +286 -0
  149. data/lib/ruby_llm/agents/{result.rb → results/base.rb} +73 -1
  150. data/lib/ruby_llm/agents/results/embedding_result.rb +243 -0
  151. data/lib/ruby_llm/agents/results/image_analysis_result.rb +314 -0
  152. data/lib/ruby_llm/agents/results/image_edit_result.rb +250 -0
  153. data/lib/ruby_llm/agents/results/image_generation_result.rb +346 -0
  154. data/lib/ruby_llm/agents/results/image_pipeline_result.rb +399 -0
  155. data/lib/ruby_llm/agents/results/image_transform_result.rb +251 -0
  156. data/lib/ruby_llm/agents/results/image_upscale_result.rb +255 -0
  157. data/lib/ruby_llm/agents/results/image_variation_result.rb +237 -0
  158. data/lib/ruby_llm/agents/results/moderation_result.rb +158 -0
  159. data/lib/ruby_llm/agents/results/speech_result.rb +338 -0
  160. data/lib/ruby_llm/agents/results/transcription_result.rb +408 -0
  161. data/lib/ruby_llm/agents/text/embedder.rb +444 -0
  162. data/lib/ruby_llm/agents/text/moderator.rb +237 -0
  163. data/lib/ruby_llm/agents/workflow/async.rb +220 -0
  164. data/lib/ruby_llm/agents/workflow/async_executor.rb +156 -0
  165. data/lib/ruby_llm/agents/{workflow.rb → workflow/orchestrator.rb} +6 -5
  166. data/lib/ruby_llm/agents/workflow/parallel.rb +34 -17
  167. data/lib/ruby_llm/agents/workflow/thread_pool.rb +185 -0
  168. data/lib/ruby_llm/agents.rb +86 -20
  169. metadata +172 -34
  170. data/lib/ruby_llm/agents/base/caching.rb +0 -40
  171. data/lib/ruby_llm/agents/base/cost_calculation.rb +0 -105
  172. data/lib/ruby_llm/agents/base/dsl.rb +0 -324
  173. data/lib/ruby_llm/agents/base/execution.rb +0 -366
  174. data/lib/ruby_llm/agents/base/reliability_dsl.rb +0 -82
  175. data/lib/ruby_llm/agents/base/reliability_execution.rb +0 -136
  176. data/lib/ruby_llm/agents/base/response_building.rb +0 -86
  177. data/lib/ruby_llm/agents/base/tool_tracking.rb +0 -57
  178. data/lib/ruby_llm/agents/base.rb +0 -210
  179. data/lib/ruby_llm/agents/budget_tracker.rb +0 -733
  180. data/lib/ruby_llm/agents/configuration.rb +0 -394
  181. /data/lib/ruby_llm/agents/{deprecations.rb → core/deprecations.rb} +0 -0
  182. /data/lib/ruby_llm/agents/{inflections.rb → core/inflections.rb} +0 -0
  183. /data/lib/ruby_llm/agents/{resolved_config.rb → core/resolved_config.rb} +0 -0
  184. /data/lib/ruby_llm/agents/{attempt_tracker.rb → infrastructure/attempt_tracker.rb} +0 -0
  185. /data/lib/ruby_llm/agents/{cache_helper.rb → infrastructure/cache_helper.rb} +0 -0
  186. /data/lib/ruby_llm/agents/{circuit_breaker.rb → infrastructure/circuit_breaker.rb} +0 -0
  187. /data/lib/ruby_llm/agents/{redactor.rb → infrastructure/redactor.rb} +0 -0
  188. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/breaker_manager.rb +0 -0
  189. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/execution_constraints.rb +0 -0
  190. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/fallback_routing.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b0d9c86b501d77defab3fb33ae73b69548d332dad116dac76a56ac1dcaa3a60
4
- data.tar.gz: 6ead43212abcb265fbb73b8daec26b49f8558c8962630d42279e3cf67328b263
3
+ metadata.gz: 34342a67c548fae89c92f0cddb75ad820dfe6a334050f806c1acab9b9b84bf29
4
+ data.tar.gz: a7d57596ff69a931e28e36ee680976557bc9f704f4d69f2296988226ed3ff9ad
5
5
  SHA512:
6
- metadata.gz: f5307aba39ba108d6104a39fcf842ab262d93237f07cc208291403f4fd1d23f604783b915c9236e85551caa0bf6e95bbe253159b4893cf174c3fb1dd12febe29
7
- data.tar.gz: 0a72c3e6ae5912a9b694bd821ce514f6f4de8af7c99487d88bc9051ee80122f2f5e0e7bf97ec698d951a1e70012e676b15a21b9abbb22c777c9b677463d567e7
6
+ metadata.gz: 89f6e9f8c05ef128e2c55652b69f5a6e986499d1811fa5ed4a92958eeea1ad129359e39762a3d72124f83b9b38981201216eb5eb45849d2cb265471b1ed45ee7
7
+ data.tar.gz: a0d1d64b761f94051b18ad0d79585678b536145a8bdfcc05d22cf4e905a4a913848901e85f3dd2ef37b755f14ceb25372c766219af69fa5f12932c108b9e6086
data/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="./logo_dark.png">
3
+ <source media="(prefers-color-scheme: light)" srcset="./logo_light.png">
4
+ <img alt="RubyLLM::Agents" src="./logo_light.png">
5
+ </picture>
6
+
1
7
  # RubyLLM::Agents
2
8
 
3
9
  > **AI Agents:** For comprehensive documentation optimized for AI consumption, see [LLMS.txt](LLMS.txt)
@@ -29,13 +35,17 @@ Build intelligent AI agents in Ruby with a clean DSL, automatic execution tracki
29
35
  | **Cost Analytics** | Track spending by agent, model, tenant, and time period | [Analytics](https://github.com/adham90/ruby_llm-agents/wiki/Execution-Tracking) |
30
36
  | **Reliability** | Automatic retries, model fallbacks, circuit breakers with block DSL | [Reliability](https://github.com/adham90/ruby_llm-agents/wiki/Reliability) |
31
37
  | **Budget Controls** | Daily/monthly limits with hard and soft enforcement | [Budgets](https://github.com/adham90/ruby_llm-agents/wiki/Budget-Controls) |
32
- | **Multi-Tenancy** | Per-tenant budgets, circuit breakers, and execution isolation | [Multi-Tenancy](https://github.com/adham90/ruby_llm-agents/wiki/Multi-Tenancy) |
38
+ | **Multi-Tenancy** | Per-tenant API keys, budgets, circuit breakers, and execution isolation | [Multi-Tenancy](https://github.com/adham90/ruby_llm-agents/wiki/Multi-Tenancy) |
33
39
  | **Workflows** | Pipelines, parallel execution, conditional routers | [Workflows](https://github.com/adham90/ruby_llm-agents/wiki/Workflows) |
40
+ | **Async/Fiber** | Concurrent execution with Ruby fibers for high-throughput workloads | [Async](https://github.com/adham90/ruby_llm-agents/wiki/Async-Fiber) |
34
41
  | **Dashboard** | Real-time Turbo-powered monitoring UI | [Dashboard](https://github.com/adham90/ruby_llm-agents/wiki/Dashboard) |
35
42
  | **Streaming** | Real-time response streaming with TTFT tracking | [Streaming](https://github.com/adham90/ruby_llm-agents/wiki/Streaming) |
36
43
  | **Conversation History** | Multi-turn conversations with message history | [Conversation History](https://github.com/adham90/ruby_llm-agents/wiki/Conversation-History) |
37
44
  | **Attachments** | Images, PDFs, and multimodal support | [Attachments](https://github.com/adham90/ruby_llm-agents/wiki/Attachments) |
38
45
  | **PII Redaction** | Automatic sensitive data protection | [Security](https://github.com/adham90/ruby_llm-agents/wiki/PII-Redaction) |
46
+ | **Content Moderation** | Input/output safety checks with OpenAI moderation API | [Moderation](https://github.com/adham90/ruby_llm-agents/wiki/Moderation) |
47
+ | **Embeddings** | Vector embeddings with batching, caching, and preprocessing | [Embeddings](https://github.com/adham90/ruby_llm-agents/wiki/Embeddings) |
48
+ | **Image Operations** | Generation, analysis, editing, pipelines with cost tracking | [Images](https://github.com/adham90/ruby_llm-agents/wiki/Image-Generation) |
39
49
  | **Alerts** | Slack, webhook, and custom notifications | [Alerts](https://github.com/adham90/ruby_llm-agents/wiki/Alerts) |
40
50
 
41
51
  ## Quick Start
@@ -69,21 +79,23 @@ rails generate ruby_llm_agents:agent SearchIntent query:required
69
79
  ```
70
80
 
71
81
  ```ruby
72
- # app/agents/search_intent_agent.rb
73
- class SearchIntentAgent < ApplicationAgent
74
- model "gpt-4o"
75
- temperature 0.0
82
+ # app/llm/agents/search_intent_agent.rb
83
+ module LLM
84
+ class SearchIntentAgent < ApplicationAgent
85
+ model "gpt-4o"
86
+ temperature 0.0
76
87
 
77
- param :query, required: true
88
+ param :query, required: true
78
89
 
79
- def user_prompt
80
- "Extract search intent from: #{query}"
81
- end
90
+ def user_prompt
91
+ "Extract search intent from: #{query}"
92
+ end
82
93
 
83
- def schema
84
- @schema ||= RubyLLM::Schema.create do
85
- string :refined_query, description: "Cleaned search query"
86
- array :filters, of: :string, description: "Extracted filters"
94
+ def schema
95
+ @schema ||= RubyLLM::Schema.create do
96
+ string :refined_query, description: "Cleaned search query"
97
+ array :filters, of: :string, description: "Extracted filters"
98
+ end
87
99
  end
88
100
  end
89
101
  end
@@ -92,7 +104,7 @@ end
92
104
  ### Call the Agent
93
105
 
94
106
  ```ruby
95
- result = SearchIntentAgent.call(query: "red summer dress under $50")
107
+ result = LLM::SearchIntentAgent.call(query: "red summer dress under $50")
96
108
 
97
109
  result.content # => { refined_query: "red dress", filters: ["color:red", "price:<50"] }
98
110
  result.total_cost # => 0.00025
@@ -117,6 +129,108 @@ result = ChatAgent.call(
117
129
 
118
130
  See [Conversation History](https://github.com/adham90/ruby_llm-agents/wiki/Conversation-History) for more patterns.
119
131
 
132
+ ### Embeddings
133
+
134
+ Generate vector embeddings for semantic search, RAG, and similarity matching:
135
+
136
+ ```bash
137
+ rails generate ruby_llm_agents:embedder Document
138
+ ```
139
+
140
+ ```ruby
141
+ # app/llm/text/embedders/document_embedder.rb
142
+ module LLM
143
+ module Text
144
+ class DocumentEmbedder < ApplicationEmbedder
145
+ model "text-embedding-3-small"
146
+ dimensions 512
147
+ batch_size 100
148
+ cache_for 1.week
149
+
150
+ # Optional: preprocess text before embedding
151
+ def preprocess(text)
152
+ text.strip.downcase.gsub(/\s+/, ' ')
153
+ end
154
+ end
155
+ end
156
+ end
157
+ ```
158
+
159
+ ```ruby
160
+ # Single text embedding
161
+ result = LLM::Text::DocumentEmbedder.call(text: "Hello world")
162
+ result.vector # => [0.123, -0.456, ...]
163
+ result.dimensions # => 512
164
+ result.total_tokens # => 2
165
+
166
+ # Batch embedding
167
+ result = LLM::Text::DocumentEmbedder.call(texts: ["Hello", "World", "Ruby"])
168
+ result.vectors # => [[...], [...], [...]]
169
+ result.count # => 3
170
+
171
+ # With progress callback for large batches
172
+ LLM::Text::DocumentEmbedder.call(texts: large_array) do |batch_result, index|
173
+ puts "Processed batch #{index + 1}"
174
+ end
175
+ ```
176
+
177
+ Features:
178
+ - **Configurable dimensions** - Reduce dimensions for efficient storage
179
+ - **Batch processing** - Embed multiple texts in optimized API calls
180
+ - **Caching** - Cache embeddings to reduce API costs
181
+ - **Preprocessing** - Clean and normalize text before embedding
182
+ - **Execution tracking** - All embeddings logged with tokens and costs
183
+
184
+ See [Embeddings](https://github.com/adham90/ruby_llm-agents/wiki/Embeddings) for more patterns.
185
+
186
+ ### Image Operations
187
+
188
+ Comprehensive image capabilities with generation, analysis, editing, and pipelines:
189
+
190
+ ```bash
191
+ # Generate image generators, analyzers, pipelines, and more
192
+ rails generate ruby_llm_agents:image_generator Logo
193
+ rails generate ruby_llm_agents:image_analyzer Product
194
+ rails generate ruby_llm_agents:background_remover Photo
195
+ rails generate ruby_llm_agents:image_pipeline Ecommerce --steps generate,upscale,analyze
196
+ ```
197
+
198
+ ```ruby
199
+ # Image Generation - create images from prompts
200
+ result = LLM::Image::LogoGenerator.call(prompt: "tech startup logo")
201
+ result.url # => "https://..."
202
+ result.save("logo.png")
203
+
204
+ # Image Analysis - extract captions, tags, objects, colors
205
+ result = LLM::Image::ProductAnalyzer.call(image: "product.jpg")
206
+ result.caption # => "Red sneaker on white background"
207
+ result.tags # => ["sneaker", "red", "footwear"]
208
+ result.colors # => [{ hex: "#FF0000", percentage: 30 }]
209
+
210
+ # Background Removal - extract subjects with transparency
211
+ result = LLM::Image::PhotoBackgroundRemover.call(image: "portrait.jpg")
212
+ result.save("portrait_transparent.png")
213
+
214
+ # Image Pipelines - chain multiple operations
215
+ result = LLM::Image::EcommercePipeline.call(
216
+ prompt: "professional laptop photo",
217
+ high_quality: true
218
+ )
219
+ result.final_image # => Final processed image
220
+ result.total_cost # => Combined cost of all steps
221
+ result.step(:analyze).tags # => Access individual step results
222
+ ```
223
+
224
+ Features:
225
+ - **8 image operation classes** - Generator, Analyzer, Editor, Transformer, Upscaler, Variator, BackgroundRemover, Pipeline
226
+ - **Prompt templates** - Consistent styling with preset templates
227
+ - **Content policy** - Validate prompts with configurable safety levels
228
+ - **Cost tracking** - Dynamic pricing with execution logging
229
+ - **Image Pipelines** - Chain operations into automated workflows
230
+ - **ActiveStorage** - Attach images directly to Rails models
231
+
232
+ See [Image Operations](https://github.com/adham90/ruby_llm-agents/wiki/Image-Generation) for full documentation.
233
+
120
234
  ## Documentation
121
235
 
122
236
  > **Note:** Wiki content lives in the [`wiki/`](wiki/) folder. To sync changes to the [GitHub Wiki](https://github.com/adham90/ruby_llm-agents/wiki), run `./scripts/sync-wiki.sh`.
@@ -129,8 +243,12 @@ See [Conversation History](https://github.com/adham90/ruby_llm-agents/wiki/Conve
129
243
  | [Workflows](https://github.com/adham90/ruby_llm-agents/wiki/Workflows) | Pipelines, parallel execution, routers |
130
244
  | [Budget Controls](https://github.com/adham90/ruby_llm-agents/wiki/Budget-Controls) | Spending limits, alerts, enforcement |
131
245
  | [Multi-Tenancy](https://github.com/adham90/ruby_llm-agents/wiki/Multi-Tenancy) | Per-tenant budgets, isolation, configuration |
246
+ | [Async/Fiber](https://github.com/adham90/ruby_llm-agents/wiki/Async-Fiber) | Concurrent execution with Ruby fibers |
132
247
  | [Testing Agents](https://github.com/adham90/ruby_llm-agents/wiki/Testing-Agents) | RSpec patterns, mocking, dry_run mode |
133
248
  | [Error Handling](https://github.com/adham90/ruby_llm-agents/wiki/Error-Handling) | Error types, recovery patterns |
249
+ | [Moderation](https://github.com/adham90/ruby_llm-agents/wiki/Moderation) | Content moderation for input/output safety |
250
+ | [Embeddings](https://github.com/adham90/ruby_llm-agents/wiki/Embeddings) | Vector embeddings, batching, caching, preprocessing |
251
+ | [Image Generation](https://github.com/adham90/ruby_llm-agents/wiki/Image-Generation) | Text-to-image, templates, content policy, cost tracking |
134
252
  | [Dashboard](https://github.com/adham90/ruby_llm-agents/wiki/Dashboard) | Setup, authentication, analytics |
135
253
  | [Production](https://github.com/adham90/ruby_llm-agents/wiki/Production-Deployment) | Deployment best practices, background jobs |
136
254
  | [API Reference](https://github.com/adham90/ruby_llm-agents/wiki/API-Reference) | Complete class documentation |
@@ -141,28 +259,31 @@ See [Conversation History](https://github.com/adham90/ruby_llm-agents/wiki/Conve
141
259
  Build resilient agents with built-in fault tolerance:
142
260
 
143
261
  ```ruby
144
- class ReliableAgent < ApplicationAgent
145
- model "gpt-4o"
146
- description "A resilient agent with automatic retries and fallbacks"
147
-
148
- # Option 1: Individual DSL methods
149
- retries max: 3, backoff: :exponential
150
- fallback_models "gpt-4o-mini", "claude-3-5-sonnet"
151
- circuit_breaker errors: 10, within: 60, cooldown: 300
152
- total_timeout 30
153
-
154
- # Option 2: Grouped reliability block (equivalent to above)
155
- reliability do
262
+ # app/llm/agents/reliable_agent.rb
263
+ module LLM
264
+ class ReliableAgent < ApplicationAgent
265
+ model "gpt-4o"
266
+ description "A resilient agent with automatic retries and fallbacks"
267
+
268
+ # Option 1: Individual DSL methods
156
269
  retries max: 3, backoff: :exponential
157
270
  fallback_models "gpt-4o-mini", "claude-3-5-sonnet"
158
271
  circuit_breaker errors: 10, within: 60, cooldown: 300
159
272
  total_timeout 30
160
- end
161
273
 
162
- param :query, required: true
274
+ # Option 2: Grouped reliability block (equivalent to above)
275
+ reliability do
276
+ retries max: 3, backoff: :exponential
277
+ fallback_models "gpt-4o-mini", "claude-3-5-sonnet"
278
+ circuit_breaker errors: 10, within: 60, cooldown: 300
279
+ total_timeout 30
280
+ end
281
+
282
+ param :query, required: true
163
283
 
164
- def user_prompt
165
- query
284
+ def user_prompt
285
+ query
286
+ end
166
287
  end
167
288
  end
168
289
  ```
@@ -172,7 +293,7 @@ end
172
293
  The result object provides detailed execution metadata:
173
294
 
174
295
  ```ruby
175
- result = ReliableAgent.call(query: "test")
296
+ result = LLM::ReliableAgent.call(query: "test")
176
297
 
177
298
  # Basic response
178
299
  result.content # => { ... }
@@ -233,6 +354,43 @@ result = SupportRouter.call(message: user_input)
233
354
  result.routed_to # :support, :sales, or :default
234
355
  ```
235
356
 
357
+ ## Async/Fiber Concurrency
358
+
359
+ Run multiple agents concurrently with minimal resources using Ruby's Fiber scheduler:
360
+
361
+ ```ruby
362
+ # Add async gem to Gemfile
363
+ gem 'async'
364
+ ```
365
+
366
+ ```ruby
367
+ require 'async'
368
+
369
+ # Run agents concurrently - non-blocking I/O
370
+ Async do
371
+ results = RubyLLM::Agents::Async.batch([
372
+ [SentimentAgent, { input: "I love this!" }],
373
+ [SummaryAgent, { input: "Long text..." }],
374
+ [CategoryAgent, { input: "Product review" }]
375
+ ], max_concurrent: 10)
376
+ end
377
+
378
+ # Process large collections efficiently
379
+ Async do
380
+ results = RubyLLM::Agents::Async.each(texts, max_concurrent: 20) do |text|
381
+ AnalyzerAgent.call(input: text)
382
+ end
383
+ end
384
+ ```
385
+
386
+ Benefits:
387
+ - **100x less memory** - Fibers use ~10KB vs ~1MB per thread
388
+ - **Shared connections** - Single database connection for all fibers
389
+ - **Auto-detection** - Parallel workflows automatically use fibers in async context
390
+ - **Non-blocking retries** - Backoff delays don't block other operations
391
+
392
+ See [Async/Fiber](https://github.com/adham90/ruby_llm-agents/wiki/Async-Fiber) for more patterns.
393
+
236
394
  ## Cost & Budget Controls
237
395
 
238
396
  Track and limit LLM spending:
@@ -30,6 +30,16 @@ module RubyLLM
30
30
  @agents = all_items.reject { |a| a[:is_workflow] }
31
31
  @workflows = all_items.select { |a| a[:is_workflow] }
32
32
 
33
+ # Group agents by type for sub-tabs
34
+ @agents_by_type = {
35
+ agent: @agents.select { |a| a[:agent_type] == "agent" },
36
+ embedder: @agents.select { |a| a[:agent_type] == "embedder" },
37
+ moderator: @agents.select { |a| a[:agent_type] == "moderator" },
38
+ speaker: @agents.select { |a| a[:agent_type] == "speaker" },
39
+ transcriber: @agents.select { |a| a[:agent_type] == "transcriber" },
40
+ image_generator: @agents.select { |a| a[:agent_type] == "image_generator" }
41
+ }
42
+
33
43
  # Group workflows by type for sub-tabs
34
44
  @workflows_by_type = {
35
45
  pipeline: @workflows.select { |w| w[:workflow_type] == "pipeline" },
@@ -44,6 +54,7 @@ module RubyLLM
44
54
  Rails.logger.error("[RubyLLM::Agents] Error loading agents: #{e.message}")
45
55
  @agents = []
46
56
  @workflows = []
57
+ @agents_by_type = { agent: [], embedder: [], moderator: [], speaker: [], transcriber: [], image_generator: [] }
47
58
  @workflows_by_type = { pipeline: [], parallel: [], router: [] }
48
59
  @agent_count = 0
49
60
  @workflow_count = 0
@@ -69,7 +80,8 @@ module RubyLLM
69
80
 
70
81
  if @agent_class
71
82
  load_agent_config
72
- load_circuit_breaker_status
83
+ # Only load circuit breaker status for base agents
84
+ load_circuit_breaker_status if @agent_type_kind == "agent"
73
85
  end
74
86
  rescue StandardError => e
75
87
  Rails.logger.error("[RubyLLM::Agents] Error loading agent #{@agent_type}: #{e.message}")
@@ -207,26 +219,134 @@ module RubyLLM
207
219
  #
208
220
  # Extracts DSL-configured values from the agent class for display.
209
221
  # Only called if the agent class still exists.
222
+ # Detects agent type and loads appropriate config.
210
223
  #
211
224
  # @return [void]
212
225
  def load_agent_config
226
+ @agent_type_kind = AgentRegistry.send(:detect_agent_type, @agent_class)
227
+
228
+ # Common config for all types
213
229
  @config = {
214
- # Basic configuration
215
- model: @agent_class.model,
216
- temperature: @agent_class.temperature,
217
- version: @agent_class.version,
218
- description: @agent_class.respond_to?(:description) ? @agent_class.description : nil,
219
- timeout: @agent_class.timeout,
220
- cache_enabled: @agent_class.cache_enabled?,
221
- cache_ttl: @agent_class.cache_ttl,
222
- params: @agent_class.params,
223
-
224
- # Reliability configuration
225
- retries: @agent_class.retries,
226
- fallback_models: @agent_class.fallback_models,
227
- total_timeout: @agent_class.total_timeout,
228
- circuit_breaker: @agent_class.circuit_breaker_config
230
+ model: safe_config_call(:model),
231
+ version: safe_config_call(:version) || "N/A",
232
+ description: safe_config_call(:description)
229
233
  }
234
+
235
+ # Type-specific config
236
+ case @agent_type_kind
237
+ when "embedder"
238
+ load_embedder_config
239
+ when "moderator"
240
+ load_moderator_config
241
+ when "speaker"
242
+ load_speaker_config
243
+ when "transcriber"
244
+ load_transcriber_config
245
+ when "image_generator"
246
+ load_image_generator_config
247
+ else
248
+ load_base_agent_config
249
+ end
250
+ end
251
+
252
+ # Loads configuration specific to Base agents
253
+ #
254
+ # @return [void]
255
+ def load_base_agent_config
256
+ @config.merge!(
257
+ temperature: safe_config_call(:temperature),
258
+ timeout: safe_config_call(:timeout),
259
+ cache_enabled: safe_config_call(:cache_enabled?) || false,
260
+ cache_ttl: safe_config_call(:cache_ttl),
261
+ params: safe_config_call(:params) || {},
262
+ retries: safe_config_call(:retries),
263
+ fallback_models: safe_config_call(:fallback_models),
264
+ total_timeout: safe_config_call(:total_timeout),
265
+ circuit_breaker: safe_config_call(:circuit_breaker_config)
266
+ )
267
+ end
268
+
269
+ # Loads configuration specific to Embedders
270
+ #
271
+ # @return [void]
272
+ def load_embedder_config
273
+ @config.merge!(
274
+ dimensions: safe_config_call(:dimensions),
275
+ batch_size: safe_config_call(:batch_size),
276
+ cache_enabled: safe_config_call(:cache_enabled?) || false,
277
+ cache_ttl: safe_config_call(:cache_ttl)
278
+ )
279
+ end
280
+
281
+ # Loads configuration specific to Moderators
282
+ #
283
+ # @return [void]
284
+ def load_moderator_config
285
+ @config.merge!(
286
+ threshold: safe_config_call(:threshold),
287
+ categories: safe_config_call(:categories)
288
+ )
289
+ end
290
+
291
+ # Loads configuration specific to Speakers
292
+ #
293
+ # @return [void]
294
+ def load_speaker_config
295
+ @config.merge!(
296
+ provider: safe_config_call(:provider),
297
+ voice: safe_config_call(:voice),
298
+ voice_id: safe_config_call(:voice_id),
299
+ speed: safe_config_call(:speed),
300
+ output_format: safe_config_call(:output_format),
301
+ streaming: safe_config_call(:streaming?),
302
+ ssml_enabled: safe_config_call(:ssml_enabled?),
303
+ cache_enabled: safe_config_call(:cache_enabled?) || false,
304
+ cache_ttl: safe_config_call(:cache_ttl)
305
+ )
306
+ end
307
+
308
+ # Loads configuration specific to Transcribers
309
+ #
310
+ # @return [void]
311
+ def load_transcriber_config
312
+ @config.merge!(
313
+ language: safe_config_call(:language),
314
+ output_format: safe_config_call(:output_format),
315
+ include_timestamps: safe_config_call(:include_timestamps),
316
+ cache_enabled: safe_config_call(:cache_enabled?) || false,
317
+ cache_ttl: safe_config_call(:cache_ttl),
318
+ fallback_models: safe_config_call(:fallback_models)
319
+ )
320
+ end
321
+
322
+ # Loads configuration specific to ImageGenerators
323
+ #
324
+ # @return [void]
325
+ def load_image_generator_config
326
+ @config.merge!(
327
+ size: safe_config_call(:size),
328
+ quality: safe_config_call(:quality),
329
+ style: safe_config_call(:style),
330
+ content_policy: safe_config_call(:content_policy),
331
+ template: safe_config_call(:template_string),
332
+ negative_prompt: safe_config_call(:negative_prompt),
333
+ seed: safe_config_call(:seed),
334
+ guidance_scale: safe_config_call(:guidance_scale),
335
+ steps: safe_config_call(:steps),
336
+ cache_enabled: safe_config_call(:cache_enabled?) || false,
337
+ cache_ttl: safe_config_call(:cache_ttl)
338
+ )
339
+ end
340
+
341
+ # Safely calls a method on the agent class, returning nil on error
342
+ #
343
+ # @param method [Symbol] The method to call
344
+ # @return [Object, nil] The result or nil if error
345
+ def safe_config_call(method)
346
+ return nil unless @agent_class&.respond_to?(method)
347
+ @agent_class.public_send(method)
348
+ rescue StandardError
349
+ nil
230
350
  end
231
351
 
232
352
  # Loads circuit breaker status for the agent's models
@@ -53,10 +53,19 @@ module RubyLLM
53
53
  end
54
54
  end
55
55
 
56
- # Builds per-agent comparison statistics
56
+ # Builds per-agent comparison statistics for all agent types
57
+ #
58
+ # Creates separate instance variables for each agent type:
59
+ # - @agent_stats: Base agents
60
+ # - @embedder_stats: Embedders
61
+ # - @transcriber_stats: Transcribers
62
+ # - @speaker_stats: Speakers
63
+ # - @image_generator_stats: Image generators
64
+ # - @moderator_stats: Moderators
65
+ # - @workflow_stats: Workflows
57
66
  #
58
67
  # @param base_scope [ActiveRecord::Relation] Base scope to filter from
59
- # @return [Array<Hash>] Array of all stats sorted by cost descending
68
+ # @return [Array<Hash>] Array of base agent stats (for backward compatibility)
60
69
  def build_agent_comparison(base_scope = Execution)
61
70
  scope = base_scope.last_n_days(@days)
62
71
  agent_types = scope.distinct.pluck(:agent_type)
@@ -67,26 +76,37 @@ module RubyLLM
67
76
  total_cost = agent_scope.sum(:total_cost) || 0
68
77
  successful = agent_scope.successful.count
69
78
 
70
- # Detect if this is a workflow
79
+ # Detect agent type using AgentRegistry
71
80
  agent_class = AgentRegistry.find(agent_type)
72
- is_workflow = agent_class&.ancestors&.any? { |a| a.name&.include?("Workflow") }
73
- workflow_type = is_workflow ? detect_workflow_type(agent_class) : nil
81
+ detected_type = AgentRegistry.send(:detect_agent_type, agent_class)
82
+
83
+ # Get workflow type if applicable
84
+ workflow_type = detected_type == "workflow" ? detect_workflow_type(agent_class) : nil
74
85
 
75
86
  {
76
87
  agent_type: agent_type,
88
+ detected_type: detected_type,
77
89
  executions: count,
78
90
  total_cost: total_cost,
79
91
  avg_cost: count > 0 ? (total_cost / count).round(6) : 0,
80
92
  avg_duration_ms: agent_scope.average(:duration_ms)&.round || 0,
81
93
  success_rate: count > 0 ? (successful.to_f / count * 100).round(1) : 0,
82
- is_workflow: is_workflow,
94
+ is_workflow: detected_type == "workflow",
83
95
  workflow_type: workflow_type
84
96
  }
85
97
  end.sort_by { |a| -(a[:total_cost] || 0) }
86
98
 
87
- # Split into agents and workflows for tabbed display
88
- @workflow_stats = all_stats.select { |a| a[:is_workflow] }
89
- all_stats.reject { |a| a[:is_workflow] }
99
+ # Split stats by agent type for 7-tab display
100
+ @agent_stats = all_stats.select { |a| a[:detected_type] == "agent" }
101
+ @embedder_stats = all_stats.select { |a| a[:detected_type] == "embedder" }
102
+ @transcriber_stats = all_stats.select { |a| a[:detected_type] == "transcriber" }
103
+ @speaker_stats = all_stats.select { |a| a[:detected_type] == "speaker" }
104
+ @image_generator_stats = all_stats.select { |a| a[:detected_type] == "image_generator" }
105
+ @moderator_stats = all_stats.select { |a| a[:detected_type] == "moderator" }
106
+ @workflow_stats = all_stats.select { |a| a[:detected_type] == "workflow" }
107
+
108
+ # Return base agents for backward compatibility
109
+ @agent_stats
90
110
  end
91
111
 
92
112
  # Detects workflow type from class hierarchy