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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_agent/action_prompt/README.md +92 -25
  3. data/lib/active_agent/action_prompt/action.rb +13 -0
  4. data/lib/active_agent/action_prompt/base.rb +127 -0
  5. data/lib/active_agent/action_prompt/message.rb +18 -16
  6. data/lib/active_agent/action_prompt/prompt.rb +14 -15
  7. data/lib/active_agent/base.rb +96 -58
  8. data/lib/active_agent/callbacks.rb +13 -0
  9. data/lib/active_agent/generation.rb +3 -3
  10. data/lib/active_agent/generation_job.rb +1 -1
  11. data/lib/active_agent/generation_provider/README.md +63 -8
  12. data/lib/active_agent/generation_provider/anthropic_provider.rb +142 -0
  13. data/lib/active_agent/generation_provider/base.rb +7 -2
  14. data/lib/active_agent/generation_provider/open_ai_provider.rb +95 -24
  15. data/lib/active_agent/generation_provider.rb +1 -2
  16. data/lib/active_agent/operation.rb +3 -3
  17. data/lib/active_agent/queued_generation.rb +1 -1
  18. data/lib/active_agent/railtie.rb +9 -11
  19. data/lib/active_agent/service.rb +1 -1
  20. data/lib/active_agent/version.rb +1 -1
  21. data/lib/active_agent.rb +7 -3
  22. data/lib/activeagent.rb +1 -0
  23. data/lib/generators/active_agent/agent_generator.rb +22 -22
  24. data/lib/generators/active_agent/install_generator.rb +21 -0
  25. data/lib/generators/active_agent/templates/active_agent.yml +6 -0
  26. data/lib/generators/active_agent/templates/agent.rb.tt +1 -1
  27. data/lib/generators/active_agent/templates/agent.text.erb +1 -0
  28. data/lib/generators/active_agent/templates/application_agent.rb.tt +7 -0
  29. metadata +65 -20
  30. data/README.md +0 -153
  31. data/Rakefile +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67bb51f0a98d5b2291b53e30b629adae069a3f24e19edfc74702a918bc3c1086
4
- data.tar.gz: 04cb6ba122dac00b145c3baf1f54157d5e443470639d16f22d614bfaaba92b49
3
+ metadata.gz: '08db8e070616e81109c24a4738d29cc5c7b2911a3b7584e90c23cd9a1072a20a'
4
+ data.tar.gz: 424e66ddfde6018b15b33d440764604db3cb3c1c3bef3f6cc0c0e765cad8d06e
5
5
  SHA512:
6
- metadata.gz: 9835738ac1bb5570c900dd9a9942591a28c8b17b6ce26afbd622f764d5bb4ee178d0fc1089824a84d924824cc0c9a291680b1a1b1df5e41f5bfff1e91700a382
7
- data.tar.gz: 78e3fd95e02a950cd2c47bf52891156d861f926374333efaeee51578fc0c96f65a94a123ec104cd0a5c32c9ea130ac85075a9904478191904936ea80381df714
6
+ metadata.gz: d6b7d4b86153dfea08db656c6b0620229902d371fd0afccbc4eca30e961875a4982339dfd4cdc77c2349d9ecf7e9085a98de07a406c73c15cf4a25ffc0fe3548
7
+ data.tar.gz: 4bb01d36f8610e25f0f0220f9b465779e15afa083786dfa8628def00b5a693a2804ff9665f967e484034ef30ea4312e2eafcc813aef1f66fb597ff7dd5bbbe49
@@ -1,44 +1,111 @@
1
1
  # Active Agent: Action Prompt
2
2
 
3
- ActionPrompt provides a structured way to create and manage prompts and tools for AI interactions. It includes several support classes to handle different aspects of prompt creation and management. The Base class implements an AbstractController to perform actions that render prompts..
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
- ## Main Components
5
+ Action Prompt manages the overall prompt structure including:
6
6
 
7
- Module - for including in your agent classes to provide prompt functionality.
8
- Base class - for creating and managing prompts in ActiveAgent.
9
- Tool class - for representing the tool object sent to the Agent's generation provider.
10
- Message - class for representing a single message within a prompt.
11
- Prompt - class for representing a the context of a prompt, including messages, actions, and other attributes.
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
- ### ActionPrompt::Base
14
-
15
- The base class is used to create and manage prompts in Active Agent. It provides the core functionality for creating and managing contexts woth prompts, tools, and messages.
16
-
17
- #### Core Methods
18
- `prompt` - Creates a new prompt object with the given attributes.
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
- ### ActionPrompt::Tool
24
+ Represents individual messages with:
22
25
 
23
- ### ActionPrompt::Message
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
- Represents a single message within a prompt.
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
- ### ActionPrompt::Prompt
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
- Manages the overall structure of a prompt, including multiple messages, actions, and other attributes.
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
- Represents an action that represents the tool object sent to the Agent's generation provider can be associated with a prompt or message.
75
+ Defines callable tools/functions:
34
76
 
35
- ## Usage
77
+ - Name and parameters schema
78
+ - Validation and type checking
79
+ - Response handling
80
+ - Action execution
36
81
 
37
- To use ActionPrompt in your agent, include the module in your agent class:
82
+ ## Usage with Base Agents
38
83
 
39
84
  ```ruby
40
- class MyAgent
41
- include ActiveAgent::ActionPrompt
42
-
43
- # Your agent code here
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, :name, :action_requested, :requested_actions
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
- @role = attributes[:role] || "user"
11
- @name = attributes[:name]
12
- @action_requested = attributes[:function_call]
13
- @requested_actions = attributes[:tool_calls] || []
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 = {role: role, content: content}
19
- hash[:name] = name if name
20
- hash[:action_requested] = action_requested if action_requested
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 perform_actions
26
- requested_actions.each do |action|
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, Message.new)
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.content
26
- set_messages if @messages.any? || @instructions.present?
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(part)
35
- message = Message.new(content: part[:body], role: :user)
36
- prompt_part = self.class.new(message: message, content: message.content, content_type: part[:content_type], chartset: part[:charset])
35
+ def add_part(message)
36
+ @message = message
37
+ set_message if @content_type == message.content_type && @message.content.present?
37
38
 
38
- set_message if @content_type == part[:content_type] && @message.content
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 @body.is_a?(String) && !@message.content
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 = [@message]
74
+ @messages << @message
76
75
  end
77
76
  end
78
77
  end