ruby_llm-agents 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/ruby_llm/agents/paginatable.rb +9 -3
  3. data/app/controllers/concerns/ruby_llm/agents/sortable.rb +58 -0
  4. data/app/controllers/ruby_llm/agents/agents_controller.rb +59 -16
  5. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +144 -20
  6. data/app/controllers/ruby_llm/agents/executions_controller.rb +13 -16
  7. data/app/controllers/ruby_llm/agents/workflows_controller.rb +279 -90
  8. data/app/helpers/ruby_llm/agents/application_helper.rb +100 -0
  9. data/app/mailers/ruby_llm/agents/alert_mailer.rb +84 -0
  10. data/app/mailers/ruby_llm/agents/application_mailer.rb +28 -0
  11. data/app/models/ruby_llm/agents/execution/analytics.rb +170 -20
  12. data/app/models/ruby_llm/agents/execution/scopes.rb +0 -31
  13. data/app/models/ruby_llm/agents/execution/workflow.rb +0 -129
  14. data/app/models/ruby_llm/agents/execution.rb +50 -14
  15. data/app/models/ruby_llm/agents/tenant/budgetable.rb +277 -0
  16. data/app/models/ruby_llm/agents/tenant/configurable.rb +135 -0
  17. data/app/models/ruby_llm/agents/tenant/trackable.rb +310 -0
  18. data/app/models/ruby_llm/agents/tenant.rb +146 -0
  19. data/app/models/ruby_llm/agents/tenant_budget.rb +12 -253
  20. data/app/services/ruby_llm/agents/agent_registry.rb +18 -12
  21. data/app/views/layouts/ruby_llm/agents/application.html.erb +72 -76
  22. data/app/views/ruby_llm/agents/agents/_agent.html.erb +0 -12
  23. data/app/views/ruby_llm/agents/agents/_sortable_header.html.erb +56 -0
  24. data/app/views/ruby_llm/agents/agents/_workflow.html.erb +5 -15
  25. data/app/views/ruby_llm/agents/agents/index.html.erb +271 -100
  26. data/app/views/ruby_llm/agents/agents/show.html.erb +1 -0
  27. data/app/views/ruby_llm/agents/alert_mailer/alert_notification.html.erb +107 -0
  28. data/app/views/ruby_llm/agents/alert_mailer/alert_notification.text.erb +18 -0
  29. data/app/views/ruby_llm/agents/api_configurations/show.html.erb +4 -1
  30. data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +66 -359
  31. data/app/views/ruby_llm/agents/dashboard/_model_comparison.html.erb +56 -0
  32. data/app/views/ruby_llm/agents/dashboard/_model_cost_breakdown.html.erb +115 -0
  33. data/app/views/ruby_llm/agents/dashboard/_now_strip.html.erb +35 -60
  34. data/app/views/ruby_llm/agents/dashboard/_top_errors.html.erb +17 -6
  35. data/app/views/ruby_llm/agents/dashboard/index.html.erb +373 -72
  36. data/app/views/ruby_llm/agents/executions/_execution.html.erb +0 -1
  37. data/app/views/ruby_llm/agents/executions/_filters.html.erb +51 -39
  38. data/app/views/ruby_llm/agents/executions/_list.html.erb +53 -195
  39. data/app/views/ruby_llm/agents/executions/_workflow_summary.html.erb +5 -20
  40. data/app/views/ruby_llm/agents/executions/index.html.erb +7 -83
  41. data/app/views/ruby_llm/agents/executions/show.html.erb +10 -20
  42. data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +2 -1
  43. data/app/views/ruby_llm/agents/shared/_doc_link.html.erb +12 -0
  44. data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +3 -15
  45. data/app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb +1 -1
  46. data/app/views/ruby_llm/agents/shared/_select_dropdown.html.erb +1 -1
  47. data/app/views/ruby_llm/agents/shared/_sortable_header.html.erb +53 -0
  48. data/app/views/ruby_llm/agents/shared/_status_badge.html.erb +7 -0
  49. data/app/views/ruby_llm/agents/shared/_status_dot.html.erb +1 -1
  50. data/app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb +9 -35
  51. data/app/views/ruby_llm/agents/system_config/show.html.erb +4 -1
  52. data/app/views/ruby_llm/agents/tenants/index.html.erb +4 -1
  53. data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +7 -15
  54. data/app/views/ruby_llm/agents/workflows/_structure_dsl.html.erb +539 -0
  55. data/app/views/ruby_llm/agents/workflows/_workflow_diagram.html.erb +920 -0
  56. data/app/views/ruby_llm/agents/workflows/index.html.erb +179 -0
  57. data/app/views/ruby_llm/agents/workflows/show.html.erb +164 -139
  58. data/config/routes.rb +1 -1
  59. data/lib/generators/ruby_llm_agents/agent_generator.rb +6 -36
  60. data/lib/generators/ruby_llm_agents/background_remover_generator.rb +7 -37
  61. data/lib/generators/ruby_llm_agents/embedder_generator.rb +5 -38
  62. data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +7 -37
  63. data/lib/generators/ruby_llm_agents/image_editor_generator.rb +7 -37
  64. data/lib/generators/ruby_llm_agents/image_generator_generator.rb +8 -41
  65. data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +18 -46
  66. data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +7 -37
  67. data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +7 -37
  68. data/lib/generators/ruby_llm_agents/image_variator_generator.rb +7 -37
  69. data/lib/generators/ruby_llm_agents/install_generator.rb +33 -56
  70. data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +480 -0
  71. data/lib/generators/ruby_llm_agents/multi_tenancy_generator.rb +42 -22
  72. data/lib/generators/ruby_llm_agents/restructure_generator.rb +2 -2
  73. data/lib/generators/ruby_llm_agents/speaker_generator.rb +8 -39
  74. data/lib/generators/ruby_llm_agents/templates/add_tenant_to_executions_migration.rb.tt +13 -2
  75. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +5 -8
  76. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +40 -42
  77. data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +20 -22
  78. data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +24 -26
  79. data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +20 -22
  80. data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +19 -17
  81. data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +31 -33
  82. data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +125 -127
  83. data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +20 -18
  84. data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +19 -17
  85. data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +19 -17
  86. data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +38 -40
  87. data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +42 -44
  88. data/lib/generators/ruby_llm_agents/templates/application_workflow.rb.tt +48 -0
  89. data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +19 -21
  90. data/lib/generators/ruby_llm_agents/templates/create_tenant_budgets_migration.rb.tt +11 -0
  91. data/lib/generators/ruby_llm_agents/templates/create_tenants_migration.rb.tt +72 -0
  92. data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +19 -21
  93. data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +20 -22
  94. data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +15 -17
  95. data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +25 -27
  96. data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +19 -21
  97. data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +20 -22
  98. data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +17 -19
  99. data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +15 -17
  100. data/lib/generators/ruby_llm_agents/templates/rename_tenant_budgets_to_tenants_migration.rb.tt +34 -0
  101. data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +87 -24
  102. data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +21 -27
  103. data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +46 -54
  104. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +31 -39
  105. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +22 -28
  106. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +53 -63
  107. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +46 -56
  108. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +23 -31
  109. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +22 -30
  110. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +23 -31
  111. data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +38 -46
  112. data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +7 -7
  113. data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +59 -71
  114. data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +274 -23
  115. data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +29 -31
  116. data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +28 -30
  117. data/lib/generators/ruby_llm_agents/transcriber_generator.rb +10 -43
  118. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +26 -0
  119. data/lib/ruby_llm/agents/core/configuration.rb +55 -43
  120. data/lib/ruby_llm/agents/core/llm_tenant.rb +60 -60
  121. data/lib/ruby_llm/agents/core/version.rb +1 -1
  122. data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +26 -0
  123. data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +4 -2
  124. data/lib/ruby_llm/agents/pipeline.rb +69 -0
  125. data/lib/ruby_llm/agents/workflow/approval.rb +205 -0
  126. data/lib/ruby_llm/agents/workflow/approval_store.rb +179 -0
  127. data/lib/ruby_llm/agents/workflow/dsl/executor.rb +467 -0
  128. data/lib/ruby_llm/agents/workflow/dsl/input_schema.rb +244 -0
  129. data/lib/ruby_llm/agents/workflow/dsl/iteration_executor.rb +289 -0
  130. data/lib/ruby_llm/agents/workflow/dsl/parallel_group.rb +107 -0
  131. data/lib/ruby_llm/agents/workflow/dsl/route_builder.rb +150 -0
  132. data/lib/ruby_llm/agents/workflow/dsl/schedule_helpers.rb +187 -0
  133. data/lib/ruby_llm/agents/workflow/dsl/step_config.rb +352 -0
  134. data/lib/ruby_llm/agents/workflow/dsl/step_executor.rb +415 -0
  135. data/lib/ruby_llm/agents/workflow/dsl/wait_config.rb +257 -0
  136. data/lib/ruby_llm/agents/workflow/dsl/wait_executor.rb +317 -0
  137. data/lib/ruby_llm/agents/workflow/dsl.rb +576 -0
  138. data/lib/ruby_llm/agents/workflow/instrumentation.rb +2 -7
  139. data/lib/ruby_llm/agents/workflow/notifiers/base.rb +117 -0
  140. data/lib/ruby_llm/agents/workflow/notifiers/email.rb +117 -0
  141. data/lib/ruby_llm/agents/workflow/notifiers/slack.rb +180 -0
  142. data/lib/ruby_llm/agents/workflow/notifiers/webhook.rb +121 -0
  143. data/lib/ruby_llm/agents/workflow/notifiers.rb +70 -0
  144. data/lib/ruby_llm/agents/workflow/orchestrator.rb +190 -23
  145. data/lib/ruby_llm/agents/workflow/result.rb +202 -0
  146. data/lib/ruby_llm/agents/workflow/throttle_manager.rb +206 -0
  147. data/lib/ruby_llm/agents/workflow/wait_result.rb +213 -0
  148. metadata +43 -6
  149. data/app/views/ruby_llm/agents/dashboard/_execution_item.html.erb +0 -66
  150. data/lib/ruby_llm/agents/workflow/parallel.rb +0 -299
  151. data/lib/ruby_llm/agents/workflow/pipeline.rb +0 -306
  152. data/lib/ruby_llm/agents/workflow/router.rb +0 -429
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:background_remover Product
10
10
  # rails generate ruby_llm_agents:background_remover Portrait --model segment-anything --alpha_matting
11
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
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/background_removers/product_background_remover.rb
14
+ # - app/agents/images/product_background_remover.rb
16
15
  #
17
16
  class BackgroundRemoverGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -29,46 +28,34 @@ module RubyLlmAgents
29
28
  desc: "Also return the segmentation mask"
30
29
  class_option :cache, type: :string, default: nil,
31
30
  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
31
 
41
32
  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"
33
+ images_dir = "app/agents/images"
45
34
 
46
35
  # Create directory if needed
47
- empty_directory removers_dir
36
+ empty_directory images_dir
48
37
 
49
38
  # Create base class if it doesn't exist
50
- base_class_path = "#{removers_dir}/application_background_remover.rb"
39
+ base_class_path = "#{images_dir}/application_background_remover.rb"
51
40
  unless File.exist?(File.join(destination_root, base_class_path))
52
41
  template "application_background_remover.rb.tt", base_class_path
53
42
  end
54
43
 
55
44
  # Create skill file if it doesn't exist
56
- skill_file_path = "#{removers_dir}/BACKGROUND_REMOVERS.md"
45
+ skill_file_path = "#{images_dir}/BACKGROUND_REMOVERS.md"
57
46
  unless File.exist?(File.join(destination_root, skill_file_path))
58
47
  template "skills/BACKGROUND_REMOVERS.md.tt", skill_file_path
59
48
  end
60
49
  end
61
50
 
62
51
  def create_background_remover_file
63
- @root_namespace = root_namespace
64
- @image_namespace = "#{root_namespace}::Image"
65
52
  remover_path = name.underscore
66
- template "background_remover.rb.tt", "app/#{root_directory}/image/background_removers/#{remover_path}_background_remover.rb"
53
+ template "background_remover.rb.tt", "app/agents/images/#{remover_path}_background_remover.rb"
67
54
  end
68
55
 
69
56
  def show_usage
70
57
  remover_class_name = name.split("/").map(&:camelize).join("::")
71
- full_class_name = "#{root_namespace}::Image::#{remover_class_name}BackgroundRemover"
58
+ full_class_name = "Images::#{remover_class_name}BackgroundRemover"
72
59
  say ""
73
60
  say "Background remover #{full_class_name} created!", :green
74
61
  say ""
@@ -89,22 +76,5 @@ module RubyLlmAgents
89
76
  say " result.mask_url # => 'https://...' (if return_mask was enabled)"
90
77
  say ""
91
78
  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
79
  end
110
80
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:embedder Document
10
10
  # rails generate ruby_llm_agents:embedder Document --model text-embedding-3-large
11
11
  # rails generate ruby_llm_agents:embedder Document --dimensions 512
12
- # rails generate ruby_llm_agents:embedder Document --root=ai
13
12
  #
14
13
  # This will create:
15
- # - app/{root}/text/embedders/document_embedder.rb
14
+ # - app/agents/embedders/document_embedder.rb
16
15
  #
17
16
  class EmbedderGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -25,19 +24,9 @@ module RubyLlmAgents
25
24
  desc: "Texts per API call for batch processing"
26
25
  class_option :cache, type: :string, default: nil,
27
26
  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
27
 
37
28
  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"
29
+ embedders_dir = "app/agents/embedders"
41
30
 
42
31
  # Create directory if needed
43
32
  empty_directory embedders_dir
@@ -56,17 +45,15 @@ module RubyLlmAgents
56
45
  end
57
46
 
58
47
  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"
48
+ # Support nested paths: "search/document" -> "app/agents/embedders/search/document_embedder.rb"
62
49
  embedder_path = name.underscore
63
- template "embedder.rb.tt", "app/#{root_directory}/text/embedders/#{embedder_path}_embedder.rb"
50
+ template "embedder.rb.tt", "app/agents/embedders/#{embedder_path}_embedder.rb"
64
51
  end
65
52
 
66
53
  def show_usage
67
54
  # Build full class name from path
68
55
  embedder_class_name = name.split("/").map(&:camelize).join("::")
69
- full_class_name = "#{root_namespace}::Text::#{embedder_class_name}Embedder"
56
+ full_class_name = "Embedders::#{embedder_class_name}Embedder"
70
57
  say ""
71
58
  say "Embedder #{full_class_name} created!", :green
72
59
  say ""
@@ -83,25 +70,5 @@ module RubyLlmAgents
83
70
  say " end"
84
71
  say ""
85
72
  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
73
  end
107
74
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:image_analyzer Product
10
10
  # rails generate ruby_llm_agents:image_analyzer Content --model gpt-4o --analysis_type detailed
11
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
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/analyzers/product_analyzer.rb
14
+ # - app/agents/images/product_analyzer.rb
16
15
  #
17
16
  class ImageAnalyzerGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -31,46 +30,34 @@ module RubyLlmAgents
31
30
  desc: "Maximum number of tags to return"
32
31
  class_option :cache, type: :string, default: nil,
33
32
  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
33
 
43
34
  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"
35
+ images_dir = "app/agents/images"
47
36
 
48
37
  # Create directory if needed
49
- empty_directory analyzers_dir
38
+ empty_directory images_dir
50
39
 
51
40
  # Create base class if it doesn't exist
52
- base_class_path = "#{analyzers_dir}/application_image_analyzer.rb"
41
+ base_class_path = "#{images_dir}/application_image_analyzer.rb"
53
42
  unless File.exist?(File.join(destination_root, base_class_path))
54
43
  template "application_image_analyzer.rb.tt", base_class_path
55
44
  end
56
45
 
57
46
  # Create skill file if it doesn't exist
58
- skill_file_path = "#{analyzers_dir}/IMAGE_ANALYZERS.md"
47
+ skill_file_path = "#{images_dir}/IMAGE_ANALYZERS.md"
59
48
  unless File.exist?(File.join(destination_root, skill_file_path))
60
49
  template "skills/IMAGE_ANALYZERS.md.tt", skill_file_path
61
50
  end
62
51
  end
63
52
 
64
53
  def create_image_analyzer_file
65
- @root_namespace = root_namespace
66
- @image_namespace = "#{root_namespace}::Image"
67
54
  analyzer_path = name.underscore
68
- template "image_analyzer.rb.tt", "app/#{root_directory}/image/analyzers/#{analyzer_path}_analyzer.rb"
55
+ template "image_analyzer.rb.tt", "app/agents/images/#{analyzer_path}_analyzer.rb"
69
56
  end
70
57
 
71
58
  def show_usage
72
59
  analyzer_class_name = name.split("/").map(&:camelize).join("::")
73
- full_class_name = "#{root_namespace}::Image::#{analyzer_class_name}Analyzer"
60
+ full_class_name = "Images::#{analyzer_class_name}Analyzer"
74
61
  say ""
75
62
  say "Image analyzer #{full_class_name} created!", :green
76
63
  say ""
@@ -94,22 +81,5 @@ module RubyLlmAgents
94
81
  say " result.colors # => [{hex: '#C0C0C0', name: 'silver', percentage: 45}]"
95
82
  say ""
96
83
  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
84
  end
115
85
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:image_editor Product
10
10
  # rails generate ruby_llm_agents:image_editor Background --model gpt-image-1 --size 1024x1024
11
11
  # rails generate ruby_llm_agents:image_editor Photo --content_policy strict
12
- # rails generate ruby_llm_agents:image_editor Product --root=ai
13
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/editors/product_editor.rb
14
+ # - app/agents/images/product_editor.rb
16
15
  #
17
16
  class ImageEditorGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -25,46 +24,34 @@ module RubyLlmAgents
25
24
  desc: "Content policy level (none, standard, moderate, strict)"
26
25
  class_option :cache, type: :string, default: nil,
27
26
  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
27
 
37
28
  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"
29
+ images_dir = "app/agents/images"
41
30
 
42
31
  # Create directory if needed
43
- empty_directory editors_dir
32
+ empty_directory images_dir
44
33
 
45
34
  # Create base class if it doesn't exist
46
- base_class_path = "#{editors_dir}/application_image_editor.rb"
35
+ base_class_path = "#{images_dir}/application_image_editor.rb"
47
36
  unless File.exist?(File.join(destination_root, base_class_path))
48
37
  template "application_image_editor.rb.tt", base_class_path
49
38
  end
50
39
 
51
40
  # Create skill file if it doesn't exist
52
- skill_file_path = "#{editors_dir}/IMAGE_EDITORS.md"
41
+ skill_file_path = "#{images_dir}/IMAGE_EDITORS.md"
53
42
  unless File.exist?(File.join(destination_root, skill_file_path))
54
43
  template "skills/IMAGE_EDITORS.md.tt", skill_file_path
55
44
  end
56
45
  end
57
46
 
58
47
  def create_image_editor_file
59
- @root_namespace = root_namespace
60
- @image_namespace = "#{root_namespace}::Image"
61
48
  editor_path = name.underscore
62
- template "image_editor.rb.tt", "app/#{root_directory}/image/editors/#{editor_path}_editor.rb"
49
+ template "image_editor.rb.tt", "app/agents/images/#{editor_path}_editor.rb"
63
50
  end
64
51
 
65
52
  def show_usage
66
53
  editor_class_name = name.split("/").map(&:camelize).join("::")
67
- full_class_name = "#{root_namespace}::Image::#{editor_class_name}Editor"
54
+ full_class_name = "Images::#{editor_class_name}Editor"
68
55
  say ""
69
56
  say "Image editor #{full_class_name} created!", :green
70
57
  say ""
@@ -87,22 +74,5 @@ module RubyLlmAgents
87
74
  say " result.urls # => ['https://...', ...]"
88
75
  say ""
89
76
  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
77
  end
108
78
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:image_generator Logo
10
10
  # rails generate ruby_llm_agents:image_generator Product --model gpt-image-1 --size 1024x1024
11
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
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/generators/logo_generator.rb
14
+ # - app/agents/images/logo_generator.rb
16
15
  #
17
16
  class ImageGeneratorGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -29,48 +28,36 @@ module RubyLlmAgents
29
28
  desc: "Content policy level (none, standard, moderate, strict)"
30
29
  class_option :cache, type: :string, default: nil,
31
30
  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
31
 
41
32
  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"
33
+ images_dir = "app/agents/images"
45
34
 
46
35
  # Create directory if needed
47
- empty_directory generators_dir
36
+ empty_directory images_dir
48
37
 
49
38
  # Create base class if it doesn't exist
50
- base_class_path = "#{generators_dir}/application_image_generator.rb"
39
+ base_class_path = "#{images_dir}/application_image_generator.rb"
51
40
  unless File.exist?(File.join(destination_root, base_class_path))
52
41
  template "application_image_generator.rb.tt", base_class_path
53
42
  end
54
43
 
55
44
  # Create skill file if it doesn't exist
56
- skill_file_path = "#{generators_dir}/IMAGE_GENERATORS.md"
45
+ skill_file_path = "#{images_dir}/IMAGE_GENERATORS.md"
57
46
  unless File.exist?(File.join(destination_root, skill_file_path))
58
47
  template "skills/IMAGE_GENERATORS.md.tt", skill_file_path
59
48
  end
60
49
  end
61
50
 
62
51
  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"
52
+ # Support nested paths: "product/hero" -> "app/agents/images/product/hero_generator.rb"
66
53
  generator_path = name.underscore
67
- template "image_generator.rb.tt", "app/#{root_directory}/image/generators/#{generator_path}_generator.rb"
54
+ template "image_generator.rb.tt", "app/agents/images/#{generator_path}_generator.rb"
68
55
  end
69
56
 
70
57
  def show_usage
71
58
  # Build full class name from path
72
59
  generator_class_name = name.split("/").map(&:camelize).join("::")
73
- full_class_name = "#{root_namespace}::Image::#{generator_class_name}Generator"
60
+ full_class_name = "Images::#{generator_class_name}Generator"
74
61
  say ""
75
62
  say "Image generator #{full_class_name} created!", :green
76
63
  say ""
@@ -92,25 +79,5 @@ module RubyLlmAgents
92
79
  say " )"
93
80
  say ""
94
81
  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
82
  end
116
83
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:image_pipeline Product
10
10
  # rails generate ruby_llm_agents:image_pipeline Ecommerce --steps generate,upscale,remove_background
11
11
  # rails generate ruby_llm_agents:image_pipeline Content --steps generate,analyze
12
- # rails generate ruby_llm_agents:image_pipeline Product --root=ai
13
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/pipelines/product_pipeline.rb
14
+ # - app/agents/images/product_pipeline.rb
16
15
  #
17
16
  class ImagePipelineGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -23,41 +22,29 @@ module RubyLlmAgents
23
22
  desc: "Stop pipeline on first error"
24
23
  class_option :cache, type: :string, default: nil,
25
24
  desc: "Cache TTL (e.g., '1.hour', '1.day')"
26
- class_option :root,
27
- type: :string,
28
- default: nil,
29
- desc: "Root directory name (default: uses config or 'llm')"
30
- class_option :namespace,
31
- type: :string,
32
- default: nil,
33
- desc: "Root namespace (default: camelized root or config)"
34
25
 
35
26
  def ensure_base_class_and_skill_file
36
- @root_namespace = root_namespace
37
- @image_namespace = "#{root_namespace}::Image"
38
- pipelines_dir = "app/#{root_directory}/image/pipelines"
27
+ images_dir = "app/agents/images"
39
28
 
40
29
  # Create directory if needed
41
- empty_directory pipelines_dir
30
+ empty_directory images_dir
42
31
 
43
32
  # Create base class if it doesn't exist
44
- base_class_path = "#{pipelines_dir}/application_image_pipeline.rb"
33
+ base_class_path = "#{images_dir}/application_image_pipeline.rb"
45
34
  unless File.exist?(File.join(destination_root, base_class_path))
46
35
  template "application_image_pipeline.rb.tt", base_class_path
47
36
  end
48
37
 
49
38
  # Create skill file if it doesn't exist
50
- skill_file_path = "#{pipelines_dir}/IMAGE_PIPELINES.md"
39
+ skill_file_path = "#{images_dir}/IMAGE_PIPELINES.md"
51
40
  unless File.exist?(File.join(destination_root, skill_file_path))
52
41
  template "skills/IMAGE_PIPELINES.md.tt", skill_file_path
53
42
  end
54
43
  end
55
44
 
56
45
  def create_image_pipeline_file
57
- @root_namespace = root_namespace
58
- @image_namespace = "#{root_namespace}::Image"
59
46
  pipeline_path = name.underscore
60
- template "image_pipeline.rb.tt", "app/#{root_directory}/image/pipelines/#{pipeline_path}_pipeline.rb"
47
+ template "image_pipeline.rb.tt", "app/agents/images/#{pipeline_path}_pipeline.rb"
61
48
  end
62
49
 
63
50
  def create_step_classes
@@ -69,7 +56,7 @@ module RubyLlmAgents
69
56
 
70
57
  def show_usage
71
58
  pipeline_class_name = name.split("/").map(&:camelize).join("::")
72
- full_class_name = "#{root_namespace}::Image::#{pipeline_class_name}Pipeline"
59
+ full_class_name = "Images::#{pipeline_class_name}Pipeline"
73
60
  say ""
74
61
  say "Image pipeline #{full_class_name} created!", :green
75
62
  say ""
@@ -98,21 +85,6 @@ module RubyLlmAgents
98
85
 
99
86
  private
100
87
 
101
- def root_directory
102
- @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
103
- end
104
-
105
- def root_namespace
106
- @root_namespace ||= options[:namespace] || camelize(root_directory)
107
- end
108
-
109
- def camelize(str)
110
- return "AI" if str.downcase == "ai"
111
- return "ML" if str.downcase == "ml"
112
- return "LLM" if str.downcase == "llm"
113
- str.split(/[-_]/).map(&:capitalize).join
114
- end
115
-
116
88
  def parsed_steps
117
89
  options[:steps].to_s.split(",").map(&:strip).map(&:to_sym)
118
90
  end
@@ -120,15 +92,15 @@ module RubyLlmAgents
120
92
  def should_create_stub?(step)
121
93
  case step
122
94
  when :generate
123
- !File.exist?("app/#{root_directory}/image/generators/#{name.underscore}_generator.rb")
95
+ !File.exist?("app/agents/images/#{name.underscore}_generator.rb")
124
96
  when :upscale
125
- !File.exist?("app/#{root_directory}/image/upscalers/#{name.underscore}_upscaler.rb")
97
+ !File.exist?("app/agents/images/#{name.underscore}_upscaler.rb")
126
98
  when :transform
127
- !File.exist?("app/#{root_directory}/image/transformers/#{name.underscore}_transformer.rb")
99
+ !File.exist?("app/agents/images/#{name.underscore}_transformer.rb")
128
100
  when :analyze
129
- !File.exist?("app/#{root_directory}/image/analyzers/#{name.underscore}_analyzer.rb")
101
+ !File.exist?("app/agents/images/#{name.underscore}_analyzer.rb")
130
102
  when :remove_background
131
- !File.exist?("app/#{root_directory}/image/background_removers/#{name.underscore}_background_remover.rb")
103
+ !File.exist?("app/agents/images/#{name.underscore}_background_remover.rb")
132
104
  else
133
105
  false
134
106
  end
@@ -160,17 +132,17 @@ module RubyLlmAgents
160
132
  class_base = name.split("/").map(&:camelize).join("::")
161
133
  case step
162
134
  when :generate
163
- { step: step, type: :generator, class_name: "#{@image_namespace}::#{class_base}Generator" }
135
+ { step: step, type: :generator, class_name: "Images::#{class_base}Generator" }
164
136
  when :upscale
165
- { step: step, type: :upscaler, class_name: "#{@image_namespace}::#{class_base}Upscaler" }
137
+ { step: step, type: :upscaler, class_name: "Images::#{class_base}Upscaler" }
166
138
  when :transform
167
- { step: step, type: :transformer, class_name: "#{@image_namespace}::#{class_base}Transformer" }
139
+ { step: step, type: :transformer, class_name: "Images::#{class_base}Transformer" }
168
140
  when :analyze
169
- { step: step, type: :analyzer, class_name: "#{@image_namespace}::#{class_base}Analyzer" }
141
+ { step: step, type: :analyzer, class_name: "Images::#{class_base}Analyzer" }
170
142
  when :remove_background
171
- { step: step, type: :remover, class_name: "#{@image_namespace}::#{class_base}BackgroundRemover" }
143
+ { step: step, type: :remover, class_name: "Images::#{class_base}BackgroundRemover" }
172
144
  else
173
- { step: step, type: step, class_name: "#{@image_namespace}::#{class_base}#{step.to_s.camelize}" }
145
+ { step: step, type: step, class_name: "Images::#{class_base}#{step.to_s.camelize}" }
174
146
  end
175
147
  end
176
148
  end
@@ -9,10 +9,9 @@ module RubyLlmAgents
9
9
  # rails generate ruby_llm_agents:image_transformer Anime
10
10
  # rails generate ruby_llm_agents:image_transformer Watercolor --model sdxl --strength 0.8
11
11
  # rails generate ruby_llm_agents:image_transformer Oil --template "oil painting, {prompt}"
12
- # rails generate ruby_llm_agents:image_transformer Anime --root=ai
13
12
  #
14
13
  # This will create:
15
- # - app/{root}/image/transformers/anime_transformer.rb
14
+ # - app/agents/images/anime_transformer.rb
16
15
  #
17
16
  class ImageTransformerGenerator < ::Rails::Generators::NamedBase
18
17
  source_root File.expand_path("templates", __dir__)
@@ -29,46 +28,34 @@ module RubyLlmAgents
29
28
  desc: "Content policy level (none, standard, moderate, strict)"
30
29
  class_option :cache, type: :string, default: nil,
31
30
  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
31
 
41
32
  def ensure_base_class_and_skill_file
42
- @root_namespace = root_namespace
43
- @image_namespace = "#{root_namespace}::Image"
44
- transformers_dir = "app/#{root_directory}/image/transformers"
33
+ images_dir = "app/agents/images"
45
34
 
46
35
  # Create directory if needed
47
- empty_directory transformers_dir
36
+ empty_directory images_dir
48
37
 
49
38
  # Create base class if it doesn't exist
50
- base_class_path = "#{transformers_dir}/application_image_transformer.rb"
39
+ base_class_path = "#{images_dir}/application_image_transformer.rb"
51
40
  unless File.exist?(File.join(destination_root, base_class_path))
52
41
  template "application_image_transformer.rb.tt", base_class_path
53
42
  end
54
43
 
55
44
  # Create skill file if it doesn't exist
56
- skill_file_path = "#{transformers_dir}/IMAGE_TRANSFORMERS.md"
45
+ skill_file_path = "#{images_dir}/IMAGE_TRANSFORMERS.md"
57
46
  unless File.exist?(File.join(destination_root, skill_file_path))
58
47
  template "skills/IMAGE_TRANSFORMERS.md.tt", skill_file_path
59
48
  end
60
49
  end
61
50
 
62
51
  def create_image_transformer_file
63
- @root_namespace = root_namespace
64
- @image_namespace = "#{root_namespace}::Image"
65
52
  transformer_path = name.underscore
66
- template "image_transformer.rb.tt", "app/#{root_directory}/image/transformers/#{transformer_path}_transformer.rb"
53
+ template "image_transformer.rb.tt", "app/agents/images/#{transformer_path}_transformer.rb"
67
54
  end
68
55
 
69
56
  def show_usage
70
57
  transformer_class_name = name.split("/").map(&:camelize).join("::")
71
- full_class_name = "#{root_namespace}::Image::#{transformer_class_name}Transformer"
58
+ full_class_name = "Images::#{transformer_class_name}Transformer"
72
59
  say ""
73
60
  say "Image transformer #{full_class_name} created!", :green
74
61
  say ""
@@ -88,22 +75,5 @@ module RubyLlmAgents
88
75
  say " )"
89
76
  say ""
90
77
  end
91
-
92
- private
93
-
94
- def root_directory
95
- @root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
96
- end
97
-
98
- def root_namespace
99
- @root_namespace ||= options[:namespace] || camelize(root_directory)
100
- end
101
-
102
- def camelize(str)
103
- return "AI" if str.downcase == "ai"
104
- return "ML" if str.downcase == "ml"
105
- return "LLM" if str.downcase == "llm"
106
- str.split(/[-_]/).map(&:capitalize).join
107
- end
108
78
  end
109
79
  end