bruteSourceBruteSubAgent

class SubAgent

A SubAgent is an Agent that exposes a tool-shaped facade so it can be dropped into another agent's tools list. The parent agent's LLMCall passes it to ruby_llm as a regular tool; when invoked, the SubAgent runs its own pipeline against a fresh Session built from the tool arguments, then returns the final assistant message as the tool result.

Usage:

researcher = Brute::SubAgent.new( name: "research", description: "Delegate a research task to a read-only sub-agent.", provider: Brute.provider, model: Brute.provider.default_model, tools: [Brute::Tools::FSRead, Brute::Tools::FSSearch], ) do use Brute::Middleware::SystemPrompt use Brute::Middleware::MaxIterations, max_iterations: 10 use Brute::Middleware::ToolCall run Brute::Middleware::LLMCall.new end

main_agent = Brute::Agent.new( provider: ..., tools: [Brute::Tools::FSRead, researcher], # SubAgent IS a tool ) ...

Definitions

def execute(arguments)

Tool-shaped entry point. Builds a session from arguments, runs the agent loop, returns the last assistant message as a string.

Implementation

def execute(arguments)
  session = build_session(arguments)
  call(session)
  extract_result(session)
end

def to_ruby_llm

Adapter so the parent agent's LLMCall (and ruby_llm) sees this as a regular tool. ToolCall middleware should call to_ruby_llm when building the tools hash if a tool responds to it.

Implementation

def to_ruby_llm
  sub = self
  Class.new(RubyLLM::Tool) do
    description sub.description
    sub.params.each { |k, opts| param k, **opts }
    define_method(:name) { sub.sub_agent_name }
    define_method(:execute) { |**args| sub.execute(args) }
  end.new
end

def name

Lets ToolCall treat SubAgents the same as RubyLLM::Tool instances without checking respond_to? everywhere.

Implementation

def name
  @sub_agent_name
end