Class: Phronomy::Agent::ReactAgent
- Defined in:
- lib/phronomy/agent/react_agent.rb
Overview
ReAct pattern (Reasoning + Acting) agent. Repeats the LLM <-> Tool loop until no more tool calls are made.
Instance Attribute Summary
Attributes included from Concerns::BeforeCompletion
Instance Method Summary collapse
-
#stream(input, messages: [], thread_id: nil, config: {}) {|Phronomy::Agent::StreamEvent| ... } ⇒ Hash
Streaming version of #invoke for the ReAct loop.
Methods inherited from Base
#_add_handoff_tool, #_handoff_tools, _on_compact_callback, _on_compaction_trigger_callback, _on_trim_callback, cache_instructions, context_overhead, #context_version_cache, context_window, instructions, #invoke, max_iterations, max_output_tokens, model, on_compact, on_compaction_trigger, on_trim, provider, #run_as_child, static_knowledge, static_knowledge_sources, temperature, tool_aliases, tools
Methods included from Concerns::Suspendable
#on_approval_required, #resume
Methods included from Concerns::BeforeCompletion
Methods included from Concerns::Guardrailable
#add_input_guardrail, #add_output_guardrail
Methods included from Concerns::Retryable
Methods included from Runnable
Instance Method Details
#stream(input, messages: [], thread_id: nil, config: {}) {|Phronomy::Agent::StreamEvent| ... } ⇒ Hash
Streaming version of #invoke for the ReAct loop. Yields StreamEvent events while the LLM-tool loop runs.
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 101 102 103 |
# File 'lib/phronomy/agent/react_agent.rb', line 63 def stream(input, messages: [], thread_id: nil, config: {}, &block) return invoke(input, messages: , thread_id: thread_id, config: config) unless block = {} [:user_id] = config[:user_id] if config[:user_id] [:session_id] = config[:session_id] if config[:session_id] trace("agent.invoke", input: input, **) do |_span| run_input_guardrails!(input) max_iter = self.class.max_iterations = Array().dup user_asked = false total_usage = Phronomy::TokenUsage.zero iterations_exhausted = true max_iter.times do response = stream_step(, input, user_asked: user_asked, thread_id: thread_id, config: config, &block) user_asked = true = response[:messages] total_usage += response[:usage] if response[:done] iterations_exhausted = false break end end # Fall back to the last message that carries non-nil content (same as # the non-streaming path above). output = .reverse.find { |m| m.content && !m.content.empty? }&.content run_output_guardrails!(output) result = {output: output, messages: , usage: total_usage, iterations_exhausted: iterations_exhausted} block.call(StreamEvent.new(type: :done, payload: result)) [result, total_usage] end rescue => e block&.call(StreamEvent.new(type: :error, payload: {error: e})) raise end |