Agent Teams (Multi-Agent)
An Agent Team is a group of specialized agents deployed behind one chat app. Each agent has its own model, prompt, tools, examples, and optional data sources, and the team coordinates them.
The TypeScript SDK calls this an Agent Team (AgentTeam). The Python SDK calls the
same backend feature a Custodian Squad (CustodianSquad).
When to use an Agent Team
- Different questions should be handled by different instructions.
- Each agent has a clear topic area.
- One agent needs a data source the others do not.
- You want the response to show which agent handled the request.
For a single agent with one prompt, use the Custodian Agent Class.
Core objects
| Object | Purpose |
|---|---|
Agent | A team member: model, prompt, topics, tools, examples, response schema, optional data source files. |
AgentTeam | Groups agents and defines the routing mode and connection config. |
TeamApp | The deployed team app returned by team.deploy(). Use it to chat. |
Create a team
import { Agent, AgentTeam } from "@custodianlabs/sdk";
const team = new AgentTeam({
agents: [
new Agent({
name: "billing",
model: "gpt-4o",
systemPrompt: "Answer billing questions.",
topics: ["billing", "invoice", "refund", "payment"],
}),
new Agent({
name: "data",
model: "gpt-4o",
systemPrompt: "Answer questions about the uploaded CSV file.",
topics: ["data", "csv", "customer", "file"],
}).addDataSourceFile("./data/customers.csv"),
],
routingMode: "single",
});
const app = await team.deploy();
const reply = await app.chat("I have a question about my invoice.");
console.log(reply?.response);
console.log(reply?.selectedAgent);
Agent options
| Option | Notes |
|---|---|
name | Required. Unique within the team. |
model | Required. |
systemPrompt | Required. |
topics | Keywords used for routing. |
canHandoffTo | Agent names this agent may hand off to. chain mode only. |
description | Metadata. |
tools | Built-in tools for this agent. See Built-in Tools. |
examples | Few-shot examples for this agent. |
outputKey | In workflow mode, the key this agent's output is stored under. |
inputSchema / responseSchema | JSON Schema for this agent. |
privacyEnabled | Inline PII masking for this agent. Default false. |
agent.addDataSourceFile(file) and agent.setPriority(n) return the agent for
chaining.
AgentTeam options
| Option | Notes |
|---|---|
agents | Required. At least one, with unique names. |
routingMode | "single" (default), "chain", or "workflow". |
maxHandoffs | chain mode only. Default 4. |
workflowOrder | Required when routingMode is "workflow": agent names in run order. |
name / description | Metadata. |
inputSchema / responseSchema | Team-level JSON Schema. In workflow mode, responseSchema governs the final output. |
apiKey / baseUrl / timeout / maxRetries | Connection config for the whole team. |
Python puts api_key / base_url on each member and reconciles them. The TypeScript
SDK puts connection config directly on AgentTeam, since a team has one connection.
Routing modes
| Mode | Behavior | Use when |
|---|---|---|
single | One agent is selected per message from topics. | Most teams — one specialist per message. |
chain | Agents hand off to each other via canHandoffTo, up to maxHandoffs. | Conversations where agents pass work between each other. |
workflow | Agents run in the fixed workflowOrder; each output feeds the next. | Deterministic multi-step pipelines. |
Handoffs are
chain-only.canHandoffToandmaxHandoffsare ignored insingleandworkflowmodes.
Chain mode
const team = new AgentTeam({
agents: [
new Agent({
name: "triage",
model: "gpt-4o",
systemPrompt: "Classify the issue.",
topics: ["billing", "support"],
canHandoffTo: ["expert"],
}),
new Agent({ name: "expert", model: "gpt-4o", systemPrompt: "Resolve the issue." }),
],
routingMode: "chain",
maxHandoffs: 3,
});
const app = await team.deploy();
const reply = await app.chat("A payment is stuck. Investigate it.");
console.log(reply?.handoffPath); // e.g. ["triage", "expert"]
Workflow mode
const team = new AgentTeam({
agents: [
new Agent({
name: "research",
model: "gpt-4o",
systemPrompt: "Research the topic.",
tools: ["web_search"],
outputKey: "research_notes",
}),
new Agent({
name: "writer",
model: "gpt-4o",
systemPrompt: "Write a summary from the research notes.",
}),
],
routingMode: "workflow",
workflowOrder: ["research", "writer"],
});
Validation
new AgentTeam(...) throws before any network call when:
agentsis empty.- Two agents share a
name. routingModeis"workflow"without a non-emptyworkflowOrder.workflowOrdernames an agent that is not inagents.
Chat with a team
TeamApp.chat() retains the session like a single-agent App:
const reply = await app.chat("Can you help with a refund question?");
console.log(reply?.response);
console.log(reply?.selectedAgent); // which agent answered
console.log(reply?.handoffPath); // chain mode
console.log(reply?.contributingAgents); // workflow mode
app.sessionId, app.resetSession(), and interactive app.chat() behave the same as
for a single Custodian Agent — see Chat Sessions.
Data sources per agent
Attach a file to the agent that should use it:
new Agent({
name: "data",
model: "gpt-4o",
systemPrompt: "Answer questions about the uploaded CSV file.",
}).addDataSourceFile("./data/customers.csv");
Staged files upload after the team is created, during .deploy().
Sharing
Configured at deploy time on the team, never on the agents:
await team.deploy(); // public (default)
await team.deploy({ shareMode: "private" });
await team.deploy({ shareMode: "password", sharePassword: "s3cret" });