Class: ComposableAgents::PromptDrivenAgent
- Defined in:
- lib/composable_agents/prompt_driven_agent.rb
Overview
Agent implementation that uses a prompt rendering strategy to render prompts for a prompting engine. The following prompts are considered:
- A system prompt, that defines the Agent's behaviour, or persona.
- User prompts, that are used as user inputs guiding the agent.
- Retry prompts, used to tell the Agent that the task at hand is still incomplete and needs more work. For example when an artifact has not been created, and the agent needs to try it again.
Prompt rendering strategies are useful because different prompt-driven agents would benefit from different
prompt formats or structures (JSON, Markdown, explicit ordered lists, in-lining artifacts' contents without tools...).
This agent automatically records non-rendered conversation (prompts + outputs) in a conversation store, part of its state.
Direct Known Subclasses
Public API collapse
-
#constraints ⇒ String?
Constraints to be respected, or nil for the agent's default.
-
#conversation ⇒ Array<Hash{Symbol => Object}>
readonly
The conversation (user prompts, responses) that happened with this agent.
-
#objective ⇒ String?
Agent's objective, or nil for the agent's default.
-
#role ⇒ String?
Agent's role, or nil for the agent's default.
-
#system_instructions ⇒ Object?
Agent's original instructions, or nil if no system instructions are needed (see Instructions#initialize).
Attributes inherited from Agent
Public API collapse
-
#initialize(*args, role: nil, objective: nil, system_instructions: nil, constraints: nil, strategy: PromptRenderingStrategy::Markdown, **kwargs) ⇒ PromptDrivenAgent
constructor
Initialize a new PromptDrivenAgent with the information needed for prompts and the selected prompt rendering strategy.
-
#run(user_instructions: nil, **input_artifacts) ⇒ Hash{Symbol => Object}
Execute the agent to generate some output artifacts based on some input artifacts.
Methods inherited from Agent
Methods included from Mixins::Logger
Internal collapse
-
#export_state ⇒ Object
Export the agent state for persistence.
-
#import_state(state) ⇒ Object
Import the agent state from persistence.
-
#input_artifacts_contracts ⇒ Hash{Symbol => Object}
Define input artifacts contracts.
-
#output_artifacts_contracts ⇒ Hash{Symbol => Object}
Define output artifacts contracts.
-
#report_error_for_output_artifact(artifact_name, error) ⇒ Object
Report an error on an output artifact.
-
#save_output_artifact(artifact_name, content) ⇒ Object
Save an output artifact.
Constructor Details
#initialize(*args, role: nil, objective: nil, system_instructions: nil, constraints: nil, strategy: PromptRenderingStrategy::Markdown, **kwargs) ⇒ PromptDrivenAgent
Initialize a new PromptDrivenAgent with the information needed for prompts and the selected prompt rendering strategy. If no name is provided, it will default to 'Executor'.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 46 def initialize( *args, role: nil, objective: nil, system_instructions: nil, constraints: nil, strategy: PromptRenderingStrategy::Markdown, **kwargs ) super(*args, **kwargs) singleton_class.include strategy @role = role @objective = objective @system_instructions = system_instructions @constraints = constraints @conversation = [] end |
Instance Attribute Details
#constraints ⇒ String?
Returns Constraints to be respected, or nil for the agent's default.
27 28 29 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 27 def constraints @constraints end |
#conversation ⇒ Array<Hash{Symbol => Object}> (readonly)
Returns The conversation (user prompts, responses) that happened with this agent. Each item of a conversation has the following properties:
- author [String] Author of the message
- at [String] UTC timestamp of the message at format YYYY-mm-dd HH:MM:SS
- message [String] The message itself
- question [Boolean] Is this message a question expecting a reply? Defaults to false.
35 36 37 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 35 def conversation @conversation end |
#objective ⇒ String?
Returns Agent's objective, or nil for the agent's default.
21 22 23 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 21 def objective @objective end |
#role ⇒ String?
Returns Agent's role, or nil for the agent's default.
18 19 20 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 18 def role @role end |
#system_instructions ⇒ Object?
Returns Agent's original instructions, or nil if no system instructions are needed (see Instructions#initialize).
24 25 26 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 24 def system_instructions @system_instructions end |
Instance Method Details
#export_state ⇒ Object
Export the agent state for persistence
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 122 def export_state deep_transform_keys( { conversation: @conversation.map do || .merge(at: [:at].strftime('%F %T')) end }, &:to_s ) end |
#import_state(state) ⇒ Object
Import the agent state from persistence
136 137 138 139 140 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 136 def import_state(state) @conversation = deep_transform_keys(state, &:to_sym)[:conversation].map do || .merge(at: Time.parse("#{.delete(:at)} UTC")) end end |
#input_artifacts_contracts ⇒ Hash{Symbol => Object}
Define input artifacts contracts
103 104 105 106 107 108 109 110 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 103 def input_artifacts_contracts { user_instructions: { description: 'User instructions', optional: true } } end |
#output_artifacts_contracts ⇒ Hash{Symbol => Object}
Define output artifacts contracts
115 116 117 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 115 def output_artifacts_contracts {} end |
#report_error_for_output_artifact(artifact_name, error) ⇒ Object
Report an error on an output artifact. This method can be used at anytime while prompting, when the agent is unable to produce an output artifact because of an error that should be communicated back to the agent. Make sure previous versions of this output artifact are removed to not store wrong versions by mistake.
160 161 162 163 164 165 166 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 160 def report_error_for_output_artifact(artifact_name, error) @output_artifacts.delete(artifact_name) @output_artifacts_errors[artifact_name] = error # TODO: Make this as a warning message log_debug "[Artifact] - Should have received content for output artifact `#{artifact_name}` " \ "but the following error occurred: #{error}" end |
#run(user_instructions: nil, **input_artifacts) ⇒ Hash{Symbol => Object}
Execute the agent to generate some output artifacts based on some input artifacts.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 70 def run(user_instructions: nil, **input_artifacts) @input_artifacts = input_artifacts @output_artifacts = {} @output_artifacts_errors = {} @system_prompt = render_system_prompt(render_instructions(@system_instructions)) log_debug "System prompt: #{@system_prompt}" converse(user_instructions, input_artifacts: @input_artifacts, author: 'User') if respond_to?(:normalized_output_artifacts_contracts, true) # We know which output artifacts we are expecting. # Therefore check if some are missing and prompt again if that's the case. # TODO: Implement a max number of retries and throw an exception if it exceeds. loop do missing_artifacts = normalized_output_artifacts_contracts .reject { |artifact_name, _artifact_description| @output_artifacts.key?(artifact_name) } .to_h do |artifact_name, artifact_description| [ artifact_name, artifact_description.merge(@output_artifacts_errors[artifact_name] ? { error: @output_artifacts_errors[artifact_name] } : {}) ] end break if missing_artifacts.empty? converse(missing_output_user_instructions(missing_artifacts)) end end @output_artifacts end |
#save_output_artifact(artifact_name, content) ⇒ Object
Save an output artifact. This method can be used at anytime while prompting, when the agent is able to produce an output artifact.
147 148 149 150 151 |
# File 'lib/composable_agents/prompt_driven_agent.rb', line 147 def save_output_artifact(artifact_name, content) @output_artifacts[artifact_name] = content @output_artifacts_errors.delete(artifact_name) log_debug "[Artifact] - Received output artifact #{artifact_name}" end |