activeagent 0.5.0 → 0.6.0rc2
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/lib/active_agent/action_prompt/base.rb +37 -15
- data/lib/active_agent/action_prompt/message.rb +17 -1
- data/lib/active_agent/action_prompt/prompt.rb +5 -3
- data/lib/active_agent/base.rb +2 -1
- data/lib/active_agent/configuration.rb +36 -0
- data/lib/active_agent/generation_provider/anthropic_provider.rb +72 -65
- data/lib/active_agent/generation_provider/base.rb +19 -5
- data/lib/active_agent/generation_provider/error_handling.rb +167 -0
- data/lib/active_agent/generation_provider/log_subscriber.rb +92 -0
- data/lib/active_agent/generation_provider/message_formatting.rb +107 -0
- data/lib/active_agent/generation_provider/open_ai_provider.rb +54 -81
- data/lib/active_agent/generation_provider/open_router_provider.rb +324 -2
- data/lib/active_agent/generation_provider/parameter_builder.rb +119 -0
- data/lib/active_agent/generation_provider/response.rb +3 -1
- data/lib/active_agent/generation_provider/stream_processing.rb +58 -0
- data/lib/active_agent/generation_provider/tool_management.rb +142 -0
- data/lib/active_agent/generation_provider.rb +1 -1
- data/lib/active_agent/log_subscriber.rb +6 -6
- data/lib/active_agent/parameterized.rb +1 -0
- data/lib/active_agent/railtie.rb +7 -1
- data/lib/active_agent/sanitizers.rb +40 -0
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +9 -6
- data/lib/generators/erb/agent_generator.rb +3 -0
- data/lib/generators/erb/templates/instructions.text.erb.tt +1 -0
- metadata +133 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9496edf8536e904969a006a14d65bd69c3257f4db22d80e859a977646a02513
|
4
|
+
data.tar.gz: 0b35eb065fe146ee027d72789826ea3af793e57140d8aefead79d73586548e6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65ce7639ce9106b99e827600b7582776413cdeb69b7de28cf7ed80e0e496ebc1be6ea613ab9f67e944bb7837344458d3709a2065eb2725fc9b7263c08146f08d
|
7
|
+
data.tar.gz: c702c8618b701979dee4871ab200e7fd60d5c09fc2670926a9f77e1c0975ab14e2a5e9b30df2eccce9276440f5e6baf396d16320aabff67a1fbbd332a88b5379
|
@@ -104,7 +104,6 @@ module ActiveAgent
|
|
104
104
|
# Define how the agent should generate content
|
105
105
|
def generate_with(provider, **options)
|
106
106
|
self.generation_provider = provider
|
107
|
-
|
108
107
|
if options.has_key?(:instructions) || (self.options || {}).empty?
|
109
108
|
# Either instructions explicitly provided, or no inherited options exist
|
110
109
|
self.options = (self.options || {}).merge(options)
|
@@ -199,9 +198,9 @@ module ActiveAgent
|
|
199
198
|
# Add embedding capability to Message class
|
200
199
|
ActiveAgent::ActionPrompt::Message.class_eval do
|
201
200
|
def embed
|
202
|
-
agent_class =
|
201
|
+
agent_class = ApplicationAgent
|
203
202
|
agent = agent_class.new
|
204
|
-
agent.context = ActiveAgent::ActionPrompt::Prompt.new(message: self)
|
203
|
+
agent.context = ActiveAgent::ActionPrompt::Prompt.new(message: self, agent_instance: agent)
|
205
204
|
agent.embed
|
206
205
|
self
|
207
206
|
end
|
@@ -217,8 +216,18 @@ module ActiveAgent
|
|
217
216
|
|
218
217
|
def handle_response(response)
|
219
218
|
return response unless response.message.requested_actions.present?
|
219
|
+
|
220
|
+
# Perform the requested actions
|
220
221
|
perform_actions(requested_actions: response.message.requested_actions)
|
221
|
-
|
222
|
+
|
223
|
+
# Continue generation with updated context
|
224
|
+
continue_generation
|
225
|
+
end
|
226
|
+
|
227
|
+
def continue_generation
|
228
|
+
# Continue generating with the updated context that includes tool results
|
229
|
+
generation_provider.generate(context) if context && generation_provider
|
230
|
+
handle_response(generation_provider.response)
|
222
231
|
end
|
223
232
|
|
224
233
|
def update_context(response)
|
@@ -233,10 +242,15 @@ module ActiveAgent
|
|
233
242
|
|
234
243
|
def perform_action(action)
|
235
244
|
current_context = context.clone
|
236
|
-
#
|
245
|
+
# Merge action params with original params to preserve context
|
246
|
+
original_params = current_context.params || {}
|
247
|
+
|
237
248
|
if action.params.is_a?(Hash)
|
238
|
-
self.params = action.params
|
249
|
+
self.params = original_params.merge(action.params)
|
250
|
+
else
|
251
|
+
self.params = original_params
|
239
252
|
end
|
253
|
+
|
240
254
|
process(action.name)
|
241
255
|
context.message.role = :tool
|
242
256
|
context.message.action_id = action.id
|
@@ -250,7 +264,7 @@ module ActiveAgent
|
|
250
264
|
def initialize # :nodoc:
|
251
265
|
super
|
252
266
|
@_prompt_was_called = false
|
253
|
-
@_context = ActiveAgent::ActionPrompt::Prompt.new(options: self.class.options || {})
|
267
|
+
@_context = ActiveAgent::ActionPrompt::Prompt.new(options: self.class.options || {}, agent_instance: self)
|
254
268
|
end
|
255
269
|
|
256
270
|
def process(method_name, *args) # :nodoc:
|
@@ -262,7 +276,7 @@ module ActiveAgent
|
|
262
276
|
|
263
277
|
ActiveSupport::Notifications.instrument("process.active_agent", payload) do
|
264
278
|
super
|
265
|
-
@_context = ActiveAgent::ActionPrompt::Prompt.new unless @_prompt_was_called
|
279
|
+
@_context = ActiveAgent::ActionPrompt::Prompt.new(agent_instance: self) unless @_prompt_was_called
|
266
280
|
end
|
267
281
|
end
|
268
282
|
ruby2_keywords(:process)
|
@@ -317,11 +331,12 @@ module ActiveAgent
|
|
317
331
|
|
318
332
|
headers = apply_defaults(headers)
|
319
333
|
context.messages = headers[:messages] || []
|
334
|
+
context.mcp_servers = headers[:mcp_servers] || []
|
320
335
|
context.context_id = headers[:context_id]
|
321
336
|
context.params = params
|
322
337
|
context.action_name = action_name
|
323
338
|
|
324
|
-
context.output_schema =
|
339
|
+
context.output_schema = render_schema(headers[:output_schema], set_prefixes(headers[:output_schema], lookup_context.prefixes))
|
325
340
|
|
326
341
|
context.charset = charset = headers[:charset]
|
327
342
|
|
@@ -350,7 +365,7 @@ module ActiveAgent
|
|
350
365
|
prefixes = set_prefixes(action_name, lookup_context.prefixes)
|
351
366
|
|
352
367
|
action_methods.map do |action|
|
353
|
-
|
368
|
+
render_schema(action, prefixes)
|
354
369
|
end.compact
|
355
370
|
end
|
356
371
|
|
@@ -359,6 +374,10 @@ module ActiveAgent
|
|
359
374
|
if headers[:message].present? && headers[:message].is_a?(ActiveAgent::ActionPrompt::Message)
|
360
375
|
headers[:body] = headers[:message].content
|
361
376
|
headers[:role] = headers[:message].role
|
377
|
+
elsif headers[:message].present? && headers[:message].is_a?(Array)
|
378
|
+
# Handle array of multipart content like [{type: "text", text: "..."}, {type: "file", file: {...}}]
|
379
|
+
headers[:body] = headers[:message]
|
380
|
+
headers[:role] = :user
|
362
381
|
elsif headers[:message].present? && headers[:message].is_a?(String)
|
363
382
|
headers[:body] = headers[:message]
|
364
383
|
headers[:role] = :user
|
@@ -380,7 +399,6 @@ module ActiveAgent
|
|
380
399
|
ActiveAgent::ActionPrompt::Message.new(content: headers[:body], content_type: "input_text")
|
381
400
|
]
|
382
401
|
end
|
383
|
-
|
384
402
|
headers
|
385
403
|
end
|
386
404
|
|
@@ -388,10 +406,14 @@ module ActiveAgent
|
|
388
406
|
prefixes = lookup_context.prefixes | [ self.class.agent_name ]
|
389
407
|
end
|
390
408
|
|
391
|
-
def
|
392
|
-
|
409
|
+
def render_schema(schema_or_action, prefixes)
|
410
|
+
# If it's already a hash (direct schema), return it
|
411
|
+
return schema_or_action if schema_or_action.is_a?(Hash)
|
412
|
+
|
413
|
+
# Otherwise try to load from template
|
414
|
+
return unless lookup_context.template_exists?(schema_or_action, prefixes, false, formats: [ :json ])
|
393
415
|
|
394
|
-
JSON.parse render_to_string(locals: { action_name:
|
416
|
+
JSON.parse render_to_string(locals: { action_name: schema_or_action }, action: schema_or_action, formats: :json)
|
395
417
|
end
|
396
418
|
|
397
419
|
def merge_options(prompt_options)
|
@@ -403,7 +425,7 @@ module ActiveAgent
|
|
403
425
|
# Extract runtime options from prompt_options (exclude instructions as it has special template logic)
|
404
426
|
runtime_options = prompt_options.slice(
|
405
427
|
:model, :temperature, :max_tokens, :stream, :top_p, :frequency_penalty,
|
406
|
-
:presence_penalty, :response_format, :seed, :stop, :tools_choice
|
428
|
+
:presence_penalty, :response_format, :seed, :stop, :tools_choice, :data_collection, :plugins
|
407
429
|
)
|
408
430
|
# Handle explicit options parameter
|
409
431
|
explicit_options = prompt_options[:options] || {}
|
@@ -27,7 +27,7 @@ module ActiveAgent
|
|
27
27
|
@metadata = attributes[:metadata] || {}
|
28
28
|
@charset = attributes[:charset] || "UTF-8"
|
29
29
|
@content = attributes[:content] || ""
|
30
|
-
@content_type = attributes
|
30
|
+
@content_type = detect_content_type(attributes)
|
31
31
|
@role = attributes[:role] || :user
|
32
32
|
@raw_actions = attributes[:raw_actions]
|
33
33
|
@requested_actions = attributes[:requested_actions] || []
|
@@ -85,6 +85,22 @@ module ActiveAgent
|
|
85
85
|
|
86
86
|
private
|
87
87
|
|
88
|
+
def detect_content_type(attributes)
|
89
|
+
# If content_type is explicitly provided, use it
|
90
|
+
return attributes[:content_type] if attributes[:content_type]
|
91
|
+
|
92
|
+
# If content is an array with multipart/mixed content, set appropriate type
|
93
|
+
if attributes[:content].is_a?(Array)
|
94
|
+
# Check if it contains multimodal content (text, image_url, file, etc.)
|
95
|
+
has_multimodal = attributes[:content].any? do |item|
|
96
|
+
item.is_a?(Hash) && (item[:type] || item["type"])
|
97
|
+
end
|
98
|
+
has_multimodal ? "multipart/mixed" : "array"
|
99
|
+
else
|
100
|
+
"text/plain"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
88
104
|
def validate_role
|
89
105
|
unless VALID_ROLES.include?(role.to_s)
|
90
106
|
raise ArgumentError, "Invalid role: #{role}. Valid roles are: #{VALID_ROLES.join(", ")}"
|
@@ -4,12 +4,13 @@ module ActiveAgent
|
|
4
4
|
module ActionPrompt
|
5
5
|
class Prompt
|
6
6
|
attr_reader :messages, :instructions
|
7
|
-
attr_accessor :actions, :body, :content_type, :context_id, :message, :options, :mime_version, :charset, :context, :parts, :params, :action_choice, :agent_class, :output_schema, :action_name
|
7
|
+
attr_accessor :actions, :body, :content_type, :context_id, :message, :options, :mime_version, :charset, :context, :parts, :params, :action_choice, :agent_class, :output_schema, :action_name, :agent_instance, :mcp_servers
|
8
8
|
|
9
9
|
def initialize(attributes = {})
|
10
10
|
@options = attributes.fetch(:options, {})
|
11
11
|
@multimodal = attributes.fetch(:multimodal, false)
|
12
12
|
@agent_class = attributes.fetch(:agent_class, ApplicationAgent)
|
13
|
+
@agent_instance = attributes.fetch(:agent_instance, nil)
|
13
14
|
@actions = attributes.fetch(:actions, [])
|
14
15
|
@action_choice = attributes.fetch(:action_choice, "")
|
15
16
|
@instructions = attributes.fetch(:instructions, "")
|
@@ -27,12 +28,13 @@ module ActiveAgent
|
|
27
28
|
@output_schema = attributes.fetch(:output_schema, nil)
|
28
29
|
@messages = Message.from_messages(@messages)
|
29
30
|
@action_name = attributes.fetch(:action_name, nil)
|
31
|
+
@mcp_servers = attributes.fetch(:mcp_servers, [])
|
30
32
|
set_message if attributes[:message].is_a?(String) || @body.is_a?(String) && @message&.content
|
31
33
|
set_messages if @instructions.present?
|
32
34
|
end
|
33
35
|
|
34
36
|
def multimodal?
|
35
|
-
@multimodal ||= @message&.content.is_a?(Array) || @messages.any? { |m| m
|
37
|
+
@multimodal ||= @message&.content.is_a?(Array) || @messages.any? { |m| m&.content.is_a?(Array) }
|
36
38
|
end
|
37
39
|
|
38
40
|
def messages=(messages)
|
@@ -81,7 +83,7 @@ module ActiveAgent
|
|
81
83
|
|
82
84
|
def inspect
|
83
85
|
"#<#{self.class}:0x#{object_id.to_s(16)}\n" +
|
84
|
-
" @options=#{@options.inspect
|
86
|
+
" @options=#{ActiveAgent.sanitize_credentials(@options.inspect)}\n" +
|
85
87
|
" @actions=#{@actions.inspect}\n" +
|
86
88
|
" @action_choice=#{@action_choice.inspect}\n" +
|
87
89
|
" @instructions=#{@instructions.inspect}\n" +
|
data/lib/active_agent/base.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveAgent
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :verbose_generation_errors
|
6
|
+
attr_accessor :generation_retry_errors
|
7
|
+
attr_accessor :generation_max_retries
|
8
|
+
attr_accessor :generation_provider_logger
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@verbose_generation_errors = false
|
12
|
+
@generation_retry_errors = []
|
13
|
+
@generation_max_retries = 3
|
14
|
+
@generation_provider_logger = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def verbose_generation_errors?
|
18
|
+
@verbose_generation_errors
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure
|
28
|
+
yield configuration if block_given?
|
29
|
+
configuration
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset_configuration!
|
33
|
+
@configuration = Configuration.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -10,23 +10,29 @@ end
|
|
10
10
|
require "active_agent/action_prompt/action"
|
11
11
|
require_relative "base"
|
12
12
|
require_relative "response"
|
13
|
+
require_relative "stream_processing"
|
14
|
+
require_relative "message_formatting"
|
15
|
+
require_relative "tool_management"
|
13
16
|
|
14
17
|
module ActiveAgent
|
15
18
|
module GenerationProvider
|
16
19
|
class AnthropicProvider < Base
|
20
|
+
include StreamProcessing
|
21
|
+
include MessageFormatting
|
22
|
+
include ToolManagement
|
17
23
|
def initialize(config)
|
18
24
|
super
|
19
25
|
@access_token ||= config["api_key"] || config["access_token"] || Anthropic.configuration.access_token || ENV["ANTHROPIC_ACCESS_TOKEN"]
|
20
|
-
@
|
26
|
+
@extra_headers = config["extra_headers"] || {}
|
27
|
+
@client = Anthropic::Client.new(access_token: @access_token, extra_headers: @extra_headers)
|
21
28
|
end
|
22
29
|
|
23
30
|
def generate(prompt)
|
24
31
|
@prompt = prompt
|
25
32
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise GenerationProviderError, error_message
|
33
|
+
with_error_handling do
|
34
|
+
chat_prompt(parameters: prompt_parameters)
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
def chat_prompt(parameters: prompt_parameters)
|
@@ -35,75 +41,75 @@ module ActiveAgent
|
|
35
41
|
chat_response(@client.messages(parameters: parameters))
|
36
42
|
end
|
37
43
|
|
38
|
-
|
44
|
+
protected
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
46
|
+
# Override from StreamProcessing module for Anthropic-specific streaming
|
47
|
+
def process_stream_chunk(chunk, message, agent_stream)
|
48
|
+
if new_content = chunk.dig(:delta, :text)
|
49
|
+
message.content += new_content
|
50
|
+
agent_stream&.call(message, new_content, false, prompt.action_name)
|
51
|
+
end
|
44
52
|
|
45
|
-
|
46
|
-
|
47
|
-
message.content += new_content
|
48
|
-
agent_stream.call(message, nil, false, prompt.action_name) if agent_stream.respond_to?(:call)
|
49
|
-
end
|
53
|
+
if chunk[:type] == "message_stop"
|
54
|
+
finalize_stream(message, agent_stream)
|
50
55
|
end
|
51
56
|
end
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
# Override from ParameterBuilder to handle Anthropic-specific requirements
|
59
|
+
def build_provider_parameters
|
60
|
+
# Anthropic requires system message separately and no system role in messages
|
61
|
+
filtered_messages = @prompt.messages.reject { |m| m.role == :system }
|
62
|
+
system_message = @prompt.messages.find { |m| m.role == :system }
|
63
|
+
|
56
64
|
params = {
|
57
|
-
|
58
|
-
system: @prompt.options[:instructions],
|
59
|
-
messages: provider_messages(messages),
|
60
|
-
temperature: temperature,
|
61
|
-
max_tokens: @prompt.options[:max_tokens] || @config["max_tokens"] || 4096
|
65
|
+
system: system_message&.content || @prompt.options[:instructions]
|
62
66
|
}
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
end
|
68
|
+
# Override messages to use filtered version
|
69
|
+
@filtered_messages = filtered_messages
|
67
70
|
|
68
71
|
params
|
69
72
|
end
|
70
73
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
}
|
74
|
+
def build_base_parameters
|
75
|
+
super.tap do |params|
|
76
|
+
# Use filtered messages if available (set by build_provider_parameters)
|
77
|
+
params[:messages] = provider_messages(@filtered_messages || @prompt.messages)
|
78
|
+
# Anthropic requires max_tokens
|
79
|
+
params[:max_tokens] ||= 4096
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
# Override from ToolManagement for Anthropic-specific tool format
|
84
|
+
def format_single_tool(tool)
|
85
|
+
{
|
86
|
+
name: tool["name"] || tool.dig("function", "name") || tool[:name] || tool.dig(:function, :name),
|
87
|
+
description: tool["description"] || tool.dig("function", "description") || tool[:description] || tool.dig(:function, :description),
|
88
|
+
input_schema: tool["parameters"] || tool.dig("function", "parameters") || tool[:parameters] || tool.dig(:function, :parameters)
|
89
|
+
}
|
90
|
+
end
|
87
91
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
}
|
96
|
-
else
|
97
|
-
{
|
98
|
-
type: "text",
|
99
|
-
text: message.content
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
provider_message
|
92
|
+
# Override from MessageFormatting for Anthropic-specific message format
|
93
|
+
def format_content(message)
|
94
|
+
# Anthropic requires content as an array
|
95
|
+
if message.content_type == "image_url"
|
96
|
+
[ format_image_content(message).first ]
|
97
|
+
else
|
98
|
+
[ { type: "text", text: message.content } ]
|
104
99
|
end
|
105
100
|
end
|
106
101
|
|
102
|
+
def format_image_content(message)
|
103
|
+
[ {
|
104
|
+
type: "image",
|
105
|
+
source: {
|
106
|
+
type: "url",
|
107
|
+
url: message.content
|
108
|
+
}
|
109
|
+
} ]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Override from MessageFormatting for Anthropic role mapping
|
107
113
|
def convert_role(role)
|
108
114
|
case role.to_s
|
109
115
|
when "system" then "system"
|
@@ -123,7 +129,7 @@ module ActiveAgent
|
|
123
129
|
content: content,
|
124
130
|
role: "assistant",
|
125
131
|
action_requested: response["stop_reason"] == "tool_use",
|
126
|
-
requested_actions: handle_actions(response["tool_use"
|
132
|
+
requested_actions: handle_actions(response["content"].map { |c| c if c["type"] == "tool_use" }.reject { |m| m.blank? }.to_a),
|
127
133
|
)
|
128
134
|
|
129
135
|
update_context(prompt: prompt, message: message, response: response)
|
@@ -135,17 +141,18 @@ module ActiveAgent
|
|
135
141
|
)
|
136
142
|
end
|
137
143
|
|
138
|
-
|
139
|
-
|
144
|
+
# Override from ToolManagement for Anthropic-specific tool parsing
|
145
|
+
def parse_tool_call(tool_use)
|
146
|
+
return nil unless tool_use
|
140
147
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
)
|
147
|
-
end
|
148
|
+
ActiveAgent::ActionPrompt::Action.new(
|
149
|
+
id: tool_use[:id],
|
150
|
+
name: tool_use[:name],
|
151
|
+
params: tool_use[:input]
|
152
|
+
)
|
148
153
|
end
|
154
|
+
|
155
|
+
private
|
149
156
|
end
|
150
157
|
end
|
151
158
|
end
|
@@ -1,21 +1,34 @@
|
|
1
1
|
# lib/active_agent/generation_provider/base.rb
|
2
2
|
|
3
|
+
require_relative "error_handling"
|
4
|
+
require_relative "parameter_builder"
|
5
|
+
|
3
6
|
module ActiveAgent
|
4
7
|
module GenerationProvider
|
5
8
|
class Base
|
9
|
+
include ErrorHandling
|
10
|
+
include ParameterBuilder
|
11
|
+
|
6
12
|
class GenerationProviderError < StandardError; end
|
13
|
+
|
7
14
|
attr_reader :client, :config, :prompt, :response, :access_token, :model_name
|
8
15
|
|
9
16
|
def initialize(config)
|
10
17
|
@config = config
|
11
18
|
@prompt = nil
|
12
19
|
@response = nil
|
20
|
+
@model_name = config["model"] if config
|
13
21
|
end
|
14
22
|
|
15
23
|
def generate(prompt)
|
16
24
|
raise NotImplementedError, "Subclasses must implement the 'generate' method"
|
17
25
|
end
|
18
26
|
|
27
|
+
def embed(prompt)
|
28
|
+
# Optional embedding support - override in providers that support it
|
29
|
+
raise NotImplementedError, "#{self.class.name} does not support embeddings"
|
30
|
+
end
|
31
|
+
|
19
32
|
private
|
20
33
|
|
21
34
|
def handle_response(response)
|
@@ -30,11 +43,12 @@ module ActiveAgent
|
|
30
43
|
|
31
44
|
protected
|
32
45
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
46
|
+
# This method is now provided by ParameterBuilder module
|
47
|
+
# but can still be overridden if needed
|
48
|
+
def build_provider_parameters
|
49
|
+
# Base implementation returns empty hash
|
50
|
+
# Providers override this to add their specific parameters
|
51
|
+
{}
|
38
52
|
end
|
39
53
|
end
|
40
54
|
end
|