activeagent 0.3 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf6889f20afa4e61e46ab6edbe801186aee0d3fe85284f3ce6379509a6a76bc4
4
- data.tar.gz: 3340dcc2d65740cea5a98f4c0640ac806e1686bb48bee2a3260cf3e65b5478b2
3
+ metadata.gz: d679bd3d4f68b5c696ed4cc194e9b5476ebb0da34d6ac683296f7f7f5feae0f8
4
+ data.tar.gz: 2f11870fc423e399c53bf0728203faf47cbe3303d7aa47bb2d5d77bc603cda8d
5
5
  SHA512:
6
- metadata.gz: 8c63eaaad2c5049fac65902d5d5676f976580fffd40477287b149d29695c15b75143e1bbf8e60128c04adfc23531770c9ab1c7893a6cf73bd4f258315a93e251
7
- data.tar.gz: 0be4d79a4755d23d1c7e2c659871d8e0480c05583e6fe1d6eae48571fd1d2540cc88ea53a827192109bf76476e237e8c09f1bbc64f97bca429416b3c7503154c
6
+ metadata.gz: 8261c5df1f59b50a96e6c46f1363b470fadff9bbc0231ab6a1c2e6975e906d73d150f0c3d11367d8c766d49ffc0c67428ed3fb40a5fcbbd4c5b78e03a4274805
7
+ data.tar.gz: 64b70a42b0f09f175e441dccab85468946df03ec5f3cd6e007a5e4180d13726230817b5b4ddc4adc348a5b9b838adf8a9d3342490e7d6e96f07c79fa983bc366
@@ -3,7 +3,8 @@ require_relative "message"
3
3
  module ActiveAgent
4
4
  module ActionPrompt
5
5
  class Prompt
6
- attr_accessor :actions, :body, :content_type, :context_id, :instructions, :message, :messages, :options, :mime_version, :charset, :context, :parts
6
+ attr_reader :messages
7
+ attr_accessor :actions, :body, :content_type, :context_id, :instructions, :message, :options, :mime_version, :charset, :context, :parts, :params, :action_choice, :agent_class
7
8
 
8
9
  def initialize(attributes = {})
9
10
  @options = attributes.fetch(:options, {})
@@ -27,6 +28,11 @@ module ActiveAgent
27
28
  set_messages
28
29
  end
29
30
 
31
+ def messages=(messages)
32
+ @messages = messages
33
+ set_messages
34
+ end
35
+
30
36
  # Generate the prompt as a string (for debugging or sending to the provider)
31
37
  def to_s
32
38
  @message.to_s
@@ -62,7 +68,7 @@ module ActiveAgent
62
68
  private
63
69
 
64
70
  def set_messages
65
- @messages = [Message.new(content: @instructions, role: :system)] + @messages
71
+ @messages = [Message.new(content: @instructions, role: :system)] + @messages if @instructions.present?
66
72
  end
67
73
 
68
74
  def set_message
@@ -71,6 +77,7 @@ module ActiveAgent
71
77
  elsif @body.is_a?(String) && @message.content.blank?
72
78
  @message = Message.new(content: @body, role: :user)
73
79
  end
80
+
74
81
  @messages << @message
75
82
  end
76
83
  end
@@ -219,15 +219,14 @@ module ActiveAgent
219
219
  end
220
220
 
221
221
  def handle_response(response)
222
- perform_actions(requested_actions: response.message.requested_actions) if response.message.requested_actions.present?
223
-
222
+ return response unless response.message.requested_actions.present?
223
+ perform_actions(requested_actions: response.message.requested_actions)
224
224
  update_prompt_context(response)
225
225
  end
226
226
 
227
227
  def update_prompt_context(response)
228
- # response.prompt = prompt_context
229
- # response.message = response.messages.last
230
- response
228
+ prompt_context.message = prompt_context.messages.last
229
+ ActiveAgent::GenerationProvider::Response.new(prompt: prompt_context)
231
230
  end
232
231
 
233
232
  def perform_actions(requested_actions:)
@@ -237,9 +236,12 @@ module ActiveAgent
237
236
  end
238
237
 
239
238
  def perform_action(action)
239
+ current_context = prompt_context.clone
240
240
  process(action.name, *action.params)
241
241
  prompt_context.messages.last.role = :tool
242
242
  prompt_context.messages.last.action_id = action.id
243
+ current_context.messages << prompt_context.messages.last
244
+ self.prompt_context = current_context
243
245
  end
244
246
 
245
247
  def initialize
@@ -299,15 +301,11 @@ module ActiveAgent
299
301
 
300
302
  def prompt(headers = {}, &block)
301
303
  return prompt_context if @_prompt_was_called && headers.blank? && !block
302
-
303
304
  content_type = headers[:content_type]
304
-
305
305
  headers = apply_defaults(headers)
306
-
306
+ prompt_context.messages = headers[:messages] || []
307
307
  prompt_context.context_id = headers[:context_id]
308
308
 
309
- prompt_context.options = options.merge(headers[:options] || {})
310
-
311
309
  prompt_context.charset = charset = headers[:charset]
312
310
 
313
311
  responses = collect_responses(headers, &block)
@@ -319,6 +317,7 @@ module ActiveAgent
319
317
  prompt_context.content_type = set_content_type(prompt_context, content_type, headers[:content_type])
320
318
  prompt_context.charset = charset
321
319
  prompt_context.actions = headers[:actions] || action_schemas
320
+
322
321
  prompt_context
323
322
  end
324
323
 
@@ -41,4 +41,4 @@ module ActiveAgent
41
41
  end
42
42
  end
43
43
  end
44
- end
44
+ end
@@ -23,12 +23,6 @@ module ActiveAgent
23
23
  raise GenerationProviderError, e.message
24
24
  end
25
25
 
26
- def chat_prompt(parameters: prompt_parameters)
27
- parameters[:stream] = provider_stream if prompt.options[:stream] || config["stream"]
28
-
29
- chat_response(@client.chat(parameters: parameters))
30
- end
31
-
32
26
  def embed(prompt)
33
27
  @prompt = prompt
34
28
 
@@ -37,39 +31,25 @@ module ActiveAgent
37
31
  raise GenerationProviderError, e.message
38
32
  end
39
33
 
40
- def embeddings_parameters(input: prompt.message.content, model: "text-embedding-3-large")
41
- {
42
- model: model,
43
- input: input
44
- }
45
- end
46
-
47
- def embeddings_response(response)
48
- message = Message.new(content: response.dig("data", 0, "embedding"), role: "assistant")
49
-
50
- @response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message: message, raw_response: response)
51
- end
52
-
53
- def embeddings_prompt(parameters:)
54
- embeddings_response(@client.embeddings(parameters: embeddings_parameters))
55
- end
56
-
57
34
  private
58
35
 
59
36
  def provider_stream
60
- # prompt.options[:stream] will define a proc found in prompt at runtime
61
- # config[:stream] will define a proc found in config. stream would come from an Agent class's generate_with or stream_with method calls
62
37
  agent_stream = prompt.options[:stream]
63
38
  message = ActiveAgent::ActionPrompt::Message.new(content: "", role: :assistant)
64
- @response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message:)
65
39
 
40
+ @response = ActiveAgent::GenerationProvider::Response.new(prompt:, message:)
66
41
  proc do |chunk, bytesize|
67
- if (new_content = chunk.dig("choices", 0, "delta", "content"))
42
+ new_content = chunk.dig("choices", 0, "delta", "content")
43
+ if new_content && !new_content.blank
68
44
  message.content += new_content
69
45
 
70
46
  agent_stream.call(message, new_content, false) do |message, new_content|
71
47
  yield message, new_content if block_given?
72
48
  end
49
+ elsif chunk.dig("choices", 0, "delta", "tool_calls") && !chunk.dig("choices", 0, "delta", "tool_calls").empty?
50
+ message = handle_message(chunk.dig("choices", 0, "delta"))
51
+ prompt.messages << message
52
+ @response = ActiveAgent::GenerationProvider::Response.new(prompt:, message:)
73
53
  end
74
54
 
75
55
  agent_stream.call(message, nil, true) do |message|
@@ -105,35 +85,61 @@ module ActiveAgent
105
85
  end
106
86
 
107
87
  def chat_response(response)
108
- binding.irb
109
88
  return @response if prompt.options[:stream]
110
89
 
111
90
  message_json = response.dig("choices", 0, "message")
112
91
 
113
- message = ActiveAgent::ActionPrompt::Message.new(
92
+ message = handle_message(message_json)
93
+
94
+ update_context(prompt: prompt, message: message, response: response)
95
+
96
+ @response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message: message, raw_response: response)
97
+ end
98
+
99
+ def handle_message(message_json)
100
+ ActiveAgent::ActionPrompt::Message.new(
114
101
  content: message_json["content"],
115
- role: message_json["role"],
102
+ role: message_json["role"].intern,
116
103
  action_requested: message_json["finish_reason"] == "tool_calls",
117
104
  requested_actions: handle_actions(message_json["tool_calls"])
118
105
  )
119
- update_context(prompt: prompt, message: message, response: response)
106
+ end
107
+
108
+ def handle_actions(tool_calls)
109
+ return [] if tool_calls.nil? || tool_calls.empty?
110
+
111
+ tool_calls.map do |tool_call|
112
+ next if tool_call["function"].nil? || tool_call["function"]["name"].blank?
113
+ args = tool_call["function"]["arguments"].blank? ? nil : JSON.parse(tool_call["function"]["arguments"], {symbolize_names: true})
114
+
115
+ ActiveAgent::ActionPrompt::Action.new(
116
+ id: tool_call["id"],
117
+ name: tool_call.dig("function", "name"),
118
+ params: args
119
+ )
120
+ end.compact
121
+ end
122
+
123
+ def chat_prompt(parameters: prompt_parameters)
124
+ parameters[:stream] = provider_stream if prompt.options[:stream] || config["stream"]
125
+ chat_response(@client.chat(parameters: parameters))
126
+ end
127
+
128
+ def embeddings_parameters(input: prompt.message.content, model: "text-embedding-3-large")
129
+ {
130
+ model: model,
131
+ input: input
132
+ }
133
+ end
134
+
135
+ def embeddings_response(response)
136
+ message = Message.new(content: response.dig("data", 0, "embedding"), role: "assistant")
120
137
 
121
138
  @response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message: message, raw_response: response)
122
139
  end
123
140
 
124
- def handle_actions(tool_calls)
125
- if tool_calls
126
- tool_calls.map do |tool_call|
127
- ActiveAgent::ActionPrompt::Action.new(
128
- id: tool_call["id"],
129
- name: tool_call.dig("function", "name"),
130
- params: JSON.parse(
131
- tool_call.dig("function", "arguments"),
132
- {symbolize_names: true}
133
- )
134
- )
135
- end
136
- end
141
+ def embeddings_prompt(parameters:)
142
+ embeddings_response(@client.embeddings(parameters: embeddings_parameters))
137
143
  end
138
144
  end
139
145
  end
@@ -5,9 +5,9 @@ module ActiveAgent
5
5
  class Response
6
6
  attr_reader :message, :prompt, :raw_response
7
7
 
8
- def initialize(prompt:, message:, raw_response: nil)
9
- @message = message
8
+ def initialize(prompt:, message: nil, raw_response: nil)
10
9
  @prompt = prompt
10
+ @message = message || prompt.message
11
11
  @raw_response = raw_response
12
12
  end
13
13
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveAgent
2
- VERSION = "0.3"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -19,57 +19,8 @@ module ActiveAgent
19
19
  end
20
20
  end
21
21
 
22
- def create_test_file
23
- if test_framework == :rspec
24
- template "agent_spec.rb", File.join("spec/agents", class_path, "#{file_name}_agent_spec.rb")
25
- else
26
- template "agent_test.rb", File.join("test/agents", class_path, "#{file_name}_agent_test.rb")
27
- end
28
- end
29
-
30
- def create_view_files
31
- actions.each do |action|
32
- @action = action
33
-
34
- # Use configured template engines or fall back to defaults
35
- json_template_engine = json_template_engine_for_views || "jbuilder"
36
- html_template_engine = html_template_engine_for_views || "erb"
37
-
38
- @schema_path = File.join("app/views", class_path, file_name, "#{action}.json.#{json_template_engine}")
39
- @view_path = File.join("app/views", class_path, file_name, "#{action}.html.#{html_template_engine}")
40
-
41
- template "action.json.#{json_template_engine}", @schema_path
42
- template "action.html.#{html_template_engine}", @view_path
43
- end
44
- end
45
-
46
- def create_layout_files
47
- # Create the application agent layouts
48
- template "layout.text.erb", "app/views/layouts/agent.text.erb"
49
- template "layout.html.erb", "app/views/layouts/agent.html.erb"
50
- end
51
-
52
22
  private
53
23
 
54
- def test_framework
55
- ::Rails.application.config.generators.options[:rails][:test_framework]
56
- end
57
-
58
- def template_engine
59
- ::Rails.application.config.generators.options[:rails][:template_engine]
60
- end
61
-
62
- def json_template_engine_for_views
63
- # Check if there's a specific JSON template engine configured
64
- json_engine = ::Rails.application.config.generators.options[:rails][:json_template_engine]
65
- json_engine || "jbuilder" # Default to jbuilder if not specified
66
- end
67
-
68
- def html_template_engine_for_views
69
- # Use the configured template engine or default to erb
70
- template_engine || "erb"
71
- end
72
-
73
24
  def file_name # :doc:
74
25
  @_file_name ||= super + "_agent"
75
26
  end
@@ -12,10 +12,6 @@ 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
19
15
  end
20
16
  end
21
17
  end
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.3'
4
+ version: 0.3.1
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-30 00:00:00.000000000 Z
11
+ date: 2025-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -150,7 +150,6 @@ files:
150
150
  - lib/active_agent/base.rb
151
151
  - lib/active_agent/callbacks.rb
152
152
  - lib/active_agent/deprecator.rb
153
- - lib/active_agent/engine.rb
154
153
  - lib/active_agent/generation.rb
155
154
  - lib/active_agent/generation_job.rb
156
155
  - lib/active_agent/generation_methods.rb
@@ -162,7 +161,6 @@ files:
162
161
  - lib/active_agent/generation_provider/response.rb
163
162
  - lib/active_agent/inline_preview_interceptor.rb
164
163
  - lib/active_agent/log_subscriber.rb
165
- - lib/active_agent/operation.rb
166
164
  - lib/active_agent/parameterized.rb
167
165
  - lib/active_agent/preview.rb
168
166
  - lib/active_agent/prompt_helper.rb
@@ -1,14 +0,0 @@
1
- # require "rails/engine"
2
-
3
- # module ActiveAgent
4
- # class Engine < ::Rails::Engine
5
- # isolate_namespace ActiveAgent
6
-
7
- # initializer "active_agent.view_paths" do |app|
8
- # # Adding your gem's view path to Rails lookup paths
9
- # ActiveSupport.on_load(:action_controller) do
10
- # append_view_path Engine.root.join("app/views")
11
- # end
12
- # end
13
- # end
14
- # end
@@ -1,13 +0,0 @@
1
- module ActiveAgent
2
- class Operation < AbstractController::Base
3
- include AbstractController::Rendering
4
- include ActionView::Rendering # Allows rendering of ERB templates without a view context tied to a request
5
- append_view_path "app/views" # Ensure the controller knows where to look for view templates
6
-
7
- def process_tool(tool_name, params)
8
- send(tool_name, params) # Dynamically calls the method corresponding to tool_name
9
- rescue NoMethodError
10
- "Tool not found: #{tool_name}"
11
- end
12
- end
13
- end