Skip to main content

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:

ResourceApproach
LLMShared reference
ToolsShared reference
Page content providerShared reference
Tabs getterShared reference
State/MessagesNew 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 CaseExample
Parallel lookupsCompare prices across multiple sites
Context isolationCheck a page without polluting main context
Task decompositionBreak complex task into independent subtasks
Background operationsFetch 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