ruby_llm-agents 0.5.0 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +189 -31
- data/app/controllers/ruby_llm/agents/agents_controller.rb +136 -16
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +29 -9
- data/app/controllers/ruby_llm/agents/workflows_controller.rb +355 -0
- data/app/helpers/ruby_llm/agents/application_helper.rb +25 -0
- data/app/models/ruby_llm/agents/execution.rb +3 -0
- data/app/models/ruby_llm/agents/tenant_budget.rb +58 -15
- data/app/services/ruby_llm/agents/agent_registry.rb +51 -12
- data/app/views/layouts/ruby_llm/agents/application.html.erb +2 -29
- data/app/views/ruby_llm/agents/agents/_agent.html.erb +13 -1
- data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +235 -0
- data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +70 -0
- data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +152 -0
- data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +63 -0
- data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +108 -0
- data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +91 -0
- data/app/views/ruby_llm/agents/agents/_workflow.html.erb +1 -1
- data/app/views/ruby_llm/agents/agents/index.html.erb +74 -9
- data/app/views/ruby_llm/agents/agents/show.html.erb +18 -378
- data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +269 -15
- data/app/views/ruby_llm/agents/executions/show.html.erb +16 -0
- data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +93 -0
- data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +236 -0
- data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +76 -0
- data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +74 -0
- data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +108 -0
- data/app/views/ruby_llm/agents/workflows/show.html.erb +442 -0
- data/config/routes.rb +1 -0
- data/lib/generators/ruby_llm_agents/agent_generator.rb +56 -7
- data/lib/generators/ruby_llm_agents/background_remover_generator.rb +110 -0
- data/lib/generators/ruby_llm_agents/embedder_generator.rb +107 -0
- data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +115 -0
- data/lib/generators/ruby_llm_agents/image_editor_generator.rb +108 -0
- data/lib/generators/ruby_llm_agents/image_generator_generator.rb +116 -0
- data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +178 -0
- data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +109 -0
- data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +103 -0
- data/lib/generators/ruby_llm_agents/image_variator_generator.rb +102 -0
- data/lib/generators/ruby_llm_agents/install_generator.rb +76 -4
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +292 -0
- data/lib/generators/ruby_llm_agents/speaker_generator.rb +121 -0
- data/lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt +8 -0
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +99 -84
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +42 -40
- data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +26 -0
- data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +50 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +26 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +38 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +139 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +21 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +49 -0
- data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +53 -0
- data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +44 -0
- data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +41 -0
- data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +45 -0
- data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +35 -0
- data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +47 -0
- data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +50 -0
- data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +44 -0
- data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +38 -0
- data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +33 -0
- data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +228 -0
- data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +131 -0
- data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +255 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +102 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +282 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +228 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +110 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +212 -0
- data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +227 -0
- data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +251 -0
- data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +300 -0
- data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +56 -0
- data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +51 -0
- data/lib/generators/ruby_llm_agents/transcriber_generator.rb +107 -0
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +152 -1
- data/lib/ruby_llm/agents/audio/speaker.rb +553 -0
- data/lib/ruby_llm/agents/audio/transcriber.rb +669 -0
- data/lib/ruby_llm/agents/base_agent.rb +675 -0
- data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +181 -0
- data/lib/ruby_llm/agents/core/base/moderation_execution.rb +274 -0
- data/lib/ruby_llm/agents/core/base.rb +135 -0
- data/lib/ruby_llm/agents/core/configuration.rb +981 -0
- data/lib/ruby_llm/agents/core/errors.rb +150 -0
- data/lib/ruby_llm/agents/{instrumentation.rb → core/instrumentation.rb} +22 -1
- data/lib/ruby_llm/agents/core/llm_tenant.rb +358 -0
- data/lib/ruby_llm/agents/{version.rb → core/version.rb} +1 -1
- data/lib/ruby_llm/agents/dsl/base.rb +110 -0
- data/lib/ruby_llm/agents/dsl/caching.rb +142 -0
- data/lib/ruby_llm/agents/dsl/reliability.rb +307 -0
- data/lib/ruby_llm/agents/dsl.rb +41 -0
- data/lib/ruby_llm/agents/image/analyzer/dsl.rb +130 -0
- data/lib/ruby_llm/agents/image/analyzer/execution.rb +402 -0
- data/lib/ruby_llm/agents/image/analyzer.rb +90 -0
- data/lib/ruby_llm/agents/image/background_remover/dsl.rb +154 -0
- data/lib/ruby_llm/agents/image/background_remover/execution.rb +240 -0
- data/lib/ruby_llm/agents/image/background_remover.rb +89 -0
- data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +91 -0
- data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +165 -0
- data/lib/ruby_llm/agents/image/editor/dsl.rb +56 -0
- data/lib/ruby_llm/agents/image/editor/execution.rb +207 -0
- data/lib/ruby_llm/agents/image/editor.rb +92 -0
- data/lib/ruby_llm/agents/image/generator/active_storage_support.rb +127 -0
- data/lib/ruby_llm/agents/image/generator/content_policy.rb +95 -0
- data/lib/ruby_llm/agents/image/generator/pricing.rb +353 -0
- data/lib/ruby_llm/agents/image/generator/templates.rb +124 -0
- data/lib/ruby_llm/agents/image/generator.rb +455 -0
- data/lib/ruby_llm/agents/image/pipeline/dsl.rb +213 -0
- data/lib/ruby_llm/agents/image/pipeline/execution.rb +382 -0
- data/lib/ruby_llm/agents/image/pipeline.rb +97 -0
- data/lib/ruby_llm/agents/image/transformer/dsl.rb +148 -0
- data/lib/ruby_llm/agents/image/transformer/execution.rb +223 -0
- data/lib/ruby_llm/agents/image/transformer.rb +95 -0
- data/lib/ruby_llm/agents/image/upscaler/dsl.rb +83 -0
- data/lib/ruby_llm/agents/image/upscaler/execution.rb +219 -0
- data/lib/ruby_llm/agents/image/upscaler.rb +81 -0
- data/lib/ruby_llm/agents/image/variator/dsl.rb +62 -0
- data/lib/ruby_llm/agents/image/variator/execution.rb +189 -0
- data/lib/ruby_llm/agents/image/variator.rb +80 -0
- data/lib/ruby_llm/agents/{alert_manager.rb → infrastructure/alert_manager.rb} +17 -22
- data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +145 -0
- data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +149 -0
- data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +68 -0
- data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +279 -0
- data/lib/ruby_llm/agents/infrastructure/budget_tracker.rb +275 -0
- data/lib/ruby_llm/agents/{execution_logger_job.rb → infrastructure/execution_logger_job.rb} +17 -1
- data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/executor.rb +2 -1
- data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/retry_strategy.rb +9 -3
- data/lib/ruby_llm/agents/{reliability.rb → infrastructure/reliability.rb} +11 -21
- data/lib/ruby_llm/agents/pipeline/builder.rb +215 -0
- data/lib/ruby_llm/agents/pipeline/context.rb +255 -0
- data/lib/ruby_llm/agents/pipeline/executor.rb +86 -0
- data/lib/ruby_llm/agents/pipeline/middleware/base.rb +124 -0
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +95 -0
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +171 -0
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +415 -0
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +276 -0
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +196 -0
- data/lib/ruby_llm/agents/pipeline.rb +68 -0
- data/lib/ruby_llm/agents/{engine.rb → rails/engine.rb} +79 -11
- data/lib/ruby_llm/agents/results/background_removal_result.rb +286 -0
- data/lib/ruby_llm/agents/{result.rb → results/base.rb} +73 -1
- data/lib/ruby_llm/agents/results/embedding_result.rb +243 -0
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +314 -0
- data/lib/ruby_llm/agents/results/image_edit_result.rb +250 -0
- data/lib/ruby_llm/agents/results/image_generation_result.rb +346 -0
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +399 -0
- data/lib/ruby_llm/agents/results/image_transform_result.rb +251 -0
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +255 -0
- data/lib/ruby_llm/agents/results/image_variation_result.rb +237 -0
- data/lib/ruby_llm/agents/results/moderation_result.rb +158 -0
- data/lib/ruby_llm/agents/results/speech_result.rb +338 -0
- data/lib/ruby_llm/agents/results/transcription_result.rb +408 -0
- data/lib/ruby_llm/agents/text/embedder.rb +444 -0
- data/lib/ruby_llm/agents/text/moderator.rb +237 -0
- data/lib/ruby_llm/agents/workflow/async.rb +220 -0
- data/lib/ruby_llm/agents/workflow/async_executor.rb +156 -0
- data/lib/ruby_llm/agents/{workflow.rb → workflow/orchestrator.rb} +6 -5
- data/lib/ruby_llm/agents/workflow/parallel.rb +34 -17
- data/lib/ruby_llm/agents/workflow/thread_pool.rb +185 -0
- data/lib/ruby_llm/agents.rb +86 -20
- metadata +172 -34
- data/lib/ruby_llm/agents/base/caching.rb +0 -40
- data/lib/ruby_llm/agents/base/cost_calculation.rb +0 -105
- data/lib/ruby_llm/agents/base/dsl.rb +0 -324
- data/lib/ruby_llm/agents/base/execution.rb +0 -366
- data/lib/ruby_llm/agents/base/reliability_dsl.rb +0 -82
- data/lib/ruby_llm/agents/base/reliability_execution.rb +0 -136
- data/lib/ruby_llm/agents/base/response_building.rb +0 -86
- data/lib/ruby_llm/agents/base/tool_tracking.rb +0 -57
- data/lib/ruby_llm/agents/base.rb +0 -210
- data/lib/ruby_llm/agents/budget_tracker.rb +0 -733
- data/lib/ruby_llm/agents/configuration.rb +0 -394
- /data/lib/ruby_llm/agents/{deprecations.rb → core/deprecations.rb} +0 -0
- /data/lib/ruby_llm/agents/{inflections.rb → core/inflections.rb} +0 -0
- /data/lib/ruby_llm/agents/{resolved_config.rb → core/resolved_config.rb} +0 -0
- /data/lib/ruby_llm/agents/{attempt_tracker.rb → infrastructure/attempt_tracker.rb} +0 -0
- /data/lib/ruby_llm/agents/{cache_helper.rb → infrastructure/cache_helper.rb} +0 -0
- /data/lib/ruby_llm/agents/{circuit_breaker.rb → infrastructure/circuit_breaker.rb} +0 -0
- /data/lib/ruby_llm/agents/{redactor.rb → infrastructure/redactor.rb} +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/breaker_manager.rb +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/execution_constraints.rb +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/fallback_routing.rb +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# Transcriber generator for creating new transcribers
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:transcriber Meeting
|
|
10
|
+
# rails generate ruby_llm_agents:transcriber Meeting --model gpt-4o-transcribe
|
|
11
|
+
# rails generate ruby_llm_agents:transcriber Meeting --language es
|
|
12
|
+
# rails generate ruby_llm_agents:transcriber Meeting --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/audio/transcribers/meeting_transcriber.rb
|
|
16
|
+
#
|
|
17
|
+
class TranscriberGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "whisper-1",
|
|
21
|
+
desc: "The transcription model to use"
|
|
22
|
+
class_option :language, type: :string, default: nil,
|
|
23
|
+
desc: "Language code (e.g., 'en', 'es')"
|
|
24
|
+
class_option :output_format, type: :string, default: "text",
|
|
25
|
+
desc: "Output format (text, srt, vtt, json)"
|
|
26
|
+
class_option :cache, type: :string, default: nil,
|
|
27
|
+
desc: "Cache TTL (e.g., '30.days')"
|
|
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
|
+
@audio_namespace = "#{root_namespace}::Audio"
|
|
40
|
+
transcribers_dir = "app/#{root_directory}/audio/transcribers"
|
|
41
|
+
|
|
42
|
+
# Create directory if needed
|
|
43
|
+
empty_directory transcribers_dir
|
|
44
|
+
|
|
45
|
+
# Create base class if it doesn't exist
|
|
46
|
+
base_class_path = "#{transcribers_dir}/application_transcriber.rb"
|
|
47
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
48
|
+
template "application_transcriber.rb.tt", base_class_path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Create skill file if it doesn't exist
|
|
52
|
+
skill_file_path = "#{transcribers_dir}/TRANSCRIBERS.md"
|
|
53
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
54
|
+
template "skills/TRANSCRIBERS.md.tt", skill_file_path
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_transcriber_file
|
|
59
|
+
# Support nested paths: "interview/meeting" -> "app/{root}/audio/transcribers/interview/meeting_transcriber.rb"
|
|
60
|
+
@root_namespace = root_namespace
|
|
61
|
+
@audio_namespace = "#{root_namespace}::Audio"
|
|
62
|
+
transcriber_path = name.underscore
|
|
63
|
+
template "transcriber.rb.tt", "app/#{root_directory}/audio/transcribers/#{transcriber_path}_transcriber.rb"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def show_usage
|
|
67
|
+
# Build full class name from path
|
|
68
|
+
transcriber_class_name = name.split("/").map(&:camelize).join("::")
|
|
69
|
+
full_class_name = "#{root_namespace}::Audio::#{transcriber_class_name}Transcriber"
|
|
70
|
+
say ""
|
|
71
|
+
say "Transcriber #{full_class_name} created!", :green
|
|
72
|
+
say ""
|
|
73
|
+
say "Usage:"
|
|
74
|
+
say " # From file path"
|
|
75
|
+
say " #{full_class_name}.call(audio: \"recording.mp3\")"
|
|
76
|
+
say ""
|
|
77
|
+
say " # From URL"
|
|
78
|
+
say " #{full_class_name}.call(audio: \"https://example.com/audio.mp3\")"
|
|
79
|
+
say ""
|
|
80
|
+
say " # Get subtitles"
|
|
81
|
+
say " result = #{full_class_name}.call(audio: \"video.mp4\")"
|
|
82
|
+
say " result.srt # SRT format"
|
|
83
|
+
say " result.vtt # VTT format"
|
|
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
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
4
|
require "rails/generators/active_record"
|
|
5
|
+
require "fileutils"
|
|
5
6
|
|
|
6
7
|
module RubyLlmAgents
|
|
7
8
|
# Upgrade generator for ruby_llm-agents
|
|
@@ -133,12 +134,62 @@ module RubyLlmAgents
|
|
|
133
134
|
)
|
|
134
135
|
end
|
|
135
136
|
|
|
137
|
+
def create_add_execution_type_migration
|
|
138
|
+
# Check if columns already exist
|
|
139
|
+
if column_exists?(:ruby_llm_agents_executions, :execution_type)
|
|
140
|
+
say_status :skip, "execution_type column already exists", :yellow
|
|
141
|
+
return
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
migration_template(
|
|
145
|
+
"add_execution_type_migration.rb.tt",
|
|
146
|
+
File.join(db_migrate_path, "add_execution_type_to_ruby_llm_agents_executions.rb")
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def migrate_agents_directory
|
|
151
|
+
root_dir = RubyLLM::Agents.configuration.root_directory
|
|
152
|
+
namespace = RubyLLM::Agents.configuration.root_namespace
|
|
153
|
+
migrate_directory("agents", "#{root_dir}/agents", namespace)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def migrate_tools_directory
|
|
157
|
+
root_dir = RubyLLM::Agents.configuration.root_directory
|
|
158
|
+
namespace = RubyLLM::Agents.configuration.root_namespace
|
|
159
|
+
migrate_directory("tools", "#{root_dir}/tools", namespace)
|
|
160
|
+
end
|
|
161
|
+
|
|
136
162
|
def show_post_upgrade_message
|
|
137
163
|
say ""
|
|
138
|
-
say "RubyLLM::Agents upgrade
|
|
164
|
+
say "RubyLLM::Agents upgrade complete!", :green
|
|
139
165
|
say ""
|
|
140
166
|
say "Next steps:"
|
|
141
167
|
say " 1. Run migrations: rails db:migrate"
|
|
168
|
+
say " 2. Update class references in your controllers, views, and tests"
|
|
169
|
+
say " 3. Run your test suite to find any broken references"
|
|
170
|
+
say ""
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def show_migration_summary
|
|
174
|
+
namespace = RubyLLM::Agents.configuration.root_namespace
|
|
175
|
+
root_dir = RubyLLM::Agents.configuration.root_directory
|
|
176
|
+
|
|
177
|
+
return unless @agents_migrated || @tools_migrated
|
|
178
|
+
|
|
179
|
+
say ""
|
|
180
|
+
say "=" * 60
|
|
181
|
+
say " File Migration Summary", :green
|
|
182
|
+
say "=" * 60
|
|
183
|
+
say ""
|
|
184
|
+
say "Your agents and tools have been migrated to the new structure:"
|
|
185
|
+
say ""
|
|
186
|
+
say " app/agents/ → app/#{root_dir}/agents/" if @agents_migrated
|
|
187
|
+
say " app/tools/ → app/#{root_dir}/tools/" if @tools_migrated
|
|
188
|
+
say ""
|
|
189
|
+
say "Classes are now namespaced under #{namespace}::"
|
|
190
|
+
say ""
|
|
191
|
+
say " Before: GeneralAgent.call(...)"
|
|
192
|
+
say " After: #{namespace}::GeneralAgent.call(...)"
|
|
142
193
|
say ""
|
|
143
194
|
end
|
|
144
195
|
|
|
@@ -159,5 +210,105 @@ module RubyLlmAgents
|
|
|
159
210
|
rescue StandardError
|
|
160
211
|
false
|
|
161
212
|
end
|
|
213
|
+
|
|
214
|
+
def migrate_directory(old_dir, new_dir, namespace)
|
|
215
|
+
source = Rails.root.join("app", old_dir)
|
|
216
|
+
destination = Rails.root.join("app", new_dir)
|
|
217
|
+
|
|
218
|
+
# Skip if source doesn't exist
|
|
219
|
+
unless File.directory?(source)
|
|
220
|
+
say_status :skip, "app/#{old_dir}/ does not exist", :yellow
|
|
221
|
+
return
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Skip if source and destination are the same
|
|
225
|
+
if source.to_s == destination.to_s
|
|
226
|
+
say_status :skip, "app/#{old_dir}/ is already at destination", :yellow
|
|
227
|
+
return
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
files_to_migrate = Dir.glob("#{source}/**/*.rb")
|
|
231
|
+
if files_to_migrate.empty?
|
|
232
|
+
say_status :skip, "app/#{old_dir}/ has no Ruby files to migrate", :yellow
|
|
233
|
+
return
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
if options[:pretend]
|
|
237
|
+
say_status :preview, "Would move #{files_to_migrate.size} files from app/#{old_dir}/ → app/#{new_dir}/", :yellow
|
|
238
|
+
files_to_migrate.each do |file|
|
|
239
|
+
relative = file.sub("#{source}/", "")
|
|
240
|
+
say_status :would_move, relative, :cyan
|
|
241
|
+
end
|
|
242
|
+
return
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Create destination directory
|
|
246
|
+
FileUtils.mkdir_p(destination)
|
|
247
|
+
|
|
248
|
+
# Track conflicts and migrated files
|
|
249
|
+
conflicts = []
|
|
250
|
+
migrated = []
|
|
251
|
+
|
|
252
|
+
files_to_migrate.each do |file|
|
|
253
|
+
relative_path = file.sub("#{source}/", "")
|
|
254
|
+
dest_file = File.join(destination, relative_path)
|
|
255
|
+
|
|
256
|
+
# Skip if destination file already exists (conflict)
|
|
257
|
+
if File.exist?(dest_file)
|
|
258
|
+
conflicts << relative_path
|
|
259
|
+
say_status :conflict, "app/#{new_dir}/#{relative_path} already exists, skipping", :red
|
|
260
|
+
next
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
FileUtils.mkdir_p(File.dirname(dest_file))
|
|
264
|
+
FileUtils.mv(file, dest_file)
|
|
265
|
+
|
|
266
|
+
wrap_in_namespace(dest_file, namespace)
|
|
267
|
+
say_status :migrated, "app/#{new_dir}/#{relative_path}", :green
|
|
268
|
+
migrated << relative_path
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Cleanup empty source directory
|
|
272
|
+
cleanup_empty_directory(source, old_dir)
|
|
273
|
+
|
|
274
|
+
# Track that migration happened for summary
|
|
275
|
+
instance_variable_set("@#{old_dir}_migrated", migrated.any?)
|
|
276
|
+
|
|
277
|
+
{ migrated: migrated, conflicts: conflicts }
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def wrap_in_namespace(file, namespace)
|
|
281
|
+
content = File.read(file)
|
|
282
|
+
|
|
283
|
+
# Skip if already namespaced
|
|
284
|
+
return if content.include?("module #{namespace}")
|
|
285
|
+
|
|
286
|
+
# Wrap content in namespace with proper indentation
|
|
287
|
+
indented = content.lines.map { |line| line.empty? || line.strip.empty? ? line : " #{line}" }.join
|
|
288
|
+
wrapped = "module #{namespace}\n#{indented}end\n"
|
|
289
|
+
|
|
290
|
+
File.write(file, wrapped)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def cleanup_empty_directory(dir, dir_name)
|
|
294
|
+
return unless File.directory?(dir)
|
|
295
|
+
|
|
296
|
+
# Remove empty subdirectories first (deepest first)
|
|
297
|
+
Dir.glob("#{dir}/**/", File::FNM_DOTMATCH).sort_by(&:length).reverse.each do |subdir|
|
|
298
|
+
next if subdir.end_with?(".", "..")
|
|
299
|
+
|
|
300
|
+
FileUtils.rmdir(subdir) if File.directory?(subdir) && Dir.empty?(subdir)
|
|
301
|
+
rescue Errno::ENOTEMPTY, Errno::ENOENT
|
|
302
|
+
# Directory not empty or already removed
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Remove main directory if empty
|
|
306
|
+
if File.directory?(dir) && Dir.empty?(dir)
|
|
307
|
+
FileUtils.rmdir(dir)
|
|
308
|
+
say_status :removed, "app/#{dir_name}/ (empty)", :yellow
|
|
309
|
+
end
|
|
310
|
+
rescue Errno::ENOTEMPTY
|
|
311
|
+
say_status :kept, "app/#{dir_name}/ (not empty)", :yellow
|
|
312
|
+
end
|
|
162
313
|
end
|
|
163
314
|
end
|