Class: Phronomy::Agent::FSM
- Inherits:
-
Object
- Object
- Phronomy::Agent::FSM
- Defined in:
- lib/phronomy/agent/fsm.rb
Overview
EventLoop-registered execution unit for a single agent invocation.
+AgentFSM+ implements the minimal interface expected by EventLoop (+#id+, +#start+, +#handle+) so it can be managed alongside FSMSession instances. It is not a traditional finite-state machine; the name reflects its role in the EventLoop rather than internal state transitions.
== Execution model
#start is called by the EventLoop on the +:start+ event. It immediately returns after spawning a background IO thread that runs the agent's full invocation pipeline (via +_invoke_impl+). The EventLoop thread is never blocked by agent execution.
Inside the IO thread, the +:phronomy_agent_parallel_tools+ thread-local flag is set to +true+ so that Base#build_chat returns a ParallelToolChat instance, enabling concurrent tool dispatch when the LLM returns multiple tool calls in one response.
== Completion events
On success:
- Posts +:finished+ to this FSM's own +#id+ so the EventLoop cleans up its registry entry and unblocks any +completion_queue.pop+ caller.
- When +parent_id+ is set (child-FSM pattern), additionally posts +:child_completed+ to +parent_id+, carrying the result hash as the event payload. The parent FSMSession must declare an +on:+ transition for +:child_completed+ to advance correctly.
On error:
- Posts +:error+ to this FSM's own +#id+. The EventLoop propagates the exception through the +completion_queue+ so that the original caller of +Agent::Base#invoke+ (in EventLoop mode) receives and re-raises it.
== Standalone usage (blocking caller)
Phronomy.configure { |c| c.event_loop = true } result = MyAgent.new.invoke("Hello!") # => { output:, messages:, usage: }
Base#invoke detects EventLoop mode, creates an +AgentFSM+, registers it via EventLoop#register, and blocks the calling thread on the returned +completion_queue+ until the agent finishes.
== Child-FSM usage (non-blocking, inside a Workflow)
state :run_agent entry :run_agent, ->(ctx) { MyAgent.new.run_as_child(ctx.query, ctx: ctx) } transition from: :run_agent, on: :child_completed, to: :process_result
Base#run_as_child creates an +AgentFSM+ with +parent_id+ set to +ctx.thread_id+, registers it with the EventLoop, and returns immediately. The parent FSMSession waits for the +:child_completed+ event.
Instance Attribute Summary collapse
-
#current_phase ⇒ Symbol
readonly
Current internal phase (:idle, :running).
-
#id ⇒ String
readonly
Unique identifier used as the EventLoop target_id.
Instance Method Summary collapse
-
#handle(_event) ⇒ Object
Called by EventLoop for external events dispatched to this id.
-
#initialize(agent:, input:, messages: [], thread_id: nil, config: {}, parent_id: nil, result_writer: nil) ⇒ FSM
constructor
A new instance of FSM.
-
#start ⇒ Object
Called by EventLoop on the +:start+ event.
Constructor Details
#initialize(agent:, input:, messages: [], thread_id: nil, config: {}, parent_id: nil, result_writer: nil) ⇒ FSM
Returns a new instance of FSM.
90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/phronomy/agent/fsm.rb', line 90 def initialize(agent:, input:, messages: [], thread_id: nil, config: {}, parent_id: nil, result_writer: nil) @agent = agent @input = input @messages = Array().dup @thread_id = thread_id || SecureRandom.uuid @config = config @parent_id = parent_id @result_writer = result_writer @id = @thread_id @current_phase = :idle end |
Instance Attribute Details
#current_phase ⇒ Symbol (readonly)
Returns current internal phase (:idle, :running).
65 66 67 |
# File 'lib/phronomy/agent/fsm.rb', line 65 def current_phase @current_phase end |
#id ⇒ String (readonly)
Returns unique identifier used as the EventLoop target_id.
62 63 64 |
# File 'lib/phronomy/agent/fsm.rb', line 62 def id @id end |
Instance Method Details
#handle(_event) ⇒ Object
112 113 114 |
# File 'lib/phronomy/agent/fsm.rb', line 112 def handle(_event) # No-op: AgentFSM is driven entirely by its IO thread. end |
#start ⇒ Object
Called by EventLoop on the +:start+ event. Transitions to +:running+ and spawns the agent IO thread.
104 105 106 107 |
# File 'lib/phronomy/agent/fsm.rb', line 104 def start @current_phase = :running spawn_agent_thread end |