ruby_llm-agents 0.5.0 → 1.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "reliability_dsl"
|
|
4
|
-
|
|
5
|
-
module RubyLLM
|
|
6
|
-
module Agents
|
|
7
|
-
class Base
|
|
8
|
-
# Class-level DSL for configuring agents
|
|
9
|
-
#
|
|
10
|
-
# Provides methods for setting model, temperature, timeout, caching,
|
|
11
|
-
# reliability, streaming, tools, and parameters.
|
|
12
|
-
module DSL
|
|
13
|
-
# @!visibility private
|
|
14
|
-
VERSION = "1.0"
|
|
15
|
-
# @!visibility private
|
|
16
|
-
CACHE_TTL = 1.hour
|
|
17
|
-
|
|
18
|
-
# @!group Configuration DSL
|
|
19
|
-
|
|
20
|
-
# Sets or returns the LLM model for this agent class
|
|
21
|
-
#
|
|
22
|
-
# @param value [String, nil] The model identifier to set
|
|
23
|
-
# @return [String] The current model setting
|
|
24
|
-
# @example
|
|
25
|
-
# model "gpt-4o"
|
|
26
|
-
def model(value = nil)
|
|
27
|
-
@model = value if value
|
|
28
|
-
@model || inherited_or_default(:model, RubyLLM::Agents.configuration.default_model)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Sets or returns the temperature for LLM responses
|
|
32
|
-
#
|
|
33
|
-
# @param value [Float, nil] Temperature value (0.0-2.0)
|
|
34
|
-
# @return [Float] The current temperature setting
|
|
35
|
-
# @example
|
|
36
|
-
# temperature 0.7
|
|
37
|
-
def temperature(value = nil)
|
|
38
|
-
@temperature = value if value
|
|
39
|
-
@temperature || inherited_or_default(:temperature, RubyLLM::Agents.configuration.default_temperature)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Sets or returns the version string for cache invalidation
|
|
43
|
-
#
|
|
44
|
-
# @param value [String, nil] Version string
|
|
45
|
-
# @return [String] The current version
|
|
46
|
-
# @example
|
|
47
|
-
# version "2.0"
|
|
48
|
-
def version(value = nil)
|
|
49
|
-
@version = value if value
|
|
50
|
-
@version || inherited_or_default(:version, VERSION)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Sets or returns the description for this agent class
|
|
54
|
-
#
|
|
55
|
-
# @param value [String, nil] The description text
|
|
56
|
-
# @return [String, nil] The current description
|
|
57
|
-
# @example
|
|
58
|
-
# description "Searches the knowledge base for relevant documents"
|
|
59
|
-
def description(value = nil)
|
|
60
|
-
@description = value if value
|
|
61
|
-
@description || inherited_or_default(:description, nil)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Sets or returns the timeout in seconds for LLM requests
|
|
65
|
-
#
|
|
66
|
-
# @param value [Integer, nil] Timeout in seconds
|
|
67
|
-
# @return [Integer] The current timeout setting
|
|
68
|
-
# @example
|
|
69
|
-
# timeout 30
|
|
70
|
-
def timeout(value = nil)
|
|
71
|
-
@timeout = value if value
|
|
72
|
-
@timeout || inherited_or_default(:timeout, RubyLLM::Agents.configuration.default_timeout)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# @!endgroup
|
|
76
|
-
|
|
77
|
-
# @!group Reliability DSL
|
|
78
|
-
|
|
79
|
-
# Configures reliability features using a block syntax
|
|
80
|
-
#
|
|
81
|
-
# Groups all reliability configuration in a single block for clarity.
|
|
82
|
-
# Individual methods (retries, fallback_models, etc.) remain available
|
|
83
|
-
# for backward compatibility.
|
|
84
|
-
#
|
|
85
|
-
# @yield Block containing reliability configuration
|
|
86
|
-
# @return [void]
|
|
87
|
-
# @example
|
|
88
|
-
# reliability do
|
|
89
|
-
# retries max: 3, backoff: :exponential
|
|
90
|
-
# fallback_models "gpt-4o-mini"
|
|
91
|
-
# total_timeout 30
|
|
92
|
-
# circuit_breaker errors: 5
|
|
93
|
-
# end
|
|
94
|
-
def reliability(&block)
|
|
95
|
-
builder = ReliabilityDSL.new
|
|
96
|
-
builder.instance_eval(&block)
|
|
97
|
-
|
|
98
|
-
@retries_config = builder.retries_config if builder.retries_config
|
|
99
|
-
@fallback_models = builder.fallback_models_list if builder.fallback_models_list.any?
|
|
100
|
-
@total_timeout = builder.total_timeout_value if builder.total_timeout_value
|
|
101
|
-
@circuit_breaker_config = builder.circuit_breaker_config if builder.circuit_breaker_config
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Configures retry behavior for this agent
|
|
105
|
-
#
|
|
106
|
-
# @param max [Integer] Maximum number of retry attempts (default: 0)
|
|
107
|
-
# @param backoff [Symbol] Backoff strategy (:constant or :exponential)
|
|
108
|
-
# @param base [Float] Base delay in seconds
|
|
109
|
-
# @param max_delay [Float] Maximum delay between retries
|
|
110
|
-
# @param on [Array<Class>] Error classes to retry on (extends defaults)
|
|
111
|
-
# @return [Hash] The current retry configuration
|
|
112
|
-
# @example
|
|
113
|
-
# retries max: 2, backoff: :exponential, base: 0.4, max_delay: 3.0, on: [Timeout::Error]
|
|
114
|
-
def retries(max: nil, backoff: nil, base: nil, max_delay: nil, on: nil)
|
|
115
|
-
if max || backoff || base || max_delay || on
|
|
116
|
-
@retries_config ||= RubyLLM::Agents.configuration.default_retries.dup
|
|
117
|
-
@retries_config[:max] = max if max
|
|
118
|
-
@retries_config[:backoff] = backoff if backoff
|
|
119
|
-
@retries_config[:base] = base if base
|
|
120
|
-
@retries_config[:max_delay] = max_delay if max_delay
|
|
121
|
-
@retries_config[:on] = on if on
|
|
122
|
-
end
|
|
123
|
-
@retries_config || inherited_or_default(:retries_config, RubyLLM::Agents.configuration.default_retries)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Returns the retry configuration for this agent
|
|
127
|
-
#
|
|
128
|
-
# @return [Hash, nil] The retry configuration
|
|
129
|
-
def retries_config
|
|
130
|
-
@retries_config || (superclass.respond_to?(:retries_config) ? superclass.retries_config : nil)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Sets or returns fallback models to try when primary model fails
|
|
134
|
-
#
|
|
135
|
-
# @param models [Array<String>, nil] Model identifiers to use as fallbacks
|
|
136
|
-
# @return [Array<String>] The current fallback models
|
|
137
|
-
# @example
|
|
138
|
-
# fallback_models ["gpt-4o-mini", "gpt-4o"]
|
|
139
|
-
def fallback_models(models = nil)
|
|
140
|
-
@fallback_models = models if models
|
|
141
|
-
@fallback_models || inherited_or_default(:fallback_models, RubyLLM::Agents.configuration.default_fallback_models)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Sets or returns the total timeout for all retry/fallback attempts
|
|
145
|
-
#
|
|
146
|
-
# @param seconds [Integer, nil] Total timeout in seconds
|
|
147
|
-
# @return [Integer, nil] The current total timeout
|
|
148
|
-
# @example
|
|
149
|
-
# total_timeout 20
|
|
150
|
-
def total_timeout(seconds = nil)
|
|
151
|
-
@total_timeout = seconds if seconds
|
|
152
|
-
@total_timeout || inherited_or_default(:total_timeout, RubyLLM::Agents.configuration.default_total_timeout)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# Configures circuit breaker for this agent
|
|
156
|
-
#
|
|
157
|
-
# @param errors [Integer] Number of errors to trigger open state
|
|
158
|
-
# @param within [Integer] Rolling window in seconds
|
|
159
|
-
# @param cooldown [Integer] Cooldown period in seconds when open
|
|
160
|
-
# @return [Hash, nil] The current circuit breaker configuration
|
|
161
|
-
# @example
|
|
162
|
-
# circuit_breaker errors: 10, within: 60, cooldown: 300
|
|
163
|
-
def circuit_breaker(errors: nil, within: nil, cooldown: nil)
|
|
164
|
-
if errors || within || cooldown
|
|
165
|
-
@circuit_breaker_config ||= { errors: 10, within: 60, cooldown: 300 }
|
|
166
|
-
@circuit_breaker_config[:errors] = errors if errors
|
|
167
|
-
@circuit_breaker_config[:within] = within if within
|
|
168
|
-
@circuit_breaker_config[:cooldown] = cooldown if cooldown
|
|
169
|
-
end
|
|
170
|
-
@circuit_breaker_config || (superclass.respond_to?(:circuit_breaker_config) ? superclass.circuit_breaker_config : nil)
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# Returns the circuit breaker configuration for this agent
|
|
174
|
-
#
|
|
175
|
-
# @return [Hash, nil] The circuit breaker configuration
|
|
176
|
-
def circuit_breaker_config
|
|
177
|
-
@circuit_breaker_config || (superclass.respond_to?(:circuit_breaker_config) ? superclass.circuit_breaker_config : nil)
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# @!endgroup
|
|
181
|
-
|
|
182
|
-
# @!group Parameter DSL
|
|
183
|
-
|
|
184
|
-
# Defines a parameter for the agent
|
|
185
|
-
#
|
|
186
|
-
# Creates an accessor method for the parameter that retrieves values
|
|
187
|
-
# from the options hash, falling back to the default value.
|
|
188
|
-
#
|
|
189
|
-
# @param name [Symbol] The parameter name
|
|
190
|
-
# @param required [Boolean] Whether the parameter is required
|
|
191
|
-
# @param default [Object, nil] Default value if not provided
|
|
192
|
-
# @param type [Class, nil] Optional type for validation (e.g., String, Integer, Array)
|
|
193
|
-
# @return [void]
|
|
194
|
-
# @example Without type (accepts anything)
|
|
195
|
-
# param :query, required: true
|
|
196
|
-
# param :data, default: {}
|
|
197
|
-
# @example With type validation
|
|
198
|
-
# param :limit, default: 10, type: Integer
|
|
199
|
-
# param :name, type: String
|
|
200
|
-
# param :tags, type: Array
|
|
201
|
-
def param(name, required: false, default: nil, type: nil)
|
|
202
|
-
@params ||= {}
|
|
203
|
-
@params[name] = { required: required, default: default, type: type }
|
|
204
|
-
define_method(name) do
|
|
205
|
-
@options[name] || @options[name.to_s] || self.class.params.dig(name, :default)
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# Returns all defined parameters including inherited ones
|
|
210
|
-
#
|
|
211
|
-
# @return [Hash{Symbol => Hash}] Parameter definitions
|
|
212
|
-
def params
|
|
213
|
-
parent = superclass.respond_to?(:params) ? superclass.params : {}
|
|
214
|
-
parent.merge(@params || {})
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# @!endgroup
|
|
218
|
-
|
|
219
|
-
# @!group Caching DSL
|
|
220
|
-
|
|
221
|
-
# Enables caching for this agent with explicit TTL
|
|
222
|
-
#
|
|
223
|
-
# This is the preferred method for enabling caching.
|
|
224
|
-
#
|
|
225
|
-
# @param ttl [ActiveSupport::Duration] Time-to-live for cached responses
|
|
226
|
-
# @return [void]
|
|
227
|
-
# @example
|
|
228
|
-
# cache_for 1.hour
|
|
229
|
-
# cache_for 30.minutes
|
|
230
|
-
def cache_for(ttl)
|
|
231
|
-
@cache_enabled = true
|
|
232
|
-
@cache_ttl = ttl
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
# Enables caching for this agent with optional TTL
|
|
236
|
-
#
|
|
237
|
-
# @deprecated Use {#cache_for} instead for clarity.
|
|
238
|
-
# This method will be removed in version 1.0.
|
|
239
|
-
# @param ttl [ActiveSupport::Duration] Time-to-live for cached responses
|
|
240
|
-
# @return [void]
|
|
241
|
-
# @example
|
|
242
|
-
# cache 1.hour # deprecated
|
|
243
|
-
# cache_for 1.hour # preferred
|
|
244
|
-
def cache(ttl = CACHE_TTL)
|
|
245
|
-
RubyLLM::Agents::Deprecations.warn(
|
|
246
|
-
"cache(ttl) is deprecated. Use cache_for(ttl) instead for clarity.",
|
|
247
|
-
caller
|
|
248
|
-
)
|
|
249
|
-
cache_for(ttl)
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
# Returns whether caching is enabled for this agent
|
|
253
|
-
#
|
|
254
|
-
# @return [Boolean] true if caching is enabled
|
|
255
|
-
def cache_enabled?
|
|
256
|
-
@cache_enabled || false
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
# Returns the cache TTL for this agent
|
|
260
|
-
#
|
|
261
|
-
# @return [ActiveSupport::Duration] The cache TTL
|
|
262
|
-
def cache_ttl
|
|
263
|
-
@cache_ttl || CACHE_TTL
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
# @!endgroup
|
|
267
|
-
|
|
268
|
-
# @!group Streaming DSL
|
|
269
|
-
|
|
270
|
-
# Enables or returns streaming mode for this agent
|
|
271
|
-
#
|
|
272
|
-
# When streaming is enabled and a block is passed to call,
|
|
273
|
-
# chunks will be yielded to the block as they arrive.
|
|
274
|
-
#
|
|
275
|
-
# @param value [Boolean, nil] Whether to enable streaming
|
|
276
|
-
# @return [Boolean] The current streaming setting
|
|
277
|
-
# @example
|
|
278
|
-
# streaming true
|
|
279
|
-
def streaming(value = nil)
|
|
280
|
-
@streaming = value unless value.nil?
|
|
281
|
-
return @streaming unless @streaming.nil?
|
|
282
|
-
|
|
283
|
-
inherited_or_default(:streaming, RubyLLM::Agents.configuration.default_streaming)
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
# @!endgroup
|
|
287
|
-
|
|
288
|
-
# @!group Tools DSL
|
|
289
|
-
|
|
290
|
-
# Sets or returns the tools available to this agent
|
|
291
|
-
#
|
|
292
|
-
# Tools are RubyLLM::Tool classes that the model can invoke.
|
|
293
|
-
# The agent will automatically execute tool calls and continue
|
|
294
|
-
# until the model produces a final response.
|
|
295
|
-
#
|
|
296
|
-
# @param tool_classes [Array<Class>] Tool classes to make available
|
|
297
|
-
# @return [Array<Class>] The current tools
|
|
298
|
-
# @example With array (preferred)
|
|
299
|
-
# tools [WeatherTool, SearchTool, CalculatorTool]
|
|
300
|
-
# @example Single tool
|
|
301
|
-
# tools [WeatherTool]
|
|
302
|
-
def tools(tool_classes = nil)
|
|
303
|
-
if tool_classes
|
|
304
|
-
@tools = Array(tool_classes)
|
|
305
|
-
end
|
|
306
|
-
@tools || inherited_or_default(:tools, RubyLLM::Agents.configuration.default_tools)
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
# @!endgroup
|
|
310
|
-
|
|
311
|
-
private
|
|
312
|
-
|
|
313
|
-
# Looks up setting from superclass or uses default
|
|
314
|
-
#
|
|
315
|
-
# @param method [Symbol] The method to call on superclass
|
|
316
|
-
# @param default [Object] Default value if not found
|
|
317
|
-
# @return [Object] The resolved value
|
|
318
|
-
def inherited_or_default(method, default)
|
|
319
|
-
superclass.respond_to?(method) ? superclass.send(method) : default
|
|
320
|
-
end
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
end
|
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module Agents
|
|
5
|
-
class Base
|
|
6
|
-
# Main execution flow for agents
|
|
7
|
-
#
|
|
8
|
-
# Handles the core execution logic including caching, streaming,
|
|
9
|
-
# client building, and parameter validation.
|
|
10
|
-
module Execution
|
|
11
|
-
# Executes the agent and returns the processed response
|
|
12
|
-
#
|
|
13
|
-
# Handles caching, dry-run mode, and delegates to uncached_call
|
|
14
|
-
# for actual LLM execution.
|
|
15
|
-
#
|
|
16
|
-
# @yield [chunk] Yields chunks when streaming is enabled
|
|
17
|
-
# @yieldparam chunk [RubyLLM::Chunk] A streaming chunk with content
|
|
18
|
-
# @return [Object] The processed LLM response
|
|
19
|
-
def call(&block)
|
|
20
|
-
# Resolve tenant configuration before execution
|
|
21
|
-
resolve_tenant_context!
|
|
22
|
-
|
|
23
|
-
return dry_run_response if @options[:dry_run]
|
|
24
|
-
return uncached_call(&block) if @options[:skip_cache] || !self.class.cache_enabled?
|
|
25
|
-
|
|
26
|
-
cache_key = agent_cache_key
|
|
27
|
-
|
|
28
|
-
# Check for cache hit BEFORE fetch to record it
|
|
29
|
-
if cache_store.exist?(cache_key)
|
|
30
|
-
started_at = Time.current
|
|
31
|
-
cached_result = cache_store.read(cache_key)
|
|
32
|
-
record_cache_hit_execution(cache_key, cached_result, started_at) if cached_result
|
|
33
|
-
return cached_result
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Cache miss - execute and store
|
|
37
|
-
cache_store.fetch(cache_key, expires_in: self.class.cache_ttl) do
|
|
38
|
-
uncached_call(&block)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Resolves tenant context from the :tenant option
|
|
43
|
-
#
|
|
44
|
-
# The tenant option can be:
|
|
45
|
-
# - String: Just the tenant_id (uses resolver or DB for config)
|
|
46
|
-
# - Hash: Full config { id:, name:, daily_limit:, daily_token_limit:, ... }
|
|
47
|
-
#
|
|
48
|
-
# @return [void]
|
|
49
|
-
def resolve_tenant_context!
|
|
50
|
-
# Idempotency guard - only resolve once
|
|
51
|
-
return if defined?(@tenant_context_resolved) && @tenant_context_resolved
|
|
52
|
-
|
|
53
|
-
tenant_option = @options[:tenant]
|
|
54
|
-
return unless tenant_option
|
|
55
|
-
|
|
56
|
-
if tenant_option.is_a?(Hash)
|
|
57
|
-
# Full config passed - extract id and store config
|
|
58
|
-
@tenant_id = tenant_option[:id]&.to_s
|
|
59
|
-
@tenant_config = tenant_option.except(:id)
|
|
60
|
-
else
|
|
61
|
-
# Just tenant_id passed
|
|
62
|
-
@tenant_id = tenant_option.to_s
|
|
63
|
-
@tenant_config = nil
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
@tenant_context_resolved = true
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Returns the resolved tenant ID
|
|
70
|
-
#
|
|
71
|
-
# @return [String, nil] The tenant identifier
|
|
72
|
-
def resolved_tenant_id
|
|
73
|
-
return @tenant_id if defined?(@tenant_id) && @tenant_id.present?
|
|
74
|
-
|
|
75
|
-
config = RubyLLM::Agents.configuration
|
|
76
|
-
return nil unless config.multi_tenancy_enabled?
|
|
77
|
-
|
|
78
|
-
config.current_tenant_id
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Returns the runtime tenant config (if passed via :tenant option)
|
|
82
|
-
#
|
|
83
|
-
# @return [Hash, nil] Runtime tenant configuration
|
|
84
|
-
def runtime_tenant_config
|
|
85
|
-
@tenant_config if defined?(@tenant_config)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Executes the agent without caching
|
|
89
|
-
#
|
|
90
|
-
# Routes to reliability-enabled execution if configured, otherwise
|
|
91
|
-
# uses simple single-attempt execution.
|
|
92
|
-
#
|
|
93
|
-
# @yield [chunk] Yields chunks when streaming is enabled
|
|
94
|
-
# @return [Object] The processed response
|
|
95
|
-
def uncached_call(&block)
|
|
96
|
-
if reliability_enabled?
|
|
97
|
-
execute_with_reliability(&block)
|
|
98
|
-
else
|
|
99
|
-
instrument_execution { execute_single_attempt(&block) }
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Executes a single LLM attempt with timeout
|
|
104
|
-
#
|
|
105
|
-
# @param model_override [String, nil] Optional model to use instead of default
|
|
106
|
-
# @yield [chunk] Yields chunks when streaming is enabled
|
|
107
|
-
# @return [Result] A Result object with processed content and metadata
|
|
108
|
-
def execute_single_attempt(model_override: nil, &block)
|
|
109
|
-
current_client = model_override ? build_client_with_model(model_override) : client
|
|
110
|
-
@execution_started_at ||= Time.current
|
|
111
|
-
reset_accumulated_tool_calls!
|
|
112
|
-
|
|
113
|
-
Timeout.timeout(self.class.timeout) do
|
|
114
|
-
if streaming_enabled? && block_given?
|
|
115
|
-
execute_with_streaming(current_client, &block)
|
|
116
|
-
else
|
|
117
|
-
response = current_client.ask(user_prompt, **ask_options)
|
|
118
|
-
extract_tool_calls_from_client(current_client)
|
|
119
|
-
capture_response(response)
|
|
120
|
-
build_result(process_response(response), response)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Executes an LLM request with streaming enabled
|
|
126
|
-
#
|
|
127
|
-
# Yields chunks to the provided block as they arrive and tracks
|
|
128
|
-
# time to first token for latency analysis.
|
|
129
|
-
#
|
|
130
|
-
# @param current_client [RubyLLM::Chat] The configured client
|
|
131
|
-
# @yield [chunk] Yields each chunk as it arrives
|
|
132
|
-
# @yieldparam chunk [RubyLLM::Chunk] A streaming chunk
|
|
133
|
-
# @return [Result] A Result object with processed content and metadata
|
|
134
|
-
def execute_with_streaming(current_client, &block)
|
|
135
|
-
first_chunk_at = nil
|
|
136
|
-
|
|
137
|
-
response = current_client.ask(user_prompt, **ask_options) do |chunk|
|
|
138
|
-
first_chunk_at ||= Time.current
|
|
139
|
-
yield chunk if block_given?
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
if first_chunk_at && @execution_started_at
|
|
143
|
-
@time_to_first_token_ms = ((first_chunk_at - @execution_started_at) * 1000).to_i
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
extract_tool_calls_from_client(current_client)
|
|
147
|
-
capture_response(response)
|
|
148
|
-
build_result(process_response(response), response)
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
# Returns prompt info without making an API call (debug mode)
|
|
152
|
-
#
|
|
153
|
-
# @return [Result] A Result with dry run configuration info
|
|
154
|
-
def dry_run_response
|
|
155
|
-
Result.new(
|
|
156
|
-
content: {
|
|
157
|
-
dry_run: true,
|
|
158
|
-
agent: self.class.name,
|
|
159
|
-
model: model,
|
|
160
|
-
temperature: temperature,
|
|
161
|
-
timeout: self.class.timeout,
|
|
162
|
-
system_prompt: system_prompt,
|
|
163
|
-
user_prompt: user_prompt,
|
|
164
|
-
attachments: @options[:with],
|
|
165
|
-
schema: schema&.class&.name,
|
|
166
|
-
streaming: self.class.streaming,
|
|
167
|
-
tools: resolved_tools.map { |t| t.respond_to?(:name) ? t.name : t.to_s }
|
|
168
|
-
},
|
|
169
|
-
model_id: model,
|
|
170
|
-
temperature: temperature,
|
|
171
|
-
streaming: self.class.streaming
|
|
172
|
-
)
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
# Resolves tools for this execution
|
|
176
|
-
#
|
|
177
|
-
# Checks for instance method override first (for dynamic tools),
|
|
178
|
-
# then falls back to class-level DSL configuration. This allows
|
|
179
|
-
# agents to define tools dynamically based on runtime context.
|
|
180
|
-
#
|
|
181
|
-
# @return [Array<Class>] Tool classes to use
|
|
182
|
-
def resolved_tools
|
|
183
|
-
# Check if instance defines tools method (not inherited from class singleton)
|
|
184
|
-
if self.class.instance_methods(false).include?(:tools)
|
|
185
|
-
tools
|
|
186
|
-
else
|
|
187
|
-
self.class.tools
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# Resolves messages for this execution
|
|
192
|
-
#
|
|
193
|
-
# Priority order:
|
|
194
|
-
# 1. @override_messages (set via with_messages)
|
|
195
|
-
# 2. :messages option passed at call time
|
|
196
|
-
# 3. messages template method defined in subclass
|
|
197
|
-
#
|
|
198
|
-
# @return [Array<Hash>] Messages to apply to conversation
|
|
199
|
-
def resolved_messages
|
|
200
|
-
return @override_messages if @override_messages&.any?
|
|
201
|
-
return @options[:messages] if @options[:messages]&.any?
|
|
202
|
-
|
|
203
|
-
messages
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
# Returns the consolidated reliability configuration for this agent instance
|
|
207
|
-
#
|
|
208
|
-
# @return [Hash] Reliability config with :retries, :fallback_models, :total_timeout, :circuit_breaker
|
|
209
|
-
def reliability_config
|
|
210
|
-
default_retries = RubyLLM::Agents.configuration.default_retries
|
|
211
|
-
{
|
|
212
|
-
retries: self.class.retries || default_retries,
|
|
213
|
-
fallback_models: self.class.fallback_models,
|
|
214
|
-
total_timeout: self.class.total_timeout,
|
|
215
|
-
circuit_breaker: self.class.circuit_breaker_config
|
|
216
|
-
}
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
# Returns whether any reliability features are enabled for this agent
|
|
220
|
-
#
|
|
221
|
-
# @return [Boolean] true if retries, fallbacks, or circuit breaker is configured
|
|
222
|
-
def reliability_enabled?
|
|
223
|
-
config = reliability_config
|
|
224
|
-
(config[:retries]&.dig(:max) || 0) > 0 ||
|
|
225
|
-
config[:fallback_models]&.any? ||
|
|
226
|
-
config[:circuit_breaker].present?
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Returns whether streaming is enabled for this execution
|
|
230
|
-
#
|
|
231
|
-
# Checks both class-level DSL setting and instance-level override
|
|
232
|
-
# (set by the stream class method).
|
|
233
|
-
#
|
|
234
|
-
# @return [Boolean] true if streaming is enabled
|
|
235
|
-
def streaming_enabled?
|
|
236
|
-
@force_streaming || self.class.streaming
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
# Returns options to pass to the ask method
|
|
240
|
-
#
|
|
241
|
-
# Currently supports :with for attachments (images, PDFs, etc.)
|
|
242
|
-
#
|
|
243
|
-
# @return [Hash] Options for the ask call
|
|
244
|
-
def ask_options
|
|
245
|
-
opts = {}
|
|
246
|
-
opts[:with] = @options[:with] if @options[:with]
|
|
247
|
-
opts
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
# Validates that all required parameters are present and types match
|
|
251
|
-
#
|
|
252
|
-
# @raise [ArgumentError] If required parameters are missing or types don't match
|
|
253
|
-
# @return [void]
|
|
254
|
-
def validate_required_params!
|
|
255
|
-
self.class.params.each do |name, config|
|
|
256
|
-
value = @options[name] || @options[name.to_s]
|
|
257
|
-
has_value = @options.key?(name) || @options.key?(name.to_s)
|
|
258
|
-
|
|
259
|
-
# Check required
|
|
260
|
-
if config[:required] && !has_value
|
|
261
|
-
raise ArgumentError, "#{self.class} missing required param: #{name}"
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
# Check type if specified and value is present (not nil)
|
|
265
|
-
if config[:type] && has_value && !value.nil?
|
|
266
|
-
unless value.is_a?(config[:type])
|
|
267
|
-
raise ArgumentError,
|
|
268
|
-
"#{self.class} expected #{config[:type]} for :#{name}, got #{value.class}"
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
# Builds and configures the RubyLLM client
|
|
275
|
-
#
|
|
276
|
-
# @return [RubyLLM::Chat] Configured chat client
|
|
277
|
-
def build_client
|
|
278
|
-
# Apply database-backed API configuration if available
|
|
279
|
-
apply_api_configuration!
|
|
280
|
-
|
|
281
|
-
client = RubyLLM.chat
|
|
282
|
-
.with_model(model)
|
|
283
|
-
.with_temperature(temperature)
|
|
284
|
-
client = client.with_instructions(system_prompt) if system_prompt
|
|
285
|
-
client = client.with_schema(schema) if schema
|
|
286
|
-
client = client.with_tools(*resolved_tools) if resolved_tools.any?
|
|
287
|
-
client = apply_messages(client, resolved_messages) if resolved_messages.any?
|
|
288
|
-
client
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
# Applies database-backed API configuration to RubyLLM
|
|
292
|
-
#
|
|
293
|
-
# Resolution priority: per-tenant DB > global DB > RubyLLM.configure
|
|
294
|
-
# Only applies if the api_configurations table exists.
|
|
295
|
-
#
|
|
296
|
-
# @return [void]
|
|
297
|
-
def apply_api_configuration!
|
|
298
|
-
return unless api_configuration_available?
|
|
299
|
-
|
|
300
|
-
resolved_config = ApiConfiguration.resolve(tenant_id: resolved_tenant_id)
|
|
301
|
-
resolved_config.apply_to_ruby_llm!
|
|
302
|
-
rescue StandardError => e
|
|
303
|
-
Rails.logger.warn("[RubyLLM::Agents] Failed to apply API config: #{e.message}")
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
# Checks if API configuration table is available
|
|
307
|
-
#
|
|
308
|
-
# @return [Boolean] true if table exists and is accessible
|
|
309
|
-
def api_configuration_available?
|
|
310
|
-
return @api_config_available if defined?(@api_config_available)
|
|
311
|
-
|
|
312
|
-
@api_config_available = begin
|
|
313
|
-
ApiConfiguration.table_exists?
|
|
314
|
-
rescue StandardError
|
|
315
|
-
false
|
|
316
|
-
end
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# Builds a client with a specific model
|
|
320
|
-
#
|
|
321
|
-
# @param model_id [String] The model identifier
|
|
322
|
-
# @return [RubyLLM::Chat] Configured chat client
|
|
323
|
-
def build_client_with_model(model_id)
|
|
324
|
-
# Apply database-backed API configuration if available
|
|
325
|
-
apply_api_configuration!
|
|
326
|
-
|
|
327
|
-
client = RubyLLM.chat
|
|
328
|
-
.with_model(model_id)
|
|
329
|
-
.with_temperature(temperature)
|
|
330
|
-
client = client.with_instructions(system_prompt) if system_prompt
|
|
331
|
-
client = client.with_schema(schema) if schema
|
|
332
|
-
client = client.with_tools(*resolved_tools) if resolved_tools.any?
|
|
333
|
-
client = apply_messages(client, resolved_messages) if resolved_messages.any?
|
|
334
|
-
client
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
# Applies conversation history to the client
|
|
338
|
-
#
|
|
339
|
-
# @param client [RubyLLM::Chat] The chat client
|
|
340
|
-
# @param msgs [Array<Hash>] Messages with :role and :content keys
|
|
341
|
-
# @return [RubyLLM::Chat] Client with messages applied
|
|
342
|
-
def apply_messages(client, msgs)
|
|
343
|
-
msgs.each do |message|
|
|
344
|
-
client.add_message(role: message[:role].to_sym, content: message[:content])
|
|
345
|
-
end
|
|
346
|
-
client
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
# Builds a client with pre-populated conversation history
|
|
350
|
-
#
|
|
351
|
-
# @deprecated Use resolved_messages and apply_messages instead.
|
|
352
|
-
# Override the messages template method or pass messages: option to call.
|
|
353
|
-
# @param messages [Array<Hash>] Messages with :role and :content keys
|
|
354
|
-
# @return [RubyLLM::Chat] Client with messages added
|
|
355
|
-
# @example
|
|
356
|
-
# build_client_with_messages([
|
|
357
|
-
# { role: "user", content: "Hello" },
|
|
358
|
-
# { role: "assistant", content: "Hi there!" }
|
|
359
|
-
# ])
|
|
360
|
-
def build_client_with_messages(messages)
|
|
361
|
-
apply_messages(build_client, messages)
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
end
|