> ## Documentation Index
> Fetch the complete documentation index at: https://icepick.hatchet.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Agent

> Orchestrate specialized agents to handle different types of requests through automatic routing

export const CallGraphSequence = props => {
  const actors = [{
    name: 'User',
    left: 20
  }, {
    name: 'Your API',
    left: 160
  }, {
    name: 'Agent',
    left: 300
  }, {
    name: 'Tool',
    left: 440
  }, {
    name: 'Business Logic',
    left: 580
  }];
  const messages = [{
    from: 0,
    to: 1,
    label: 'API Request',
    top: 90,
    dashed: false
  }, {
    from: 1,
    to: 2,
    label: 'agent.run()',
    top: 125,
    dashed: false,
    link: '/api-reference/agent'
  }, {
    from: 2,
    to: 3,
    label: 'tool.run()',
    top: 160,
    dashed: false,
    link: '/api-reference/tool'
  }, {
    from: 3,
    to: 4,
    label: 'External Call',
    top: 195,
    dashed: false
  }, {
    from: 4,
    to: 3,
    label: 'Response',
    top: 230,
    dashed: true
  }, {
    from: 3,
    to: 2,
    label: 'Tool Result',
    top: 265,
    dashed: true
  }, {
    from: 2,
    to: 1,
    label: 'Agent Response',
    top: 300,
    dashed: true
  }, {
    from: 1,
    to: 0,
    label: 'API Response',
    top: 335,
    dashed: true
  }];
  const actorData = props && props.actors ? props.actors : actors;
  const messageData = props && props.messages ? props.messages : messages;
  const height = props && props.height ? props.height : 370;
  const config = {
    actorTop: 30,
    actorWidth: 80,
    lifelineTop: 60,
    lifelineHeight: height,
    lifelineOffset: 40,
    messageSpacing: 140
  };
  return <div className="call-graph-container">
<div className="call-graph-canvas" style={{
    height: height + 30
  }}>
{actorData.map((actor, index) => <div key={index} className="call-graph-actor" style={{
    top: config.actorTop,
    left: actor.left,
    width: config.actorWidth
  }}>
{actor.name}
</div>)}

        {actorData.map((actor, index) => <div key={index} className="call-graph-lifeline" style={{
    top: config.lifelineTop,
    left: actor.left + config.lifelineOffset,
    height: config.lifelineHeight
  }}></div>)}

        {messageData.map((message, index) => {
    const fromActor = actorData[message.from];
    const toActor = actorData[message.to];
    const isReturn = message.from > message.to;
    const messageLeft = isReturn ? toActor.left + config.lifelineOffset + 6 : fromActor.left + config.lifelineOffset;
    const messageWidth = isReturn ? fromActor.left + config.lifelineOffset - (toActor.left + config.lifelineOffset + 6) : toActor.left + config.lifelineOffset - (fromActor.left + config.lifelineOffset);
    return <div key={index} className="call-graph-message" style={{
      top: message.top,
      left: messageLeft,
      width: messageWidth
    }}>
              <div className={`call-graph-message-line ${message.dashed ? 'dashed' : ''}`} style={{
      width: '100%'
    }}></div>
              <div className={`call-graph-arrow ${isReturn ? 'return' : ''}`} style={{
      position: 'absolute',
      [isReturn ? 'left' : 'right']: isReturn ? -4 : -3,
      top: -2
    }}></div>
              {message.link ? <a href={message.link} className="call-graph-message-label" style={{
      position: 'absolute',
      top: -12,
      left: '50%',
      transform: 'translateX(-50%)',
      textDecoration: 'none'
    }}>
                  {message.label}
                </a> : <div className="call-graph-message-label" style={{
      position: 'absolute',
      top: -12,
      left: '50%',
      transform: 'translateX(-50%)'
    }}>
                  {message.label}
                </div>}
            </div>;
  })}
      </div>
    </div>;
};

*Based on [Anthropic's "Building Effective Agents"](https://www.anthropic.com/engineering/building-effective-agents) framework.*

Multi-agent orchestration delegates incoming requests to specialized agents based on the request type or domain. A coordinating agent acts as a router, automatically selecting the most appropriate specialized agent to handle each specific request, enabling focused expertise while maintaining a unified interface.

export const multiAgentActors = [{
  name: 'Client',
  left: 20
}, {
  name: 'Orchestrator',
  left: 160
}, {
  name: 'Agent A',
  left: 300
}, {
  name: 'Agent B',
  left: 440
}];

export const multiAgentMessages = [{
  from: 0,
  to: 1,
  label: 'request',
  top: 90,
  dashed: false
}, {
  from: 1,
  to: 2,
  label: 'route to specialist',
  top: 125,
  dashed: false
}, {
  from: 2,
  to: 1,
  label: 'specialized response',
  top: 160,
  dashed: true
}, {
  from: 1,
  to: 0,
  label: 'final response',
  top: 195,
  dashed: true
}];

<CallGraphSequence actors={multiAgentActors} messages={multiAgentMessages} height={220} />

## When to Use

Use multi-agent orchestration when you have distinct request categories that benefit from specialized handling, such as support versus sales inquiries or different product domains. This pattern works best when each specialist agent can operate independently and when automatic routing based on request content is reliable. Avoid when requests frequently require multiple specialists or when the routing logic becomes complex.

## Implementation

This example demonstrates a customer service system where a coordinating agent automatically routes between support and sales specialists based on the nature of incoming requests.

### Agent Code

```typescript theme={null}
import { icepick } from "@hatchet-dev/icepick";
import z from "zod";
import { supportAgent } from "@tools/support-agent";
import { salesAgent } from "@tools/sales-agent";

const CustomerServiceInput = z.object({
  userMessage: z.string(),
});

const CustomerServiceOutput = z.object({
  response: z.string(),
  category: z.string(),
});

const customerServiceToolbox = icepick.toolbox({
  tools: [supportAgent, salesAgent],
});

export const customerServiceAgent = icepick.agent({
  name: "customer-service-agent",
  executionTimeout: "5m",
  inputSchema: CustomerServiceInput,
  outputSchema: CustomerServiceOutput,
  description: "Routes customer inquiries to specialized agents",
  fn: async (input, ctx) => {
    // AUTOMATIC ROUTING: Let the toolbox select the appropriate specialist
    const result = await customerServiceToolbox.pickAndRun({
      prompt: input.userMessage,
    });

    switch (result.name) {
      case "support-agent":
        return {
          response: result.output.response,
          category: "support",
        };
      case "sales-agent":
        return {
          response: result.output.response,
          category: "sales",
        };
      default:
        return customerServiceToolbox.assertExhaustive(result);
    }
  },
});
```

<AccordionGroup>
  <Accordion title="Support Agent: Technical Assistance">
    ```typescript theme={null}
    import { icepick } from "@hatchet-dev/icepick";
    import z from "zod";
    import { generateText } from "ai";

    export const supportAgent = icepick.tool({
      name: "support-agent",
      description: "Handles technical support, troubleshooting, and product issues",
      inputSchema: z.object({
        prompt: z.string(),
      }),
      outputSchema: z.object({
        response: z.string(),
      }),
      fn: async (input) => {
        const result = await generateText({
          model: icepick.defaultLanguageModel,
          prompt: `You are a technical support specialist. Help the customer with their technical issue, troubleshooting question, or product problem. Be helpful, detailed, and provide step-by-step solutions when appropriate.

    Customer message: ${input.prompt}`,
        });

        return {
          response: result.text,
        };
      },
    });
    ```

    This agent specializes in technical support scenarios, providing detailed troubleshooting guidance and product assistance. It focuses on problem-solving and technical expertise.
  </Accordion>

  <Accordion title="Sales Agent: Product Information">
    ```typescript theme={null}
    import { icepick } from "@hatchet-dev/icepick";
    import z from "zod";
    import { generateText } from "ai";

    export const salesAgent = icepick.tool({
      name: "sales-agent",
      description: "Handles product inquiries, pricing questions, and sales-related requests",
      inputSchema: z.object({
        prompt: z.string(),
      }),
      outputSchema: z.object({
        response: z.string(),
      }),
      fn: async (input) => {
        const result = await generateText({
          model: icepick.defaultLanguageModel,
          prompt: `You are a sales specialist. Help the customer with product information, pricing questions, feature comparisons, and purchasing decisions. Be persuasive but helpful, highlighting relevant benefits and addressing their specific needs.

    Customer message: ${input.prompt}`,
        });

        return {
          response: result.text,
        };
      },
    });
    ```

    This agent specializes in sales scenarios, focusing on product benefits, pricing information, and helping customers make purchasing decisions with persuasive but helpful responses.
  </Accordion>
</AccordionGroup>

The pattern uses `pickAndRun()` for automatic agent selection based on the request content, with each specialist agent optimized for its specific domain. The orchestrator maintains a consistent interface while delegating to the most appropriate expert.

## Related Patterns

This pattern complements routing for complex decision trees and can be combined with human-in-the-loop for scenarios requiring specialist review or approval.
