Overview
Agentes personalizados são as definições de agentes leves que você anexa a uma sessão. Cada agente tem seu próprio prompt do sistema, restrições de ferramenta e servidores MCP opcionais. Quando a solicitação de um usuário corresponde à especialidade de um agente, o runtime do Copilot delega automaticamente para esse agente, como um sub-agent—executando-o em um contexto isolado enquanto transmite os eventos do ciclo de vida de volta para a sessão principal.

| Conceito | Description |
|---|---|
| Agente personalizado | Uma configuração de agente nomeado com seu próprio prompt e conjunto de ferramentas |
| Subagente | Um agente personalizado invocado pelo runtime para lidar com parte de uma tarefa |
| Inferência | A capacidade do runtime de selecionar automaticamente um agente com base na intenção do usuário |
| Sessão principal | A sessão que gerou o subagente; recebe todos os eventos do ciclo de vida. |
Definindo agentes personalizados
Passe customAgents ao criar uma sessão. Cada agente precisa, no mínimo, de um name e um prompt.
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-4.1",
customAgents: [
{
name: "researcher",
displayName: "Research Agent",
description: "Explores codebases and answers questions using read-only tools",
tools: ["grep", "glob", "view"],
prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
name: "editor",
displayName: "Editor Agent",
description: "Makes targeted code changes",
tools: ["view", "edit", "bash"],
prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
},
],
onPermissionRequest: async () => ({ kind: "approve-once" }),
});
from copilot import CopilotClient, PermissionDecisionApproveOnce
client = CopilotClient()
await client.start()
session = await client.create_session(
on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
model="gpt-4.1",
custom_agents=[
{
"name": "researcher",
"display_name": "Research Agent",
"description": "Explores codebases and answers questions using read-only tools",
"tools": ["grep", "glob", "view"],
"prompt": "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
"name": "editor",
"display_name": "Editor Agent",
"description": "Makes targeted code changes",
"tools": ["view", "edit", "bash"],
"prompt": "You are a code editor. Make minimal, surgical changes to files as requested.",
},
],
)
package main
import (
"context"
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/rpc"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
client.Start(ctx)
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
CustomAgents: []copilot.CustomAgentConfig{
{
Name: "researcher",
DisplayName: "Research Agent",
Description: "Explores codebases and answers questions using read-only tools",
Tools: []string{"grep", "glob", "view"},
Prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
Name: "editor",
DisplayName: "Editor Agent",
Description: "Makes targeted code changes",
Tools: []string{"view", "edit", "bash"},
Prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
},
},
OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionApproveOnce{}, nil
},
})
_ = session
}
ctx := context.Background()
client := copilot.NewClient(nil)
client.Start(ctx)
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
CustomAgents: []copilot.CustomAgentConfig{
{
Name: "researcher",
DisplayName: "Research Agent",
Description: "Explores codebases and answers questions using read-only tools",
Tools: []string{"grep", "glob", "view"},
Prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
Name: "editor",
DisplayName: "Editor Agent",
Description: "Makes targeted code changes",
Tools: []string{"view", "edit", "bash"},
Prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
},
},
OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionApproveOnce{}, nil
},
})
using GitHub.Copilot;
using GitHub.Copilot.Rpc;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
CustomAgents = new List<CustomAgentConfig>
{
new()
{
Name = "researcher",
DisplayName = "Research Agent",
Description = "Explores codebases and answers questions using read-only tools",
Tools = new List<string> { "grep", "glob", "view" },
Prompt = "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
new()
{
Name = "editor",
DisplayName = "Editor Agent",
Description = "Makes targeted code changes",
Tools = new List<string> { "view", "edit", "bash" },
Prompt = "You are a code editor. Make minimal, surgical changes to files as requested.",
},
},
OnPermissionRequest = (req, inv) =>
Task.FromResult(PermissionDecision.ApproveOnce()),
});
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;
import java.util.List;
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setCustomAgents(List.of(
new CustomAgentConfig()
.setName("researcher")
.setDisplayName("Research Agent")
.setDescription("Explores codebases and answers questions using read-only tools")
.setTools(List.of("grep", "glob", "view"))
.setPrompt("You are a research assistant. Analyze code and answer questions. Do not modify any files."),
new CustomAgentConfig()
.setName("editor")
.setDisplayName("Editor Agent")
.setDescription("Makes targeted code changes")
.setTools(List.of("view", "edit", "bash"))
.setPrompt("You are a code editor. Make minimal, surgical changes to files as requested.")
))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
}
Referência de configuração
| Property | Tipo | Obrigatório | Description |
|---|---|---|---|
name | string | ✅ | Identificador exclusivo para o agente |
displayName | string | ||
| Nome legível por humanos exibido em eventos | |||
description | string | ||
| O que o agente faz — ajuda o runtime a selecioná-lo | |||
tools | |||
string[] ou null | |||
| Nomes de ferramentas que o agente pode usar. | |||
null ou excluído = todas as ferramentas | |||
prompt | string | ✅ | Comando do sistema ao agente |
mcpServers | object | ||
| Configurações de servidor MCP específicas para este agente | |||
infer | boolean | ||
Se o runtime pode selecionar automaticamente este agente (padrão: true) | |||
skills | string[] | ||
| Nomes de habilidades para precarregar no contexto do agente ao iniciar |
Dica
Um bom description ajuda o runtime a corresponder a intenção do usuário com o agente certo. Seja específico sobre a experiência e as funcionalidades do agente.
Além da configuração por agente acima, você pode definir agent na própria configuração da sessão para selecionar previamente qual agente personalizado está ativo quando a sessão é iniciada. Veja a seleção de um agente na criação da sessão abaixo.
| Propriedade de configuração da sessão | Tipo | Description |
|---|---|---|
agent | string | Nome do agente personalizado a ser pré-selecionado na criação da sessão. Deve corresponder a um name em customAgents. |
Habilidades por agente
Você pode carregar previamente habilidades no contexto de um agente usando a propriedade skills. Quando especificado, o conteúdo completo de cada habilidade listada é injetado ansiosamente no contexto do agente na inicialização– o agente não precisa invocar uma ferramenta de habilidade; as instruções já estão presentes. As habilidades são opcionais: os agentes não recebem nenhuma habilidade por padrão, e os subagentes não herdam habilidades do agente pai. Os nomes das habilidades são determinados a partir de skillDirectories no nível da sessão.
const session = await client.createSession({
skillDirectories: ["./skills"],
customAgents: [
{
name: "security-auditor",
description: "Security-focused code reviewer",
prompt: "Focus on OWASP Top 10 vulnerabilities",
skills: ["security-scan", "dependency-check"],
},
{
name: "docs-writer",
description: "Technical documentation writer",
prompt: "Write clear, concise documentation",
skills: ["markdown-lint"],
},
],
onPermissionRequest: async () => ({ kind: "approve-once" }),
});
Neste exemplo, security-auditor começa com security-scan e dependency-check já injetado em seu contexto, enquanto docs-writer começa com markdown-lint. Um agente sem um skills campo não recebe nenhum conteúdo de habilidade.
Selecionando um agente na criação da sessão
Você pode passar agent na configuração da sessão para predefinir qual agente personalizado deverá ser ativado quando a sessão for iniciada. O valor deve corresponder ao name de um dos agentes definidos em customAgents.
Isso é equivalente à chamada session.rpc.agent.select() após a criação, mas evita a chamada extra à API e garante que o agente esteja ativo desde o primeiro prompt.
const session = await client.createSession({
customAgents: [
{
name: "researcher",
prompt: "You are a research assistant. Analyze code and answer questions.",
},
{
name: "editor",
prompt: "You are a code editor. Make minimal, surgical changes.",
},
],
agent: "researcher", // Pre-select the researcher agent
});
session = await client.create_session(
on_permission_request=PermissionHandler.approve_all,
custom_agents=[
{
"name": "researcher",
"prompt": "You are a research assistant. Analyze code and answer questions.",
},
{
"name": "editor",
"prompt": "You are a code editor. Make minimal, surgical changes.",
},
],
agent="researcher", # Pre-select the researcher agent
)
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
CustomAgents: []copilot.CustomAgentConfig{
{
Name: "researcher",
Prompt: "You are a research assistant. Analyze code and answer questions.",
},
{
Name: "editor",
Prompt: "You are a code editor. Make minimal, surgical changes.",
},
},
Agent: "researcher", // Pre-select the researcher agent
})
var session = await client.CreateSessionAsync(new SessionConfig
{
CustomAgents = new List<CustomAgentConfig>
{
new() { Name = "researcher", Prompt = "You are a research assistant. Analyze code and answer questions." },
new() { Name = "editor", Prompt = "You are a code editor. Make minimal, surgical changes." },
},
Agent = "researcher", // Pre-select the researcher agent
});
import com.github.copilot.sdk.json.*;
import java.util.List;
var session = client.createSession(
new SessionConfig()
.setCustomAgents(List.of(
new CustomAgentConfig()
.setName("researcher")
.setPrompt("You are a research assistant. Analyze code and answer questions."),
new CustomAgentConfig()
.setName("editor")
.setPrompt("You are a code editor. Make minimal, surgical changes.")
))
.setAgent("researcher") // Pre-select the researcher agent
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
Como funciona a delegação de subagente
Quando você envia um prompt para uma sessão com agentes personalizados, o runtime avalia se deseja delegar a um subagente:
- Correspondência de intenção – o runtime analisa o prompt do usuário em relação a cada agente
nameedescription - Seleção de agente— Se uma correspondência for encontrada e
infernão forfalse, o runtime selecionará o agente - Execução isolada – o sub-agente é executado com seu próprio prompt e conjunto de ferramentas restritas
- Transmissão de eventos — eventos de ciclo de vida (
subagent.started,subagent.completedetc.) são transmitidos de volta para a sessão pai - Integração de resultados – a saída do sub-agente é incorporada à resposta do agente pai
Controlando a inferência
Por padrão, todos os agentes personalizados estão disponíveis para seleção automática (infer: true). Defina infer: false para impedir que o runtime selecione automaticamente um agente, útil para agentes que você só deseja invocar por meio de solicitações explícitas do usuário:
{
name: "dangerous-cleanup",
description: "Deletes unused files and dead code",
tools: ["bash", "edit", "view"],
prompt: "You clean up codebases by removing dead code and unused files.",
infer: false, // Only invoked when user explicitly asks for this agent
}
Escutando eventos de subagente
Quando um subagente é executado, a sessão pai emite eventos de ciclo de vida. Assine esses eventos para criar UIs que visualizam a atividade do agente.
Tipos de evento
| Acontecimento | Emitido quando | Dados |
|---|---|---|
subagent.selected | O runtime seleciona um agente para a tarefa | |
agentName, agentDisplayName, tools | ||
subagent.started | Subagente inicia a execução | |
toolCallId, agentName, , agentDisplayName``agentDescription | ||
subagent.completed | O subagente foi concluído com êxito | |
toolCallId, agentName, agentDisplayName | ||
subagent.failed | O subagente encontra um erro | |
toolCallId, agentName, , agentDisplayName``error | ||
subagent.deselected | O runtime muda seu foco do sub-agente | — |
Inscrevendo-se para eventos
session.on((event) => {
switch (event.type) {
case "subagent.started":
console.log(`▶ Sub-agent started: ${event.data.agentDisplayName}`);
console.log(` Description: ${event.data.agentDescription}`);
console.log(` Tool call ID: ${event.data.toolCallId}`);
break;
case "subagent.completed":
console.log(`✅ Sub-agent completed: ${event.data.agentDisplayName}`);
break;
case "subagent.failed":
console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);
console.log(` Error: ${event.data.error}`);
break;
case "subagent.selected":
console.log(`🎯 Agent selected: ${event.data.agentDisplayName}`);
console.log(` Tools: ${event.data.tools?.join(", ") ?? "all"}`);
break;
case "subagent.deselected":
console.log("↩ Agent deselected, returning to parent");
break;
}
});
const response = await session.sendAndWait({
prompt: "Research how authentication works in this codebase",
});
def handle_event(event):
if event.type == "subagent.started":
print(f"▶ Sub-agent started: {event.data.agent_display_name}")
print(f" Description: {event.data.agent_description}")
elif event.type == "subagent.completed":
print(f"✅ Sub-agent completed: {event.data.agent_display_name}")
elif event.type == "subagent.failed":
print(f"❌ Sub-agent failed: {event.data.agent_display_name}")
print(f" Error: {event.data.error}")
elif event.type == "subagent.selected":
tools = event.data.tools or "all"
print(f"🎯 Agent selected: {event.data.agent_display_name} (tools: {tools})")
unsubscribe = session.on(handle_event)
response = await session.send_and_wait("Research how authentication works in this codebase")
package main
import (
"context"
"fmt"
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/rpc"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
client.Start(ctx)
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionApproveOnce{}, nil
},
})
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.SubagentStartedData:
fmt.Printf("▶ Sub-agent started: %s\n", d.AgentDisplayName)
fmt.Printf(" Description: %s\n", d.AgentDescription)
fmt.Printf(" Tool call ID: %s\n", d.ToolCallID)
case *copilot.SubagentCompletedData:
fmt.Printf("✅ Sub-agent completed: %s\n", d.AgentDisplayName)
case *copilot.SubagentFailedData:
fmt.Printf("❌ Sub-agent failed: %s — %v\n", d.AgentDisplayName, d.Error)
case *copilot.SubagentSelectedData:
fmt.Printf("🎯 Agent selected: %s\n", d.AgentDisplayName)
}
})
_, err := session.SendAndWait(ctx, copilot.MessageOptions{
Prompt: "Research how authentication works in this codebase",
})
_ = err
}
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.SubagentStartedData:
fmt.Printf("▶ Sub-agent started: %s\n", d.AgentDisplayName)
fmt.Printf(" Description: %s\n", d.AgentDescription)
fmt.Printf(" Tool call ID: %s\n", d.ToolCallID)
case *copilot.SubagentCompletedData:
fmt.Printf("✅ Sub-agent completed: %s\n", d.AgentDisplayName)
case *copilot.SubagentFailedData:
fmt.Printf("❌ Sub-agent failed: %s — %v\n", d.AgentDisplayName, d.Error)
case *copilot.SubagentSelectedData:
fmt.Printf("🎯 Agent selected: %s\n", d.AgentDisplayName)
}
})
_, err := session.SendAndWait(ctx, copilot.MessageOptions{
Prompt: "Research how authentication works in this codebase",
})
using GitHub.Copilot;
public static class SubAgentEventsExample
{
public static async Task Example(CopilotSession session)
{
using var subscription = session.On<SessionEvent>(evt =>
{
switch (evt)
{
case SubagentStartedEvent started:
Console.WriteLine($"▶ Sub-agent started: {started.Data.AgentDisplayName}");
Console.WriteLine($" Description: {started.Data.AgentDescription}");
Console.WriteLine($" Tool call ID: {started.Data.ToolCallId}");
break;
case SubagentCompletedEvent completed:
Console.WriteLine($"✅ Sub-agent completed: {completed.Data.AgentDisplayName}");
break;
case SubagentFailedEvent failed:
Console.WriteLine($"❌ Sub-agent failed: {failed.Data.AgentDisplayName} — {failed.Data.Error}");
break;
case SubagentSelectedEvent selected:
Console.WriteLine($"🎯 Agent selected: {selected.Data.AgentDisplayName}");
break;
}
});
await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Research how authentication works in this codebase"
});
}
}
using var subscription = session.On<SessionEvent>(evt =>
{
switch (evt)
{
case SubagentStartedEvent started:
Console.WriteLine($"▶ Sub-agent started: {started.Data.AgentDisplayName}");
Console.WriteLine($" Description: {started.Data.AgentDescription}");
Console.WriteLine($" Tool call ID: {started.Data.ToolCallId}");
break;
case SubagentCompletedEvent completed:
Console.WriteLine($"✅ Sub-agent completed: {completed.Data.AgentDisplayName}");
break;
case SubagentFailedEvent failed:
Console.WriteLine($"❌ Sub-agent failed: {failed.Data.AgentDisplayName} — {failed.Data.Error}");
break;
case SubagentSelectedEvent selected:
Console.WriteLine($"🎯 Agent selected: {selected.Data.AgentDisplayName}");
break;
}
});
await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Research how authentication works in this codebase"
});
session.on(event -> {
if (event instanceof SubagentStartedEvent e) {
System.out.println("▶ Sub-agent started: " + e.getData().agentDisplayName());
System.out.println(" Description: " + e.getData().agentDescription());
System.out.println(" Tool call ID: " + e.getData().toolCallId());
} else if (event instanceof SubagentCompletedEvent e) {
System.out.println("✅ Sub-agent completed: " + e.getData().agentName());
} else if (event instanceof SubagentFailedEvent e) {
System.out.println("❌ Sub-agent failed: " + e.getData().agentName());
System.out.println(" Error: " + e.getData().error());
} else if (event instanceof SubagentSelectedEvent e) {
System.out.println("🎯 Agent selected: " + e.getData().agentDisplayName());
} else if (event instanceof SubagentDeselectedEvent e) {
System.out.println("↩ Agent deselected, returning to parent");
}
});
var response = session.sendAndWait(
new MessageOptions().setPrompt("Research how authentication works in this codebase")
).get();
Construindo uma interface do usuário de árvore de agente
Eventos de subagente incluem campos que permitem toolCallId reconstruir a árvore de execução. Aqui está um padrão para acompanhar a atividade do agente:
interface AgentNode {
toolCallId: string;
name: string;
displayName: string;
status: "running" | "completed" | "failed";
error?: string;
startedAt: Date;
completedAt?: Date;
}
const agentTree = new Map<string, AgentNode>();
session.on((event) => {
if (event.type === "subagent.started") {
agentTree.set(event.data.toolCallId, {
toolCallId: event.data.toolCallId,
name: event.data.agentName,
displayName: event.data.agentDisplayName,
status: "running",
startedAt: new Date(event.timestamp),
});
}
if (event.type === "subagent.completed") {
const node = agentTree.get(event.data.toolCallId);
if (node) {
node.status = "completed";
node.completedAt = new Date(event.timestamp);
}
}
if (event.type === "subagent.failed") {
const node = agentTree.get(event.data.toolCallId);
if (node) {
node.status = "failed";
node.error = event.data.error;
node.completedAt = new Date(event.timestamp);
}
}
// Render your UI with the updated tree
renderAgentTree(agentTree);
});
Ferramentas de escopo por agente
Use a tools propriedade para restringir quais ferramentas um agente pode acessar. Isso é essencial para a segurança e para manter os agentes focados:
const session = await client.createSession({
customAgents: [
{
name: "reader",
description: "Read-only exploration of the codebase",
tools: ["grep", "glob", "view"], // No write access
prompt: "You explore and analyze code. Never suggest modifications directly.",
},
{
name: "writer",
description: "Makes code changes",
tools: ["view", "edit", "bash"], // Write access
prompt: "You make precise code changes as instructed.",
},
{
name: "unrestricted",
description: "Full access agent for complex tasks",
tools: null, // All tools available
prompt: "You handle complex multi-step tasks using any available tools.",
},
],
});
Observação
Quando tools é null ou omitido, o agente herda o acesso a todas as ferramentas configuradas na sessão. Use listas de ferramentas explícitas para impor o princípio do privilégio mínimo.
Ferramentas exclusivas do agente
Use a defaultAgent propriedade na configuração de sessão para ocultar ferramentas específicas do agente padrão (o agente interno que manipula turnos quando nenhum agente personalizado é selecionado). Isso força o agente principal a delegar a sub-agentes quando as funcionalidades dessas ferramentas são necessárias, mantendo o contexto do agente principal limpo.
Isso é útil quando:
- Determinadas ferramentas geram grandes quantidades de contexto que sobrecarregariam o agente principal
- Você deseja que o agente principal atue como um orquestrador, delegando trabalho pesado a sub-agentes especializados
- Você precisa de separação estrita entre orquestração e execução
import { CopilotClient, defineTool, approveAll } from "@github/copilot-sdk";
import { z } from "zod";
const heavyContextTool = defineTool("analyze-codebase", {
description: "Performs deep analysis of the codebase, generating extensive context",
parameters: z.object({ query: z.string() }),
handler: async ({ query }) => {
// ... expensive analysis that returns lots of data
return { analysis: "..." };
},
});
const session = await client.createSession({
tools: [heavyContextTool],
defaultAgent: {
excludedTools: ["analyze-codebase"],
},
customAgents: [
{
name: "researcher",
description: "Deep codebase analysis agent with access to heavy-context tools",
tools: ["analyze-codebase"],
prompt: "You perform thorough codebase analysis using the analyze-codebase tool.",
},
],
});
from copilot import CopilotClient
from copilot.tools import Tool
heavy_tool = Tool(
name="analyze-codebase",
description="Performs deep analysis of the codebase",
handler=analyze_handler,
parameters={"type": "object", "properties": {"query": {"type": "string"}}},
)
session = await client.create_session(
tools=[heavy_tool],
default_agent={"excluded_tools": ["analyze-codebase"]},
custom_agents=[
{
"name": "researcher",
"description": "Deep codebase analysis agent",
"tools": ["analyze-codebase"],
"prompt": "You perform thorough codebase analysis.",
},
],
on_permission_request=approve_all,
)
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Tools: []copilot.Tool{heavyTool},
DefaultAgent: &copilot.DefaultAgentConfig{
ExcludedTools: []string{"analyze-codebase"},
},
CustomAgents: []copilot.CustomAgentConfig{
{
Name: "researcher",
Description: "Deep codebase analysis agent",
Tools: []string{"analyze-codebase"},
Prompt: "You perform thorough codebase analysis.",
},
},
})
var session = await client.CreateSessionAsync(new SessionConfig
{
Tools = [analyzeCodebaseTool],
DefaultAgent = new DefaultAgentConfig
{
ExcludedTools = ["analyze-codebase"],
},
CustomAgents =
[
new CustomAgentConfig
{
Name = "researcher",
Description = "Deep codebase analysis agent",
Tools = ["analyze-codebase"],
Prompt = "You perform thorough codebase analysis.",
},
],
});
Como funciona
Ferramentas listadas em defaultAgent.excludedTools:
- Estão registrados– seus manipuladores estão disponíveis para execução
- Estão ocultos na lista de ferramentas do agente principal– a LLM não os verá nem os chamará diretamente
- Permanecer disponível para qualquer subagente personalizado que os inclua em sua
toolsmatriz
Interação com outros filtros de ferramenta
defaultAgent.excludedTools é ortogonal a availableTools e excludedTools no nível da sessão:
| Filtro | Scope | Efeito |
|---|---|---|
availableTools | Em toda a sessão | Lista de permissões – somente essas ferramentas existem para qualquer pessoa |
excludedTools | Em toda a sessão | Lista de bloqueios – essas ferramentas são bloqueadas para todos |
defaultAgent.excludedTools | Somente agente principal | Essas ferramentas estão ocultas do agente principal, mas estão disponíveis para sub-agentes |
Precedência:
- O nível
availableTools/excludedToolsda sessão é aplicado primeiro (globalmente) defaultAgent.excludedToolsé aplicado na parte superior, restringindo ainda mais o agente principal somente
Observação
Se uma ferramenta estiver em ambos excludedTools (nível de sessão) e defaultAgent.excludedTools, a exclusão no nível da sessão tiver precedência, a ferramenta não estará disponível para todos.
Anexando servidores MCP a agentes
Cada agente personalizado pode ter seus próprios servidores MCP (Model Context Protocol), dando-lhe acesso a fontes de dados especializadas:
const session = await client.createSession({
customAgents: [
{
name: "db-analyst",
description: "Analyzes database schemas and queries",
prompt: "You are a database expert. Use the database MCP server to analyze schemas.",
mcpServers: {
"database": {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
},
},
},
],
});
Padrões e melhores práticas
Emparelhar um pesquisador com um editor
Um padrão comum é definir um agente de pesquisa somente leitura e um agente editor com capacidade de escrita. O tempo de execução delega tarefas de exploração ao pesquisador e tarefas de modificação ao editor.
customAgents: [
{
name: "researcher",
description: "Analyzes code structure, finds patterns, and answers questions",
tools: ["grep", "glob", "view"],
prompt: "You are a code analyst. Thoroughly explore the codebase to answer questions.",
},
{
name: "implementer",
description: "Implements code changes based on analysis",
tools: ["view", "edit", "bash"],
prompt: "You make minimal, targeted code changes. Always verify changes compile.",
},
]
Manter descrições de agente específicas
O runtime usa o description para corresponder à intenção do usuário. Descrições vagas levam à má delegação:
// ❌ Too vague — runtime can't distinguish from other agents
{ description: "Helps with code" }
// ✅ Specific — runtime knows when to delegate
{ description: "Analyzes Python test coverage and identifies untested code paths" }
Lidar com falhas de forma elegante
Sub-agentes podem falhar. Sempre ouça subagent.failed eventos e manipule-os em seu aplicativo:
session.on((event) => {
if (event.type === "subagent.failed") {
logger.error(`Agent ${event.data.agentName} failed: ${event.data.error}`);
// Show error in UI, retry, or fall back to parent agent
}
});