ruby_llm-agents 3.8.0 → 3.10.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -10
  3. data/app/controllers/ruby_llm/agents/requests_controller.rb +117 -0
  4. data/app/models/ruby_llm/agents/execution.rb +4 -0
  5. data/app/models/ruby_llm/agents/tool_execution.rb +25 -0
  6. data/app/views/layouts/ruby_llm/agents/application.html.erb +4 -2
  7. data/app/views/ruby_llm/agents/requests/index.html.erb +153 -0
  8. data/app/views/ruby_llm/agents/requests/show.html.erb +136 -0
  9. data/config/routes.rb +2 -0
  10. data/lib/generators/ruby_llm_agents/agent_generator.rb +2 -2
  11. data/lib/generators/ruby_llm_agents/demo_generator.rb +102 -0
  12. data/lib/generators/ruby_llm_agents/doctor_generator.rb +196 -0
  13. data/lib/generators/ruby_llm_agents/install_generator.rb +7 -19
  14. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +27 -80
  15. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +18 -51
  16. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +19 -17
  17. data/lib/ruby_llm/agents/base_agent.rb +70 -7
  18. data/lib/ruby_llm/agents/core/base.rb +4 -0
  19. data/lib/ruby_llm/agents/core/configuration.rb +12 -0
  20. data/lib/ruby_llm/agents/core/errors.rb +3 -0
  21. data/lib/ruby_llm/agents/core/version.rb +1 -1
  22. data/lib/ruby_llm/agents/pipeline/context.rb +26 -0
  23. data/lib/ruby_llm/agents/pipeline/middleware/base.rb +58 -4
  24. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +17 -17
  25. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +34 -22
  26. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +105 -50
  27. data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +7 -5
  28. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +6 -4
  29. data/lib/ruby_llm/agents/rails/engine.rb +11 -0
  30. data/lib/ruby_llm/agents/results/background_removal_result.rb +7 -1
  31. data/lib/ruby_llm/agents/results/base.rb +39 -2
  32. data/lib/ruby_llm/agents/results/embedding_result.rb +4 -0
  33. data/lib/ruby_llm/agents/results/image_analysis_result.rb +7 -1
  34. data/lib/ruby_llm/agents/results/image_edit_result.rb +7 -1
  35. data/lib/ruby_llm/agents/results/image_generation_result.rb +7 -1
  36. data/lib/ruby_llm/agents/results/image_pipeline_result.rb +7 -1
  37. data/lib/ruby_llm/agents/results/image_transform_result.rb +7 -1
  38. data/lib/ruby_llm/agents/results/image_upscale_result.rb +7 -1
  39. data/lib/ruby_llm/agents/results/image_variation_result.rb +7 -1
  40. data/lib/ruby_llm/agents/results/speech_result.rb +6 -0
  41. data/lib/ruby_llm/agents/results/trackable.rb +25 -0
  42. data/lib/ruby_llm/agents/results/transcription_result.rb +6 -0
  43. data/lib/ruby_llm/agents/text/embedder.rb +7 -4
  44. data/lib/ruby_llm/agents/tool.rb +169 -0
  45. data/lib/ruby_llm/agents/tool_context.rb +71 -0
  46. data/lib/ruby_llm/agents/track_report.rb +127 -0
  47. data/lib/ruby_llm/agents/tracker.rb +32 -0
  48. data/lib/ruby_llm/agents.rb +212 -0
  49. data/lib/tasks/ruby_llm_agents.rake +6 -0
  50. metadata +13 -2
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # Demo generator — scaffolds a working HelloAgent with a smoke-test script.
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:demo
10
+ #
11
+ # Creates:
12
+ # - app/agents/hello_agent.rb — minimal working agent
13
+ # - bin/smoke_test_agent — one-command verification script
14
+ #
15
+ class DemoGenerator < ::Rails::Generators::Base
16
+ source_root File.expand_path("templates", __dir__)
17
+
18
+ def ensure_base_class
19
+ agents_dir = "app/agents"
20
+ empty_directory agents_dir
21
+
22
+ base_class_path = "#{agents_dir}/application_agent.rb"
23
+ unless File.exist?(File.join(destination_root, base_class_path))
24
+ template "application_agent.rb.tt", base_class_path
25
+ end
26
+ end
27
+
28
+ def create_hello_agent
29
+ create_file "app/agents/hello_agent.rb", <<~RUBY
30
+ # frozen_string_literal: true
31
+
32
+ class HelloAgent < ApplicationAgent
33
+ system "You are a friendly assistant. Keep responses under 2 sentences."
34
+
35
+ prompt "Say hello to {name} and tell them one fun fact."
36
+ end
37
+ RUBY
38
+ end
39
+
40
+ def create_smoke_test
41
+ create_file "bin/smoke_test_agent", <<~RUBY
42
+ #!/usr/bin/env ruby
43
+ # frozen_string_literal: true
44
+
45
+ # Smoke test — verifies your RubyLLM::Agents setup end-to-end.
46
+ #
47
+ # Usage:
48
+ # bin/rails runner bin/smoke_test_agent
49
+ #
50
+ puts "Running RubyLLM::Agents smoke test..."
51
+ puts ""
52
+
53
+ # 1. Check configuration
54
+ config = RubyLLM::Agents.configuration
55
+ model = config.default_model
56
+ puts "Default model: \#{model}"
57
+
58
+ # 2. Dry-run (no API call)
59
+ puts ""
60
+ puts "Dry run:"
61
+ dry = HelloAgent.call(name: "World", dry_run: true)
62
+ puts " System prompt: \#{dry.system_prompt[0..80]}..."
63
+ puts " User prompt: \#{dry.user_prompt}"
64
+ puts " Model: \#{dry.model}"
65
+ puts " Dry run OK!"
66
+
67
+ # 3. Live call
68
+ puts ""
69
+ puts "Live call (calling \#{model})..."
70
+ begin
71
+ result = HelloAgent.call(name: "World")
72
+ puts " Response: \#{result.content}"
73
+ puts ""
74
+ puts "Success! Your setup is working."
75
+ rescue => e
76
+ puts " Error: \#{e.class}: \#{e.message}"
77
+ puts ""
78
+ puts "The dry run worked but the live call failed."
79
+ puts "This usually means your API key is missing or invalid."
80
+ puts ""
81
+ puts "Run 'rails ruby_llm_agents:doctor' for detailed diagnostics."
82
+ exit 1
83
+ end
84
+ RUBY
85
+
86
+ chmod "bin/smoke_test_agent", 0o755
87
+ end
88
+
89
+ def show_next_steps
90
+ say ""
91
+ say "Demo agent created!", :green
92
+ say ""
93
+ say "Try it:"
94
+ say " bin/rails runner bin/smoke_test_agent"
95
+ say ""
96
+ say "Or in the Rails console:"
97
+ say " HelloAgent.call(name: \"World\")"
98
+ say " HelloAgent.call(name: \"World\", dry_run: true)"
99
+ say ""
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RubyLlmAgents
6
+ # Doctor generator — validates that setup is complete and working.
7
+ #
8
+ # Usage:
9
+ # rails generate ruby_llm_agents:doctor
10
+ # rails ruby_llm_agents:doctor (rake task alias)
11
+ #
12
+ # Checks:
13
+ # 1. API keys — at least one provider key is configured
14
+ # 2. Migrations — required tables exist
15
+ # 3. Routes — engine is mounted
16
+ # 4. Background jobs — ActiveJob adapter is configured (not :async/:inline in prod)
17
+ # 5. Agents — at least one agent file exists
18
+ #
19
+ class DoctorGenerator < ::Rails::Generators::Base
20
+ desc "Validate your RubyLLM::Agents setup and print actionable fixes"
21
+
22
+ def run_checks
23
+ @pass = 0
24
+ @fail = 0
25
+ @warn = 0
26
+
27
+ say ""
28
+ say "RubyLLM::Agents Doctor", :bold
29
+ say "=" * 40
30
+
31
+ check_api_keys
32
+ check_migrations
33
+ check_routes
34
+ check_background_jobs
35
+ check_agents
36
+
37
+ say ""
38
+ say "=" * 40
39
+ summary = "#{@pass} passed, #{@fail} failed, #{@warn} warnings"
40
+ if @fail > 0
41
+ say "Result: #{summary}", :red
42
+ elsif @warn > 0
43
+ say "Result: #{summary}", :yellow
44
+ else
45
+ say "Result: #{summary} — you're all set!", :green
46
+ end
47
+ say ""
48
+ end
49
+
50
+ private
51
+
52
+ def check_api_keys
53
+ say ""
54
+ say "API Keys", :bold
55
+
56
+ config = RubyLLM::Agents.configuration
57
+ providers = {
58
+ "OpenAI" => -> { config.openai_api_key },
59
+ "Anthropic" => -> { config.anthropic_api_key },
60
+ "Gemini" => -> { config.gemini_api_key },
61
+ "DeepSeek" => -> { config.deepseek_api_key },
62
+ "OpenRouter" => -> { config.openrouter_api_key },
63
+ "Mistral" => -> { config.mistral_api_key }
64
+ }
65
+
66
+ configured = providers.select { |_, v| v.call.present? }.keys
67
+
68
+ if configured.any?
69
+ configured.each { |name| pass "#{name} API key configured" }
70
+ else
71
+ fail_check "No API keys configured"
72
+ fix "Add to config/initializers/ruby_llm_agents.rb:"
73
+ fix " config.openai_api_key = ENV[\"OPENAI_API_KEY\"]"
74
+ fix "Then set the environment variable in .env or credentials."
75
+ end
76
+ end
77
+
78
+ def check_migrations
79
+ say ""
80
+ say "Database", :bold
81
+
82
+ tables = {
83
+ "ruby_llm_agents_executions" => "rails generate ruby_llm_agents:install && rails db:migrate",
84
+ "ruby_llm_agents_execution_details" => "rails generate ruby_llm_agents:upgrade && rails db:migrate"
85
+ }
86
+
87
+ tables.each do |table, fix_cmd|
88
+ if table_exists?(table)
89
+ pass "Table #{table} exists"
90
+ else
91
+ fail_check "Table #{table} missing"
92
+ fix fix_cmd
93
+ end
94
+ end
95
+ end
96
+
97
+ def check_routes
98
+ say ""
99
+ say "Routes", :bold
100
+
101
+ routes_file = File.join(destination_root, "config/routes.rb")
102
+ if File.exist?(routes_file)
103
+ content = File.read(routes_file)
104
+ if content.include?("RubyLLM::Agents::Engine")
105
+ pass "Dashboard engine mounted"
106
+ else
107
+ warn_check "Dashboard engine not mounted in routes"
108
+ fix "Add to config/routes.rb:"
109
+ fix " mount RubyLLM::Agents::Engine => \"/agents\""
110
+ end
111
+ else
112
+ warn_check "Could not find config/routes.rb"
113
+ end
114
+ end
115
+
116
+ def check_background_jobs
117
+ say ""
118
+ say "Background Jobs", :bold
119
+
120
+ adapter = ActiveJob::Base.queue_adapter.class.name
121
+ async_logging = RubyLLM::Agents.configuration.async_logging
122
+
123
+ if !async_logging
124
+ pass "Async logging disabled (synchronous mode)"
125
+ elsif adapter.include?("Async") || adapter.include?("Inline")
126
+ if Rails.env.production?
127
+ warn_check "ActiveJob adapter is #{adapter} — execution logging may be lost in production"
128
+ fix "Configure a persistent adapter (Sidekiq, GoodJob, SolidQueue, etc.)"
129
+ fix "Or set config.async_logging = false for synchronous logging."
130
+ else
131
+ pass "ActiveJob adapter: #{adapter} (OK for development)"
132
+ end
133
+ else
134
+ pass "ActiveJob adapter: #{adapter}"
135
+ end
136
+ end
137
+
138
+ def check_agents
139
+ say ""
140
+ say "Agents", :bold
141
+
142
+ agents_dir = File.join(destination_root, "app/agents")
143
+ if Dir.exist?(agents_dir)
144
+ agent_files = Dir.glob(File.join(agents_dir, "**/*_agent.rb"))
145
+ .reject { |f| f.end_with?("application_agent.rb") }
146
+
147
+ if agent_files.any?
148
+ pass "Found #{agent_files.size} agent(s)"
149
+ else
150
+ warn_check "No agents found (only application_agent.rb)"
151
+ fix "rails generate ruby_llm_agents:agent HelloWorld query:required"
152
+ fix "Or: rails generate ruby_llm_agents:demo"
153
+ end
154
+ else
155
+ fail_check "app/agents/ directory missing"
156
+ fix "rails generate ruby_llm_agents:install"
157
+ end
158
+ end
159
+
160
+ # Helpers
161
+
162
+ def table_exists?(name)
163
+ ActiveRecord::Base.connection.table_exists?(name)
164
+ rescue => e
165
+ say " (Could not check database: #{e.message})", :yellow
166
+ false
167
+ end
168
+
169
+ def pass(msg)
170
+ @pass += 1
171
+ say " #{status_icon(:pass)} #{msg}", :green
172
+ end
173
+
174
+ def fail_check(msg)
175
+ @fail += 1
176
+ say " #{status_icon(:fail)} #{msg}", :red
177
+ end
178
+
179
+ def warn_check(msg)
180
+ @warn += 1
181
+ say " #{status_icon(:warn)} #{msg}", :yellow
182
+ end
183
+
184
+ def fix(msg)
185
+ say " Fix: #{msg}"
186
+ end
187
+
188
+ def status_icon(type)
189
+ case type
190
+ when :pass then "OK"
191
+ when :fail then "FAIL"
192
+ when :warn then "WARN"
193
+ end
194
+ end
195
+ end
196
+ end
@@ -96,28 +96,16 @@ module RubyLlmAgents
96
96
  say ""
97
97
  say "RubyLLM::Agents has been installed!", :green
98
98
  say ""
99
- say "Directory structure created:"
100
- say " app/"
101
- say " ├── agents/"
102
- say " │ ├── application_agent.rb"
103
- say " │ ├── concerns/"
104
- say " │ └── AGENTS.md"
105
- say " └── tools/"
106
- say " └── TOOLS.md"
107
- say ""
108
- say "Skill files (*.md) help AI coding assistants understand how to use this gem."
109
- say ""
110
99
  say "Next steps:"
111
- say " 1. Set your API keys in config/initializers/ruby_llm_agents.rb"
100
+ say " 1. Set your API key in config/initializers/ruby_llm_agents.rb"
112
101
  say " 2. Run migrations: rails db:migrate"
113
- say " 3. Generate an agent: rails generate ruby_llm_agents:agent MyAgent query:required"
114
- say " 4. Access the dashboard at: /agents"
102
+ say " 3. Verify setup: rails ruby_llm_agents:doctor"
103
+ say " 4. Try it out: rails generate ruby_llm_agents:demo"
104
+ say ""
105
+ say "Or generate a custom agent:"
106
+ say " rails generate ruby_llm_agents:agent MyAgent query:required"
115
107
  say ""
116
- say "Generator commands:"
117
- say " rails generate ruby_llm_agents:agent CustomerSupport query:required"
118
- say " rails generate ruby_llm_agents:image_generator Product"
119
- say " rails generate ruby_llm_agents:transcriber Meeting"
120
- say " rails generate ruby_llm_agents:embedder Semantic"
108
+ say "Dashboard: /agents"
121
109
  say ""
122
110
  end
123
111
 
@@ -8,108 +8,55 @@
8
8
  <%- else -%>
9
9
  class <%= class_name %>Agent < ApplicationAgent
10
10
  <%- end -%>
11
- # ============================================
12
- # Model Configuration
13
- # ============================================
14
-
11
+ <% if options[:model] != "default" -%>
15
12
  model "<%= options[:model] %>"
13
+ <% end -%>
14
+ <% if options[:temperature] != 0.0 -%>
16
15
  temperature <%= options[:temperature] %>
17
- # timeout 30 # Per-request timeout in seconds (default: 60)
18
-
19
- # ============================================
20
- # Caching
21
- # ============================================
22
-
23
- <% if options[:cache] -%>
24
- cache <%= options[:cache] %>
25
- <% else -%>
26
- # cache 1.hour # Enable response caching with TTL
27
16
  <% end -%>
28
17
 
29
18
  # ============================================
30
- # Reliability (Retries & Fallbacks)
19
+ # Prompts
31
20
  # ============================================
21
+ # Use {placeholder} syntax — placeholders become required params automatically.
32
22
 
33
- # Automatic retries with exponential backoff
34
- # - max: Number of retry attempts
35
- # - backoff: :constant or :exponential
36
- # - base: Base delay in seconds
37
- # - max_delay: Maximum delay between retries
38
- # - on: Additional error classes to retry on
39
- # retries max: 2, backoff: :exponential, base: 0.4, max_delay: 3.0
40
-
41
- # Fallback models (tried in order when primary model fails)
42
- # fallback_models ["gpt-4o-mini", "claude-3-haiku"]
43
-
44
- # Total timeout across all retry/fallback attempts
45
- # total_timeout 30
46
-
47
- # Circuit breaker (prevents repeated calls to failing models)
48
- # - errors: Number of errors to trigger open state
49
- # - within: Rolling window in seconds
50
- # - cooldown: Time to wait before allowing requests again
51
- # circuit_breaker errors: 5, within: 60, cooldown: 300
52
-
53
- # ============================================
54
- # Parameters
55
- # ============================================
23
+ system "You are a helpful assistant."
56
24
 
57
- <% parsed_params.each do |param| -%>
58
- param :<%= param.name %><%= ", required: true" if param.required? %><%= ", default: #{param.default.inspect}" if param.default && !param.required? %>
25
+ <% if parsed_params.any? -%>
26
+ prompt "<%= parsed_params.map { |p| "{#{p.name}}" }.join(" ") %>"
27
+ <% else -%>
28
+ prompt "Your prompt here"
59
29
  <% end -%>
60
30
 
61
- private
31
+ <% parsed_params.select { |p| !p.required? && p.default }.each do |param| -%>
32
+ param :<%= param.name %>, default: <%= param.default.inspect %>
33
+ <% end -%>
34
+ <% if options[:cache] -%>
62
35
 
63
36
  # ============================================
64
- # Prompts (required)
37
+ # Caching
65
38
  # ============================================
66
39
 
67
- def system_prompt
68
- <<~PROMPT
69
- You are a helpful assistant.
70
- # Define your system instructions here
71
- PROMPT
72
- end
73
-
74
- def user_prompt
75
- # Build the prompt from parameters
76
- <% if parsed_params.any? -%>
77
- <%= parsed_params.first.name %>
78
- <% else -%>
79
- "Your prompt here"
40
+ cache for: <%= options[:cache] %>
80
41
  <% end -%>
81
- end
82
42
 
83
43
  # ============================================
84
- # Optional Overrides
44
+ # Error Handling (uncomment to enable)
85
45
  # ============================================
86
46
 
87
- # Structured output schema (returns parsed hash instead of raw text)
88
- # def schema
89
- # @schema ||= RubyLLM::Schema.create do
90
- # string :result, description: "The result"
91
- # integer :confidence, description: "Confidence score 1-100"
92
- # array :tags, description: "Relevant tags" do
93
- # string
94
- # end
95
- # end
96
- # end
97
-
98
- # Custom response processing (default: symbolize hash keys)
99
- # def process_response(response)
100
- # content = response.content
101
- # # Transform or validate the response
102
- # content
47
+ # on_failure do
48
+ # retries times: 2, backoff: :exponential
49
+ # fallback to: ["gpt-4o-mini"]
50
+ # timeout 30
103
51
  # end
104
52
 
105
- # Custom metadata to include in execution logs
106
- # def metadata
107
- # { custom_field: "value", request_id: params[:request_id] }
108
- # end
53
+ # ============================================
54
+ # Structured Output (uncomment to enable)
55
+ # ============================================
109
56
 
110
- # Custom cache key data (default: all params except skip_cache, dry_run)
111
- # def cache_key_data
112
- # { query: params[:query], locale: I18n.locale }
57
+ # returns do
58
+ # string :result, description: "The result"
59
+ # integer :confidence, description: "Confidence score 1-100"
113
60
  # end
114
61
  <%- if class_name.include?("::") -%>
115
62
  <%- (class_name.split("::").length - 1).times do |i| -%>
@@ -2,15 +2,15 @@
2
2
 
3
3
  # ApplicationAgent - Base class for all agents in this application
4
4
  #
5
- # All agents inherit from this class. Configure shared settings here
6
- # that apply to all agents, or override them per-agent as needed.
5
+ # All agents inherit from this class. Configure shared settings here.
7
6
  #
8
- # Example:
7
+ # Quick reference:
9
8
  # class MyAgent < ApplicationAgent
10
- # param :query, required: true
9
+ # system "You are a helpful assistant."
10
+ # prompt "Answer this: {query}" # {query} becomes a required param
11
11
  #
12
- # def user_prompt
13
- # query
12
+ # returns do # Optional: structured output
13
+ # string :answer, description: "The answer"
14
14
  # end
15
15
  # end
16
16
  #
@@ -20,50 +20,17 @@
20
20
  # MyAgent.call(query: "hello", skip_cache: true) # Bypass cache
21
21
  #
22
22
  class ApplicationAgent < RubyLLM::Agents::Base
23
- # ============================================
24
- # Shared Model Configuration
25
- # ============================================
26
- # These settings are inherited by all agents
27
-
28
- # model "gemini-2.0-flash" # Default model for all agents
29
- # temperature 0.0 # Default temperature (0.0 = deterministic)
30
- # timeout 60 # Default timeout in seconds
31
-
32
- # ============================================
33
- # Shared Caching
34
- # ============================================
35
-
36
- # cache 1.hour # Enable caching for all agents (override per-agent if needed)
37
-
38
- # ============================================
39
- # Shared Reliability Settings
40
- # ============================================
41
- # Configure once here, all agents inherit these settings
42
-
43
- # Automatic retries for all agents
44
- # retries max: 2, backoff: :exponential, base: 0.4, max_delay: 3.0
45
-
46
- # Shared fallback models
47
- # fallback_models ["gpt-4o-mini", "claude-3-haiku"]
48
-
49
- # Total timeout across retries/fallbacks
50
- # total_timeout 30
51
-
52
- # Circuit breaker (per agent-model pair)
53
- # circuit_breaker errors: 5, within: 60, cooldown: 300
54
-
55
- # ============================================
56
- # Shared Helper Methods
57
- # ============================================
58
- # Define methods here that can be used by all agents
59
-
60
- # Example: Common system prompt prefix
61
- # def system_prompt_prefix
62
- # "You are an AI assistant for #{Rails.application.class.module_parent_name}."
63
- # end
64
-
65
- # Example: Common metadata
66
- # def metadata
67
- # { app_version: Rails.application.config.version }
23
+ # Shared settings inherited by all agents.
24
+ # Override per-agent as needed.
25
+
26
+ # model "gpt-4o" # Override the configured default model
27
+ # temperature 0.0 # 0.0 = deterministic, 2.0 = creative
28
+ # cache for: 1.hour # Enable caching for all agents
29
+
30
+ # Shared error handling (uncomment to apply to all agents)
31
+ # on_failure do
32
+ # retries times: 2, backoff: :exponential
33
+ # fallback to: ["gpt-4o-mini"]
34
+ # timeout 30
68
35
  # end
69
36
  end
@@ -6,29 +6,14 @@
6
6
 
7
7
  RubyLLM::Agents.configure do |config|
8
8
  # ============================================
9
- # LLM Provider API Keys
9
+ # Quick Start — set ONE API key to get going
10
10
  # ============================================
11
- # Configure at least one provider. Set these in your environment
12
- # or replace ENV[] calls with your keys directly.
11
+ # Uncomment one line below, then run: rails ruby_llm_agents:doctor
13
12
 
14
13
  # config.openai_api_key = ENV["OPENAI_API_KEY"]
15
14
  # config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
16
15
  # config.gemini_api_key = ENV["GOOGLE_API_KEY"]
17
16
 
18
- # Additional providers:
19
- # config.deepseek_api_key = ENV["DEEPSEEK_API_KEY"]
20
- # config.openrouter_api_key = ENV["OPENROUTER_API_KEY"]
21
- # config.mistral_api_key = ENV["MISTRAL_API_KEY"]
22
- # config.xai_api_key = ENV["XAI_API_KEY"]
23
-
24
- # Custom endpoints (e.g., Azure OpenAI, local Ollama):
25
- # config.openai_api_base = "https://your-resource.openai.azure.com"
26
- # config.ollama_api_base = "http://localhost:11434"
27
-
28
- # Connection settings:
29
- # config.request_timeout = 120
30
- # config.max_retries = 3
31
-
32
17
  # ============================================
33
18
  # Model Defaults
34
19
  # ============================================
@@ -46,6 +31,23 @@ RubyLLM::Agents.configure do |config|
46
31
  # When enabled, agents stream responses and track time-to-first-token
47
32
  # config.default_streaming = false
48
33
 
34
+ # ============================================
35
+ # Additional Providers (uncomment as needed)
36
+ # ============================================
37
+
38
+ # config.deepseek_api_key = ENV["DEEPSEEK_API_KEY"]
39
+ # config.openrouter_api_key = ENV["OPENROUTER_API_KEY"]
40
+ # config.mistral_api_key = ENV["MISTRAL_API_KEY"]
41
+ # config.xai_api_key = ENV["XAI_API_KEY"]
42
+
43
+ # Custom endpoints (e.g., Azure OpenAI, local Ollama):
44
+ # config.openai_api_base = "https://your-resource.openai.azure.com"
45
+ # config.ollama_api_base = "http://localhost:11434"
46
+
47
+ # Connection settings:
48
+ # config.request_timeout = 120
49
+ # config.max_retries = 3
50
+
49
51
  # ============================================
50
52
  # Caching
51
53
  # ============================================