# Agentes personalizados e orquestração de subagentes

Defina agentes especializados com ferramentas e prompts com escopo definido e, em seguida, permita que o Copilot os orquestre como subagentes em uma única sessão. Para executar vários subagentes em paralelo, consulte Modo de frota.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## 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.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-custom-agents-diagram-0.png)

| 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`.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
    model: "gpt-5.4",
    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" }),
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient, PermissionDecisionApproveOnce

client = CopilotClient()
await client.start()

session = await client.create_session(
    on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
    model="gpt-5.4",
    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.",
        },
    ],
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
ctx := context.Background()
client := copilot.NewClient(nil)
client.Start(ctx)

session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
    Model: "gpt-5.4",
    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
    },
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;
using GitHub.Copilot.Rpc;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5.4",
    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()),
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;
import java.util.List;

try (var client = new CopilotClient()) {
    client.start().get();

    var session = client.createSession(
        new SessionConfig()
            .setModel("gpt-5.4")
            .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();
}
```

</div>

</div>

## 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 omitido = 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 habilidade a serem pré-carregados no contexto do agente na inicialização                                                                                                                       |            |             |                                       |
| `model`                                                                                                                                                                                                 | `string`   |             |                                       |
| Identificador de modelo a ser usado enquanto este agente é executado                                                                                                                                    |            |             |                                       |
| `reasoningEffort`                                                                                                                                                                                       | `string`   |             |                                       |
| Esforço de raciocínio a ser usado enquanto este agente estiver em execução. Quando omitido, o SDK não envia nenhuma substituição por agente e o runtime resolve o esforço (confira a observação abaixo) |            |             |                                       |

> \[!TIP]
> 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.

Defina `model` e `reasoningEffort` para substituir as configurações do modelo da sessão pai enquanto um agente personalizado estiver em execução. Quando `reasoningEffort` é omitido, o SDK não envia nenhuma substituição específica por agente, e o runtime determina o esforço com base na própria ordem de precedência: uma opção do cliente por chamada, o padrão do modelo resolvido ou a definição do agente têm prioridade; caso contrário, o runtime herda o esforço da sessão pai somente quando o subagente usa o mesmo modelo que o pai. Quando o subagente passa a usar um modelo diferente, ele recorre ao padrão desse modelo em vez de herdar o esforço do agente pai. Python usa`reasoning_effort`, .NET usa`ReasoningEffort`, Go usa`ReasoningEffort`, Java usa `setReasoningEffort`e o Rust usa `with_reasoning_effort`.

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](#selecting-an-agent-at-session-creation) 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 pré-carregar 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 **aceitas**: os agentes não recebem habilidades por padrão, e os sub-agentes não herdam habilidades do pai. Os nomes de habilidade são resolvidos no nível da sessão `skillDirectories`.

```typescript
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.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

<!-- docs-validate: skip -->

```typescript
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
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: skip -->

```python
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
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
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
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

<!-- docs-validate: skip -->

```csharp
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
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
import com.github.copilot.rpc.*;
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();
```

</div>

</div>

## 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:

1. **Correspondência de intenção** – o runtime analisa o prompt do usuário em relação a `name` e `description` de cada agente
2. **Seleção de agente**— Se uma correspondência for encontrada e `infer` não for `false`, o runtime selecionará o agente
3. **Execução isolada** – o sub-agente é executado com seu próprio prompt e conjunto de ferramentas restritas
4. **Transmissão de eventos** — eventos de ciclo de vida (`subagent.started`, `subagent.completed` etc.) são transmitidos de volta para a sessão pai
5. **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:

```typescript
{
    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
}
```

## Escutar 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.

Os eventos de sessão originados por subagentes compartilham o fluxo da sessão pai e incluem `agentId` no nível do envelope. Eventos do agente raiz/principal e eventos no nível da sessão omitem `agentId`, de modo que os renderizadores possam manter a resposta principal separada dos rastreamentos de subagentes ao verificar o envelope do evento.

### 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``model?`                                          |                                             |       |
| `subagent.completed`                                                                                                 | O subagente foi concluído com êxito         |       |
| `toolCallId`, `agentName`, `agentDisplayName`, `model?`, , `durationMs?`, `totalTokens?`, `totalToolCalls?`          |                                             |       |
| `subagent.failed`                                                                                                    | O subagente encontra um erro                |       |
| `toolCallId`, `agentName`, `agentDisplayName`, `error`, `model?`, `durationMs?`, `totalTokens?`, , `totalToolCalls?` |                                             |       |
| `subagent.deselected`                                                                                                | O runtime muda seu foco do subagente        | —     |

### Inscrevendo-se para eventos

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
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}`);
            if (event.data.durationMs !== undefined) console.log(`  Duration: ${event.data.durationMs}ms`);
            if (event.data.totalTokens !== undefined) console.log(`  Tokens: ${event.data.totalTokens}`);
            if (event.data.totalToolCalls !== undefined) console.log(`  Tool calls: ${event.data.totalToolCalls}`);
            break;

        case "subagent.failed":
            console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);
            console.log(`  Error: ${event.data.error}`);
            if (event.data.durationMs !== undefined) console.log(`  Duration: ${event.data.durationMs}ms`);
            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",
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
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")
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
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",
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
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"
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
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();
```

</div>

</div>

## Construir uma interface de usuário de árvore de agente

Eventos de subagente incluem campos `toolCallId` que permitem reconstruir a árvore de execução. Aqui está um padrão para acompanhar a atividade do agente:

```typescript
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:

```typescript
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.",
        },
    ],
});
```

> \[!NOTE]
> 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

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
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.",
        },
    ],
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
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,
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
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.",
        },
    },
})
```

</div>

<div class="ghd-codetab" data-lang="csharp" data-label="C#"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">C#</div>

<!-- docs-validate: skip -->

```csharp
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.",
        },
    ],
});
```

</div>

</div>

### Como funciona

Ferramentas listadas em `defaultAgent.excludedTools`:

1. **Estão registrados**– seus manipuladores estão disponíveis para execução
2. **Estão ocultos** na lista de ferramentas do agente principal– a LLM não os verá nem os chamará diretamente
3. **Permanecer disponível** para qualquer subagente personalizado que os inclua em sua `tools` matriz

### 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:

1. O nível `availableTools`/`excludedTools` da sessão é aplicado primeiro (globalmente)
2. `defaultAgent.excludedTools` é aplicado na parte superior, restringindo ainda mais apenas o agente principal

> \[!NOTE]
> 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:

```typescript
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 gravação. O tempo de execução delega tarefas de exploração ao pesquisador e tarefas de modificação ao editor.

```typescript
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:

```typescript
// ❌ 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 eventos `subagent.failed` e manipule-os em seu aplicativo:

```typescript
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
    }
});
```