activeagent 0.1.1 → 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/README.md +92 -25
- data/lib/active_agent/action_prompt/action.rb +13 -0
- data/lib/active_agent/action_prompt/base.rb +127 -0
- data/lib/active_agent/action_prompt/message.rb +18 -16
- data/lib/active_agent/action_prompt/prompt.rb +14 -15
- data/lib/active_agent/base.rb +96 -58
- data/lib/active_agent/callbacks.rb +13 -0
- data/lib/active_agent/generation.rb +3 -3
- data/lib/active_agent/generation_job.rb +1 -1
- data/lib/active_agent/generation_provider/README.md +63 -8
- data/lib/active_agent/generation_provider/anthropic_provider.rb +142 -0
- data/lib/active_agent/generation_provider/base.rb +7 -2
- data/lib/active_agent/generation_provider/open_ai_provider.rb +95 -24
- data/lib/active_agent/generation_provider.rb +1 -2
- data/lib/active_agent/operation.rb +3 -3
- data/lib/active_agent/queued_generation.rb +1 -1
- data/lib/active_agent/railtie.rb +9 -11
- data/lib/active_agent/service.rb +1 -1
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +7 -3
- data/lib/activeagent.rb +1 -0
- data/lib/generators/active_agent/agent_generator.rb +22 -22
- data/lib/generators/active_agent/install_generator.rb +21 -0
- data/lib/generators/active_agent/templates/active_agent.yml +6 -0
- data/lib/generators/active_agent/templates/agent.rb.tt +1 -1
- data/lib/generators/active_agent/templates/agent.text.erb +1 -0
- data/lib/generators/active_agent/templates/application_agent.rb.tt +7 -0
- metadata +65 -20
- data/README.md +0 -153
- data/Rakefile +0 -3
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
|
@@ -1,44 +1,111 @@
|
|
1
1
|
# Active Agent: Action Prompt
|
2
2
|
|
3
|
-
|
3
|
+
Action Prompt provides a structured way to create and manage prompts for AI interactions. It enables composing messages, handling actions/tools, and managing conversation context through several key components.
|
4
4
|
|
5
|
-
|
5
|
+
Action Prompt manages the overall prompt structure including:
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
- Messages list with system/user/assistant roles
|
8
|
+
- Action/tool definitions
|
9
|
+
- Headers and context tracking
|
10
|
+
- Content type and encoding
|
11
|
+
- Multipart message handling
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
```ruby
|
14
|
+
prompt = ActionPrompt::Prompt.new(
|
15
|
+
instructions: "System guidance",
|
16
|
+
message: "User input",
|
17
|
+
actions: [tool_definition, action_schema],
|
18
|
+
context: messages
|
19
|
+
)
|
20
|
+
```
|
19
21
|
|
22
|
+
## ActionPrompt::Message
|
20
23
|
|
21
|
-
|
24
|
+
Represents individual messages with:
|
22
25
|
|
23
|
-
###
|
26
|
+
### Content and Role
|
27
|
+
```ruby
|
28
|
+
message = ActionPrompt::Message.new(
|
29
|
+
content: "Search for a hotel",
|
30
|
+
role: :user
|
31
|
+
)
|
32
|
+
```
|
24
33
|
|
25
|
-
|
34
|
+
- Content stores the actual message text
|
35
|
+
- Role defines the message sender type (system/user/assistant/function/tool)
|
36
|
+
- Messages form interactions between roles in a Context
|
26
37
|
|
27
|
-
###
|
38
|
+
### Action Requests and Responses
|
39
|
+
```ruby
|
40
|
+
message = ActionPrompt::Message.new(
|
41
|
+
content: "Search for a hotel",
|
42
|
+
role: :tool,
|
43
|
+
requested_actions: [{name: "search", params: {query: "hotel"}}]
|
44
|
+
)
|
45
|
+
```
|
46
|
+
|
47
|
+
- Tracks if message requests actions/tools
|
48
|
+
- Maintains list of requested_actions
|
49
|
+
- Action responses include function call results
|
50
|
+
- Handles tool execution state
|
51
|
+
|
52
|
+
### Content Type and Encoding
|
53
|
+
- Default content_type is "text/plain"
|
54
|
+
- Supports multiple content types for rich messages
|
55
|
+
- Default charset is UTF-8
|
56
|
+
- Handles content encoding/decoding
|
57
|
+
|
58
|
+
### Role Validation
|
59
|
+
- Enforces valid roles via VALID_ROLES constant
|
60
|
+
- Validates on message creation
|
61
|
+
- Raises ArgumentError for invalid roles
|
62
|
+
- Supported roles: system, assistant, user, tool, function
|
28
63
|
|
29
|
-
|
64
|
+
```ruby
|
65
|
+
message = ActionPrompt::Message.new(
|
66
|
+
content: "Hello",
|
67
|
+
role: :user,
|
68
|
+
content_type: "text/plain",
|
69
|
+
charset: "UTF-8"
|
70
|
+
)
|
71
|
+
```
|
30
72
|
|
31
73
|
### ActionPrompt::Action
|
32
74
|
|
33
|
-
|
75
|
+
Defines callable tools/functions:
|
34
76
|
|
35
|
-
|
77
|
+
- Name and parameters schema
|
78
|
+
- Validation and type checking
|
79
|
+
- Response handling
|
80
|
+
- Action execution
|
36
81
|
|
37
|
-
|
82
|
+
## Usage with Base Agents
|
38
83
|
|
39
84
|
```ruby
|
40
|
-
class MyAgent
|
41
|
-
|
42
|
-
|
43
|
-
|
85
|
+
class MyAgent < ActiveAgent::Base
|
86
|
+
# Define available actions
|
87
|
+
def action_schemas
|
88
|
+
[
|
89
|
+
{name: "search", params: {query: :string}}
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
# Handle action responses
|
94
|
+
def perform_action(action)
|
95
|
+
case action.name
|
96
|
+
when "search"
|
97
|
+
search_service.query(action.params[:query])
|
98
|
+
end
|
99
|
+
end
|
44
100
|
end
|
101
|
+
```
|
102
|
+
|
103
|
+
The Base agent integrates with ActionPrompt to:
|
104
|
+
|
105
|
+
1. Create prompts with context
|
106
|
+
2. Register available actions
|
107
|
+
3. Process action requests
|
108
|
+
4. Handle responses and update context
|
109
|
+
5. Manage the conversation flow
|
110
|
+
|
111
|
+
See Base.rb for full agent integration details.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveAgent
|
2
|
+
module ActionPrompt
|
3
|
+
class Action
|
4
|
+
attr_accessor :agent_name, :id, :name, :params
|
5
|
+
|
6
|
+
def initialize(attributes = {})
|
7
|
+
@id = attributes.fetch(:id, nil)
|
8
|
+
@name = attributes.fetch(:name, "")
|
9
|
+
@params = attributes.fetch(:params, {})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,127 @@
|
|
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
|
+
|
19
|
+
# included do
|
20
|
+
# include AbstractController::Rendering
|
21
|
+
# include AbstractController::Layouts
|
22
|
+
# include AbstractController::Helpers
|
23
|
+
# include AbstractController::Translation
|
24
|
+
# include AbstractController::AssetPaths
|
25
|
+
# include AbstractController::Callbacks
|
26
|
+
# include AbstractController::Caching
|
27
|
+
|
28
|
+
# include ActionView::Layouts
|
29
|
+
|
30
|
+
# helper ActiveAgent::PromptHelper
|
31
|
+
# # class_attribute :default_params, default: {
|
32
|
+
# # content_type: "text/plain",
|
33
|
+
# # parts_order: ["text/plain", "text/html", "application/json"]
|
34
|
+
# # }.freeze
|
35
|
+
# end
|
36
|
+
|
37
|
+
# # # def self.prompt(headers = {}, &)
|
38
|
+
# # # new.prompt(headers, &)
|
39
|
+
# # # end
|
40
|
+
|
41
|
+
# # def prompt(headers = {}, &block)
|
42
|
+
# # return @_message if @_prompt_was_called && headers.blank? && !block
|
43
|
+
|
44
|
+
# # headers = apply_defaults(headers)
|
45
|
+
|
46
|
+
# # @_message = ActiveAgent::ActionPrompt::Prompt.new
|
47
|
+
|
48
|
+
# # assign_headers_to_message(@_message, headers)
|
49
|
+
|
50
|
+
# # responses = collect_responses(headers, &block)
|
51
|
+
|
52
|
+
# # @_prompt_was_called = true
|
53
|
+
|
54
|
+
# # create_parts_from_responses(@_message, responses)
|
55
|
+
|
56
|
+
# # @_message
|
57
|
+
# # end
|
58
|
+
|
59
|
+
# private
|
60
|
+
|
61
|
+
# def apply_defaults(headers)
|
62
|
+
# headers.reverse_merge(self.class.default_params)
|
63
|
+
# end
|
64
|
+
|
65
|
+
# def assign_headers_to_message(message, headers)
|
66
|
+
# assignable = headers.except(:parts_order, :content_type, :body, :template_name, :template_path)
|
67
|
+
# assignable.each { |k, v| message.send(:"#{k}=", v) }
|
68
|
+
# end
|
69
|
+
|
70
|
+
# def collect_responses(headers, &block)
|
71
|
+
# if block
|
72
|
+
# collect_responses_from_block(headers, &block)
|
73
|
+
# elsif headers[:body]
|
74
|
+
# collect_responses_from_text(headers)
|
75
|
+
# else
|
76
|
+
# collect_responses_from_templates(headers)
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
|
80
|
+
# def collect_responses_from_block(headers, &block)
|
81
|
+
# templates_name = headers[:template_name] || action_name
|
82
|
+
# collector = ActiveAgent::ActionPrompt::Collector.new(lookup_context) { render(templates_name) }
|
83
|
+
# yield(collector)
|
84
|
+
# collector.responses
|
85
|
+
# end
|
86
|
+
|
87
|
+
# def collect_responses_from_text(headers)
|
88
|
+
# [{
|
89
|
+
# body: headers.delete(:body),
|
90
|
+
# content_type: headers[:content_type] || "text/plain"
|
91
|
+
# }]
|
92
|
+
# end
|
93
|
+
|
94
|
+
# def collect_responses_from_templates(headers)
|
95
|
+
# templates_path = headers[:template_path] || self.class.name.sub(/Agent$/, "").underscore
|
96
|
+
# templates_name = headers[:template_name] || action_name
|
97
|
+
# each_template(Array(templates_path), templates_name).map do |template|
|
98
|
+
# format = template.format || formats.first
|
99
|
+
# {
|
100
|
+
# body: render(template: template, formats: [format]),
|
101
|
+
# content_type: Mime[format].to_s
|
102
|
+
# }
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
|
106
|
+
# def each_template(paths, name, &)
|
107
|
+
# templates = lookup_context.find_all(name, paths)
|
108
|
+
# if templates.empty?
|
109
|
+
# raise ActionView::MissingTemplate.new(paths, name, paths, false, "prompt")
|
110
|
+
# else
|
111
|
+
# templates.uniq(&:format).each(&)
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
|
115
|
+
# def create_parts_from_responses(message, responses)
|
116
|
+
# responses.each do |response|
|
117
|
+
# message.add_part(response[:body], content_type: response[:content_type])
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
|
121
|
+
# class TestAgent
|
122
|
+
# class << self
|
123
|
+
# attr_accessor :generations
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
# end
|
@@ -3,33 +3,35 @@ module ActiveAgent
|
|
3
3
|
class Message
|
4
4
|
VALID_ROLES = %w[system assistant user tool function].freeze
|
5
5
|
|
6
|
-
attr_accessor :content, :role, :
|
6
|
+
attr_accessor :action_id, :content, :role, :action_requested, :requested_actions, :content_type, :charset
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
|
+
@action_id = attributes[:action_id]
|
10
|
+
@charset = attributes[:charset] || "UTF-8"
|
9
11
|
@content = attributes[:content] || ""
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
12
|
+
@content_type = attributes[:content_type] || "text/plain"
|
13
|
+
@role = attributes[:role] || :user
|
14
|
+
@requested_actions = attributes[:requested_actions] || []
|
15
|
+
@action_requested = @requested_actions.any?
|
14
16
|
validate_role
|
15
17
|
end
|
16
18
|
|
17
19
|
def to_h
|
18
|
-
hash = {
|
19
|
-
|
20
|
-
|
20
|
+
hash = {
|
21
|
+
role: role,
|
22
|
+
action_id: action_id,
|
23
|
+
content: content,
|
24
|
+
type: content_type,
|
25
|
+
charset: charset
|
26
|
+
}
|
27
|
+
|
28
|
+
hash[:action_requested] = requested_actions.any?
|
21
29
|
hash[:requested_actions] = requested_actions if requested_actions.any?
|
22
30
|
hash
|
23
31
|
end
|
24
32
|
|
25
|
-
def
|
26
|
-
|
27
|
-
action.call(self) if action.respond_to?(:call)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def action_requested?
|
32
|
-
action_requested.present? || requested_actions.any?
|
33
|
+
def embed
|
34
|
+
@agent_class.embed(@content)
|
33
35
|
end
|
34
36
|
|
35
37
|
private
|
@@ -1,29 +1,30 @@
|
|
1
|
-
# lib/active_agent/action_prompt/prompt.rb
|
2
1
|
require_relative "message"
|
3
2
|
|
4
3
|
module ActiveAgent
|
5
4
|
module ActionPrompt
|
6
5
|
class Prompt
|
7
|
-
attr_accessor :actions, :body, :content_type, :instructions, :message, :messages, :options, :mime_version, :charset, :context
|
6
|
+
attr_accessor :actions, :body, :content_type, :context_id, :instructions, :message, :messages, :options, :mime_version, :charset, :context, :parts
|
8
7
|
|
9
8
|
def initialize(attributes = {})
|
10
9
|
@options = attributes.fetch(:options, {})
|
10
|
+
@agent_class = attributes.fetch(:agent_class, ApplicationAgent)
|
11
11
|
@actions = attributes.fetch(:actions, [])
|
12
12
|
@action_choice = attributes.fetch(:action_choice, "")
|
13
13
|
@instructions = attributes.fetch(:instructions, "")
|
14
14
|
@body = attributes.fetch(:body, "")
|
15
15
|
@content_type = attributes.fetch(:content_type, "text/plain")
|
16
|
-
@message = attributes.fetch(:message,
|
16
|
+
@message = attributes.fetch(:message, nil)
|
17
17
|
@messages = attributes.fetch(:messages, [])
|
18
18
|
@params = attributes.fetch(:params, {})
|
19
19
|
@mime_version = attributes.fetch(:mime_version, "1.0")
|
20
20
|
@charset = attributes.fetch(:charset, "UTF-8")
|
21
21
|
@context = attributes.fetch(:context, [])
|
22
|
+
@context_id = attributes.fetch(:context_id, nil)
|
22
23
|
@headers = attributes.fetch(:headers, {})
|
23
24
|
@parts = attributes.fetch(:parts, [])
|
24
25
|
|
25
|
-
set_message if attributes[:message].is_a?(String) || @body.is_a?(String) && @message
|
26
|
-
set_messages
|
26
|
+
set_message if attributes[:message].is_a?(String) || @body.is_a?(String) && @message&.content
|
27
|
+
set_messages
|
27
28
|
end
|
28
29
|
|
29
30
|
# Generate the prompt as a string (for debugging or sending to the provider)
|
@@ -31,13 +32,11 @@ module ActiveAgent
|
|
31
32
|
@message.to_s
|
32
33
|
end
|
33
34
|
|
34
|
-
def add_part(
|
35
|
-
message =
|
36
|
-
|
35
|
+
def add_part(message)
|
36
|
+
@message = message
|
37
|
+
set_message if @content_type == message.content_type && @message.content.present?
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
@parts << prompt_part
|
39
|
+
@parts << context
|
41
40
|
end
|
42
41
|
|
43
42
|
def multipart?
|
@@ -67,12 +66,12 @@ module ActiveAgent
|
|
67
66
|
end
|
68
67
|
|
69
68
|
def set_message
|
70
|
-
if @
|
71
|
-
@message = Message.new(content: @body, role: :user)
|
72
|
-
elsif @message.is_a? String
|
69
|
+
if @message.is_a? String
|
73
70
|
@message = Message.new(content: @message, role: :user)
|
71
|
+
elsif @body.is_a?(String) && @message.content.blank?
|
72
|
+
@message = Message.new(content: @body, role: :user)
|
74
73
|
end
|
75
|
-
@messages
|
74
|
+
@messages << @message
|
76
75
|
end
|
77
76
|
end
|
78
77
|
end
|