ruby_llm-agents 3.0.0 → 3.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.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/controllers/ruby_llm/agents/agents_controller.rb +16 -14
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +20 -20
- data/app/controllers/ruby_llm/agents/executions_controller.rb +5 -7
- data/app/helpers/ruby_llm/agents/application_helper.rb +57 -58
- data/app/models/ruby_llm/agents/execution/analytics.rb +27 -27
- data/app/models/ruby_llm/agents/execution/scopes.rb +4 -6
- data/app/models/ruby_llm/agents/execution.rb +26 -26
- data/app/models/ruby_llm/agents/tenant/budgetable.rb +16 -10
- data/app/models/ruby_llm/agents/tenant/resettable.rb +12 -12
- data/app/models/ruby_llm/agents/tenant/trackable.rb +7 -7
- data/app/services/ruby_llm/agents/agent_registry.rb +6 -6
- data/app/views/layouts/ruby_llm/agents/application.html.erb +142 -11
- data/app/views/ruby_llm/agents/agents/show.html.erb +10 -10
- data/app/views/ruby_llm/agents/dashboard/index.html.erb +10 -10
- data/app/views/ruby_llm/agents/executions/show.html.erb +13 -0
- data/lib/generators/ruby_llm_agents/agent_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/background_remover_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/embedder_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +7 -7
- data/lib/generators/ruby_llm_agents/image_editor_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_generator_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +9 -9
- data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_variator_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/install_generator.rb +3 -3
- data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/multi_tenancy_generator.rb +2 -2
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +13 -13
- data/lib/generators/ruby_llm_agents/speaker_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/templates/add_assistant_prompt_migration.rb.tt +9 -0
- data/lib/generators/ruby_llm_agents/templates/split_execution_details_migration.rb.tt +2 -1
- data/lib/generators/ruby_llm_agents/transcriber_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +22 -3
- data/lib/ruby_llm/agents/audio/speaker.rb +40 -31
- data/lib/ruby_llm/agents/audio/speech_client.rb +328 -0
- data/lib/ruby_llm/agents/audio/speech_pricing.rb +273 -0
- data/lib/ruby_llm/agents/audio/transcriber.rb +33 -33
- data/lib/ruby_llm/agents/base_agent.rb +16 -15
- data/lib/ruby_llm/agents/core/base/callbacks.rb +3 -3
- data/lib/ruby_llm/agents/core/configuration.rb +86 -73
- data/lib/ruby_llm/agents/core/errors.rb +27 -2
- data/lib/ruby_llm/agents/core/instrumentation.rb +101 -65
- data/lib/ruby_llm/agents/core/llm_tenant.rb +7 -7
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/dsl/base.rb +3 -3
- data/lib/ruby_llm/agents/dsl/reliability.rb +9 -9
- data/lib/ruby_llm/agents/image/analyzer/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/analyzer/execution.rb +4 -4
- data/lib/ruby_llm/agents/image/background_remover/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/background_remover/execution.rb +3 -3
- data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +8 -8
- data/lib/ruby_llm/agents/image/editor/execution.rb +1 -1
- data/lib/ruby_llm/agents/image/generator/pricing.rb +9 -10
- data/lib/ruby_llm/agents/image/generator.rb +6 -6
- data/lib/ruby_llm/agents/image/pipeline/dsl.rb +6 -6
- data/lib/ruby_llm/agents/image/pipeline/execution.rb +9 -9
- data/lib/ruby_llm/agents/image/pipeline.rb +1 -1
- data/lib/ruby_llm/agents/image/transformer/execution.rb +1 -1
- data/lib/ruby_llm/agents/image/upscaler/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/upscaler/execution.rb +3 -5
- data/lib/ruby_llm/agents/image/variator/execution.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +4 -4
- data/lib/ruby_llm/agents/infrastructure/attempt_tracker.rb +4 -4
- data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +9 -9
- data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +3 -3
- data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +17 -17
- data/lib/ruby_llm/agents/infrastructure/circuit_breaker.rb +1 -0
- data/lib/ruby_llm/agents/infrastructure/execution_logger_job.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/reliability.rb +6 -6
- data/lib/ruby_llm/agents/pipeline/builder.rb +11 -11
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +3 -3
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +4 -4
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +62 -21
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +2 -3
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +82 -4
- data/lib/ruby_llm/agents/results/background_removal_result.rb +6 -6
- data/lib/ruby_llm/agents/results/embedding_result.rb +15 -15
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +7 -7
- data/lib/ruby_llm/agents/results/image_edit_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_generation_result.rb +5 -5
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_transform_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +5 -5
- data/lib/ruby_llm/agents/results/image_variation_result.rb +4 -4
- data/lib/ruby_llm/agents/results/transcription_result.rb +1 -1
- data/lib/ruby_llm/agents/text/embedder.rb +13 -13
- metadata +4 -1
|
@@ -17,13 +17,13 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "text-embedding-3-small",
|
|
20
|
-
|
|
20
|
+
desc: "The embedding model to use"
|
|
21
21
|
class_option :dimensions, type: :numeric, default: nil,
|
|
22
|
-
|
|
22
|
+
desc: "Vector dimensions (nil for model default)"
|
|
23
23
|
class_option :batch_size, type: :numeric, default: 100,
|
|
24
|
-
|
|
24
|
+
desc: "Texts per API call for batch processing"
|
|
25
25
|
class_option :cache, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Cache TTL (e.g., '1.week', '1.day')"
|
|
27
27
|
|
|
28
28
|
def ensure_base_class_and_skill_file
|
|
29
29
|
embedders_dir = "app/agents/embedders"
|
|
@@ -17,19 +17,19 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "gpt-4o",
|
|
20
|
-
|
|
20
|
+
desc: "The vision model to use"
|
|
21
21
|
class_option :analysis_type, type: :string, default: "detailed",
|
|
22
|
-
|
|
22
|
+
desc: "Analysis type (caption, detailed, tags, objects, colors, all)"
|
|
23
23
|
class_option :extract_colors, type: :boolean, default: false,
|
|
24
|
-
|
|
24
|
+
desc: "Enable color extraction"
|
|
25
25
|
class_option :detect_objects, type: :boolean, default: false,
|
|
26
|
-
|
|
26
|
+
desc: "Enable object detection"
|
|
27
27
|
class_option :extract_text, type: :boolean, default: false,
|
|
28
|
-
|
|
28
|
+
desc: "Enable text extraction (OCR)"
|
|
29
29
|
class_option :max_tags, type: :string, default: "10",
|
|
30
|
-
|
|
30
|
+
desc: "Maximum number of tags to return"
|
|
31
31
|
class_option :cache, type: :string, default: nil,
|
|
32
|
-
|
|
32
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
33
33
|
|
|
34
34
|
def ensure_base_class_and_skill_file
|
|
35
35
|
images_dir = "app/agents/images"
|
|
@@ -17,13 +17,13 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "gpt-image-1",
|
|
20
|
-
|
|
20
|
+
desc: "The image model to use"
|
|
21
21
|
class_option :size, type: :string, default: "1024x1024",
|
|
22
|
-
|
|
22
|
+
desc: "Output image size (e.g., 1024x1024)"
|
|
23
23
|
class_option :content_policy, type: :string, default: "standard",
|
|
24
|
-
|
|
24
|
+
desc: "Content policy level (none, standard, moderate, strict)"
|
|
25
25
|
class_option :cache, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
27
27
|
|
|
28
28
|
def ensure_base_class_and_skill_file
|
|
29
29
|
images_dir = "app/agents/images"
|
|
@@ -17,17 +17,17 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "gpt-image-1",
|
|
20
|
-
|
|
20
|
+
desc: "The image generation model to use"
|
|
21
21
|
class_option :size, type: :string, default: "1024x1024",
|
|
22
|
-
|
|
22
|
+
desc: "Image size (e.g., 1024x1024, 1792x1024)"
|
|
23
23
|
class_option :quality, type: :string, default: "standard",
|
|
24
|
-
|
|
24
|
+
desc: "Image quality (standard, hd)"
|
|
25
25
|
class_option :style, type: :string, default: "vivid",
|
|
26
|
-
|
|
26
|
+
desc: "Image style (vivid, natural)"
|
|
27
27
|
class_option :content_policy, type: :string, default: "standard",
|
|
28
|
-
|
|
28
|
+
desc: "Content policy level (none, standard, moderate, strict)"
|
|
29
29
|
class_option :cache, type: :string, default: nil,
|
|
30
|
-
|
|
30
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
31
31
|
|
|
32
32
|
def ensure_base_class_and_skill_file
|
|
33
33
|
images_dir = "app/agents/images"
|
|
@@ -17,11 +17,11 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :steps, type: :string, default: "generate,upscale",
|
|
20
|
-
|
|
20
|
+
desc: "Pipeline steps (comma-separated: generate,upscale,transform,analyze,remove_background)"
|
|
21
21
|
class_option :stop_on_error, type: :boolean, default: true,
|
|
22
|
-
|
|
22
|
+
desc: "Stop pipeline on first error"
|
|
23
23
|
class_option :cache, type: :string, default: nil,
|
|
24
|
-
|
|
24
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
25
25
|
|
|
26
26
|
def ensure_base_class_and_skill_file
|
|
27
27
|
images_dir = "app/agents/images"
|
|
@@ -132,17 +132,17 @@ module RubyLlmAgents
|
|
|
132
132
|
class_base = name.split("/").map(&:camelize).join("::")
|
|
133
133
|
case step
|
|
134
134
|
when :generate
|
|
135
|
-
{
|
|
135
|
+
{step: step, type: :generator, class_name: "Images::#{class_base}Generator"}
|
|
136
136
|
when :upscale
|
|
137
|
-
{
|
|
137
|
+
{step: step, type: :upscaler, class_name: "Images::#{class_base}Upscaler"}
|
|
138
138
|
when :transform
|
|
139
|
-
{
|
|
139
|
+
{step: step, type: :transformer, class_name: "Images::#{class_base}Transformer"}
|
|
140
140
|
when :analyze
|
|
141
|
-
{
|
|
141
|
+
{step: step, type: :analyzer, class_name: "Images::#{class_base}Analyzer"}
|
|
142
142
|
when :remove_background
|
|
143
|
-
{
|
|
143
|
+
{step: step, type: :remover, class_name: "Images::#{class_base}BackgroundRemover"}
|
|
144
144
|
else
|
|
145
|
-
{
|
|
145
|
+
{step: step, type: step, class_name: "Images::#{class_base}#{step.to_s.camelize}"}
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
end
|
|
@@ -17,17 +17,17 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "sdxl",
|
|
20
|
-
|
|
20
|
+
desc: "The image model to use"
|
|
21
21
|
class_option :size, type: :string, default: "1024x1024",
|
|
22
|
-
|
|
22
|
+
desc: "Output image size (e.g., 1024x1024)"
|
|
23
23
|
class_option :strength, type: :string, default: "0.75",
|
|
24
|
-
|
|
24
|
+
desc: "Transformation strength (0.0-1.0)"
|
|
25
25
|
class_option :template, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Prompt template (use {prompt} as placeholder)"
|
|
27
27
|
class_option :content_policy, type: :string, default: "standard",
|
|
28
|
-
|
|
28
|
+
desc: "Content policy level (none, standard, moderate, strict)"
|
|
29
29
|
class_option :cache, type: :string, default: nil,
|
|
30
|
-
|
|
30
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
31
31
|
|
|
32
32
|
def ensure_base_class_and_skill_file
|
|
33
33
|
images_dir = "app/agents/images"
|
|
@@ -17,13 +17,13 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "real-esrgan",
|
|
20
|
-
|
|
20
|
+
desc: "The upscaling model to use"
|
|
21
21
|
class_option :scale, type: :string, default: "4",
|
|
22
|
-
|
|
22
|
+
desc: "Upscale factor (2, 4, or 8)"
|
|
23
23
|
class_option :face_enhance, type: :boolean, default: false,
|
|
24
|
-
|
|
24
|
+
desc: "Enable face enhancement"
|
|
25
25
|
class_option :cache, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
27
27
|
|
|
28
28
|
def ensure_base_class_and_skill_file
|
|
29
29
|
images_dir = "app/agents/images"
|
|
@@ -17,13 +17,13 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "gpt-image-1",
|
|
20
|
-
|
|
20
|
+
desc: "The image model to use"
|
|
21
21
|
class_option :size, type: :string, default: "1024x1024",
|
|
22
|
-
|
|
22
|
+
desc: "Output image size (e.g., 1024x1024)"
|
|
23
23
|
class_option :variation_strength, type: :string, default: "0.5",
|
|
24
|
-
|
|
24
|
+
desc: "Variation strength (0.0-1.0)"
|
|
25
25
|
class_option :cache, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
27
27
|
|
|
28
28
|
def ensure_base_class_and_skill_file
|
|
29
29
|
images_dir = "app/agents/images"
|
|
@@ -22,11 +22,11 @@ module RubyLlmAgents
|
|
|
22
22
|
source_root File.expand_path("templates", __dir__)
|
|
23
23
|
|
|
24
24
|
class_option :skip_migration, type: :boolean, default: false,
|
|
25
|
-
|
|
25
|
+
desc: "Skip generating the migration file"
|
|
26
26
|
class_option :skip_initializer, type: :boolean, default: false,
|
|
27
|
-
|
|
27
|
+
desc: "Skip generating the initializer file"
|
|
28
28
|
class_option :mount_dashboard, type: :boolean, default: true,
|
|
29
|
-
|
|
29
|
+
desc: "Mount the dashboard engine in routes"
|
|
30
30
|
|
|
31
31
|
def create_migration_file
|
|
32
32
|
return if options[:skip_migration]
|
|
@@ -158,7 +158,7 @@ module RubyLlmAgents
|
|
|
158
158
|
|
|
159
159
|
directories.each do |dir|
|
|
160
160
|
if options[:dry_run]
|
|
161
|
-
say_status :dry_run, "Would create #{dir.sub(Rails.root.to_s +
|
|
161
|
+
say_status :dry_run, "Would create #{dir.sub(Rails.root.to_s + "/", "")}", :yellow
|
|
162
162
|
else
|
|
163
163
|
FileUtils.mkdir_p(dir)
|
|
164
164
|
say_status :mkdir, dir.sub(Rails.root.to_s + "/", ""), :green
|
|
@@ -393,7 +393,7 @@ module RubyLlmAgents
|
|
|
393
393
|
|
|
394
394
|
if content != original_content
|
|
395
395
|
File.write(file_path, content)
|
|
396
|
-
say_status :updated, "base classes in #{file_path.sub(Rails.root.to_s +
|
|
396
|
+
say_status :updated, "base classes in #{file_path.sub(Rails.root.to_s + "/", "")}", :blue
|
|
397
397
|
end
|
|
398
398
|
end
|
|
399
399
|
|
|
@@ -441,7 +441,7 @@ module RubyLlmAgents
|
|
|
441
441
|
next unless File.directory?(subdir) && Dir.empty?(subdir)
|
|
442
442
|
|
|
443
443
|
if options[:dry_run]
|
|
444
|
-
say_status :dry_run, "Would remove empty #{subdir.sub(Rails.root.to_s +
|
|
444
|
+
say_status :dry_run, "Would remove empty #{subdir.sub(Rails.root.to_s + "/", "")}", :yellow
|
|
445
445
|
else
|
|
446
446
|
FileUtils.rmdir(subdir)
|
|
447
447
|
say_status :removed, subdir.sub(Rails.root.to_s + "/", ""), :red
|
|
@@ -452,7 +452,7 @@ module RubyLlmAgents
|
|
|
452
452
|
return unless File.directory?(dir) && Dir.empty?(dir)
|
|
453
453
|
|
|
454
454
|
if options[:dry_run]
|
|
455
|
-
say_status :dry_run, "Would remove empty #{dir.sub(Rails.root.to_s +
|
|
455
|
+
say_status :dry_run, "Would remove empty #{dir.sub(Rails.root.to_s + "/", "")}", :yellow
|
|
456
456
|
else
|
|
457
457
|
FileUtils.rmdir(dir)
|
|
458
458
|
say_status :removed, dir.sub(Rails.root.to_s + "/", ""), :red
|
|
@@ -102,7 +102,7 @@ module RubyLlmAgents
|
|
|
102
102
|
|
|
103
103
|
def table_exists?(table)
|
|
104
104
|
ActiveRecord::Base.connection.table_exists?(table)
|
|
105
|
-
rescue
|
|
105
|
+
rescue
|
|
106
106
|
false
|
|
107
107
|
end
|
|
108
108
|
|
|
@@ -110,7 +110,7 @@ module RubyLlmAgents
|
|
|
110
110
|
return false unless ActiveRecord::Base.connection.table_exists?(table)
|
|
111
111
|
|
|
112
112
|
ActiveRecord::Base.connection.column_exists?(table, column)
|
|
113
|
-
rescue
|
|
113
|
+
rescue
|
|
114
114
|
false
|
|
115
115
|
end
|
|
116
116
|
end
|
|
@@ -37,25 +37,25 @@ module RubyLlmAgents
|
|
|
37
37
|
# Maps old directory -> { category:, type: }
|
|
38
38
|
DIRECTORY_MAPPING = {
|
|
39
39
|
# Top-level under llm/
|
|
40
|
-
"agents" => {
|
|
41
|
-
"tools" => {
|
|
40
|
+
"agents" => {category: nil, type: "agents"},
|
|
41
|
+
"tools" => {category: nil, type: "tools"},
|
|
42
42
|
|
|
43
43
|
# Audio group
|
|
44
|
-
"speakers" => {
|
|
45
|
-
"transcribers" => {
|
|
44
|
+
"speakers" => {category: :audio, type: "speakers"},
|
|
45
|
+
"transcribers" => {category: :audio, type: "transcribers"},
|
|
46
46
|
|
|
47
47
|
# Image group
|
|
48
|
-
"image_generators" => {
|
|
49
|
-
"image_editors" => {
|
|
50
|
-
"image_analyzers" => {
|
|
51
|
-
"image_transformers" => {
|
|
52
|
-
"image_upscalers" => {
|
|
53
|
-
"image_variators" => {
|
|
54
|
-
"background_removers" => {
|
|
48
|
+
"image_generators" => {category: :image, type: "generators"},
|
|
49
|
+
"image_editors" => {category: :image, type: "editors"},
|
|
50
|
+
"image_analyzers" => {category: :image, type: "analyzers"},
|
|
51
|
+
"image_transformers" => {category: :image, type: "transformers"},
|
|
52
|
+
"image_upscalers" => {category: :image, type: "upscalers"},
|
|
53
|
+
"image_variators" => {category: :image, type: "variators"},
|
|
54
|
+
"background_removers" => {category: :image, type: "background_removers"},
|
|
55
55
|
|
|
56
56
|
# Text group
|
|
57
|
-
"embedders" => {
|
|
58
|
-
"moderators" => {
|
|
57
|
+
"embedders" => {category: :text, type: "embedders"},
|
|
58
|
+
"moderators" => {category: :text, type: "moderators"}
|
|
59
59
|
}.freeze
|
|
60
60
|
|
|
61
61
|
def validate_root_directory
|
|
@@ -17,17 +17,17 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :provider, type: :string, default: "openai",
|
|
20
|
-
|
|
20
|
+
desc: "The TTS provider to use (openai, elevenlabs)"
|
|
21
21
|
class_option :model, type: :string, default: nil,
|
|
22
|
-
|
|
22
|
+
desc: "The TTS model to use"
|
|
23
23
|
class_option :voice, type: :string, default: "nova",
|
|
24
|
-
|
|
24
|
+
desc: "The voice to use"
|
|
25
25
|
class_option :speed, type: :numeric, default: 1.0,
|
|
26
|
-
|
|
26
|
+
desc: "Speech speed (0.25-4.0 for OpenAI)"
|
|
27
27
|
class_option :format, type: :string, default: "mp3",
|
|
28
|
-
|
|
28
|
+
desc: "Output format (mp3, wav, ogg, flac)"
|
|
29
29
|
class_option :cache, type: :string, default: nil,
|
|
30
|
-
|
|
30
|
+
desc: "Cache TTL (e.g., '7.days')"
|
|
31
31
|
|
|
32
32
|
def ensure_base_class_and_skill_file
|
|
33
33
|
audio_dir = "app/agents/audio"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddAssistantPromptToExecutionDetails < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
unless column_exists?(:ruby_llm_agents_execution_details, :assistant_prompt)
|
|
6
|
+
add_column :ruby_llm_agents_execution_details, :assistant_prompt, :text
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
class SplitExecutionDetailsFromExecutions < ActiveRecord::Migration<%= migration_version %>
|
|
10
10
|
# Columns that belong on execution_details, not executions
|
|
11
11
|
DETAIL_COLUMNS = %i[
|
|
12
|
-
error_message system_prompt user_prompt response messages_summary
|
|
12
|
+
error_message system_prompt user_prompt assistant_prompt response messages_summary
|
|
13
13
|
tool_calls attempts fallback_chain parameters routed_to
|
|
14
14
|
classification_result cached_at cache_creation_tokens
|
|
15
15
|
].freeze
|
|
@@ -50,6 +50,7 @@ class SplitExecutionDetailsFromExecutions < ActiveRecord::Migration<%= migration
|
|
|
50
50
|
t.text :error_message
|
|
51
51
|
t.text :system_prompt
|
|
52
52
|
t.text :user_prompt
|
|
53
|
+
t.text :assistant_prompt
|
|
53
54
|
t.json :response, default: {}
|
|
54
55
|
t.json :messages_summary, default: {}, null: false
|
|
55
56
|
t.json :tool_calls, default: [], null: false
|
|
@@ -17,13 +17,13 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "whisper-1",
|
|
20
|
-
|
|
20
|
+
desc: "The transcription model to use"
|
|
21
21
|
class_option :language, type: :string, default: nil,
|
|
22
|
-
|
|
22
|
+
desc: "Language code (e.g., 'en', 'es')"
|
|
23
23
|
class_option :output_format, type: :string, default: "text",
|
|
24
|
-
|
|
24
|
+
desc: "Output format (text, srt, vtt, json)"
|
|
25
25
|
class_option :cache, type: :string, default: nil,
|
|
26
|
-
|
|
26
|
+
desc: "Cache TTL (e.g., '30.days')"
|
|
27
27
|
|
|
28
28
|
def ensure_base_class_and_skill_file
|
|
29
29
|
audio_dir = "app/agents/audio"
|
|
@@ -60,6 +60,25 @@ module RubyLlmAgents
|
|
|
60
60
|
)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
# Add assistant_prompt column to execution_details (v3.0 -> v3.1 upgrade)
|
|
64
|
+
def create_add_assistant_prompt_migration
|
|
65
|
+
if column_exists?(:ruby_llm_agents_execution_details, :assistant_prompt)
|
|
66
|
+
say_status :skip, "assistant_prompt column already exists on execution_details", :yellow
|
|
67
|
+
return
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
unless table_exists?(:ruby_llm_agents_execution_details)
|
|
71
|
+
say_status :skip, "execution_details table does not exist yet", :yellow
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
say_status :upgrade, "Adding assistant_prompt to execution_details", :blue
|
|
76
|
+
migration_template(
|
|
77
|
+
"add_assistant_prompt_migration.rb.tt",
|
|
78
|
+
File.join(db_migrate_path, "add_assistant_prompt_to_execution_details.rb")
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
|
|
63
82
|
def suggest_config_consolidation
|
|
64
83
|
ruby_llm_initializer = File.join(destination_root, "config/initializers/ruby_llm.rb")
|
|
65
84
|
agents_initializer = File.join(destination_root, "config/initializers/ruby_llm_agents.rb")
|
|
@@ -116,7 +135,7 @@ module RubyLlmAgents
|
|
|
116
135
|
|
|
117
136
|
# Detail columns that should only exist on execution_details, not executions
|
|
118
137
|
DETAIL_COLUMNS = %i[
|
|
119
|
-
error_message system_prompt user_prompt response messages_summary
|
|
138
|
+
error_message system_prompt user_prompt assistant_prompt response messages_summary
|
|
120
139
|
tool_calls attempts fallback_chain parameters routed_to
|
|
121
140
|
classification_result cached_at cache_creation_tokens
|
|
122
141
|
].freeze
|
|
@@ -145,13 +164,13 @@ module RubyLlmAgents
|
|
|
145
164
|
return false unless ActiveRecord::Base.connection.table_exists?(table)
|
|
146
165
|
|
|
147
166
|
ActiveRecord::Base.connection.column_exists?(table, column)
|
|
148
|
-
rescue
|
|
167
|
+
rescue
|
|
149
168
|
false
|
|
150
169
|
end
|
|
151
170
|
|
|
152
171
|
def table_exists?(table)
|
|
153
172
|
ActiveRecord::Base.connection.table_exists?(table)
|
|
154
|
-
rescue
|
|
173
|
+
rescue
|
|
155
174
|
false
|
|
156
175
|
end
|
|
157
176
|
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "digest"
|
|
4
4
|
require_relative "../results/speech_result"
|
|
5
|
+
require_relative "speech_client"
|
|
6
|
+
require_relative "speech_pricing"
|
|
5
7
|
|
|
6
8
|
module RubyLLM
|
|
7
9
|
module Agents
|
|
@@ -194,19 +196,19 @@ module RubyLLM
|
|
|
194
196
|
|
|
195
197
|
def default_tts_provider
|
|
196
198
|
RubyLLM::Agents.configuration.default_tts_provider
|
|
197
|
-
rescue
|
|
199
|
+
rescue
|
|
198
200
|
:openai
|
|
199
201
|
end
|
|
200
202
|
|
|
201
203
|
def default_tts_model
|
|
202
204
|
RubyLLM::Agents.configuration.default_tts_model
|
|
203
|
-
rescue
|
|
205
|
+
rescue
|
|
204
206
|
"tts-1"
|
|
205
207
|
end
|
|
206
208
|
|
|
207
209
|
def default_tts_voice
|
|
208
210
|
RubyLLM::Agents.configuration.default_tts_voice
|
|
209
|
-
rescue
|
|
211
|
+
rescue
|
|
210
212
|
"nova"
|
|
211
213
|
end
|
|
212
214
|
end
|
|
@@ -410,7 +412,15 @@ module RubyLLM
|
|
|
410
412
|
|
|
411
413
|
# Executes standard (non-streaming) speech synthesis
|
|
412
414
|
def execute_standard_speech(text, options)
|
|
413
|
-
response =
|
|
415
|
+
response = speech_client.speak(
|
|
416
|
+
text,
|
|
417
|
+
model: options[:model],
|
|
418
|
+
voice: options[:voice],
|
|
419
|
+
voice_id: resolved_voice_id,
|
|
420
|
+
speed: options[:speed],
|
|
421
|
+
response_format: options[:response_format] || "mp3",
|
|
422
|
+
voice_settings: options[:voice_settings]
|
|
423
|
+
)
|
|
414
424
|
|
|
415
425
|
{
|
|
416
426
|
audio: response.audio,
|
|
@@ -428,9 +438,17 @@ module RubyLLM
|
|
|
428
438
|
def execute_streaming_speech(text, options)
|
|
429
439
|
audio_chunks = []
|
|
430
440
|
|
|
431
|
-
|
|
441
|
+
speech_client.speak_streaming(
|
|
442
|
+
text,
|
|
443
|
+
model: options[:model],
|
|
444
|
+
voice: options[:voice],
|
|
445
|
+
voice_id: resolved_voice_id,
|
|
446
|
+
speed: options[:speed],
|
|
447
|
+
response_format: options[:response_format] || "mp3",
|
|
448
|
+
voice_settings: options[:voice_settings]
|
|
449
|
+
) do |chunk|
|
|
432
450
|
audio_chunks << chunk.audio if chunk.respond_to?(:audio)
|
|
433
|
-
@streaming_block
|
|
451
|
+
@streaming_block&.call(chunk)
|
|
434
452
|
end
|
|
435
453
|
|
|
436
454
|
{
|
|
@@ -445,7 +463,7 @@ module RubyLLM
|
|
|
445
463
|
}
|
|
446
464
|
end
|
|
447
465
|
|
|
448
|
-
# Builds options for
|
|
466
|
+
# Builds options for SpeechClient
|
|
449
467
|
def build_speak_options
|
|
450
468
|
options = {
|
|
451
469
|
model: resolved_model,
|
|
@@ -453,13 +471,11 @@ module RubyLLM
|
|
|
453
471
|
}
|
|
454
472
|
|
|
455
473
|
speed = resolved_speed
|
|
456
|
-
options[:speed] = speed if speed && speed
|
|
474
|
+
options[:speed] = speed if speed && (speed - 1.0).abs > Float::EPSILON
|
|
457
475
|
options[:response_format] = resolved_output_format.to_s
|
|
458
476
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
options[:voice_settings] = voice_settings.to_h if voice_settings
|
|
462
|
-
end
|
|
477
|
+
voice_settings = self.class.voice_settings_config
|
|
478
|
+
options[:voice_settings] = voice_settings.to_h if voice_settings
|
|
463
479
|
|
|
464
480
|
options
|
|
465
481
|
end
|
|
@@ -488,29 +504,17 @@ module RubyLLM
|
|
|
488
504
|
|
|
489
505
|
# Calculates cost for speech synthesis
|
|
490
506
|
def calculate_cost(raw_result)
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if raw_result[:raw_response].respond_to?(:cost) && raw_result[:raw_response].cost
|
|
507
|
+
if raw_result[:raw_response].respond_to?(:cost) && raw_result[:raw_response]&.cost
|
|
494
508
|
return raw_result[:raw_response].cost
|
|
495
509
|
end
|
|
496
510
|
|
|
497
|
-
|
|
498
|
-
model_name = raw_result[:model].to_s
|
|
499
|
-
|
|
500
|
-
price_per_1k_chars = case provider
|
|
501
|
-
when :openai
|
|
502
|
-
model_name.include?("hd") ? 0.030 : 0.015
|
|
503
|
-
when :elevenlabs
|
|
504
|
-
0.30
|
|
505
|
-
when :google
|
|
506
|
-
0.016
|
|
507
|
-
when :polly
|
|
508
|
-
0.016
|
|
509
|
-
else
|
|
510
|
-
0.015
|
|
511
|
-
end
|
|
511
|
+
characters = raw_result[:characters] || 0
|
|
512
512
|
|
|
513
|
-
(
|
|
513
|
+
Audio::SpeechPricing.calculate_cost(
|
|
514
|
+
provider: raw_result[:provider],
|
|
515
|
+
model_id: raw_result[:model].to_s,
|
|
516
|
+
characters: characters
|
|
517
|
+
)
|
|
514
518
|
end
|
|
515
519
|
|
|
516
520
|
# Resolves the provider to use
|
|
@@ -547,6 +551,11 @@ module RubyLLM
|
|
|
547
551
|
def streaming_enabled?
|
|
548
552
|
@runtime_streaming || self.class.streaming?
|
|
549
553
|
end
|
|
554
|
+
|
|
555
|
+
# Returns a SpeechClient for the resolved provider
|
|
556
|
+
def speech_client
|
|
557
|
+
@speech_client ||= Audio::SpeechClient.new(provider: resolved_provider)
|
|
558
|
+
end
|
|
550
559
|
end
|
|
551
560
|
end
|
|
552
561
|
end
|