SubAgent Architecture
Overview
SubAgentTool enables the main agent to spawn child agents for parallel or isolated task execution. The architecture follows an inheritance pattern where subagents reuse parent's resources while maintaining isolated context.
Architecture Diagram
┌─────────────────────────────────────────────────────────────────────────────┐
│ MAIN AGENT │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ReactAgent (main) │ │
│ │ │ │
│ │ Constructor: │ │
│ │ ┌────────────────────────────────────────────────────────────────┐ │ │
│ │ │ this.llm = llm │ │ │
│ │ │ this.langchainTools = [ │ │ │
│ │ │ NavigateToURLTool, │ │ │
│ │ │ ClickByIndexTool, │ │ │
│ │ │ FillByIndexTool, │ │ │
│ │ │ SubAgentTool, <-- receives parent config │ │ │
│ │ │ ...other tools │ │ │
│ │ │ ] │ │ │
│ │ │ this.getPageContentTool = getPageContentTool │ │ │
│ │ │ this.getTabs = getTabs │ │ │
│ │ │ this.modelName = modelName │ │ │
│ │ └────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ // Pass config to SubAgentTool via inherit() │ │
│ │ for (tool of langchainTools) { │ │
│ │ if (tool.inherit) { │ │
│ │ tool.inherit({ llm, langchainTools, options, modelName }); │ │
│ │ } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────── ──────────────────────────────┘
│
│ LLM calls subagent tool
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SubAgentTool.call() │
│ │
│ Input: { systemPrompt: "Find the price on the current page" } │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ const { llm, langchainTools, options, modelName } = this.parentConfig; │
│ │ │ │
│ │ // Create NEW ReactAgent with SAME config │ │
│ │ const subAgent = new ReactAgent({ │ │
│ │ llm, // REUSE parent's LLM │ │
│ │ langchainTools, // REUSE parent's tools │ │
│ │ options: { │ │
│ │ getPageContentTool, // REUSE parent's page provider │ │
│ │ getTabs, // REUSE parent's tabs getter │ │
│ │ ...options │ │
│ │ } │ │
│ │ }); │ │
│ │ │ │
│ │ const result = await subAgent.run(systemPrompt); │ │
│ │ return { result: result.output, success: result.completed }; │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SUBAGENT (child) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ReactAgent (subagent) │ │
│ │ │ │
│ │ SHARED (reference): ISOLATED (new instance): │ │
│ │ ├── llm ├── state │ │
│ │ ├── langchainTools ├── messages │ │
│ │ ├── getPageContentTool ├── workflow │ │
│ │ └── getTabs └── iterations │ │
│ │ │ │
│ │ Runs own ReAct loop: │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ ASSISTANT│───>│ TOOLS │───>│REFLECTION│ │ │
│ │ └────▲─────┘ └──────────┘ └────┬─────┘ │ │
│ │ └───────────────────────────────┘ │ │
│ │ │ │
│ │ SUBAGENT DECIDES autonomously: │ │
│ │ - Need new tab? -> Call create_new_tab tool │ │
│ │ - Need to navigate? -> Call navigate_to_url tool │ │
│ │ - Done? -> Return result │ │
│ └──────────────────────────────────────────── ─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Result: { result: "Price is $29.99", success: true, iterations: 3 } │
└─────────────────────────────────────────────────────────────────────────────┘
Key Design Principles
1. Inheritance over Creation
Subagent reuses parent's resources instead of creating new ones:
| Resource | Approach |
|---|---|
| LLM | Shared reference |
| Tools | Shared reference |
| Page content provider | Shared reference |
| Tabs getter | Shared reference |
| State/Messages | New instance (isolated) |
2. Subagent Autonomy
The subagent decides by itself what it needs:
- If it needs a new tab, it calls
create_new_tab - If it needs to navigate, it calls
navigate_to_url - Parent does NOT pre-create tabs or wrap tools
3. Context Isolation
While resources are shared, each subagent has:
- Own message history (no cross-task pollution)
- Own state and iterations
- Own ReAct workflow instance
Implementation
Tool Wrapper Chain
Tools are wrapped before reaching ReactAgent:
BrowserTool (SubAgentTool)
↓ addReasoningToTools()
ReasoningBrowserTool (wrapper with reasoning field)
↓ toLangChainTool()
LangChain Tool (with _browserTool reference)
Critical: ReasoningBrowserTool must forward inherit() to the original tool:
// CommonTools.js - ReasoningBrowserTool
inherit(config) {
if (this.originalTool?.inherit && typeof this.originalTool.inherit === 'function') {
this.originalTool.inherit(config);
}
}
ReactGraph.ts - Passing Config
// In ReactAgent constructor
for (const tool of this.langchainTools) {
const browserTool = (tool as any)._browserTool;
if (browserTool?.inherit && typeof browserTool.inherit === 'function') {
browserTool.inherit({
llm: this.llm,
langchainTools: this.langchainTools,
options,
modelName: this.modelName
});
}
}
SubAgentTool.js - Receiving and Using Config
class SubAgentTool extends BrowserTool {
parentConfig = null;
inherit(config) {
this.parentConfig = config;
}
async call({ systemPrompt }) {
const { llm, langchainTools, options, modelName } = this.parentConfig;
const subAgent = new ReactAgent({
llm,
langchainTools,
options: {
...options,
onEvent: (type) => console.log(`[SubAgent] ${type}`)
},
mode: 'agent'
});
const result = await subAgent.run(systemPrompt, { maxIterations: 15 });
return { result: result.output, success: result.completed };
}
}
Usage Examples
Single Subagent
// LLM calls subagent tool
{
"name": "subagent",
"args": {
"systemPrompt": "Find the price of the first product on this page"
}
}
Parallel Subagents
// Use multi_tool_use.parallel for concurrent execution
{
"name": "parallel",
"args": {
"tool_uses": [
{ "name": "subagent", "args": { "systemPrompt": "Get price from site A" } },
{ "name": "subagent", "args": { "systemPrompt": "Get price from site B" } }
]
}
}
When to Use Subagents
| Use Case | Example |
|---|---|
| Parallel lookups | Compare prices across multiple sites |
| Context isolation | Check a page without polluting main context |
| Task decomposition | Break complex task into independent subtasks |
| Background operations | Fetch data while continuing main task |
Constraints
- Max iterations per subagent: 15
- Subagent cannot use
switch_tab(blocked for safety) - Doom loop prevention: Enhanced prompt tells subagent to complete task itself