Class: Brute::Tools::SubAgent
- Inherits:
-
Brute::Turn::AgentPipeline
- Object
- Rack::Builder
- Brute::Turn::Pipeline
- Brute::Turn::AgentPipeline
- Brute::Tools::SubAgent
- Defined in:
- lib/brute/tools/sub_agent.rb
Overview
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 hands it to the 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::Tools::SubAgent.new(
name: "research",
description: "Delegate a research task to a read-only sub-agent.",
) do
use Brute::Middleware::SystemPrompt
use Brute::Middleware::Loop::ToolResult
use Brute::Middleware::MaxIterations, max_iterations: 10
use Brute::Middleware::ToolPipeline, tools: [Brute::Tools::FSRead, Brute::Tools::FSSearch]
run ->(env) do
ctx = RubyLLM.context { |c| c.ollama_api_base = ENV["OLLAMA_API_BASE"] }
model, provider = RubyLLM::Models.resolve(
"llama3.2", provider: :ollama, assume_exists: true, config: ctx.config)
response = provider.complete(env[:messages],
tools: Brute.rubyllm_tools(env[:tools]),
temperature: 0.7,
model: model)
RubyLLM::MessageTransport.new(response).wrap_each { |m| env[:messages] << m }
end
end
# The SubAgent IS a tool — hand it to a parent agent's ToolPipeline:
main_agent = Brute.agent do
use Brute::Middleware::ToolPipeline, tools: [Brute::Tools::FSRead, researcher]
run ->(env) { ... }
end
main_agent.start("delegate some research")
Constant Summary collapse
- DEFAULT_PARAMS =
{ task: { type: "string", desc: "A clear, detailed description of the task", required: true }, }.freeze
Instance Attribute Summary collapse
-
#description ⇒ Object
readonly
Returns the value of attribute description.
-
#params ⇒ Object
readonly
Returns the value of attribute params.
-
#sub_agent_name ⇒ Object
readonly
Returns the value of attribute sub_agent_name.
Instance Method Summary collapse
-
#execute(arguments) ⇒ Object
Tool-shaped entry point.
-
#initialize(name:, description:, params: DEFAULT_PARAMS, &block) ⇒ SubAgent
constructor
A new instance of SubAgent.
-
#name ⇒ Object
Lets ToolPipeline treat SubAgents the same as RubyLLM::Tool instances without checking respond_to? everywhere.
-
#to_ruby_llm ⇒ Object
Adapter so the parent agent's completion middleware (and ruby_llm) sees this as a regular tool.
Methods inherited from Brute::Turn::AgentPipeline
Methods inherited from Brute::Turn::Pipeline
Methods included from Brute::Turn::Pipeline::Chainable
Constructor Details
#initialize(name:, description:, params: DEFAULT_PARAMS, &block) ⇒ SubAgent
Returns a new instance of SubAgent.
51 52 53 54 55 56 |
# File 'lib/brute/tools/sub_agent.rb', line 51 def initialize(name:, description:, params: DEFAULT_PARAMS, &block) @sub_agent_name = name.to_s @description = description @params = params super(&block) end |
Instance Attribute Details
#description ⇒ Object (readonly)
Returns the value of attribute description.
49 50 51 |
# File 'lib/brute/tools/sub_agent.rb', line 49 def description @description end |
#params ⇒ Object (readonly)
Returns the value of attribute params.
49 50 51 |
# File 'lib/brute/tools/sub_agent.rb', line 49 def params @params end |
#sub_agent_name ⇒ Object (readonly)
Returns the value of attribute sub_agent_name.
49 50 51 |
# File 'lib/brute/tools/sub_agent.rb', line 49 def sub_agent_name @sub_agent_name end |
Instance Method Details
#execute(arguments) ⇒ Object
Tool-shaped entry point. Builds a session from arguments, runs the agent loop, returns the last assistant message as a string.
60 61 62 63 64 |
# File 'lib/brute/tools/sub_agent.rb', line 60 def execute(arguments) session = build_session(arguments) start(session) extract_result(session) end |
#name ⇒ Object
Lets ToolPipeline treat SubAgents the same as RubyLLM::Tool instances without checking respond_to? everywhere.
81 82 83 |
# File 'lib/brute/tools/sub_agent.rb', line 81 def name @sub_agent_name end |
#to_ruby_llm ⇒ Object
Adapter so the parent agent's completion middleware (and ruby_llm)
sees this as a regular tool. ToolPipeline middleware should call
to_ruby_llm when building the tools hash if a tool responds to it.
69 70 71 72 73 74 75 76 77 |
# File 'lib/brute/tools/sub_agent.rb', line 69 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 |