Class: Phronomy::Agent::Runner

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

Overview

Orchestrates a multi-agent conversation by routing between agents based on handoff tool calls detected in each agent's conversation history.

Runner configures handoff tools on source agent instances at construction time, then coordinates invocations: after each agent turn it inspects the returned messages for a handoff sentinel and routes accordingly.

Examples:

Linear handoff (triage → billing)

triage  = TriageAgent.new
billing = BillingAgent.new
runner  = Phronomy::Agent::Runner.new(
  agents: [triage, billing],
  routes: { triage => [billing] }
)
result = runner.invoke("I need help with my invoice")
puts result[:output]
puts result[:agent].class  # => BillingAgent

Constant Summary collapse

MAX_HANDOFFS =

Maximum number of agent handoffs allowed per invoke call.

20

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(agents:, routes: {}) ⇒ Runner

Returns a new instance of Runner.

Parameters:

  • agents (Array<Phronomy::Agent::Base>)

    agents managed by this runner; first element is the entry agent

  • routes (Hash{Phronomy::Agent::Base => Array<Phronomy::Agent::Base>}) (defaults to: {})

    declares which target agents each source agent may hand off to; when omitted no handoffs are configured and the entry agent handles everything

Raises:

  • (ArgumentError)


33
34
35
36
37
38
39
40
# File 'lib/phronomy/agent/runner.rb', line 33

def initialize(agents:, routes: {})
  @agents = Array(agents)
  raise ArgumentError, "At least one agent is required" if @agents.empty?

  @entry_agent = @agents.first
  @sentinel_map = {}
  build_handoffs(routes)
end

Instance Attribute Details

#agentsObject (readonly)

Returns the value of attribute agents.



26
27
28
# File 'lib/phronomy/agent/runner.rb', line 26

def agents
  @agents
end

Instance Method Details

#invoke(input, config: {}) ⇒ Hash

Invokes the runner with the given input, routing between agents as needed. Stops when an agent's turn produces no handoff signal, or when MAX_HANDOFFS is reached (raises HandoffError in that case).

Parameters:

  • input (String, Hash)

    the initial user message

  • config (Hash) (defaults to: {})

    forwarded to each agent's #invoke

Returns:

  • (Hash)

    { output:, messages:, usage:, agent: }

Raises:



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/phronomy/agent/runner.rb', line 50

def invoke(input, config: {})
  current = @entry_agent
  handoffs_taken = 0

  loop do
    result = current.invoke(input, config: config)
    target = find_handoff_target(result[:messages])
    return result.merge(agent: current) unless target

    if handoffs_taken >= MAX_HANDOFFS
      raise Phronomy::HandoffError, "Exceeded maximum handoffs (#{MAX_HANDOFFS})"
    end

    current = target
    handoffs_taken += 1
  end
end