activeagent 0.6.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +240 -2
- data/README.md +15 -24
- data/lib/active_agent/base.rb +389 -39
- data/lib/active_agent/concerns/callbacks.rb +251 -0
- data/lib/active_agent/concerns/observers.rb +147 -0
- data/lib/active_agent/concerns/parameterized.rb +292 -0
- data/lib/active_agent/concerns/provider.rb +120 -0
- data/lib/active_agent/concerns/queueing.rb +36 -0
- data/lib/active_agent/concerns/rescue.rb +64 -0
- data/lib/active_agent/concerns/streaming.rb +282 -0
- data/lib/active_agent/concerns/tooling.rb +23 -0
- data/lib/active_agent/concerns/view.rb +150 -0
- data/lib/active_agent/configuration.rb +442 -20
- data/lib/active_agent/generation.rb +141 -47
- data/lib/active_agent/providers/_base_provider.rb +420 -0
- data/lib/active_agent/providers/anthropic/_types.rb +63 -0
- data/lib/active_agent/providers/anthropic/options.rb +53 -0
- data/lib/active_agent/providers/anthropic/request.rb +163 -0
- data/lib/active_agent/providers/anthropic/transforms.rb +353 -0
- data/lib/active_agent/providers/anthropic_provider.rb +254 -0
- data/lib/active_agent/providers/common/messages/_types.rb +160 -0
- data/lib/active_agent/providers/common/messages/assistant.rb +57 -0
- data/lib/active_agent/providers/common/messages/base.rb +17 -0
- data/lib/active_agent/providers/common/messages/system.rb +20 -0
- data/lib/active_agent/providers/common/messages/tool.rb +21 -0
- data/lib/active_agent/providers/common/messages/user.rb +20 -0
- data/lib/active_agent/providers/common/model.rb +361 -0
- data/lib/active_agent/providers/common/response.rb +13 -0
- data/lib/active_agent/providers/common/responses/_types.rb +51 -0
- data/lib/active_agent/providers/common/responses/base.rb +199 -0
- data/lib/active_agent/providers/common/responses/embed.rb +33 -0
- data/lib/active_agent/providers/common/responses/format.rb +31 -0
- data/lib/active_agent/providers/common/responses/message.rb +3 -0
- data/lib/active_agent/providers/common/responses/prompt.rb +42 -0
- data/lib/active_agent/providers/common/usage.rb +385 -0
- data/lib/active_agent/providers/concerns/exception_handler.rb +72 -0
- data/lib/active_agent/providers/concerns/instrumentation.rb +263 -0
- data/lib/active_agent/providers/concerns/previewable.rb +150 -0
- data/lib/active_agent/providers/log_subscriber.rb +178 -0
- data/lib/active_agent/providers/mock/_types.rb +77 -0
- data/lib/active_agent/providers/mock/embedding_request.rb +17 -0
- data/lib/active_agent/providers/mock/messages/_types.rb +103 -0
- data/lib/active_agent/providers/mock/messages/assistant.rb +26 -0
- data/lib/active_agent/providers/mock/messages/base.rb +63 -0
- data/lib/active_agent/providers/mock/messages/user.rb +18 -0
- data/lib/active_agent/providers/mock/options.rb +30 -0
- data/lib/active_agent/providers/mock/request.rb +38 -0
- data/lib/active_agent/providers/mock_provider.rb +311 -0
- data/lib/active_agent/providers/ollama/_types.rb +5 -0
- data/lib/active_agent/providers/ollama/chat/_types.rb +44 -0
- data/lib/active_agent/providers/ollama/chat/request.rb +249 -0
- data/lib/active_agent/providers/ollama/chat/transforms.rb +135 -0
- data/lib/active_agent/providers/ollama/embedding/_types.rb +44 -0
- data/lib/active_agent/providers/ollama/embedding/request.rb +190 -0
- data/lib/active_agent/providers/ollama/embedding/transforms.rb +160 -0
- data/lib/active_agent/providers/ollama/options.rb +27 -0
- data/lib/active_agent/providers/ollama_provider.rb +94 -0
- data/lib/active_agent/providers/open_ai/_base.rb +59 -0
- data/lib/active_agent/providers/open_ai/_types.rb +5 -0
- data/lib/active_agent/providers/open_ai/chat/_types.rb +56 -0
- data/lib/active_agent/providers/open_ai/chat/request.rb +161 -0
- data/lib/active_agent/providers/open_ai/chat/transforms.rb +364 -0
- data/lib/active_agent/providers/open_ai/chat_provider.rb +219 -0
- data/lib/active_agent/providers/open_ai/embedding/_types.rb +56 -0
- data/lib/active_agent/providers/open_ai/embedding/request.rb +53 -0
- data/lib/active_agent/providers/open_ai/embedding/transforms.rb +88 -0
- data/lib/active_agent/providers/open_ai/options.rb +74 -0
- data/lib/active_agent/providers/open_ai/responses/_types.rb +44 -0
- data/lib/active_agent/providers/open_ai/responses/request.rb +129 -0
- data/lib/active_agent/providers/open_ai/responses/transforms.rb +228 -0
- data/lib/active_agent/providers/open_ai/responses_provider.rb +200 -0
- data/lib/active_agent/providers/open_ai_provider.rb +94 -0
- data/lib/active_agent/providers/open_router/_types.rb +71 -0
- data/lib/active_agent/providers/open_router/options.rb +141 -0
- data/lib/active_agent/providers/open_router/request.rb +249 -0
- data/lib/active_agent/providers/open_router/requests/_types.rb +197 -0
- data/lib/active_agent/providers/open_router/requests/messages/_types.rb +56 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/_types.rb +97 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +43 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/files/_types.rb +61 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +37 -0
- data/lib/active_agent/providers/open_router/requests/plugin.rb +41 -0
- data/lib/active_agent/providers/open_router/requests/plugins/_types.rb +46 -0
- data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +51 -0
- data/lib/active_agent/providers/open_router/requests/prediction.rb +34 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/_types.rb +44 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +64 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +105 -0
- data/lib/active_agent/providers/open_router/requests/response_format.rb +77 -0
- data/lib/active_agent/providers/open_router/transforms.rb +134 -0
- data/lib/active_agent/providers/open_router_provider.rb +62 -0
- data/lib/active_agent/providers/openai_provider.rb +2 -0
- data/lib/active_agent/providers/openrouter_provider.rb +2 -0
- data/lib/active_agent/railtie.rb +8 -6
- data/lib/active_agent/schema_generator.rb +333 -166
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +112 -36
- data/lib/generators/active_agent/agent/USAGE +78 -0
- data/lib/generators/active_agent/{agent_generator.rb → agent/agent_generator.rb} +14 -4
- data/lib/generators/active_agent/install/USAGE +25 -0
- data/lib/generators/active_agent/{install_generator.rb → install/install_generator.rb} +1 -19
- data/lib/generators/active_agent/templates/agent.rb.tt +7 -3
- data/lib/generators/active_agent/templates/application_agent.rb.tt +0 -2
- data/lib/generators/erb/agent_generator.rb +31 -16
- data/lib/generators/erb/templates/instructions.md.erb.tt +3 -0
- data/lib/generators/erb/templates/instructions.md.tt +3 -0
- data/lib/generators/erb/templates/instructions.text.tt +1 -0
- data/lib/generators/erb/templates/message.md.erb.tt +5 -0
- data/lib/generators/erb/templates/schema.json.tt +10 -0
- data/lib/generators/test_unit/agent_generator.rb +1 -1
- data/lib/generators/test_unit/templates/functional_test.rb.tt +4 -2
- metadata +182 -71
- data/lib/active_agent/action_prompt/action.rb +0 -13
- data/lib/active_agent/action_prompt/base.rb +0 -623
- data/lib/active_agent/action_prompt/message.rb +0 -126
- data/lib/active_agent/action_prompt/prompt.rb +0 -136
- data/lib/active_agent/action_prompt.rb +0 -19
- data/lib/active_agent/callbacks.rb +0 -33
- data/lib/active_agent/generation_provider/anthropic_provider.rb +0 -163
- data/lib/active_agent/generation_provider/base.rb +0 -55
- data/lib/active_agent/generation_provider/base_adapter.rb +0 -19
- data/lib/active_agent/generation_provider/error_handling.rb +0 -167
- data/lib/active_agent/generation_provider/log_subscriber.rb +0 -92
- data/lib/active_agent/generation_provider/message_formatting.rb +0 -107
- data/lib/active_agent/generation_provider/ollama_provider.rb +0 -66
- data/lib/active_agent/generation_provider/open_ai_provider.rb +0 -279
- data/lib/active_agent/generation_provider/open_router_provider.rb +0 -385
- data/lib/active_agent/generation_provider/parameter_builder.rb +0 -119
- data/lib/active_agent/generation_provider/response.rb +0 -75
- data/lib/active_agent/generation_provider/responses_adapter.rb +0 -44
- data/lib/active_agent/generation_provider/stream_processing.rb +0 -58
- data/lib/active_agent/generation_provider/tool_management.rb +0 -142
- data/lib/active_agent/generation_provider.rb +0 -67
- data/lib/active_agent/log_subscriber.rb +0 -44
- data/lib/active_agent/parameterized.rb +0 -75
- data/lib/active_agent/prompt_helper.rb +0 -19
- data/lib/active_agent/queued_generation.rb +0 -12
- data/lib/active_agent/rescuable.rb +0 -34
- data/lib/active_agent/sanitizers.rb +0 -40
- data/lib/active_agent/streaming.rb +0 -34
- data/lib/active_agent/test_case.rb +0 -125
- data/lib/generators/USAGE +0 -47
- data/lib/generators/active_agent/USAGE +0 -56
- data/lib/generators/erb/install_generator.rb +0 -44
- data/lib/generators/erb/templates/layout.html.erb.tt +0 -1
- data/lib/generators/erb/templates/layout.json.erb.tt +0 -1
- data/lib/generators/erb/templates/layout.text.erb.tt +0 -1
- data/lib/generators/erb/templates/view.html.erb.tt +0 -5
- data/lib/generators/erb/templates/view.json.erb.tt +0 -16
- /data/lib/active_agent/{preview.rb → concerns/preview.rb} +0 -0
- /data/lib/generators/erb/templates/{view.text.erb.tt → message.text.erb.tt} +0 -0
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
module ActiveAgent
|
|
2
|
-
module ActionPrompt
|
|
3
|
-
class Message
|
|
4
|
-
class << self
|
|
5
|
-
def from_messages(messages)
|
|
6
|
-
return messages if messages.empty? || messages.first.is_a?(Message)
|
|
7
|
-
|
|
8
|
-
messages.map do |message|
|
|
9
|
-
if message.is_a?(Hash)
|
|
10
|
-
new(message)
|
|
11
|
-
elsif message.is_a?(Message)
|
|
12
|
-
message
|
|
13
|
-
else
|
|
14
|
-
raise ArgumentError, "Messages must be Hash or Message objects"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
VALID_ROLES = %w[system assistant user tool].freeze
|
|
20
|
-
|
|
21
|
-
attr_accessor :action_id, :action_name, :raw_actions, :generation_id, :content, :raw_content, :role, :action_requested, :requested_actions, :content_type, :charset, :metadata
|
|
22
|
-
|
|
23
|
-
def initialize(attributes = {})
|
|
24
|
-
@action_id = attributes[:action_id]
|
|
25
|
-
@action_name = attributes[:action_name]
|
|
26
|
-
@generation_id = attributes[:generation_id]
|
|
27
|
-
@metadata = attributes[:metadata] || {}
|
|
28
|
-
@charset = attributes[:charset] || "UTF-8"
|
|
29
|
-
@raw_content = attributes[:content] || ""
|
|
30
|
-
@content_type = detect_content_type(attributes)
|
|
31
|
-
@content = parse_content(@raw_content, @content_type)
|
|
32
|
-
@role = attributes[:role] || :user
|
|
33
|
-
@raw_actions = attributes[:raw_actions]
|
|
34
|
-
@requested_actions = attributes[:requested_actions] || []
|
|
35
|
-
@action_requested = @requested_actions.any?
|
|
36
|
-
validate_role
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def to_s
|
|
40
|
-
@content.to_s
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def to_h
|
|
44
|
-
hash = {
|
|
45
|
-
role: role,
|
|
46
|
-
action_id: action_id,
|
|
47
|
-
name: action_name,
|
|
48
|
-
generation_id: generation_id,
|
|
49
|
-
content: content,
|
|
50
|
-
type: content_type,
|
|
51
|
-
charset: charset
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
hash[:action_requested] = requested_actions.any?
|
|
55
|
-
hash[:requested_actions] = requested_actions if requested_actions.any?
|
|
56
|
-
hash
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def embed
|
|
60
|
-
@agent_class.embed(@content)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def inspect
|
|
64
|
-
truncated_content = if @content.is_a?(String) && @content.length > 256
|
|
65
|
-
@content[0, 256] + "..."
|
|
66
|
-
elsif @content.is_a?(Array)
|
|
67
|
-
@content.map do |item|
|
|
68
|
-
if item.is_a?(String) && item.length > 256
|
|
69
|
-
item[0, 256] + "..."
|
|
70
|
-
else
|
|
71
|
-
item
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
else
|
|
75
|
-
@content
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
"#<#{self.class}:0x#{object_id.to_s(16)}\n" +
|
|
79
|
-
" @action_id=#{@action_id.inspect},\n" +
|
|
80
|
-
" @action_name=#{@action_name.inspect},\n" +
|
|
81
|
-
" @action_requested=#{@action_requested.inspect},\n" +
|
|
82
|
-
" @charset=#{@charset.inspect},\n" +
|
|
83
|
-
" @content=#{truncated_content.inspect},\n" +
|
|
84
|
-
" @role=#{@role.inspect}>"
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
private
|
|
88
|
-
|
|
89
|
-
def parse_content(content, content_type)
|
|
90
|
-
# Auto-parse JSON content if content_type indicates JSON
|
|
91
|
-
if content_type&.match?(/json/i) && content.is_a?(String) && !content.empty?
|
|
92
|
-
begin
|
|
93
|
-
JSON.parse(content)
|
|
94
|
-
rescue JSON::ParserError
|
|
95
|
-
# If parsing fails, return the raw content
|
|
96
|
-
content
|
|
97
|
-
end
|
|
98
|
-
else
|
|
99
|
-
content
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def detect_content_type(attributes)
|
|
104
|
-
# If content_type is explicitly provided, use it
|
|
105
|
-
return attributes[:content_type] if attributes[:content_type]
|
|
106
|
-
|
|
107
|
-
# If content is an array with multipart/mixed content, set appropriate type
|
|
108
|
-
if attributes[:content].is_a?(Array)
|
|
109
|
-
# Check if it contains multimodal content (text, image_url, file, etc.)
|
|
110
|
-
has_multimodal = attributes[:content].any? do |item|
|
|
111
|
-
item.is_a?(Hash) && (item[:type] || item["type"])
|
|
112
|
-
end
|
|
113
|
-
has_multimodal ? "multipart/mixed" : "array"
|
|
114
|
-
else
|
|
115
|
-
"text/plain"
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def validate_role
|
|
120
|
-
unless VALID_ROLES.include?(role.to_s)
|
|
121
|
-
raise ArgumentError, "Invalid role: #{role}. Valid roles are: #{VALID_ROLES.join(", ")}"
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
require_relative "message"
|
|
2
|
-
|
|
3
|
-
module ActiveAgent
|
|
4
|
-
module ActionPrompt
|
|
5
|
-
class Prompt
|
|
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, :agent_instance, :mcp_servers
|
|
8
|
-
|
|
9
|
-
def initialize(attributes = {})
|
|
10
|
-
@options = attributes.fetch(:options, {})
|
|
11
|
-
@multimodal = attributes.fetch(:multimodal, false)
|
|
12
|
-
@agent_class = attributes.fetch(:agent_class, ApplicationAgent)
|
|
13
|
-
@agent_instance = attributes.fetch(:agent_instance, nil)
|
|
14
|
-
@actions = attributes.fetch(:actions, [])
|
|
15
|
-
@action_choice = attributes.fetch(:action_choice, "")
|
|
16
|
-
@instructions = attributes.fetch(:instructions, "")
|
|
17
|
-
@body = attributes.fetch(:body, "")
|
|
18
|
-
@content_type = attributes.fetch(:content_type, "text/plain")
|
|
19
|
-
@message = attributes.fetch(:message, nil)
|
|
20
|
-
@messages = attributes.fetch(:messages, [])
|
|
21
|
-
@params = attributes.fetch(:params, {})
|
|
22
|
-
@mime_version = attributes.fetch(:mime_version, "1.0")
|
|
23
|
-
@charset = attributes.fetch(:charset, "UTF-8")
|
|
24
|
-
@context = attributes.fetch(:context, [])
|
|
25
|
-
@context_id = attributes.fetch(:context_id, nil)
|
|
26
|
-
@headers = attributes.fetch(:headers, {})
|
|
27
|
-
@parts = attributes.fetch(:parts, [])
|
|
28
|
-
@output_schema = attributes.fetch(:output_schema, nil)
|
|
29
|
-
@messages = Message.from_messages(@messages)
|
|
30
|
-
@action_name = attributes.fetch(:action_name, nil)
|
|
31
|
-
@mcp_servers = attributes.fetch(:mcp_servers, [])
|
|
32
|
-
set_message if attributes[:message].is_a?(String) || @body.is_a?(String) && @message&.content
|
|
33
|
-
# Ensure we have a system message with instructions at the start
|
|
34
|
-
if @messages.empty? || @messages[0].role != :system
|
|
35
|
-
@messages.unshift(instructions_message)
|
|
36
|
-
elsif @instructions.present?
|
|
37
|
-
@messages[0] = instructions_message
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def multimodal?
|
|
42
|
-
@multimodal ||= @message&.content.is_a?(Array) || @messages.any? { |m| m&.content.is_a?(Array) }
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def messages=(messages)
|
|
46
|
-
@messages = messages
|
|
47
|
-
# Only add system message if we have instructions and don't already have a system message
|
|
48
|
-
if @instructions.present? && (@messages.empty? || @messages.first&.role != :system)
|
|
49
|
-
set_messages
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def instructions=(instructions)
|
|
54
|
-
# Store the instructions even if blank (will use empty string)
|
|
55
|
-
@instructions = instructions || ""
|
|
56
|
-
|
|
57
|
-
# Update or add the system message
|
|
58
|
-
if @messages[0].present? && @messages[0].role == :system
|
|
59
|
-
@messages[0] = instructions_message
|
|
60
|
-
elsif @messages.empty? || @messages[0].role != :system
|
|
61
|
-
# Only add system message if we don't have one at the start
|
|
62
|
-
@messages.unshift(instructions_message)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Generate the prompt as a string (for debugging or sending to the provider)
|
|
67
|
-
def to_s
|
|
68
|
-
@message.to_s
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def add_part(message)
|
|
72
|
-
@message = message
|
|
73
|
-
set_message
|
|
74
|
-
|
|
75
|
-
@parts << message
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def multipart?
|
|
79
|
-
@parts.any?
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def to_h
|
|
83
|
-
{
|
|
84
|
-
actions: @actions,
|
|
85
|
-
action: @action_choice,
|
|
86
|
-
instructions: @instructions,
|
|
87
|
-
message: @message.to_h,
|
|
88
|
-
messages: @messages.map(&:to_h),
|
|
89
|
-
headers: @headers,
|
|
90
|
-
context: @context
|
|
91
|
-
}
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def inspect
|
|
95
|
-
"#<#{self.class}:0x#{object_id.to_s(16)}\n" +
|
|
96
|
-
" @options=#{ActiveAgent.sanitize_credentials(@options.inspect)}\n" +
|
|
97
|
-
" @actions=#{@actions.inspect}\n" +
|
|
98
|
-
" @action_choice=#{@action_choice.inspect}\n" +
|
|
99
|
-
" @instructions=#{@instructions.inspect}\n" +
|
|
100
|
-
" @message=#{@message.inspect}\n" +
|
|
101
|
-
" @output_schema=#{@output_schema}\n" +
|
|
102
|
-
" @headers=#{@headers.inspect}\n" +
|
|
103
|
-
" @context=#{@context.inspect}\n" +
|
|
104
|
-
" @messages=#{@messages.inspect}\n" +
|
|
105
|
-
">"
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def headers(headers = {})
|
|
109
|
-
@headers.merge!(headers)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
private
|
|
113
|
-
|
|
114
|
-
def instructions_message
|
|
115
|
-
Message.new(content: @instructions, role: :system)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def set_messages
|
|
119
|
-
@messages = [ instructions_message ] + @messages
|
|
120
|
-
# if @message.nil? || @message.content.blank?
|
|
121
|
-
# @message = @messages.last
|
|
122
|
-
# end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def set_message
|
|
126
|
-
if @message.is_a? String
|
|
127
|
-
@message = Message.new(content: @message, role: :user)
|
|
128
|
-
elsif @body.is_a?(String) && @message.content.blank?
|
|
129
|
-
@message = Message.new(content: @body, role: :user)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
@messages = @messages + [ @message ]
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require "abstract_controller"
|
|
2
|
-
require "active_support/core_ext/string/inflections"
|
|
3
|
-
|
|
4
|
-
module ActiveAgent
|
|
5
|
-
module ActionPrompt
|
|
6
|
-
extend ::ActiveSupport::Autoload
|
|
7
|
-
|
|
8
|
-
eager_autoload do
|
|
9
|
-
autoload :Collector
|
|
10
|
-
autoload :Message
|
|
11
|
-
autoload :Prompt
|
|
12
|
-
autoload :PromptHelper
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
autoload :Base
|
|
16
|
-
|
|
17
|
-
extend ActiveSupport::Concern
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActiveAgent
|
|
4
|
-
module Callbacks
|
|
5
|
-
extend ActiveSupport::Concern
|
|
6
|
-
|
|
7
|
-
included do
|
|
8
|
-
include ActiveSupport::Callbacks
|
|
9
|
-
define_callbacks :generation, skip_after_callbacks_if_terminated: true
|
|
10
|
-
define_callbacks :embedding, skip_after_callbacks_if_terminated: true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
module ClassMethods
|
|
14
|
-
# # Defines a callback that will get called right before/after/around the
|
|
15
|
-
# # generation provider method.
|
|
16
|
-
[ :before, :after, :around ].each do |callback|
|
|
17
|
-
define_method "#{callback}_generation" do |*names, &blk|
|
|
18
|
-
_insert_callbacks(names, blk) do |name, options|
|
|
19
|
-
set_callback(:generation, callback, name, options)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# # Defines a callback that will get called right before/after/around the
|
|
24
|
-
# # embedding provider method.
|
|
25
|
-
define_method "#{callback}_embedding" do |*names, &blk|
|
|
26
|
-
_insert_callbacks(names, blk) do |name, options|
|
|
27
|
-
set_callback(:embedding, callback, name, options)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
# lib/active_agent/generation_provider/anthropic_provider.rb
|
|
2
|
-
|
|
3
|
-
begin
|
|
4
|
-
gem "ruby-anthropic", "~> 0.4.2"
|
|
5
|
-
require "anthropic"
|
|
6
|
-
rescue LoadError
|
|
7
|
-
raise LoadError, "The 'ruby-anthropic ~> 0.4.2' gem is required for AnthropicProvider. Please add it to your Gemfile and run `bundle install`."
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
require "active_agent/action_prompt/action"
|
|
11
|
-
require_relative "base"
|
|
12
|
-
require_relative "response"
|
|
13
|
-
require_relative "stream_processing"
|
|
14
|
-
require_relative "message_formatting"
|
|
15
|
-
require_relative "tool_management"
|
|
16
|
-
|
|
17
|
-
module ActiveAgent
|
|
18
|
-
module GenerationProvider
|
|
19
|
-
class AnthropicProvider < Base
|
|
20
|
-
include StreamProcessing
|
|
21
|
-
include MessageFormatting
|
|
22
|
-
include ToolManagement
|
|
23
|
-
def initialize(config)
|
|
24
|
-
super
|
|
25
|
-
@access_token ||= config["api_key"] || config["access_token"] || Anthropic.configuration.access_token || ENV["ANTHROPIC_ACCESS_TOKEN"]
|
|
26
|
-
@extra_headers = config["extra_headers"] || {}
|
|
27
|
-
@client = Anthropic::Client.new(access_token: @access_token, extra_headers: @extra_headers)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def generate(prompt)
|
|
31
|
-
@prompt = prompt
|
|
32
|
-
|
|
33
|
-
with_error_handling do
|
|
34
|
-
chat_prompt(parameters: prompt_parameters)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def chat_prompt(parameters: prompt_parameters)
|
|
39
|
-
if prompt.options[:stream] || config["stream"]
|
|
40
|
-
parameters[:stream] = provider_stream
|
|
41
|
-
@streaming_request_params = parameters
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
chat_response(@client.messages(parameters: parameters), parameters)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
protected
|
|
48
|
-
|
|
49
|
-
# Override from StreamProcessing module for Anthropic-specific streaming
|
|
50
|
-
def process_stream_chunk(chunk, message, agent_stream)
|
|
51
|
-
if new_content = chunk.dig(:delta, :text)
|
|
52
|
-
message.content += new_content
|
|
53
|
-
agent_stream&.call(message, new_content, false, prompt.action_name)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
if chunk[:type] == "message_stop"
|
|
57
|
-
finalize_stream(message, agent_stream)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Override from ParameterBuilder to handle Anthropic-specific requirements
|
|
62
|
-
def build_provider_parameters
|
|
63
|
-
# Anthropic requires system message separately and no system role in messages
|
|
64
|
-
filtered_messages = @prompt.messages.reject { |m| m.role == :system }
|
|
65
|
-
system_message = @prompt.messages.find { |m| m.role == :system }
|
|
66
|
-
|
|
67
|
-
params = {
|
|
68
|
-
system: system_message&.content || @prompt.options[:instructions]
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
# Override messages to use filtered version
|
|
72
|
-
@filtered_messages = filtered_messages
|
|
73
|
-
|
|
74
|
-
params
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def build_base_parameters
|
|
78
|
-
super.tap do |params|
|
|
79
|
-
# Use filtered messages if available (set by build_provider_parameters)
|
|
80
|
-
params[:messages] = provider_messages(@filtered_messages || @prompt.messages)
|
|
81
|
-
# Anthropic requires max_tokens
|
|
82
|
-
params[:max_tokens] ||= 4096
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Override from ToolManagement for Anthropic-specific tool format
|
|
87
|
-
def format_single_tool(tool)
|
|
88
|
-
{
|
|
89
|
-
name: tool["name"] || tool.dig("function", "name") || tool[:name] || tool.dig(:function, :name),
|
|
90
|
-
description: tool["description"] || tool.dig("function", "description") || tool[:description] || tool.dig(:function, :description),
|
|
91
|
-
input_schema: tool["parameters"] || tool.dig("function", "parameters") || tool[:parameters] || tool.dig(:function, :parameters)
|
|
92
|
-
}
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Override from MessageFormatting for Anthropic-specific message format
|
|
96
|
-
def format_content(message)
|
|
97
|
-
# Anthropic requires content as an array
|
|
98
|
-
if message.content_type == "image_url"
|
|
99
|
-
[ format_image_content(message).first ]
|
|
100
|
-
else
|
|
101
|
-
[ { type: "text", text: message.content } ]
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def format_image_content(message)
|
|
106
|
-
[ {
|
|
107
|
-
type: "image",
|
|
108
|
-
source: {
|
|
109
|
-
type: "url",
|
|
110
|
-
url: message.content
|
|
111
|
-
}
|
|
112
|
-
} ]
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Override from MessageFormatting for Anthropic role mapping
|
|
116
|
-
def convert_role(role)
|
|
117
|
-
case role.to_s
|
|
118
|
-
when "system" then "system"
|
|
119
|
-
when "user" then "user"
|
|
120
|
-
when "assistant" then "assistant"
|
|
121
|
-
when "tool", "function" then "assistant"
|
|
122
|
-
else "user"
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def chat_response(response, request_params = nil)
|
|
127
|
-
return @response if prompt.options[:stream]
|
|
128
|
-
|
|
129
|
-
content = response["content"].first["text"]
|
|
130
|
-
|
|
131
|
-
message = ActiveAgent::ActionPrompt::Message.new(
|
|
132
|
-
content: content,
|
|
133
|
-
content_type: prompt.output_schema.present? ? "application/json" : "text/plain",
|
|
134
|
-
role: "assistant",
|
|
135
|
-
action_requested: response["stop_reason"] == "tool_use",
|
|
136
|
-
requested_actions: handle_actions(response["content"].map { |c| c if c["type"] == "tool_use" }.reject { |m| m.blank? }.to_a),
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
update_context(prompt: prompt, message: message, response: response)
|
|
140
|
-
|
|
141
|
-
@response = ActiveAgent::GenerationProvider::Response.new(
|
|
142
|
-
prompt: prompt,
|
|
143
|
-
message: message,
|
|
144
|
-
raw_response: response,
|
|
145
|
-
raw_request: request_params
|
|
146
|
-
)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Override from ToolManagement for Anthropic-specific tool parsing
|
|
150
|
-
def parse_tool_call(tool_use)
|
|
151
|
-
return nil unless tool_use
|
|
152
|
-
|
|
153
|
-
ActiveAgent::ActionPrompt::Action.new(
|
|
154
|
-
id: tool_use[:id],
|
|
155
|
-
name: tool_use[:name],
|
|
156
|
-
params: tool_use[:input]
|
|
157
|
-
)
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
private
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# lib/active_agent/generation_provider/base.rb
|
|
2
|
-
|
|
3
|
-
require_relative "error_handling"
|
|
4
|
-
require_relative "parameter_builder"
|
|
5
|
-
|
|
6
|
-
module ActiveAgent
|
|
7
|
-
module GenerationProvider
|
|
8
|
-
class Base
|
|
9
|
-
include ErrorHandling
|
|
10
|
-
include ParameterBuilder
|
|
11
|
-
|
|
12
|
-
class GenerationProviderError < StandardError; end
|
|
13
|
-
|
|
14
|
-
attr_reader :client, :config, :prompt, :response, :access_token, :model_name
|
|
15
|
-
|
|
16
|
-
def initialize(config)
|
|
17
|
-
@config = config
|
|
18
|
-
@prompt = nil
|
|
19
|
-
@response = nil
|
|
20
|
-
@model_name = config["model"] if config
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def generate(prompt)
|
|
24
|
-
raise NotImplementedError, "Subclasses must implement the 'generate' method"
|
|
25
|
-
end
|
|
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
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def handle_response(response)
|
|
35
|
-
@response = ActiveAgent::GenerationProvider::Response.new(message:, raw_response: response)
|
|
36
|
-
raise NotImplementedError, "Subclasses must implement the 'handle_response' method"
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def update_context(prompt:, message:, response:)
|
|
40
|
-
prompt.message = message
|
|
41
|
-
prompt.messages << message
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
protected
|
|
45
|
-
|
|
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
|
-
{}
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module ActiveAgent
|
|
2
|
-
module GenerationProvider
|
|
3
|
-
class BaseAdapter
|
|
4
|
-
attr_reader :prompt
|
|
5
|
-
|
|
6
|
-
def initialize(prompt)
|
|
7
|
-
@prompt = prompt
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def input
|
|
11
|
-
raise NotImplementedError, "Subclasses must implement the 'input' method"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def response
|
|
15
|
-
raise NotImplementedError, "Subclasses must implement the 'response' method"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|