Skip to content

Agent Delegation

Agent delegation is a powerful pattern that allows you to build hierarchical agent systems where coordinator agents delegate tasks to specialist agents. This is implemented using the ToolWrapper class, which wraps agents as tools.

Overview

The agent delegation pattern enables:

  • Hierarchical agent architectures: Coordinator agents manage multiple specialist agents
  • Domain expertise: Each specialist agent can focus on a specific domain with its own tools
  • Composability: Agents can be nested and combined in flexible ways
  • Modularity: Easy to add, remove, or replace specialist agents

Core Components

Agent

The Agent class combines an LLM broker, tools, and behavior into a cohesive unit:

typescript
import { Agent, LlmBroker, OllamaGateway, DateResolverTool } from 'mojentic';

const agent = new Agent(
  new LlmBroker('qwen3:32b', new OllamaGateway()),
  [new DateResolverTool()],
  'You are a helpful assistant that can resolve dates.'
);

const result = await agent.generate('What day is next Friday?');

ToolWrapper

The ToolWrapper class wraps an agent as a tool, making it callable by other agents:

typescript
import { ToolWrapper } from 'mojentic';

const wrappedAgent = new ToolWrapper(
  agent,
  'date_specialist',
  'A specialist in date and time queries.'
);

The wrapped agent becomes a tool with a single input parameter that accepts string instructions.

Basic Example

Here's a simple example of a coordinator using a specialist:

typescript
import {
  Agent,
  LlmBroker,
  OllamaGateway,
  ToolWrapper,
  DateResolverTool,
} from 'mojentic';

// Create a temporal specialist
const temporalSpecialist = new Agent(
  new LlmBroker('qwen3:7b', new OllamaGateway()),
  [new DateResolverTool()],
  'You are a temporal specialist with expertise in dates and time.'
);

// Create a coordinator that uses the specialist
const coordinator = new Agent(
  new LlmBroker('qwen3:32b', new OllamaGateway()),
  [
    new ToolWrapper(
      temporalSpecialist,
      'temporal_specialist',
      'Expert in date and time queries. Use for questions about dates, calendars, and temporal references.'
    ),
  ],
  `You are an intelligent coordinator that delegates tasks to specialist agents.
When users ask about dates or time, use the temporal_specialist tool.`
);

// Use the coordinator
const result = await coordinator.generate('What day of the week is next Friday?');

Advanced Example: Multiple Specialists

You can create coordinators with multiple specialists:

typescript
// Create specialists
const temporalSpecialist = new Agent(
  new LlmBroker('qwen3:7b', gateway),
  [new DateResolverTool(), new CurrentDatetimeTool()],
  'You are a temporal specialist...'
);

const knowledgeSpecialist = new Agent(
  new LlmBroker('qwen3:7b', gateway),
  [],
  'You are a general knowledge expert...'
);

// Create coordinator with multiple specialists
const coordinator = new Agent(
  new LlmBroker('qwen3:32b', gateway),
  [
    new ToolWrapper(
      temporalSpecialist,
      'temporal_specialist',
      'Specialist in dates and time'
    ),
    new ToolWrapper(
      knowledgeSpecialist,
      'knowledge_specialist',
      'General knowledge expert'
    ),
  ],
  `You are a coordinator. Analyze requests and delegate to appropriate specialists:
- temporal_specialist: For date/time queries
- knowledge_specialist: For general knowledge questions`
);

// The coordinator can now handle diverse queries
const result1 = await coordinator.generate('What day is tomorrow?');
const result2 = await coordinator.generate('What is TypeScript?');
const result3 = await coordinator.generate(
  'What day is tomorrow and what year did World War II end?'
);

How It Works

  1. User sends query to coordinator: The coordinator agent receives the user's input
  2. Coordinator analyzes: The coordinator's LLM analyzes which specialist(s) to use
  3. Tool calls generated: The LLM generates tool calls for the appropriate specialists
  4. Specialist execution: Each wrapped agent:
    • Receives input through its run() method
    • Creates initial messages from its behavior
    • Appends the input as a user message
    • Calls its broker with its own tools
    • Returns the response
  5. Response synthesis: The coordinator synthesizes specialist responses into a final answer

Message Flow

When a specialist agent is called through ToolWrapper:

User Query → Coordinator Agent

             Coordinator LLM analyzes query

             Tool call: temporal_specialist("What day is next Friday?")

             ToolWrapper.run({ input: "What day is next Friday?" })

             Creates messages:
             [
               { role: "system", content: "You are a temporal specialist..." },
               { role: "user", content: "What day is next Friday?" }
             ]

             Calls specialist's broker.generate(messages, specialist's tools)

             Specialist may use its own tools (DateResolverTool)

             Returns response to coordinator

             Coordinator synthesizes final response

Best Practices

1. Clear Specialist Descriptions

Provide clear, specific descriptions for wrapped agents:

typescript
new ToolWrapper(
  agent,
  'temporal_specialist',
  'Expert in date and time queries. Use for: relative dates (tomorrow, next Friday), current time, date calculations, and calendrical questions.'
);

2. Appropriate Model Selection

Use smaller, faster models for specialists and larger models for coordinators:

typescript
// Smaller model for specialist tasks
const specialist = new Agent(new LlmBroker('qwen3:7b', gateway), tools, behavior);

// Larger model for coordination and synthesis
const coordinator = new Agent(
  new LlmBroker('qwen3:32b', gateway),
  wrappedSpecialists,
  coordinatorBehavior
);

3. Focused Specialist Behaviors

Give each specialist a focused, clear role:

typescript
const specialist = new Agent(
  broker,
  [new DateResolverTool()],
  `You are a temporal specialist with deep knowledge of dates and time.
Your expertise includes:
- Resolving relative date references
- Providing current date and time information
- Calculating date differences
Always be precise and provide complete information.`
);

4. Clear Coordinator Instructions

Help the coordinator understand when to use each specialist:

typescript
const coordinator = new Agent(
  broker,
  specialists,
  `You are an intelligent coordinator that delegates tasks to specialist agents.

Available specialists:
- temporal_specialist: For date/time queries
- knowledge_specialist: For general knowledge questions
- calculation_specialist: For mathematical computations

Analyze the user's request and delegate to the appropriate specialist(s).
You can call multiple specialists if needed.`
);

Nested Delegation

Specialists can themselves be coordinators, creating multi-level hierarchies:

typescript
// Sub-specialist
const dateSpecialist = new Agent(broker, [new DateResolverTool()], 'Date expert');

// Mid-level coordinator
const temporalCoordinator = new Agent(
  broker,
  [new ToolWrapper(dateSpecialist, 'date_specialist', 'Date calculations')],
  'Temporal coordinator'
);

// Top-level coordinator
const mainCoordinator = new Agent(
  broker,
  [
    new ToolWrapper(temporalCoordinator, 'temporal_coordinator', 'All temporal queries'),
    // ... other specialists
  ],
  'Main coordinator'
);

Complete Example

See examples/broker_as_tool.ts for a complete, runnable example demonstrating:

  • Creating specialist agents with specific tools
  • Wrapping specialists as tools
  • Building a coordinator agent
  • Handling various types of queries
  • Multi-specialist coordination

Performance Considerations

  • Latency: Each delegation adds an LLM call, so use judiciously
  • Cost: Multiple LLM calls increase costs
  • Token usage: Coordinator prompts and specialist behaviors add to token counts
  • Optimization: Cache specialist responses when appropriate

Error Handling

ToolWrapper handles errors gracefully:

typescript
// Missing input parameter
const result = await wrappedAgent.run({});
// Returns: { error: 'input is required' }

// Broker errors are propagated
if (!result.ok) {
  console.error('Specialist failed:', result.error.message);
}

API Reference

Agent

typescript
class Agent {
  constructor(
    broker: LlmBroker,
    tools?: LlmTool[],
    behavior?: string
  );

  generate(input: string): Promise<Result<string, Error>>;
  createInitialMessages(): LlmMessage[];
  getBroker(): LlmBroker;
  getTools(): LlmTool[];
  getBehavior(): string;
}

ToolWrapper

typescript
class ToolWrapper extends BaseTool {
  constructor(
    agent: Agent,
    toolName: string,
    toolDescription: string
  );

  run(args: ToolArgs): Promise<Result<ToolResult, Error>>;
  descriptor(): ToolDescriptor;
  name(): string;
}

See Also

Released under the MIT License.