Class: Phronomy::Agent::ToolInvocation
- Inherits:
-
Object
- Object
- Phronomy::Agent::ToolInvocation
- Defined in:
- lib/phronomy/agent/tool_invocation.rb
Defined Under Namespace
Classes: AuthorizationOutcome, ExecutionOutcome
Constant Summary collapse
- PREFLIGHT_SETTLED_STATES =
%i[ authorized awaiting_approval rejected failed cancelled completed ].freeze
- TERMINAL_STATES =
%i[completed rejected failed cancelled].freeze
Instance Attribute Summary collapse
-
#agent ⇒ Object
readonly
Returns the value of attribute agent.
-
#approval_context ⇒ Object
readonly
Returns the value of attribute approval_context.
-
#approval_policy ⇒ Object
readonly
Returns the value of attribute approval_policy.
-
#arguments ⇒ Object
readonly
Returns the value of attribute arguments.
-
#authorization_reason ⇒ Object
readonly
Returns the value of attribute authorization_reason.
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#error ⇒ Object
readonly
Returns the value of attribute error.
-
#facts ⇒ Object
readonly
Returns the value of attribute facts.
-
#final_decision ⇒ Object
readonly
Returns the value of attribute final_decision.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#metadata ⇒ Object
readonly
Returns the value of attribute metadata.
-
#origin ⇒ Object
readonly
Returns the value of attribute origin.
-
#parent_agent_invocation_id ⇒ Object
readonly
Returns the value of attribute parent_agent_invocation_id.
-
#phase ⇒ Object
readonly
Returns the value of attribute phase.
-
#raw_arguments ⇒ Object
readonly
Returns the value of attribute raw_arguments.
-
#result ⇒ Object
readonly
Returns the value of attribute result.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
-
#tool ⇒ Object
readonly
Returns the value of attribute tool.
-
#tool_call_id ⇒ Object
readonly
Returns the value of attribute tool_call_id.
-
#tool_name ⇒ Object
readonly
Returns the value of attribute tool_name.
Class Method Summary collapse
Instance Method Summary collapse
- #authorized? ⇒ Boolean
- #awaiting_approval? ⇒ Boolean
- #cancelled? ⇒ Boolean
- #dispatchable? ⇒ Boolean
- #display_arguments ⇒ Object
- #display_facts ⇒ Object
- #execution_completed? ⇒ Boolean
- #failed? ⇒ Boolean
- #handle_fsm_event(event) ⇒ Object
-
#initialize(parent_agent_invocation_id:, agent:, tool:, tool_call:, config:, approval_policy: nil, approval_context: {}, id: SecureRandom.uuid) ⇒ ToolInvocation
constructor
A new instance of ToolInvocation.
- #mark_authorized! ⇒ Object
- #mark_awaiting_approval! ⇒ Object
- #mark_cancelled! ⇒ Object
- #mark_framework_failed!(error) ⇒ Object
- #mark_queued! ⇒ Object
- #mark_rejected! ⇒ Object
- #mark_running! ⇒ Object
- #preflight_settled? ⇒ Boolean
- #rejected? ⇒ Boolean
- #set_graph_metadata(thread_id: nil, phase: nil) ⇒ Object
-
#start_authorization(runtime: Phronomy::Runtime.instance, &callback) ⇒ Object
Starts authorization and reports exactly one AuthorizationOutcome through the callback.
-
#start_execution(runtime: Phronomy::Runtime.instance, &callback) ⇒ Object
Starts Tool execution and reports completion through the callback.
- #terminal? ⇒ Boolean
- #tool_schema ⇒ Object
- #validate! ⇒ Object
- #validation_completed? ⇒ Boolean
- #validation_passed? ⇒ Boolean
Constructor Details
#initialize(parent_agent_invocation_id:, agent:, tool:, tool_call:, config:, approval_policy: nil, approval_context: {}, id: SecureRandom.uuid) ⇒ ToolInvocation
Returns a new instance of ToolInvocation.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 48 def initialize( parent_agent_invocation_id:, agent:, tool:, tool_call:, config:, approval_policy: nil, approval_context: {}, id: SecureRandom.uuid ) @id = id.to_s @parent_agent_invocation_id = parent_agent_invocation_id.to_s @agent = agent @tool = tool @tool_name = tool_call.name.to_s @tool_call_id = tool_call.respond_to?(:id) ? tool_call.id : nil raw_arguments = tool_call.respond_to?(:arguments) ? (tool_call.arguments || {}) : {} @raw_arguments = immutable_copy(raw_arguments) @config = config @approval_policy = approval_policy @approval_context = immutable_copy(approval_context || {}) @origin = tool&.respond_to?(:tool_origin) ? tool.tool_origin.to_sym : :local @metadata = immutable_copy( tool&.respond_to?(:approval_metadata) ? tool. : {} ) @arguments = nil @facts = {}.freeze @final_decision = nil @authorization_reason = nil @result = nil @error = nil @approval_consumed = false @status = :created @session_id = nil @phase = nil end |
Instance Attribute Details
#agent ⇒ Object (readonly)
Returns the value of attribute agent.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def agent @agent end |
#approval_context ⇒ Object (readonly)
Returns the value of attribute approval_context.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def approval_context @approval_context end |
#approval_policy ⇒ Object (readonly)
Returns the value of attribute approval_policy.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def approval_policy @approval_policy end |
#arguments ⇒ Object (readonly)
Returns the value of attribute arguments.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def arguments @arguments end |
#authorization_reason ⇒ Object (readonly)
Returns the value of attribute authorization_reason.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def @authorization_reason end |
#config ⇒ Object (readonly)
Returns the value of attribute config.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def config @config end |
#error ⇒ Object (readonly)
Returns the value of attribute error.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def error @error end |
#facts ⇒ Object (readonly)
Returns the value of attribute facts.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def facts @facts end |
#final_decision ⇒ Object (readonly)
Returns the value of attribute final_decision.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def final_decision @final_decision end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def id @id end |
#metadata ⇒ Object (readonly)
Returns the value of attribute metadata.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def @metadata end |
#origin ⇒ Object (readonly)
Returns the value of attribute origin.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def origin @origin end |
#parent_agent_invocation_id ⇒ Object (readonly)
Returns the value of attribute parent_agent_invocation_id.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def parent_agent_invocation_id @parent_agent_invocation_id end |
#phase ⇒ Object (readonly)
Returns the value of attribute phase.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def phase @phase end |
#raw_arguments ⇒ Object (readonly)
Returns the value of attribute raw_arguments.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def raw_arguments @raw_arguments end |
#result ⇒ Object (readonly)
Returns the value of attribute result.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def result @result end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def session_id @session_id end |
#status ⇒ Object (readonly)
Returns the value of attribute status.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def status @status end |
#tool ⇒ Object (readonly)
Returns the value of attribute tool.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def tool @tool end |
#tool_call_id ⇒ Object (readonly)
Returns the value of attribute tool_call_id.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def tool_call_id @tool_call_id end |
#tool_name ⇒ Object (readonly)
Returns the value of attribute tool_name.
16 17 18 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 16 def tool_name @tool_name end |
Class Method Details
.missing(parent_agent_invocation_id:, agent:, tool_call:, config: {}) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 38 def self.missing(parent_agent_invocation_id:, agent:, tool_call:, config: {}) new( parent_agent_invocation_id: parent_agent_invocation_id, agent: agent, tool: nil, tool_call: tool_call, config: config ).tap { |invocation| invocation.send(:complete_missing_tool!) } end |
Instance Method Details
#authorized? ⇒ Boolean
246 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 246 def = @status == :authorized |
#awaiting_approval? ⇒ Boolean
245 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 245 def awaiting_approval? = @status == :awaiting_approval |
#cancelled? ⇒ Boolean
243 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 243 def cancelled? = @status == :cancelled |
#dispatchable? ⇒ Boolean
251 252 253 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 251 def dispatchable? @status == :queued && (@final_decision == :allow || @approval_consumed) end |
#display_arguments ⇒ Object
259 260 261 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 259 def display_arguments redact_for_display(@arguments || @raw_arguments) end |
#display_facts ⇒ Object
263 264 265 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 263 def display_facts redact_value(@facts, sensitive_argument_values) end |
#execution_completed? ⇒ Boolean
247 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 247 def execution_completed? = @status == :completed |
#failed? ⇒ Boolean
242 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 242 def failed? = @status == :failed |
#handle_fsm_event(event) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 90 def handle_fsm_event(event) case event.type when :authorization_completed outcome = event.payload outcome = AuthorizationOutcome.new(error: outcome) if outcome.is_a?(Exception) (outcome) true when :execution_completed outcome = event.payload if outcome.is_a?(Exception) outcome = ExecutionOutcome.new( error: outcome, cancelled: outcome.is_a?(Phronomy::CancellationError) ) end apply_execution_outcome(outcome) true else false end end |
#mark_authorized! ⇒ Object
217 218 219 220 221 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 217 def @approval_consumed = true if @status == :awaiting_approval @status = :authorized self end |
#mark_awaiting_approval! ⇒ Object
214 215 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 214 def mark_awaiting_approval! = (@status = :awaiting_approval self) |
#mark_cancelled! ⇒ Object
233 234 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 233 def mark_cancelled! = (@status = :cancelled self) |
#mark_framework_failed!(error) ⇒ Object
236 237 238 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 236 def mark_framework_failed!(error) = (@error = error @status = :failed self) |
#mark_queued! ⇒ Object
223 224 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 223 def mark_queued! = (@status = :queued self) |
#mark_rejected! ⇒ Object
229 230 231 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 229 def mark_rejected! = (@final_decision = :reject @status = :rejected self) |
#mark_running! ⇒ Object
226 227 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 226 def mark_running! = (@status = :running self) |
#preflight_settled? ⇒ Boolean
248 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 248 def preflight_settled? = PREFLIGHT_SETTLED_STATES.include?(@status) |
#rejected? ⇒ Boolean
244 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 244 def rejected? = @status == :rejected |
#set_graph_metadata(thread_id: nil, phase: nil) ⇒ Object
85 86 87 88 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 85 def (thread_id: nil, phase: nil) @session_id = thread_id if thread_id @phase = phase end |
#start_authorization(runtime: Phronomy::Runtime.instance, &callback) ⇒ Object
Starts authorization and reports exactly one AuthorizationOutcome through the callback. No Task is created.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 145 def (runtime: Phronomy::Runtime.instance, &callback) raise ArgumentError, "start_authorization requires a callback" unless callback pool = runtime.pool( :authorization, size: Phronomy.configuration., queue_size: Phronomy.configuration. ) timeout = @config.fetch( :authorization_timeout, Phronomy.configuration. ) operation = pool.submit( timeout: timeout, cancellation_token: @config[:cancellation_token], on_full: :raise ) { } operation.on_complete do |outcome, error| callback.call(error ? (error) : outcome) end self rescue => error callback.call((error)) self end |
#start_execution(runtime: Phronomy::Runtime.instance, &callback) ⇒ Object
Starts Tool execution and reports completion through the callback.
Both core execution paths use Tool#call_async:
- :cooperative returns a Task without consuming an OffloadPool worker. Ordinary cooperative Tools settle that Task inline; Agent-backed Tools may start child EventLoop/FSM work and settle later.
- :offloaded returns an OffloadPool PendingOperation for synchronous work that must not occupy the EventLoop.
In either case ToolInvocation remains in :running and resumes only from the explicit :execution_completed FSM event posted by the session builder.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 183 def start_execution(runtime: Phronomy::Runtime.instance, &callback) raise ArgumentError, "start_execution requires a callback" unless callback unless dispatchable? callback.call(ExecutionOutcome.new(error: Phronomy::ToolError.new( "ToolInvocation #{@id} is not authorized for dispatch" ))) return self end case @tool.class.execution_mode when :cooperative, :offloaded operation = start_async_tool_operation(runtime) unless operation.respond_to?(:on_complete) raise Phronomy::ToolError, "Tool #{@tool.class.name}#call_async must return a completion handle" end operation.on_complete do |result, error| callback.call(execution_outcome(result, error)) end else callback.call(ExecutionOutcome.new(error: Phronomy::ConfigurationError.new( "unknown Tool execution_mode: #{@tool.class.execution_mode.inspect}" ))) end self rescue => error callback.call(execution_outcome(nil, error)) self end |
#terminal? ⇒ Boolean
249 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 249 def terminal? = TERMINAL_STATES.include?(@status) |
#tool_schema ⇒ Object
255 256 257 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 255 def tool_schema @tool&.respond_to?(:params_schema) ? @tool.params_schema : {} end |
#validate! ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 112 def validate! return self if terminal? validated, schema_error = if @tool.respond_to?(:validate_and_coerce, true) @tool.send(:validate_and_coerce, @raw_arguments) else [@raw_arguments, nil] end if schema_error if @tool.class.respond_to?(:on_schema_error) && @tool.class.on_schema_error == :raise @error = Phronomy::ToolError.new( "#{@tool.class.name} schema error: #{schema_error}" ) @status = :failed else @result = "Schema validation failed: #{schema_error}" @status = :completed end return self end @arguments = immutable_copy(validated || {}) @status = :valid self rescue => error @error = error @status = :failed self end |
#validation_completed? ⇒ Boolean
241 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 241 def validation_completed? = @status == :completed |
#validation_passed? ⇒ Boolean
240 |
# File 'lib/phronomy/agent/tool_invocation.rb', line 240 def validation_passed? = @status == :valid |