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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 046bee054500815713a48ba1f4b6716d82c15ce122a2bd94867fa1287052ca94
4
- data.tar.gz: b625b8759720d87b5570db0322ed83d98c39cfaf97cf66d1d3bf1516cc2c8170
3
+ metadata.gz: '08db8e070616e81109c24a4738d29cc5c7b2911a3b7584e90c23cd9a1072a20a'
4
+ data.tar.gz: 424e66ddfde6018b15b33d440764604db3cb3c1c3bef3f6cc0c0e765cad8d06e
5
5
  SHA512:
6
- metadata.gz: 5b26d995bea053663904e9e26b898c6dc60a30b5d70d46c97c28aa3e943eed198d09627431f711e94e39f97de038851463307bb321767aebf63ca08219b7938a
7
- data.tar.gz: 94b53137b2496b6c8c8958d8ae0686a4c7d6106ce71bc59ad5bdd11c215e94718d92f5a0458ff41f5502ba6b3a6bffc7fda1805e7c75421ccdebac2b69e22d66
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, :name, :action_requested, :requested_actions, :content_type, :charset
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
 
@@ -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] = name
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 :context
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
- context.options.merge(options)
207
- generation_provider.embed(context) if context && generation_provider
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
- context.options.merge(options)
213
- generation_provider.generate(context) if context && generation_provider
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
- update_context(response)
224
+ update_prompt_context(response)
221
225
  end
222
226
 
223
- def update_context(response)
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
- @_context = ActiveAgent::ActionPrompt::Prompt.new(instructions: options[:instructions], options: options)
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
- @_context = ActiveAgent::ActionPrompt::Prompt.new unless @_prompt_was_called
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
- @_context.headers(args)
290
+ @_prompt_context.headers(args)
286
291
  else
287
- @_context
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
- context.update_context(*)
314
+ prompt_context.update_prompt_context(*)
318
315
  end
319
316
 
320
317
  def prompt(headers = {}, &block)
321
- return context if @_prompt_was_called && headers.blank? && !block
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
- context.charset = charset = headers[:charset]
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(context, responses)
332
+ create_parts_from_responses(prompt_context, responses)
334
333
 
335
- context.content_type = set_content_type(context, content_type, headers[:content_type])
336
- context.charset = charset
337
- context.actions = headers[:actions] || action_schemas
338
- context
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
- context.content_type || class_default
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 assign_headers_to_context(context, headers)
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| context[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(context, 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(context, r, context.charset) }
445
- # context.add_part(prompt_container)
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(context, r, context.charset) }
446
+ responses.each { |r| insert_part(prompt_context, r, prompt_context.charset) }
448
447
  end
449
448
  end
450
449
 
451
- def insert_part(context, response, charset)
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
- context.add_part(message)
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.context
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 context
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
- binding.irb
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
- agent_stream.call(message) if agent_stream.respond_to?(:call)
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
@@ -1,3 +1,3 @@
1
1
  module ActiveAgent
2
- VERSION = "0.2.6.7"
2
+ VERSION = "0.2.6.9"
3
3
  end
@@ -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.#{template_engine}")
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.#{template_engine}", @view_path
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.7
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-17 00:00:00.000000000 Z
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