Class: Phronomy::Agent::InvocationSession Private

Inherits:
Object
  • Object
show all
Defined in:
lib/phronomy/agent/invocation_session.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Factory that builds a Phronomy::FSMSession configured for a single Agent#invoke execution.

This is the Agent counterpart to WorkflowRunner — it assembles the FSMSession with the correct phase machine class, entry actions, and context, then hands it to EventLoop for execution.

Usage

session = Agent::InvocationSession.build(
agent:    my_agent,
input:    "What is Ruby?",
messages: [],
config:   { thread_id: "t-1" }
)
completion_queue = Phronomy::EventLoop.instance.register(session)
ctx = completion_queue.pop

Streaming mode

Pass mode: :stream and an on_event: block to receive token/tool events. The state graph is identical; only the :calling_llm entry action differs.

Constant Summary collapse

AUTO_STATE_SET =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

States that have an automatic transition after their action completes.

{
  idle: true,
  filtering_input: true,
  building_context: true,
  calling_llm: true,
  executing_tool: true,
  output_filtering: true
}.freeze
DECLARED_STATES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

All declared action states (terminals excluded).

%i[
  idle filtering_input building_context calling_llm
  executing_tool awaiting_approval output_filtering
  completed blocked
].freeze

Class Method Summary collapse

Class Method Details

.build(agent:, input:, messages:, config:, mode: :invoke, on_event: nil) ⇒ Phronomy::FSMSession

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Builds a Phronomy::FSMSession for the given agent invocation.

Parameters:

  • agent (Phronomy::Agent::Base)
  • input (String, Hash)
  • messages (Array)
  • config (Hash)
  • mode (:invoke, :stream) (defaults to: :invoke)
  • on_event (Proc, nil) (defaults to: nil)

    stream event callback (stream mode only)

Returns:



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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/phronomy/agent/invocation_session.rb', line 59

def self.build(agent:, input:, messages:, config:, mode: :invoke, on_event: nil)
  ctx = Agent::InvocationContext.new(
    agent: agent,
    input: input,
    messages: messages,
    config: config
  )

  actions = (mode == :stream && on_event) ?
    build_stream_entry_actions(agent, on_event) :
    build_entry_actions(agent)

  # Calculate recursion_limit for the FSM:
  # Base states: idle→filtering_input→building_context→calling_llm→
  #              output_filtering→completed = 6 transitions
  # Each tool call loop: calling_llm→executing_tool→calling_llm = 2 transitions
  # Safety margin: +4
  iterations = agent.class.max_iterations || 10
  fsm_recursion_limit = 6 + (iterations * 2) + 4

  # Entry actions are registered as after_transition callbacks in the
  # phase machine class. Pass empty hash to FSMSession (it uses @entry_actions
  # only for the entry_point state, which has no action for :idle).
  phase_machine = Agent::PhaseMachineBuilder.new(entry_actions: actions).build
  session_id = config[:thread_id] || SecureRandom.uuid

  Phronomy::FSMSession.new(
    id: session_id,
    context: ctx,
    entry_point: :idle,
    phase_machine_class: phase_machine,
    entry_actions: {},
    auto_state_set: AUTO_STATE_SET,
    declared_states: DECLARED_STATES,
    wait_state_names: %i[awaiting_approval],
    external_events: {
      approve: [{from: :awaiting_approval, to: :executing_tool, guard: nil}],
      reject: [{from: :awaiting_approval, to: :blocked, guard: nil}]
    },
    recursion_limit: fsm_recursion_limit
  )
end

.build_for_resume(agent:, context:, resume_event:, resume_phase:) ⇒ Phronomy::FSMSession

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Builds a FSMSession that resumes an existing InvocationContext from a wait state (e.g. :awaiting_approval) using an external event.

Parameters:

Returns:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/phronomy/agent/invocation_session.rb', line 111

def self.build_for_resume(agent:, context:, resume_event:, resume_phase:)
  actions = build_entry_actions(agent)
  phase_machine = Agent::PhaseMachineBuilder.new(entry_actions: actions).build

  iterations = agent.class.max_iterations || 10
  fsm_recursion_limit = 6 + (iterations * 2) + 4

  Phronomy::FSMSession.new(
    id: context.session_id || SecureRandom.uuid,
    context: context,
    entry_point: :idle,
    phase_machine_class: phase_machine,
    entry_actions: {},
    auto_state_set: AUTO_STATE_SET,
    declared_states: DECLARED_STATES,
    wait_state_names: %i[awaiting_approval],
    external_events: {
      approve: [{from: :awaiting_approval, to: :executing_tool, guard: nil}],
      reject: [{from: :awaiting_approval, to: :blocked, guard: nil}]
    },
    recursion_limit: fsm_recursion_limit,
    resume_event: resume_event,
    resume_phase: resume_phase
  )
end