activeagent 0.2.5.202503060823 → 0.2.6.rc2
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/action.rb +2 -5
- data/lib/active_agent/action_prompt/message.rb +10 -4
- data/lib/active_agent/action_prompt/prompt.rb +1 -1
- data/lib/active_agent/base.rb +10 -9
- data/lib/active_agent/generation_job.rb +1 -1
- data/lib/active_agent/generation_provider/base.rb +1 -0
- data/lib/active_agent/generation_provider/open_ai_provider.rb +21 -7
- data/lib/active_agent/railtie.rb +8 -10
- data/lib/active_agent/version.rb +1 -1
- data/lib/activeagent.rb +1 -0
- data/lib/generators/active_agent/install_generator.rb +1 -5
- metadata +9 -7
- data/README.md +0 -188
- data/Rakefile +0 -2
- data/lib/generators/active_agent/templates/initializer.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b9c764679c8c11bbf82e3aa132c5d563fc0a6c3cd5c28da2f6804639d1c153b
|
4
|
+
data.tar.gz: ec6a3c3495d44071264665e88be075005a240e52afe9202c506819e89897b1f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de1673c61fabca8b9bdcf5a4d72d963d7de1538fb96d72580af25cff5c074199cb2a325b3ef0ef34f5c05a8aa5ad642b09782c4655cd5e1b7a98de6a59b50d1a
|
7
|
+
data.tar.gz: b70d1f16c1056d7c54bf964f9b5d0202e8b63f027d2eb1457276fd1bb07dd7acf00c6bff1ae45a36c33253463a348fdb75a1b9906559544b58b1f853ec77983c
|
@@ -1,16 +1,13 @@
|
|
1
1
|
module ActiveAgent
|
2
2
|
module ActionPrompt
|
3
3
|
class Action
|
4
|
-
attr_accessor :agent_name, :name, :params
|
4
|
+
attr_accessor :agent_name, :id, :name, :params
|
5
5
|
|
6
6
|
def initialize(attributes = {})
|
7
|
+
@id = attributes.fetch(:id, nil)
|
7
8
|
@name = attributes.fetch(:name, "")
|
8
9
|
@params = attributes.fetch(:params, {})
|
9
10
|
end
|
10
|
-
|
11
|
-
def perform_action
|
12
|
-
agent_name.constantize
|
13
|
-
end
|
14
11
|
end
|
15
12
|
end
|
16
13
|
end
|
@@ -3,10 +3,10 @@ module ActiveAgent
|
|
3
3
|
class Message
|
4
4
|
VALID_ROLES = %w[system assistant user tool function].freeze
|
5
5
|
|
6
|
-
attr_accessor :content, :role, :name, :action_requested, :requested_actions, :content_type, :charset
|
6
|
+
attr_accessor :action_id, :content, :role, :name, :action_requested, :requested_actions, :content_type, :charset
|
7
7
|
|
8
|
-
def initialize(attributes = {})
|
9
|
-
@
|
8
|
+
def initialize(attributes = {})
|
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"
|
@@ -20,16 +20,22 @@ module ActiveAgent
|
|
20
20
|
def to_h
|
21
21
|
hash = {
|
22
22
|
role: role,
|
23
|
+
action_id: action_id,
|
23
24
|
content: content,
|
24
|
-
|
25
|
+
type: content_type,
|
25
26
|
charset: charset
|
26
27
|
}
|
28
|
+
|
27
29
|
hash[:name] = name if name
|
28
30
|
hash[:action_requested] = requested_actions.any?
|
29
31
|
hash[:requested_actions] = requested_actions if requested_actions.any?
|
30
32
|
hash
|
31
33
|
end
|
32
34
|
|
35
|
+
def embed
|
36
|
+
@agent_class.embed(@content)
|
37
|
+
end
|
38
|
+
|
33
39
|
private
|
34
40
|
|
35
41
|
def validate_role
|
@@ -22,7 +22,7 @@ module ActiveAgent
|
|
22
22
|
@parts = attributes.fetch(:parts, [])
|
23
23
|
|
24
24
|
set_message if attributes[:message].is_a?(String) || @body.is_a?(String) && @message&.content
|
25
|
-
set_messages
|
25
|
+
set_messages
|
26
26
|
end
|
27
27
|
|
28
28
|
# Generate the prompt as a string (for debugging or sending to the provider)
|
data/lib/active_agent/base.rb
CHANGED
@@ -202,6 +202,12 @@ module ActiveAgent
|
|
202
202
|
|
203
203
|
attr_internal :context
|
204
204
|
|
205
|
+
def embed
|
206
|
+
context.options.merge(options)
|
207
|
+
generation_provider.embed(context) if context && generation_provider
|
208
|
+
handle_response(generation_provider.response)
|
209
|
+
end
|
210
|
+
|
205
211
|
def perform_generation
|
206
212
|
context.options.merge(options)
|
207
213
|
generation_provider.generate(context) if context && generation_provider
|
@@ -215,20 +221,15 @@ module ActiveAgent
|
|
215
221
|
end
|
216
222
|
|
217
223
|
def update_context(response)
|
218
|
-
|
219
|
-
response = ActiveAgent::GenerationProvider::Response.new(
|
220
|
-
prompt: response.prompt,
|
221
|
-
message: response.prompt.messages.last,
|
222
|
-
raw_response: response.raw_response
|
223
|
-
)
|
224
|
-
end
|
225
|
-
context.message = response.message
|
224
|
+
context = response.prompt
|
226
225
|
response
|
227
226
|
end
|
228
227
|
|
229
228
|
def perform_actions(requested_actions:)
|
230
229
|
requested_actions.each do |action|
|
231
230
|
perform_action(action)
|
231
|
+
prompt.messages.last.role = :tool
|
232
|
+
prompt.messages.last.action_id = action.id
|
232
233
|
end
|
233
234
|
end
|
234
235
|
|
@@ -248,7 +249,7 @@ module ActiveAgent
|
|
248
249
|
action: method_name,
|
249
250
|
args: args
|
250
251
|
}
|
251
|
-
|
252
|
+
|
252
253
|
ActiveSupport::Notifications.instrument("process.active_agent", payload) do
|
253
254
|
super
|
254
255
|
@_context = ActiveAgent::ActionPrompt::Prompt.new unless @_prompt_was_called
|
@@ -17,9 +17,6 @@ module ActiveAgent
|
|
17
17
|
|
18
18
|
def generate(prompt)
|
19
19
|
@prompt = prompt
|
20
|
-
|
21
|
-
# prompt_parameters(model: @model_name, messages: prompt.messages, tools: prompt.actions)
|
22
|
-
# parameters[:instructions] = prompt.instructions.content if prompt.instructions.present?
|
23
20
|
|
24
21
|
chat_prompt(parameters: prompt_parameters)
|
25
22
|
rescue => e
|
@@ -28,6 +25,7 @@ module ActiveAgent
|
|
28
25
|
|
29
26
|
def chat_prompt(parameters: prompt_parameters)
|
30
27
|
parameters[:stream] = provider_stream if prompt.options[:stream] || config["stream"]
|
28
|
+
|
31
29
|
chat_response(@client.chat(parameters: parameters))
|
32
30
|
end
|
33
31
|
|
@@ -39,7 +37,7 @@ module ActiveAgent
|
|
39
37
|
raise GenerationProviderError, e.message
|
40
38
|
end
|
41
39
|
|
42
|
-
def embeddings_parameters(input: prompt.message.content, model: "text-embedding-
|
40
|
+
def embeddings_parameters(input: prompt.message.content, model: "text-embedding-3-large")
|
43
41
|
{
|
44
42
|
model: model,
|
45
43
|
input: input
|
@@ -76,24 +74,39 @@ module ActiveAgent
|
|
76
74
|
def prompt_parameters(model: @prompt.options[:model] || @model_name, messages: @prompt.messages, temperature: @config["temperature"] || 0.7, tools: @prompt.actions)
|
77
75
|
{
|
78
76
|
model: model,
|
79
|
-
messages: messages,
|
77
|
+
messages: provider_messages(messages),
|
80
78
|
temperature: temperature,
|
81
79
|
tools: tools.presence
|
82
80
|
}
|
83
81
|
end
|
84
82
|
|
83
|
+
def provider_messages(messages)
|
84
|
+
messages.map do |message|
|
85
|
+
provider_message {
|
86
|
+
role: message.role,
|
87
|
+
tool_call_id: message.action_id.presence,
|
88
|
+
content: message.content,
|
89
|
+
type: message.content_type,
|
90
|
+
charset: message.charset
|
91
|
+
}.compact
|
92
|
+
|
93
|
+
if content_type == "image_url"
|
94
|
+
provider_message[:image_url] = { url: content }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
85
99
|
def chat_response(response)
|
86
100
|
return @response if prompt.options[:stream]
|
87
101
|
|
88
102
|
message_json = response.dig("choices", 0, "message")
|
89
|
-
|
103
|
+
|
90
104
|
message = ActiveAgent::ActionPrompt::Message.new(
|
91
105
|
content: message_json["content"],
|
92
106
|
role: message_json["role"],
|
93
107
|
action_requested: message_json["finish_reason"] == "tool_calls",
|
94
108
|
requested_actions: handle_actions(message_json["tool_calls"])
|
95
109
|
)
|
96
|
-
|
97
110
|
update_context(prompt: prompt, message: message, response: response)
|
98
111
|
|
99
112
|
@response = ActiveAgent::GenerationProvider::Response.new(prompt: prompt, message: message, raw_response: response)
|
@@ -103,6 +116,7 @@ module ActiveAgent
|
|
103
116
|
if tool_calls
|
104
117
|
tool_calls.map do |tool_call|
|
105
118
|
ActiveAgent::ActionPrompt::Action.new(
|
119
|
+
id: tool_call["id"],
|
106
120
|
name: tool_call.dig("function", "name"),
|
107
121
|
params: JSON.parse(
|
108
122
|
tool_call.dig("function", "arguments"),
|
data/lib/active_agent/railtie.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "active_job/railtie"
|
4
4
|
require "active_agent"
|
5
|
-
require "active_agent/engine"
|
5
|
+
# require "active_agent/engine"
|
6
6
|
require "rails"
|
7
7
|
require "abstract_controller/railties/routes_helpers"
|
8
8
|
|
@@ -10,7 +10,7 @@ module ActiveAgent
|
|
10
10
|
class Railtie < Rails::Railtie # :nodoc:
|
11
11
|
config.active_agent = ActiveSupport::OrderedOptions.new
|
12
12
|
config.active_agent.preview_paths = []
|
13
|
-
config.eager_load_namespaces <<
|
13
|
+
config.eager_load_namespaces << ActiveAgent
|
14
14
|
|
15
15
|
initializer "active_agent.deprecator", before: :load_environment_config do |app|
|
16
16
|
app.deprecators[:active_agent] = ActiveAgent.deprecator
|
@@ -34,6 +34,8 @@ module ActiveAgent
|
|
34
34
|
# make sure readers methods get compiled
|
35
35
|
options.asset_host ||= app.config.asset_host
|
36
36
|
options.relative_url_root ||= app.config.relative_url_root
|
37
|
+
|
38
|
+
ActiveAgent.load_configuration(Rails.root.join('config', 'active_agent.yml'))
|
37
39
|
|
38
40
|
ActiveSupport.on_load(:active_agent) do
|
39
41
|
include AbstractController::UrlFor
|
@@ -46,20 +48,16 @@ module ActiveAgent
|
|
46
48
|
self.view_paths = ["#{Rails.root}/app/views"]
|
47
49
|
self.preview_paths |= options[:preview_paths]
|
48
50
|
|
49
|
-
if
|
50
|
-
self.
|
51
|
-
end
|
52
|
-
|
53
|
-
if options.smtp_settings
|
54
|
-
self.smtp_settings = options.smtp_settings
|
51
|
+
if generation_job = options.delete(:generation_job)
|
52
|
+
self.generation_job = generation_job.constantize
|
55
53
|
end
|
56
54
|
|
57
55
|
options.each { |k, v| send(:"#{k}=", v) }
|
58
56
|
end
|
59
57
|
|
60
58
|
ActiveSupport.on_load(:action_dispatch_integration_test) do
|
61
|
-
include ActiveAgent::TestHelper
|
62
|
-
include ActiveAgent::TestCase::ClearTestDeliveries
|
59
|
+
# include ActiveAgent::TestHelper
|
60
|
+
# include ActiveAgent::TestCase::ClearTestDeliveries
|
63
61
|
end
|
64
62
|
end
|
65
63
|
|
data/lib/active_agent/version.rb
CHANGED
data/lib/activeagent.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "active_agent"
|
@@ -4,11 +4,7 @@ module ActiveAgent
|
|
4
4
|
module Generators
|
5
5
|
class InstallGenerator < ::Rails::Generators::Base
|
6
6
|
source_root File.expand_path("templates", __dir__)
|
7
|
-
|
8
|
-
def create_initializer
|
9
|
-
template "initializer.rb", "config/initializers/active_agent.rb"
|
10
|
-
end
|
11
|
-
|
7
|
+
|
12
8
|
def create_configuration
|
13
9
|
template "active_agent.yml", "config/active_agent.yml"
|
14
10
|
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.2.
|
4
|
+
version: 0.2.6.rc2
|
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-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -137,8 +137,6 @@ executables: []
|
|
137
137
|
extensions: []
|
138
138
|
extra_rdoc_files: []
|
139
139
|
files:
|
140
|
-
- README.md
|
141
|
-
- Rakefile
|
142
140
|
- lib/active_agent.rb
|
143
141
|
- lib/active_agent/README.md
|
144
142
|
- lib/active_agent/action_prompt.rb
|
@@ -172,6 +170,7 @@ files:
|
|
172
170
|
- lib/active_agent/service.rb
|
173
171
|
- lib/active_agent/test_case.rb
|
174
172
|
- lib/active_agent/version.rb
|
173
|
+
- lib/activeagent.rb
|
175
174
|
- lib/generators/active_agent/USAGE
|
176
175
|
- lib/generators/active_agent/agent_generator.rb
|
177
176
|
- lib/generators/active_agent/install_generator.rb
|
@@ -182,11 +181,14 @@ files:
|
|
182
181
|
- lib/generators/active_agent/templates/agent_spec.rb.tt
|
183
182
|
- lib/generators/active_agent/templates/agent_test.rb.tt
|
184
183
|
- lib/generators/active_agent/templates/application_agent.rb.tt
|
185
|
-
|
186
|
-
homepage: https://rubygems.org/gems/activeagent
|
184
|
+
homepage: https://activeagents.ai
|
187
185
|
licenses:
|
188
186
|
- MIT
|
189
|
-
metadata:
|
187
|
+
metadata:
|
188
|
+
bug_tracker_uri: https://github.com/activeagents/activeagent/issues
|
189
|
+
documentation_uri: https://github.com/activeagents/activeagent
|
190
|
+
source_code_uri: https://github.com/activeagents/activeagent
|
191
|
+
rubygems_mfa_required: 'true'
|
190
192
|
post_install_message:
|
191
193
|
rdoc_options: []
|
192
194
|
require_paths:
|
data/README.md
DELETED
@@ -1,188 +0,0 @@
|
|
1
|
-
# Active Agent
|
2
|
-
|
3
|
-
## Install
|
4
|
-
|
5
|
-
### Gemfile
|
6
|
-
`gem 'activeagent', require: 'active_agent'`
|
7
|
-
|
8
|
-
### CLI
|
9
|
-
`gem install activeagent`
|
10
|
-
|
11
|
-
### Rails Generator
|
12
|
-
After installing the gem, run the Rails installation generator:
|
13
|
-
|
14
|
-
```bash
|
15
|
-
$ rails generate active_agent:install
|
16
|
-
```
|
17
|
-
|
18
|
-
This will create:
|
19
|
-
```
|
20
|
-
create config/initializers/active_agent.rb
|
21
|
-
create config/active_agent.yml
|
22
|
-
create app/agents/application_agent.rb
|
23
|
-
create app/agents
|
24
|
-
```
|
25
|
-
|
26
|
-
- An initializer that uses default configurations
|
27
|
-
```ruby
|
28
|
-
# config/initializers/active_agent.rb
|
29
|
-
ActiveAgent.load_configuration(Rails.root.join('config', 'active_agent.yml'))
|
30
|
-
```
|
31
|
-
- A YAML configuration file for provider settings, such as OpenAI and might include environment-specific configurations:
|
32
|
-
```yaml
|
33
|
-
# config/active_agent.yml
|
34
|
-
development:
|
35
|
-
openai:
|
36
|
-
service: "OpenAI"
|
37
|
-
api_key: <%= Rails.application.credentials.dig(:openai, :api_key) %>
|
38
|
-
model: "gpt-3.5-turbo"
|
39
|
-
temperature: 0.7
|
40
|
-
|
41
|
-
production:
|
42
|
-
openai:
|
43
|
-
service: "OpenAI"
|
44
|
-
api_key: <%= Rails.application.credentials.dig(:openai, :api_key) %>
|
45
|
-
model: "gpt-3.5-turbo"
|
46
|
-
temperature: 0.7
|
47
|
-
|
48
|
-
```
|
49
|
-
- A base application agent class
|
50
|
-
```ruby
|
51
|
-
# app/agents/application_agent.rb
|
52
|
-
class ApplicationAgent < ActiveAgent::Base
|
53
|
-
layout 'agent'
|
54
|
-
|
55
|
-
def prompt
|
56
|
-
super { |format| format.text { render plain: params[:message] } }
|
57
|
-
end
|
58
|
-
```
|
59
|
-
- The agents directory structure
|
60
|
-
|
61
|
-
## Agent
|
62
|
-
Create agents that take instructions, prompts, and perform actions
|
63
|
-
|
64
|
-
### Rails Generator
|
65
|
-
To use the Rails Active Agent generator to create a new agent and the associated views for the requested action prompts:
|
66
|
-
|
67
|
-
```bash
|
68
|
-
$ rails generate active_agent:agent travel search book plans
|
69
|
-
```
|
70
|
-
This will create:
|
71
|
-
```
|
72
|
-
create app/agents/travel_agent.rb
|
73
|
-
create app/views/agents/travel/search.text.erb
|
74
|
-
create app/views/agents/travel/book.text.erb
|
75
|
-
create app/views/agents/travel/plans.text.erb
|
76
|
-
```
|
77
|
-
|
78
|
-
The generator creates:
|
79
|
-
- An agent class inheriting from ApplicationAgent
|
80
|
-
- Text template views for each action
|
81
|
-
- Action methods in the agent class for processing prompts
|
82
|
-
|
83
|
-
### Agent Actions
|
84
|
-
```ruby
|
85
|
-
class TravelAgent < ApplicationAgent
|
86
|
-
def search
|
87
|
-
|
88
|
-
prompt { |format| format.text { render plain: "Searching for travel options" } }
|
89
|
-
end
|
90
|
-
|
91
|
-
def book
|
92
|
-
prompt { |format| format.text { render plain: "Booking travel plans" } }
|
93
|
-
end
|
94
|
-
|
95
|
-
def plans
|
96
|
-
prompt { |format| format.text { render plain: "Making travel plans" } }
|
97
|
-
end
|
98
|
-
end
|
99
|
-
```
|
100
|
-
|
101
|
-
## Action Prompt
|
102
|
-
|
103
|
-
Action Prompt provides the structured interface for composing AI interactions through messages, actions/tools, and conversation context. [Read more about Action Prompt](lib/active_agent/action_prompt/README.md)
|
104
|
-
|
105
|
-
```ruby
|
106
|
-
agent.prompt(message: "Find hotels in Paris",
|
107
|
-
actions: [{name: "search", params: {query: "hotels paris"}}])
|
108
|
-
```
|
109
|
-
|
110
|
-
The prompt interface manages:
|
111
|
-
- Message content and roles (system/user/assistant)
|
112
|
-
- Action/tool definitions and requests
|
113
|
-
- Headers and context tracking
|
114
|
-
- Content types and multipart handling
|
115
|
-
|
116
|
-
### Generation Provider
|
117
|
-
|
118
|
-
Generation Provider defines how prompts are sent to AI services for completion and embedding generation. [Read more about Generation Providers](lib/active_agent/generation_provider/README.md)
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
class VacationAgent < ActiveAgent::Base
|
122
|
-
# Try not to get too model-rous with the parameters!
|
123
|
-
generate_with :openai,
|
124
|
-
model: "gpt-4",
|
125
|
-
temperature: 0.7
|
126
|
-
|
127
|
-
# Embed yourself in the joy of vector search
|
128
|
-
embed_with :openai,
|
129
|
-
model: "text-embedding-ada-002"
|
130
|
-
end
|
131
|
-
```
|
132
|
-
|
133
|
-
Providers handle:
|
134
|
-
- API client configuration
|
135
|
-
- Prompt/completion generation
|
136
|
-
- Stream processing
|
137
|
-
- Embedding generation
|
138
|
-
- Context management
|
139
|
-
- Error handling
|
140
|
-
|
141
|
-
### Queue Generation
|
142
|
-
|
143
|
-
Active Agent also supports queued generation with Active Job using a common Generation Job interface.
|
144
|
-
|
145
|
-
### Perform actions
|
146
|
-
|
147
|
-
Active Agents can define methods that are autoloaded as callable tools. These actions’ default schema will be provided to the agent’s context as part of the prompt request to the Generation Provider.
|
148
|
-
|
149
|
-
## Actions
|
150
|
-
|
151
|
-
```ruby
|
152
|
-
def get_cat_image_base64
|
153
|
-
uri = URI("https://cataas.com/cat")
|
154
|
-
response = Net::HTTP.get_response(uri)
|
155
|
-
|
156
|
-
if response.is_a?(Net::HTTPSuccess)
|
157
|
-
image_data = response.body
|
158
|
-
Base64.strict_encode64(image_data)
|
159
|
-
else
|
160
|
-
raise "Failed to fetch cat image. Status code: #{response.code}"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
class SupportAgent < ActiveAgent
|
165
|
-
generate_with :openai,
|
166
|
-
model: "gpt-4o",
|
167
|
-
instructions: "Help people with their problems",
|
168
|
-
temperature: 0.7
|
169
|
-
|
170
|
-
def get_cat_image
|
171
|
-
prompt { |format| format.text { render plain: get_cat_image_base64 } }
|
172
|
-
end
|
173
|
-
end
|
174
|
-
```
|
175
|
-
|
176
|
-
## Prompts
|
177
|
-
|
178
|
-
### Basic
|
179
|
-
|
180
|
-
#### Plain text prompt and response templates
|
181
|
-
|
182
|
-
### HTML
|
183
|
-
|
184
|
-
### Action Schema JSON
|
185
|
-
|
186
|
-
response = SupportAgent.prompt(‘show me a picture of a cat’).generate_now
|
187
|
-
|
188
|
-
response.message
|
data/Rakefile
DELETED