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
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # BackgroundRemover generator for creating new background removers
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:background_remover Product
10
+ # rails generate ruby_llm_agents:background_remover Portrait --model segment-anything --alpha_matting
11
+ # rails generate ruby_llm_agents:background_remover Photo --refine_edges --return_mask
12
+ # rails generate ruby_llm_agents:background_remover Product --root=ai
13
+ #
14
+ # This will create:
15
+ # - app/{root}/image/background_removers/product_background_remover.rb
16
+ #
17
+ class BackgroundRemoverGenerator < ::Rails::Generators::NamedBase
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :model, type: :string, default: "rembg",
21
+ desc: "The segmentation model to use"
22
+ class_option :output_format, type: :string, default: "png",
23
+ desc: "Output format (png, webp)"
24
+ class_option :refine_edges, type: :boolean, default: false,
25
+ desc: "Enable edge refinement"
26
+ class_option :alpha_matting, type: :boolean, default: false,
27
+ desc: "Enable alpha matting for better edges"
28
+ class_option :return_mask, type: :boolean, default: false,
29
+ desc: "Also return the segmentation mask"
30
+ class_option :cache, type: :string, default: nil,
31
+ desc: "Cache TTL (e.g., '1.hour', '1.day')"
32
+ class_option :root,
33
+ type: :string,
34
+ default: nil,
35
+ desc: "Root directory name (default: uses config or 'llm')"
36
+ class_option :namespace,
37
+ type: :string,
38
+ default: nil,
39
+ desc: "Root namespace (default: camelized root or config)"
40
+
41
+ def ensure_base_class_and_skill_file
42
+ @root_namespace = root_namespace
43
+ @image_namespace = "#{root_namespace}::Image"
44
+ removers_dir = "app/#{root_directory}/image/background_removers"
45
+
46
+ # Create directory if needed
47
+ empty_directory removers_dir
48
+
49
+ # Create base class if it doesn't exist
50
+ base_class_path = "#{removers_dir}/application_background_remover.rb"
51
+ unless File.exist?(File.join(destination_root, base_class_path))
52
+ template "application_background_remover.rb.tt", base_class_path
53
+ end
54
+
55
+ # Create skill file if it doesn't exist
56
+ skill_file_path = "#{removers_dir}/BACKGROUND_REMOVERS.md"
57
+ unless File.exist?(File.join(destination_root, skill_file_path))
58
+ template "skills/BACKGROUND_REMOVERS.md.tt", skill_file_path
59
+ end
60
+ end
61
+
62
+ def create_background_remover_file
63
+ @root_namespace = root_namespace
64
+ @image_namespace = "#{root_namespace}::Image"
65
+ remover_path = name.underscore
66
+ template "background_remover.rb.tt", "app/#{root_directory}/image/background_removers/#{remover_path}_background_remover.rb"
67
+ end
68
+
69
+ def show_usage
70
+ remover_class_name = name.split("/").map(&:camelize).join("::")
71
+ full_class_name = "#{root_namespace}::Image::#{remover_class_name}BackgroundRemover"
72
+ say ""
73
+ say "Background remover #{full_class_name} created!", :green
74
+ say ""
75
+ say "Usage:"
76
+ say " # Remove background from an image"
77
+ say " result = #{full_class_name}.call(image: 'photo.jpg')"
78
+ say " result.url # => 'https://...' (transparent PNG)"
79
+ say " result.has_alpha? # => true"
80
+ say ""
81
+ say " # Override settings at runtime"
82
+ say " result = #{full_class_name}.call("
83
+ say " image: 'portrait.jpg',"
84
+ say " alpha_matting: true,"
85
+ say " return_mask: true"
86
+ say " )"
87
+ say ""
88
+ say " # Access the segmentation mask"
89
+ say " result.mask_url # => 'https://...' (if return_mask was enabled)"
90
+ say ""
91
+ end
92
+
93
+ private
94
+
95
+ def root_directory
96
+ @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
97
+ end
98
+
99
+ def root_namespace
100
+ @root_namespace ||= options[:namespace] || camelize(root_directory)
101
+ end
102
+
103
+ def camelize(str)
104
+ return "AI" if str.downcase == "ai"
105
+ return "ML" if str.downcase == "ml"
106
+ return "LLM" if str.downcase == "llm"
107
+ str.split(/[-_]/).map(&:capitalize).join
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # Embedder generator for creating new embedders
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:embedder Document
10
+ # rails generate ruby_llm_agents:embedder Document --model text-embedding-3-large
11
+ # rails generate ruby_llm_agents:embedder Document --dimensions 512
12
+ # rails generate ruby_llm_agents:embedder Document --root=ai
13
+ #
14
+ # This will create:
15
+ # - app/{root}/text/embedders/document_embedder.rb
16
+ #
17
+ class EmbedderGenerator < ::Rails::Generators::NamedBase
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :model, type: :string, default: "text-embedding-3-small",
21
+ desc: "The embedding model to use"
22
+ class_option :dimensions, type: :numeric, default: nil,
23
+ desc: "Vector dimensions (nil for model default)"
24
+ class_option :batch_size, type: :numeric, default: 100,
25
+ desc: "Texts per API call for batch processing"
26
+ class_option :cache, type: :string, default: nil,
27
+ desc: "Cache TTL (e.g., '1.week', '1.day')"
28
+ class_option :root,
29
+ type: :string,
30
+ default: nil,
31
+ desc: "Root directory name (default: uses config or 'llm')"
32
+ class_option :namespace,
33
+ type: :string,
34
+ default: nil,
35
+ desc: "Root namespace (default: camelized root or config)"
36
+
37
+ def ensure_base_class_and_skill_file
38
+ @root_namespace = root_namespace
39
+ @text_namespace = "#{root_namespace}::Text"
40
+ embedders_dir = "app/#{root_directory}/text/embedders"
41
+
42
+ # Create directory if needed
43
+ empty_directory embedders_dir
44
+
45
+ # Create base class if it doesn't exist
46
+ base_class_path = "#{embedders_dir}/application_embedder.rb"
47
+ unless File.exist?(File.join(destination_root, base_class_path))
48
+ template "application_embedder.rb.tt", base_class_path
49
+ end
50
+
51
+ # Create skill file if it doesn't exist
52
+ skill_file_path = "#{embedders_dir}/EMBEDDERS.md"
53
+ unless File.exist?(File.join(destination_root, skill_file_path))
54
+ template "skills/EMBEDDERS.md.tt", skill_file_path
55
+ end
56
+ end
57
+
58
+ def create_embedder_file
59
+ # Support nested paths: "search/document" -> "app/{root}/text/embedders/search/document_embedder.rb"
60
+ @root_namespace = root_namespace
61
+ @text_namespace = "#{root_namespace}::Text"
62
+ embedder_path = name.underscore
63
+ template "embedder.rb.tt", "app/#{root_directory}/text/embedders/#{embedder_path}_embedder.rb"
64
+ end
65
+
66
+ def show_usage
67
+ # Build full class name from path
68
+ embedder_class_name = name.split("/").map(&:camelize).join("::")
69
+ full_class_name = "#{root_namespace}::Text::#{embedder_class_name}Embedder"
70
+ say ""
71
+ say "Embedder #{full_class_name} created!", :green
72
+ say ""
73
+ say "Usage:"
74
+ say " # Single text"
75
+ say " #{full_class_name}.call(text: \"Hello world\")"
76
+ say ""
77
+ say " # Multiple texts (batch)"
78
+ say " #{full_class_name}.call(texts: [\"Hello\", \"World\"])"
79
+ say ""
80
+ say " # With progress tracking"
81
+ say " #{full_class_name}.call(texts: large_array) do |batch, idx|"
82
+ say " puts \"Processed batch \#{idx}\""
83
+ say " end"
84
+ say ""
85
+ end
86
+
87
+ private
88
+
89
+ def root_directory
90
+ @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
91
+ end
92
+
93
+ def root_namespace
94
+ @root_namespace ||= options[:namespace] || camelize(root_directory)
95
+ end
96
+
97
+ def camelize(str)
98
+ # Handle special cases for common abbreviations
99
+ return "AI" if str.downcase == "ai"
100
+ return "ML" if str.downcase == "ml"
101
+ return "LLM" if str.downcase == "llm"
102
+
103
+ # Standard camelization
104
+ str.split(/[-_]/).map(&:capitalize).join
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # ImageAnalyzer generator for creating new image analyzers
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:image_analyzer Product
10
+ # rails generate ruby_llm_agents:image_analyzer Content --model gpt-4o --analysis_type detailed
11
+ # rails generate ruby_llm_agents:image_analyzer Photo --extract_colors --detect_objects
12
+ # rails generate ruby_llm_agents:image_analyzer Product --root=ai
13
+ #
14
+ # This will create:
15
+ # - app/{root}/image/analyzers/product_analyzer.rb
16
+ #
17
+ class ImageAnalyzerGenerator < ::Rails::Generators::NamedBase
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :model, type: :string, default: "gpt-4o",
21
+ desc: "The vision model to use"
22
+ class_option :analysis_type, type: :string, default: "detailed",
23
+ desc: "Analysis type (caption, detailed, tags, objects, colors, all)"
24
+ class_option :extract_colors, type: :boolean, default: false,
25
+ desc: "Enable color extraction"
26
+ class_option :detect_objects, type: :boolean, default: false,
27
+ desc: "Enable object detection"
28
+ class_option :extract_text, type: :boolean, default: false,
29
+ desc: "Enable text extraction (OCR)"
30
+ class_option :max_tags, type: :string, default: "10",
31
+ desc: "Maximum number of tags to return"
32
+ class_option :cache, type: :string, default: nil,
33
+ desc: "Cache TTL (e.g., '1.hour', '1.day')"
34
+ class_option :root,
35
+ type: :string,
36
+ default: nil,
37
+ desc: "Root directory name (default: uses config or 'llm')"
38
+ class_option :namespace,
39
+ type: :string,
40
+ default: nil,
41
+ desc: "Root namespace (default: camelized root or config)"
42
+
43
+ def ensure_base_class_and_skill_file
44
+ @root_namespace = root_namespace
45
+ @image_namespace = "#{root_namespace}::Image"
46
+ analyzers_dir = "app/#{root_directory}/image/analyzers"
47
+
48
+ # Create directory if needed
49
+ empty_directory analyzers_dir
50
+
51
+ # Create base class if it doesn't exist
52
+ base_class_path = "#{analyzers_dir}/application_image_analyzer.rb"
53
+ unless File.exist?(File.join(destination_root, base_class_path))
54
+ template "application_image_analyzer.rb.tt", base_class_path
55
+ end
56
+
57
+ # Create skill file if it doesn't exist
58
+ skill_file_path = "#{analyzers_dir}/IMAGE_ANALYZERS.md"
59
+ unless File.exist?(File.join(destination_root, skill_file_path))
60
+ template "skills/IMAGE_ANALYZERS.md.tt", skill_file_path
61
+ end
62
+ end
63
+
64
+ def create_image_analyzer_file
65
+ @root_namespace = root_namespace
66
+ @image_namespace = "#{root_namespace}::Image"
67
+ analyzer_path = name.underscore
68
+ template "image_analyzer.rb.tt", "app/#{root_directory}/image/analyzers/#{analyzer_path}_analyzer.rb"
69
+ end
70
+
71
+ def show_usage
72
+ analyzer_class_name = name.split("/").map(&:camelize).join("::")
73
+ full_class_name = "#{root_namespace}::Image::#{analyzer_class_name}Analyzer"
74
+ say ""
75
+ say "Image analyzer #{full_class_name} created!", :green
76
+ say ""
77
+ say "Usage:"
78
+ say " # Analyze an image"
79
+ say " result = #{full_class_name}.call(image: 'photo.jpg')"
80
+ say " result.caption # => 'A sunset over mountains'"
81
+ say " result.tags # => ['sunset', 'mountains', 'nature']"
82
+ say " result.description # => 'Detailed description...'"
83
+ say ""
84
+ say " # Override settings at runtime"
85
+ say " result = #{full_class_name}.call("
86
+ say " image: 'product.jpg',"
87
+ say " analysis_type: :all,"
88
+ say " extract_colors: true,"
89
+ say " detect_objects: true"
90
+ say " )"
91
+ say ""
92
+ say " # Access detected objects and colors"
93
+ say " result.objects # => [{name: 'laptop', location: 'center', confidence: 'high'}]"
94
+ say " result.colors # => [{hex: '#C0C0C0', name: 'silver', percentage: 45}]"
95
+ say ""
96
+ end
97
+
98
+ private
99
+
100
+ def root_directory
101
+ @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
102
+ end
103
+
104
+ def root_namespace
105
+ @root_namespace ||= options[:namespace] || camelize(root_directory)
106
+ end
107
+
108
+ def camelize(str)
109
+ return "AI" if str.downcase == "ai"
110
+ return "ML" if str.downcase == "ml"
111
+ return "LLM" if str.downcase == "llm"
112
+ str.split(/[-_]/).map(&:capitalize).join
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # ImageEditor generator for creating new image editors
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:image_editor Product
10
+ # rails generate ruby_llm_agents:image_editor Background --model gpt-image-1 --size 1024x1024
11
+ # rails generate ruby_llm_agents:image_editor Photo --content_policy strict
12
+ # rails generate ruby_llm_agents:image_editor Product --root=ai
13
+ #
14
+ # This will create:
15
+ # - app/{root}/image/editors/product_editor.rb
16
+ #
17
+ class ImageEditorGenerator < ::Rails::Generators::NamedBase
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :model, type: :string, default: "gpt-image-1",
21
+ desc: "The image model to use"
22
+ class_option :size, type: :string, default: "1024x1024",
23
+ desc: "Output image size (e.g., 1024x1024)"
24
+ class_option :content_policy, type: :string, default: "standard",
25
+ desc: "Content policy level (none, standard, moderate, strict)"
26
+ class_option :cache, type: :string, default: nil,
27
+ desc: "Cache TTL (e.g., '1.hour', '1.day')"
28
+ class_option :root,
29
+ type: :string,
30
+ default: nil,
31
+ desc: "Root directory name (default: uses config or 'llm')"
32
+ class_option :namespace,
33
+ type: :string,
34
+ default: nil,
35
+ desc: "Root namespace (default: camelized root or config)"
36
+
37
+ def ensure_base_class_and_skill_file
38
+ @root_namespace = root_namespace
39
+ @image_namespace = "#{root_namespace}::Image"
40
+ editors_dir = "app/#{root_directory}/image/editors"
41
+
42
+ # Create directory if needed
43
+ empty_directory editors_dir
44
+
45
+ # Create base class if it doesn't exist
46
+ base_class_path = "#{editors_dir}/application_image_editor.rb"
47
+ unless File.exist?(File.join(destination_root, base_class_path))
48
+ template "application_image_editor.rb.tt", base_class_path
49
+ end
50
+
51
+ # Create skill file if it doesn't exist
52
+ skill_file_path = "#{editors_dir}/IMAGE_EDITORS.md"
53
+ unless File.exist?(File.join(destination_root, skill_file_path))
54
+ template "skills/IMAGE_EDITORS.md.tt", skill_file_path
55
+ end
56
+ end
57
+
58
+ def create_image_editor_file
59
+ @root_namespace = root_namespace
60
+ @image_namespace = "#{root_namespace}::Image"
61
+ editor_path = name.underscore
62
+ template "image_editor.rb.tt", "app/#{root_directory}/image/editors/#{editor_path}_editor.rb"
63
+ end
64
+
65
+ def show_usage
66
+ editor_class_name = name.split("/").map(&:camelize).join("::")
67
+ full_class_name = "#{root_namespace}::Image::#{editor_class_name}Editor"
68
+ say ""
69
+ say "Image editor #{full_class_name} created!", :green
70
+ say ""
71
+ say "Usage:"
72
+ say " # Edit an image with a mask"
73
+ say " result = #{full_class_name}.call("
74
+ say " image: 'photo.png',"
75
+ say " mask: 'mask.png',"
76
+ say " prompt: 'Replace the background with a beach scene'"
77
+ say " )"
78
+ say " result.url # => 'https://...'"
79
+ say ""
80
+ say " # Generate multiple edit variations"
81
+ say " result = #{full_class_name}.call("
82
+ say " image: 'photo.png',"
83
+ say " mask: 'mask.png',"
84
+ say " prompt: 'Add a sunset',"
85
+ say " count: 3"
86
+ say " )"
87
+ say " result.urls # => ['https://...', ...]"
88
+ say ""
89
+ end
90
+
91
+ private
92
+
93
+ def root_directory
94
+ @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
95
+ end
96
+
97
+ def root_namespace
98
+ @root_namespace ||= options[:namespace] || camelize(root_directory)
99
+ end
100
+
101
+ def camelize(str)
102
+ return "AI" if str.downcase == "ai"
103
+ return "ML" if str.downcase == "ml"
104
+ return "LLM" if str.downcase == "llm"
105
+ str.split(/[-_]/).map(&:capitalize).join
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # ImageGenerator generator for creating new image generators
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:image_generator Logo
10
+ # rails generate ruby_llm_agents:image_generator Product --model gpt-image-1 --size 1024x1024
11
+ # rails generate ruby_llm_agents:image_generator Avatar --quality hd --style vivid
12
+ # rails generate ruby_llm_agents:image_generator Logo --root=ai
13
+ #
14
+ # This will create:
15
+ # - app/{root}/image/generators/logo_generator.rb
16
+ #
17
+ class ImageGeneratorGenerator < ::Rails::Generators::NamedBase
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :model, type: :string, default: "gpt-image-1",
21
+ desc: "The image generation model to use"
22
+ class_option :size, type: :string, default: "1024x1024",
23
+ desc: "Image size (e.g., 1024x1024, 1792x1024)"
24
+ class_option :quality, type: :string, default: "standard",
25
+ desc: "Image quality (standard, hd)"
26
+ class_option :style, type: :string, default: "vivid",
27
+ desc: "Image style (vivid, natural)"
28
+ class_option :content_policy, type: :string, default: "standard",
29
+ desc: "Content policy level (none, standard, moderate, strict)"
30
+ class_option :cache, type: :string, default: nil,
31
+ desc: "Cache TTL (e.g., '1.hour', '1.day')"
32
+ class_option :root,
33
+ type: :string,
34
+ default: nil,
35
+ desc: "Root directory name (default: uses config or 'llm')"
36
+ class_option :namespace,
37
+ type: :string,
38
+ default: nil,
39
+ desc: "Root namespace (default: camelized root or config)"
40
+
41
+ def ensure_base_class_and_skill_file
42
+ @root_namespace = root_namespace
43
+ @image_namespace = "#{root_namespace}::Image"
44
+ generators_dir = "app/#{root_directory}/image/generators"
45
+
46
+ # Create directory if needed
47
+ empty_directory generators_dir
48
+
49
+ # Create base class if it doesn't exist
50
+ base_class_path = "#{generators_dir}/application_image_generator.rb"
51
+ unless File.exist?(File.join(destination_root, base_class_path))
52
+ template "application_image_generator.rb.tt", base_class_path
53
+ end
54
+
55
+ # Create skill file if it doesn't exist
56
+ skill_file_path = "#{generators_dir}/IMAGE_GENERATORS.md"
57
+ unless File.exist?(File.join(destination_root, skill_file_path))
58
+ template "skills/IMAGE_GENERATORS.md.tt", skill_file_path
59
+ end
60
+ end
61
+
62
+ def create_image_generator_file
63
+ # Support nested paths: "product/hero" -> "app/{root}/image/generators/product/hero_generator.rb"
64
+ @root_namespace = root_namespace
65
+ @image_namespace = "#{root_namespace}::Image"
66
+ generator_path = name.underscore
67
+ template "image_generator.rb.tt", "app/#{root_directory}/image/generators/#{generator_path}_generator.rb"
68
+ end
69
+
70
+ def show_usage
71
+ # Build full class name from path
72
+ generator_class_name = name.split("/").map(&:camelize).join("::")
73
+ full_class_name = "#{root_namespace}::Image::#{generator_class_name}Generator"
74
+ say ""
75
+ say "Image generator #{full_class_name} created!", :green
76
+ say ""
77
+ say "Usage:"
78
+ say " # Generate a single image"
79
+ say " result = #{full_class_name}.call(prompt: \"A beautiful sunset\")"
80
+ say " result.url # => \"https://...\""
81
+ say " result.save(\"sunset.png\")"
82
+ say ""
83
+ say " # Generate multiple images"
84
+ say " result = #{full_class_name}.call(prompt: \"Logos\", count: 4)"
85
+ say " result.urls # => [\"https://...\", ...]"
86
+ say ""
87
+ say " # Override settings at runtime"
88
+ say " result = #{full_class_name}.call("
89
+ say " prompt: \"High quality portrait\","
90
+ say " quality: \"hd\","
91
+ say " size: \"1792x1024\""
92
+ say " )"
93
+ say ""
94
+ end
95
+
96
+ private
97
+
98
+ def root_directory
99
+ @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
100
+ end
101
+
102
+ def root_namespace
103
+ @root_namespace ||= options[:namespace] || camelize(root_directory)
104
+ end
105
+
106
+ def camelize(str)
107
+ # Handle special cases for common abbreviations
108
+ return "AI" if str.downcase == "ai"
109
+ return "ML" if str.downcase == "ml"
110
+ return "LLM" if str.downcase == "llm"
111
+
112
+ # Standard camelization
113
+ str.split(/[-_]/).map(&:capitalize).join
114
+ end
115
+ end
116
+ end