activeagent 0.2.6.7 → 0.2.6.9
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/message.rb +1 -3
- data/lib/active_agent/action_prompt/prompt.rb +3 -1
- data/lib/active_agent/base.rb +44 -45
- data/lib/active_agent/generation.rb +2 -2
- data/lib/active_agent/generation_provider/anthropic_provider.rb +142 -0
- data/lib/active_agent/generation_provider/open_ai_provider.rb +10 -3
- data/lib/active_agent/version.rb +1 -1
- data/lib/generators/active_agent/agent_generator.rb +2 -2
- data/lib/generators/active_agent/install_generator.rb +4 -0
- data/lib/generators/active_agent/templates/agent.text.erb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08db8e070616e81109c24a4738d29cc5c7b2911a3b7584e90c23cd9a1072a20a'
|
4
|
+
data.tar.gz: 424e66ddfde6018b15b33d440764604db3cb3c1c3bef3f6cc0c0e765cad8d06e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6b7d4b86153dfea08db656c6b0620229902d371fd0afccbc4eca30e961875a4982339dfd4cdc77c2349d9ecf7e9085a98de07a406c73c15cf4a25ffc0fe3548
|
7
|
+
data.tar.gz: 4bb01d36f8610e25f0f0220f9b465779e15afa083786dfa8628def00b5a693a2804ff9665f967e484034ef30ea4312e2eafcc813aef1f66fb597ff7dd5bbbe49
|
@@ -3,14 +3,13 @@ module ActiveAgent
|
|
3
3
|
class Message
|
4
4
|
VALID_ROLES = %w[system assistant user tool function].freeze
|
5
5
|
|
6
|
-
attr_accessor :action_id, :content, :role, :
|
6
|
+
attr_accessor :action_id, :content, :role, :action_requested, :requested_actions, :content_type, :charset
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
9
|
@action_id = attributes[:action_id]
|
10
10
|
@charset = attributes[:charset] || "UTF-8"
|
11
11
|
@content = attributes[:content] || ""
|
12
12
|
@content_type = attributes[:content_type] || "text/plain"
|
13
|
-
@name = attributes[:name]
|
14
13
|
@role = attributes[:role] || :user
|
15
14
|
@requested_actions = attributes[:requested_actions] || []
|
16
15
|
@action_requested = @requested_actions.any?
|
@@ -26,7 +25,6 @@ module ActiveAgent
|
|
26
25
|
charset: charset
|
27
26
|
}
|
28
27
|
|
29
|
-
hash[:name] = name if name
|
30
28
|
hash[:action_requested] = requested_actions.any?
|
31
29
|
hash[:requested_actions] = requested_actions if requested_actions.any?
|
32
30
|
hash
|
@@ -3,10 +3,11 @@ require_relative "message"
|
|
3
3
|
module ActiveAgent
|
4
4
|
module ActionPrompt
|
5
5
|
class Prompt
|
6
|
-
attr_accessor :actions, :body, :content_type, :instructions, :message, :messages, :options, :mime_version, :charset, :context, :parts
|
6
|
+
attr_accessor :actions, :body, :content_type, :context_id, :instructions, :message, :messages, :options, :mime_version, :charset, :context, :parts
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
9
|
@options = attributes.fetch(:options, {})
|
10
|
+
@agent_class = attributes.fetch(:agent_class, ApplicationAgent)
|
10
11
|
@actions = attributes.fetch(:actions, [])
|
11
12
|
@action_choice = attributes.fetch(:action_choice, "")
|
12
13
|
@instructions = attributes.fetch(:instructions, "")
|
@@ -18,6 +19,7 @@ module ActiveAgent
|
|
18
19
|
@mime_version = attributes.fetch(:mime_version, "1.0")
|
19
20
|
@charset = attributes.fetch(:charset, "UTF-8")
|
20
21
|
@context = attributes.fetch(:context, [])
|
22
|
+
@context_id = attributes.fetch(:context_id, nil)
|
21
23
|
@headers = attributes.fetch(:headers, {})
|
22
24
|
@parts = attributes.fetch(:parts, [])
|
23
25
|
|
data/lib/active_agent/base.rb
CHANGED
@@ -129,6 +129,7 @@ module ActiveAgent
|
|
129
129
|
def generate_with(provider, **options)
|
130
130
|
self.generation_provider = provider
|
131
131
|
self.options = (options || {}).merge(options)
|
132
|
+
self.options[:stream] = new.agent_stream if self.options[:stream]
|
132
133
|
generation_provider.config.merge!(self.options)
|
133
134
|
end
|
134
135
|
|
@@ -176,13 +177,8 @@ module ActiveAgent
|
|
176
177
|
|
177
178
|
def set_payload_for_prompt(payload, prompt)
|
178
179
|
payload[:prompt] = prompt.encoded
|
179
|
-
payload[:agent] =
|
180
|
+
payload[:agent] = agent_name
|
180
181
|
payload[:message_id] = prompt.message_id
|
181
|
-
payload[:subject] = prompt.subject
|
182
|
-
payload[:to] = prompt.to
|
183
|
-
payload[:from] = prompt.from
|
184
|
-
payload[:bcc] = prompt.bcc if prompt.bcc.present?
|
185
|
-
payload[:cc] = prompt.cc if prompt.cc.present?
|
186
182
|
payload[:date] = prompt.date
|
187
183
|
payload[:perform_generations] = prompt.perform_generations
|
188
184
|
end
|
@@ -200,47 +196,56 @@ module ActiveAgent
|
|
200
196
|
end
|
201
197
|
end
|
202
198
|
|
203
|
-
attr_internal :
|
199
|
+
attr_internal :prompt_context
|
200
|
+
|
201
|
+
def agent_stream
|
202
|
+
proc do |message, delta, stop|
|
203
|
+
run_stream_callbacks(message, delta, stop) do |message, delta, stop|
|
204
|
+
yield message, delta, stop if block_given?
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
204
208
|
|
205
209
|
def embed
|
206
|
-
|
207
|
-
generation_provider.embed(
|
210
|
+
prompt_context.options.merge(options)
|
211
|
+
generation_provider.embed(prompt_context) if prompt_context && generation_provider
|
208
212
|
handle_response(generation_provider.response)
|
209
213
|
end
|
210
214
|
|
211
215
|
def perform_generation
|
212
|
-
|
213
|
-
generation_provider.generate(
|
216
|
+
prompt_context.options.merge(options)
|
217
|
+
generation_provider.generate(prompt_context) if prompt_context && generation_provider
|
214
218
|
handle_response(generation_provider.response)
|
215
219
|
end
|
216
220
|
|
217
221
|
def handle_response(response)
|
218
222
|
perform_actions(requested_actions: response.message.requested_actions) if response.message.requested_actions.present?
|
219
223
|
|
220
|
-
|
224
|
+
update_prompt_context(response)
|
221
225
|
end
|
222
226
|
|
223
|
-
def
|
224
|
-
response.prompt
|
227
|
+
def update_prompt_context(response)
|
228
|
+
# response.prompt = prompt_context
|
229
|
+
# response.message = response.messages.last
|
225
230
|
response
|
226
231
|
end
|
227
232
|
|
228
233
|
def perform_actions(requested_actions:)
|
229
234
|
requested_actions.each do |action|
|
230
235
|
perform_action(action)
|
231
|
-
prompt.messages.last.role = :tool
|
232
|
-
prompt.messages.last.action_id = action.id
|
233
236
|
end
|
234
237
|
end
|
235
238
|
|
236
239
|
def perform_action(action)
|
237
240
|
process(action.name, *action.params)
|
241
|
+
prompt_context.messages.last.role = :tool
|
242
|
+
prompt_context.messages.last.action_id = action.id
|
238
243
|
end
|
239
244
|
|
240
245
|
def initialize
|
241
246
|
super
|
242
247
|
@_prompt_was_called = false
|
243
|
-
@
|
248
|
+
@_prompt_context = ActiveAgent::ActionPrompt::Prompt.new(instructions: options[:instructions], options: options)
|
244
249
|
end
|
245
250
|
|
246
251
|
def process(method_name, *args) # :nodoc:
|
@@ -252,7 +257,7 @@ module ActiveAgent
|
|
252
257
|
|
253
258
|
ActiveSupport::Notifications.instrument("process.active_agent", payload) do
|
254
259
|
super
|
255
|
-
@
|
260
|
+
@_prompt_context = ActiveAgent::ActionPrompt::Prompt.new unless @_prompt_was_called
|
256
261
|
end
|
257
262
|
end
|
258
263
|
ruby2_keywords(:process)
|
@@ -282,20 +287,12 @@ module ActiveAgent
|
|
282
287
|
|
283
288
|
def headers(args = nil)
|
284
289
|
if args
|
285
|
-
@
|
290
|
+
@_prompt_context.headers(args)
|
286
291
|
else
|
287
|
-
@
|
292
|
+
@_prompt_context
|
288
293
|
end
|
289
294
|
end
|
290
295
|
|
291
|
-
# def attachments
|
292
|
-
# if @_prompt_was_called
|
293
|
-
# LateAttachmentsProxy.new(@_context.attachments)
|
294
|
-
# else
|
295
|
-
# @_context.attachments
|
296
|
-
# end
|
297
|
-
# end
|
298
|
-
|
299
296
|
class LateAttachmentsProxy < SimpleDelegator
|
300
297
|
def inline
|
301
298
|
self
|
@@ -314,28 +311,30 @@ module ActiveAgent
|
|
314
311
|
end
|
315
312
|
|
316
313
|
def prompt_with(*)
|
317
|
-
|
314
|
+
prompt_context.update_prompt_context(*)
|
318
315
|
end
|
319
316
|
|
320
317
|
def prompt(headers = {}, &block)
|
321
|
-
return
|
318
|
+
return prompt_context if @_prompt_was_called && headers.blank? && !block
|
322
319
|
|
323
320
|
content_type = headers[:content_type]
|
324
321
|
|
325
322
|
headers = apply_defaults(headers)
|
326
323
|
|
327
|
-
|
324
|
+
prompt_context.context_id = headers[:context_id]
|
325
|
+
|
326
|
+
prompt_context.charset = charset = headers[:charset]
|
328
327
|
|
329
328
|
responses = collect_responses(headers, &block)
|
330
329
|
|
331
330
|
@_prompt_was_called = true
|
332
331
|
|
333
|
-
create_parts_from_responses(
|
332
|
+
create_parts_from_responses(prompt_context, responses)
|
334
333
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
334
|
+
prompt_context.content_type = set_content_type(prompt_context, content_type, headers[:content_type])
|
335
|
+
prompt_context.charset = charset
|
336
|
+
prompt_context.actions = headers[:actions] || action_schemas
|
337
|
+
prompt_context
|
339
338
|
end
|
340
339
|
|
341
340
|
def action_schemas
|
@@ -352,7 +351,7 @@ module ActiveAgent
|
|
352
351
|
if user_content_type.present?
|
353
352
|
user_content_type
|
354
353
|
else
|
355
|
-
|
354
|
+
prompt_context.content_type || class_default
|
356
355
|
end
|
357
356
|
end
|
358
357
|
|
@@ -383,10 +382,10 @@ module ActiveAgent
|
|
383
382
|
end
|
384
383
|
end
|
385
384
|
|
386
|
-
def
|
385
|
+
def assign_headers_to_prompt_context(prompt_context, headers)
|
387
386
|
assignable = headers.except(:parts_order, :content_type, :body, :template_name,
|
388
387
|
:template_path, :delivery_method, :delivery_method_options)
|
389
|
-
assignable.each { |k, v|
|
388
|
+
assignable.each { |k, v| prompt_context[k] = v }
|
390
389
|
end
|
391
390
|
|
392
391
|
def collect_responses(headers, &)
|
@@ -437,24 +436,24 @@ module ActiveAgent
|
|
437
436
|
end
|
438
437
|
end
|
439
438
|
|
440
|
-
def create_parts_from_responses(
|
439
|
+
def create_parts_from_responses(prompt_context, responses)
|
441
440
|
if responses.size > 1
|
442
441
|
# prompt_container = ActiveAgent::ActionPrompt::Prompt.new
|
443
442
|
# prompt_container.content_type = "multipart/alternative"
|
444
|
-
responses.each { |r| insert_part(
|
445
|
-
#
|
443
|
+
responses.each { |r| insert_part(prompt_context, r, prompt_context.charset) }
|
444
|
+
# prompt_context.add_part(prompt_container)
|
446
445
|
else
|
447
|
-
responses.each { |r| insert_part(
|
446
|
+
responses.each { |r| insert_part(prompt_context, r, prompt_context.charset) }
|
448
447
|
end
|
449
448
|
end
|
450
449
|
|
451
|
-
def insert_part(
|
450
|
+
def insert_part(prompt_context, response, charset)
|
452
451
|
message = ActiveAgent::ActionPrompt::Message.new(
|
453
452
|
content: response[:body],
|
454
453
|
content_type: response[:content_type],
|
455
454
|
charset: charset
|
456
455
|
)
|
457
|
-
|
456
|
+
prompt_context.add_part(message)
|
458
457
|
end
|
459
458
|
|
460
459
|
# This and #instrument_name is for caching instrument
|
@@ -11,14 +11,14 @@ module ActiveAgent
|
|
11
11
|
ruby2_keywords(:initialize)
|
12
12
|
|
13
13
|
def __getobj__
|
14
|
-
@prompt_context ||= processed_agent.
|
14
|
+
@prompt_context ||= processed_agent.prompt_context
|
15
15
|
end
|
16
16
|
|
17
17
|
def __setobj__(prompt_context)
|
18
18
|
@prompt_context = prompt_context
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def prompt_context
|
22
22
|
__getobj__
|
23
23
|
end
|
24
24
|
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# lib/active_agent/generation_provider/anthropic_provider.rb
|
2
|
+
|
3
|
+
require "anthropic"
|
4
|
+
require "active_agent/action_prompt/action"
|
5
|
+
require_relative "base"
|
6
|
+
require_relative "response"
|
7
|
+
|
8
|
+
module ActiveAgent
|
9
|
+
module GenerationProvider
|
10
|
+
class AnthropicProvider < Base
|
11
|
+
def initialize(config)
|
12
|
+
super
|
13
|
+
@api_key = config["api_key"]
|
14
|
+
@model_name = config["model"] || "claude-3-5-sonnet-20240620"
|
15
|
+
@client = Anthropic::Client.new(access_token: @api_key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate(prompt)
|
19
|
+
@prompt = prompt
|
20
|
+
|
21
|
+
chat_prompt(parameters: prompt_parameters)
|
22
|
+
rescue => e
|
23
|
+
raise GenerationProviderError, e.message
|
24
|
+
end
|
25
|
+
|
26
|
+
def chat_prompt(parameters: prompt_parameters)
|
27
|
+
parameters[:stream] = provider_stream if prompt.options[:stream] || config["stream"]
|
28
|
+
|
29
|
+
chat_response(@client.messages(parameters))
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def provider_stream
|
35
|
+
agent_stream = prompt.options[:stream]
|
36
|
+
message = ActiveAgent::ActionPrompt::Message.new(content: "", role: :assistant)
|
37
|
+
@response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message:)
|
38
|
+
|
39
|
+
proc do |chunk|
|
40
|
+
if new_content = chunk.dig(:delta, :text)
|
41
|
+
message.content += new_content
|
42
|
+
agent_stream.call(message) if agent_stream.respond_to?(:call)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def prompt_parameters(model: @prompt.options[:model] || @model_name, messages: @prompt.messages, temperature: @config["temperature"] || 0.7, tools: @prompt.actions)
|
48
|
+
params = {
|
49
|
+
model: model,
|
50
|
+
messages: provider_messages(messages),
|
51
|
+
temperature: temperature,
|
52
|
+
max_tokens: 4096
|
53
|
+
}
|
54
|
+
|
55
|
+
if tools&.present?
|
56
|
+
params[:tools] = format_tools(tools)
|
57
|
+
end
|
58
|
+
|
59
|
+
params
|
60
|
+
end
|
61
|
+
|
62
|
+
def format_tools(tools)
|
63
|
+
tools.map do |tool|
|
64
|
+
{
|
65
|
+
name: tool[:name] || tool[:function][:name],
|
66
|
+
description: tool[:description],
|
67
|
+
input_schema: tool[:parameters]
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def provider_messages(messages)
|
73
|
+
messages.map do |message|
|
74
|
+
provider_message = {
|
75
|
+
role: convert_role(message.role),
|
76
|
+
content: []
|
77
|
+
}
|
78
|
+
|
79
|
+
provider_message[:content] << if message.content_type == "image_url"
|
80
|
+
{
|
81
|
+
type: "image",
|
82
|
+
source: {
|
83
|
+
type: "url",
|
84
|
+
url: message.content
|
85
|
+
}
|
86
|
+
}
|
87
|
+
else
|
88
|
+
{
|
89
|
+
type: "text",
|
90
|
+
text: message.content
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
provider_message
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def convert_role(role)
|
99
|
+
case role.to_s
|
100
|
+
when "system" then "system"
|
101
|
+
when "user" then "user"
|
102
|
+
when "assistant" then "assistant"
|
103
|
+
when "tool", "function" then "assistant"
|
104
|
+
else "user"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def chat_response(response)
|
109
|
+
return @response if prompt.options[:stream]
|
110
|
+
|
111
|
+
content = response.content.first[:text]
|
112
|
+
|
113
|
+
message = ActiveAgent::ActionPrompt::Message.new(
|
114
|
+
content: content,
|
115
|
+
role: "assistant",
|
116
|
+
action_requested: response.stop_reason == "tool_use",
|
117
|
+
requested_actions: handle_actions(response.tool_use)
|
118
|
+
)
|
119
|
+
|
120
|
+
update_context(prompt: prompt, message: message, response: response)
|
121
|
+
|
122
|
+
@response = ActiveAgent::GenerationProvider::Response.new(
|
123
|
+
prompt: prompt,
|
124
|
+
message: message,
|
125
|
+
raw_response: response
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
def handle_actions(tool_uses)
|
130
|
+
return unless tool_uses&.present?
|
131
|
+
|
132
|
+
tool_uses.map do |tool_use|
|
133
|
+
ActiveAgent::ActionPrompt::Action.new(
|
134
|
+
id: tool_use[:id],
|
135
|
+
name: tool_use[:name],
|
136
|
+
params: tool_use[:input]
|
137
|
+
)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -17,7 +17,7 @@ module ActiveAgent
|
|
17
17
|
|
18
18
|
def generate(prompt)
|
19
19
|
@prompt = prompt
|
20
|
-
|
20
|
+
|
21
21
|
chat_prompt(parameters: prompt_parameters)
|
22
22
|
rescue => e
|
23
23
|
raise GenerationProviderError, e.message
|
@@ -64,9 +64,16 @@ module ActiveAgent
|
|
64
64
|
@response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message:)
|
65
65
|
|
66
66
|
proc do |chunk, bytesize|
|
67
|
-
if new_content = chunk.dig("choices", 0, "delta", "content")
|
67
|
+
if (new_content = chunk.dig("choices", 0, "delta", "content"))
|
68
68
|
message.content += new_content
|
69
|
-
|
69
|
+
|
70
|
+
agent_stream.call(message, new_content, false) do |message, new_content|
|
71
|
+
yield message, new_content if block_given?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
agent_stream.call(message, nil, true) do |message|
|
76
|
+
yield message, nil if block_given?
|
70
77
|
end
|
71
78
|
end
|
72
79
|
end
|
data/lib/active_agent/version.rb
CHANGED
@@ -31,9 +31,9 @@ module ActiveAgent
|
|
31
31
|
actions.each do |action|
|
32
32
|
@action = action
|
33
33
|
@schema_path = File.join("app/views", class_path, file_name, "#{action}.json.jbuilder")
|
34
|
-
@view_path = File.join("app/views", class_path, file_name, "#{action}.html
|
34
|
+
@view_path = File.join("app/views", class_path, file_name, "#{action}.html.erb")
|
35
35
|
template "action.json.jbuilder", @schema_path
|
36
|
-
template "action.html
|
36
|
+
template "action.html.erb", @view_path
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -12,6 +12,10 @@ module ActiveAgent
|
|
12
12
|
def create_application_agent
|
13
13
|
template "application_agent.rb", "app/agents/application_agent.rb"
|
14
14
|
end
|
15
|
+
|
16
|
+
def create_agent_layout_template
|
17
|
+
template "agent.text.erb", "app/views/layouts/agent.text.erb"
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeagent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.6.
|
4
|
+
version: 0.2.6.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Bowen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- lib/active_agent/generation_methods.rb
|
157
157
|
- lib/active_agent/generation_provider.rb
|
158
158
|
- lib/active_agent/generation_provider/README.md
|
159
|
+
- lib/active_agent/generation_provider/anthropic_provider.rb
|
159
160
|
- lib/active_agent/generation_provider/base.rb
|
160
161
|
- lib/active_agent/generation_provider/open_ai_provider.rb
|
161
162
|
- lib/active_agent/generation_provider/response.rb
|
@@ -179,6 +180,7 @@ files:
|
|
179
180
|
- lib/generators/active_agent/templates/action.json.jbuilder.tt
|
180
181
|
- lib/generators/active_agent/templates/active_agent.yml
|
181
182
|
- lib/generators/active_agent/templates/agent.rb.tt
|
183
|
+
- lib/generators/active_agent/templates/agent.text.erb
|
182
184
|
- lib/generators/active_agent/templates/agent_spec.rb.tt
|
183
185
|
- lib/generators/active_agent/templates/agent_test.rb.tt
|
184
186
|
- lib/generators/active_agent/templates/application_agent.rb.tt
|