{"meta":{"title":"Agentes personalizados e orquestração de subagentes","intro":"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.","product":"GitHub Copilot","breadcrumbs":[{"href":"/pt/enterprise-cloud@latest/copilot","title":"GitHub Copilot"},{"href":"/pt/enterprise-cloud@latest/copilot/how-tos","title":"Instruções"},{"href":"/pt/enterprise-cloud@latest/copilot/how-tos/copilot-sdk","title":"SDK do Copilot"},{"href":"/pt/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features","title":"Features"},{"href":"/pt/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/custom-agents","title":"Agentes Personalizados"}],"documentType":"article"},"body":"# Agentes personalizados e orquestração de subagentes\n\nDefina 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.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Overview\n\nAgentes 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.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-custom-agents-diagram-0.png)\n\n| Conceito                 | Description                                                                                     |\n| ------------------------ | ----------------------------------------------------------------------------------------------- |\n| **Agente personalizado** | Uma configuração de agente nomeado com seu próprio prompt e conjunto de ferramentas             |\n| **Subagente**            | Um agente personalizado invocado pelo runtime para lidar com parte de uma tarefa                |\n| **Inferência**           | A capacidade do runtime de selecionar automaticamente um agente com base na intenção do usuário |\n| **Sessão principal**     | A sessão que gerou o subagente; recebe todos os eventos do ciclo de vida.                       |\n\n## Definindo agentes personalizados\n\nPasse `customAgents` ao criar uma sessão. Cada agente precisa, no mínimo, de um `name` e um `prompt`.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\nawait client.start();\n\nconst session = await client.createSession({\n    model: \"gpt-5.4\",\n    customAgents: [\n        {\n            name: \"researcher\",\n            displayName: \"Research Agent\",\n            description: \"Explores codebases and answers questions using read-only tools\",\n            tools: [\"grep\", \"glob\", \"view\"],\n            prompt: \"You are a research assistant. Analyze code and answer questions. Do not modify any files.\",\n        },\n        {\n            name: \"editor\",\n            displayName: \"Editor Agent\",\n            description: \"Makes targeted code changes\",\n            tools: [\"view\", \"edit\", \"bash\"],\n            prompt: \"You are a code editor. Make minimal, surgical changes to files as requested.\",\n        },\n    ],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient, PermissionDecisionApproveOnce\n\nclient = CopilotClient()\nawait client.start()\n\nsession = await client.create_session(\n    on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),\n    model=\"gpt-5.4\",\n    custom_agents=[\n        {\n            \"name\": \"researcher\",\n            \"display_name\": \"Research Agent\",\n            \"description\": \"Explores codebases and answers questions using read-only tools\",\n            \"tools\": [\"grep\", \"glob\", \"view\"],\n            \"prompt\": \"You are a research assistant. Analyze code and answer questions. Do not modify any files.\",\n        },\n        {\n            \"name\": \"editor\",\n            \"display_name\": \"Editor Agent\",\n            \"description\": \"Makes targeted code changes\",\n            \"tools\": [\"view\", \"edit\", \"bash\"],\n            \"prompt\": \"You are a code editor. Make minimal, surgical changes to files as requested.\",\n        },\n    ],\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nctx := context.Background()\nclient := copilot.NewClient(nil)\nclient.Start(ctx)\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    Model: \"gpt-5.4\",\n    CustomAgents: []copilot.CustomAgentConfig{\n        {\n            Name:        \"researcher\",\n            DisplayName: \"Research Agent\",\n            Description: \"Explores codebases and answers questions using read-only tools\",\n            Tools:       []string{\"grep\", \"glob\", \"view\"},\n            Prompt:      \"You are a research assistant. Analyze code and answer questions. Do not modify any files.\",\n        },\n        {\n            Name:        \"editor\",\n            DisplayName: \"Editor Agent\",\n            Description: \"Makes targeted code changes\",\n            Tools:       []string{\"view\", \"edit\", \"bash\"},\n            Prompt:      \"You are a code editor. Make minimal, surgical changes to files as requested.\",\n        },\n    },\n    OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {\n        return &rpc.PermissionDecisionApproveOnce{}, nil\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing GitHub.Copilot;\nusing GitHub.Copilot.Rpc;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"gpt-5.4\",\n    CustomAgents = new List<CustomAgentConfig>\n    {\n        new()\n        {\n            Name = \"researcher\",\n            DisplayName = \"Research Agent\",\n            Description = \"Explores codebases and answers questions using read-only tools\",\n            Tools = new List<string> { \"grep\", \"glob\", \"view\" },\n            Prompt = \"You are a research assistant. Analyze code and answer questions. Do not modify any files.\",\n        },\n        new()\n        {\n            Name = \"editor\",\n            DisplayName = \"Editor Agent\",\n            Description = \"Makes targeted code changes\",\n            Tools = new List<string> { \"view\", \"edit\", \"bash\" },\n            Prompt = \"You are a code editor. Make minimal, surgical changes to files as requested.\",\n        },\n    },\n    OnPermissionRequest = (req, inv) =>\n        Task.FromResult(PermissionDecision.ApproveOnce()),\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\ntry (var client = new CopilotClient()) {\n    client.start().get();\n\n    var session = client.createSession(\n        new SessionConfig()\n            .setModel(\"gpt-5.4\")\n            .setCustomAgents(List.of(\n                new CustomAgentConfig()\n                    .setName(\"researcher\")\n                    .setDisplayName(\"Research Agent\")\n                    .setDescription(\"Explores codebases and answers questions using read-only tools\")\n                    .setTools(List.of(\"grep\", \"glob\", \"view\"))\n                    .setPrompt(\"You are a research assistant. Analyze code and answer questions. Do not modify any files.\"),\n                new CustomAgentConfig()\n                    .setName(\"editor\")\n                    .setDisplayName(\"Editor Agent\")\n                    .setDescription(\"Makes targeted code changes\")\n                    .setTools(List.of(\"view\", \"edit\", \"bash\"))\n                    .setPrompt(\"You are a code editor. Make minimal, surgical changes to files as requested.\")\n            ))\n            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n    ).get();\n}\n```\n\n</div>\n\n</div>\n\n## Referência de configuração\n\n| Property                                                                                                                                                                                                | Tipo       | Obrigatório | Description                           |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ----------- | ------------------------------------- |\n| `name`                                                                                                                                                                                                  | `string`   | ✅           | Identificador exclusivo para o agente |\n| `displayName`                                                                                                                                                                                           | `string`   |             |                                       |\n| Nome legível por humanos exibido em eventos                                                                                                                                                             |            |             |                                       |\n| `description`                                                                                                                                                                                           | `string`   |             |                                       |\n| O que o agente faz — ajuda o runtime a selecioná-lo                                                                                                                                                     |            |             |                                       |\n| `tools`                                                                                                                                                                                                 |            |             |                                       |\n| `string[]` ou `null`                                                                                                                                                                                    |            |             |                                       |\n| Nomes de ferramentas que o agente pode usar.                                                                                                                                                            |            |             |                                       |\n| `null` ou omitido = todas as ferramentas                                                                                                                                                                |            |             |                                       |\n| `prompt`                                                                                                                                                                                                | `string`   | ✅           | Comando do sistema ao agente          |\n| `mcpServers`                                                                                                                                                                                            | `object`   |             |                                       |\n| Configurações de servidor MCP específicas para este agente                                                                                                                                              |            |             |                                       |\n| `infer`                                                                                                                                                                                                 | `boolean`  |             |                                       |\n| Se o runtime pode selecionar automaticamente este agente (padrão: `true`)                                                                                                                               |            |             |                                       |\n| `skills`                                                                                                                                                                                                | `string[]` |             |                                       |\n| Nomes de habilidade a serem pré-carregados no contexto do agente na inicialização                                                                                                                       |            |             |                                       |\n| `model`                                                                                                                                                                                                 | `string`   |             |                                       |\n| Identificador de modelo a ser usado enquanto este agente é executado                                                                                                                                    |            |             |                                       |\n| `reasoningEffort`                                                                                                                                                                                       | `string`   |             |                                       |\n| 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) |            |             |                                       |\n\n> \\[!TIP]\n> 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.\n\nDefina `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`.\n\nAlé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.\n\n| Propriedade de configuração da sessão | Tipo     | Description                                                                                                               |\n| ------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |\n| `agent`                               | `string` | Nome do agente personalizado a ser pré-selecionado na criação da sessão. Deve corresponder a um `name` em `customAgents`. |\n\n## Habilidades por agente\n\nVocê 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`.\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills\"],\n    customAgents: [\n        {\n            name: \"security-auditor\",\n            description: \"Security-focused code reviewer\",\n            prompt: \"Focus on OWASP Top 10 vulnerabilities\",\n            skills: [\"security-scan\", \"dependency-check\"],\n        },\n        {\n            name: \"docs-writer\",\n            description: \"Technical documentation writer\",\n            prompt: \"Write clear, concise documentation\",\n            skills: [\"markdown-lint\"],\n        },\n    ],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\nNeste 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.\n\n## Selecionando um agente na criação da sessão\n\nVocê 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`.\n\nIsso é 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.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n<!-- docs-validate: skip -->\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [\n        {\n            name: \"researcher\",\n            prompt: \"You are a research assistant. Analyze code and answer questions.\",\n        },\n        {\n            name: \"editor\",\n            prompt: \"You are a code editor. Make minimal, surgical changes.\",\n        },\n    ],\n    agent: \"researcher\", // Pre-select the researcher agent\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n<!-- docs-validate: skip -->\n\n```python\nsession = await client.create_session(\n    on_permission_request=PermissionHandler.approve_all,\n    custom_agents=[\n        {\n            \"name\": \"researcher\",\n            \"prompt\": \"You are a research assistant. Analyze code and answer questions.\",\n        },\n        {\n            \"name\": \"editor\",\n            \"prompt\": \"You are a code editor. Make minimal, surgical changes.\",\n        },\n    ],\n    agent=\"researcher\",  # Pre-select the researcher agent\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n<!-- docs-validate: skip -->\n\n```golang\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    CustomAgents: []copilot.CustomAgentConfig{\n        {\n            Name:   \"researcher\",\n            Prompt: \"You are a research assistant. Analyze code and answer questions.\",\n        },\n        {\n            Name:   \"editor\",\n            Prompt: \"You are a code editor. Make minimal, surgical changes.\",\n        },\n    },\n    Agent: \"researcher\", // Pre-select the researcher agent\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n<!-- docs-validate: skip -->\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    CustomAgents = new List<CustomAgentConfig>\n    {\n        new() { Name = \"researcher\", Prompt = \"You are a research assistant. Analyze code and answer questions.\" },\n        new() { Name = \"editor\", Prompt = \"You are a code editor. Make minimal, surgical changes.\" },\n    },\n    Agent = \"researcher\", // Pre-select the researcher agent\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setCustomAgents(List.of(\n            new CustomAgentConfig()\n                .setName(\"researcher\")\n                .setPrompt(\"You are a research assistant. Analyze code and answer questions.\"),\n            new CustomAgentConfig()\n                .setName(\"editor\")\n                .setPrompt(\"You are a code editor. Make minimal, surgical changes.\")\n        ))\n        .setAgent(\"researcher\") // Pre-select the researcher agent\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n).get();\n```\n\n</div>\n\n</div>\n\n## Como funciona a delegação de subagente\n\nQuando você envia um prompt para uma sessão com agentes personalizados, o runtime avalia se deseja delegar a um subagente:\n\n1. **Correspondência de intenção** – o runtime analisa o prompt do usuário em relação a `name` e `description` de cada agente\n2. **Seleção de agente**— Se uma correspondência for encontrada e `infer` não for `false`, o runtime selecionará o agente\n3. **Execução isolada** – o sub-agente é executado com seu próprio prompt e conjunto de ferramentas restritas\n4. **Transmissão de eventos** — eventos de ciclo de vida (`subagent.started`, `subagent.completed` etc.) são transmitidos de volta para a sessão pai\n5. **Integração de resultados** – a saída do sub-agente é incorporada à resposta do agente pai\n\n### Controlando a inferência\n\nPor 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:\n\n```typescript\n{\n    name: \"dangerous-cleanup\",\n    description: \"Deletes unused files and dead code\",\n    tools: [\"bash\", \"edit\", \"view\"],\n    prompt: \"You clean up codebases by removing dead code and unused files.\",\n    infer: false, // Only invoked when user explicitly asks for this agent\n}\n```\n\n## Escutar eventos de subagente\n\nQuando 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.\n\nOs 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.\n\n### Tipos de evento\n\n| Acontecimento                                                                                                        | Emitido quando                              | Dados |\n| -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ----- |\n| `subagent.selected`                                                                                                  | O runtime seleciona um agente para a tarefa |       |\n| `agentName`, `agentDisplayName`, `tools`                                                                             |                                             |       |\n| `subagent.started`                                                                                                   | Subagente inicia a execução                 |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, , `agentDescription``model?`                                          |                                             |       |\n| `subagent.completed`                                                                                                 | O subagente foi concluído com êxito         |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, `model?`, , `durationMs?`, `totalTokens?`, `totalToolCalls?`          |                                             |       |\n| `subagent.failed`                                                                                                    | O subagente encontra um erro                |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, `error`, `model?`, `durationMs?`, `totalTokens?`, , `totalToolCalls?` |                                             |       |\n| `subagent.deselected`                                                                                                | O runtime muda seu foco do subagente        | —     |\n\n### Inscrevendo-se para eventos\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nsession.on((event) => {\n    switch (event.type) {\n        case \"subagent.started\":\n            console.log(`▶ Sub-agent started: ${event.data.agentDisplayName}`);\n            console.log(`  Description: ${event.data.agentDescription}`);\n            console.log(`  Tool call ID: ${event.data.toolCallId}`);\n            break;\n\n        case \"subagent.completed\":\n            console.log(`✅ Sub-agent completed: ${event.data.agentDisplayName}`);\n            if (event.data.durationMs !== undefined) console.log(`  Duration: ${event.data.durationMs}ms`);\n            if (event.data.totalTokens !== undefined) console.log(`  Tokens: ${event.data.totalTokens}`);\n            if (event.data.totalToolCalls !== undefined) console.log(`  Tool calls: ${event.data.totalToolCalls}`);\n            break;\n\n        case \"subagent.failed\":\n            console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);\n            console.log(`  Error: ${event.data.error}`);\n            if (event.data.durationMs !== undefined) console.log(`  Duration: ${event.data.durationMs}ms`);\n            break;\n\n        case \"subagent.selected\":\n            console.log(`🎯 Agent selected: ${event.data.agentDisplayName}`);\n            console.log(`  Tools: ${event.data.tools?.join(\", \") ?? \"all\"}`);\n            break;\n\n        case \"subagent.deselected\":\n            console.log(\"↩ Agent deselected, returning to parent\");\n            break;\n    }\n});\n\nconst response = await session.sendAndWait({\n    prompt: \"Research how authentication works in this codebase\",\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\ndef handle_event(event):\n    if event.type == \"subagent.started\":\n        print(f\"▶ Sub-agent started: {event.data.agent_display_name}\")\n        print(f\"  Description: {event.data.agent_description}\")\n    elif event.type == \"subagent.completed\":\n        print(f\"✅ Sub-agent completed: {event.data.agent_display_name}\")\n    elif event.type == \"subagent.failed\":\n        print(f\"❌ Sub-agent failed: {event.data.agent_display_name}\")\n        print(f\"  Error: {event.data.error}\")\n    elif event.type == \"subagent.selected\":\n        tools = event.data.tools or \"all\"\n        print(f\"🎯 Agent selected: {event.data.agent_display_name} (tools: {tools})\")\n\nunsubscribe = session.on(handle_event)\n\nresponse = await session.send_and_wait(\"Research how authentication works in this codebase\")\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession.On(func(event copilot.SessionEvent) {\n    switch d := event.Data.(type) {\n    case *copilot.SubagentStartedData:\n        fmt.Printf(\"▶ Sub-agent started: %s\\n\", d.AgentDisplayName)\n        fmt.Printf(\"  Description: %s\\n\", d.AgentDescription)\n        fmt.Printf(\"  Tool call ID: %s\\n\", d.ToolCallID)\n    case *copilot.SubagentCompletedData:\n        fmt.Printf(\"✅ Sub-agent completed: %s\\n\", d.AgentDisplayName)\n    case *copilot.SubagentFailedData:\n        fmt.Printf(\"❌ Sub-agent failed: %s — %v\\n\", d.AgentDisplayName, d.Error)\n    case *copilot.SubagentSelectedData:\n        fmt.Printf(\"🎯 Agent selected: %s\\n\", d.AgentDisplayName)\n    }\n})\n\n_, err := session.SendAndWait(ctx, copilot.MessageOptions{\n    Prompt: \"Research how authentication works in this codebase\",\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing var subscription = session.On<SessionEvent>(evt =>\n{\n    switch (evt)\n    {\n        case SubagentStartedEvent started:\n            Console.WriteLine($\"▶ Sub-agent started: {started.Data.AgentDisplayName}\");\n            Console.WriteLine($\"  Description: {started.Data.AgentDescription}\");\n            Console.WriteLine($\"  Tool call ID: {started.Data.ToolCallId}\");\n            break;\n        case SubagentCompletedEvent completed:\n            Console.WriteLine($\"✅ Sub-agent completed: {completed.Data.AgentDisplayName}\");\n            break;\n        case SubagentFailedEvent failed:\n            Console.WriteLine($\"❌ Sub-agent failed: {failed.Data.AgentDisplayName} — {failed.Data.Error}\");\n            break;\n        case SubagentSelectedEvent selected:\n            Console.WriteLine($\"🎯 Agent selected: {selected.Data.AgentDisplayName}\");\n            break;\n    }\n});\n\nawait session.SendAndWaitAsync(new MessageOptions\n{\n    Prompt = \"Research how authentication works in this codebase\"\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nsession.on(event -> {\n    if (event instanceof SubagentStartedEvent e) {\n        System.out.println(\"▶ Sub-agent started: \" + e.getData().agentDisplayName());\n        System.out.println(\"  Description: \" + e.getData().agentDescription());\n        System.out.println(\"  Tool call ID: \" + e.getData().toolCallId());\n    } else if (event instanceof SubagentCompletedEvent e) {\n        System.out.println(\"✅ Sub-agent completed: \" + e.getData().agentName());\n    } else if (event instanceof SubagentFailedEvent e) {\n        System.out.println(\"❌ Sub-agent failed: \" + e.getData().agentName());\n        System.out.println(\"  Error: \" + e.getData().error());\n    } else if (event instanceof SubagentSelectedEvent e) {\n        System.out.println(\"🎯 Agent selected: \" + e.getData().agentDisplayName());\n    } else if (event instanceof SubagentDeselectedEvent e) {\n        System.out.println(\"↩ Agent deselected, returning to parent\");\n    }\n});\n\nvar response = session.sendAndWait(\n    new MessageOptions().setPrompt(\"Research how authentication works in this codebase\")\n).get();\n```\n\n</div>\n\n</div>\n\n## Construir uma interface de usuário de árvore de agente\n\nEventos de subagente incluem campos `toolCallId` que permitem reconstruir a árvore de execução. Aqui está um padrão para acompanhar a atividade do agente:\n\n```typescript\ninterface AgentNode {\n    toolCallId: string;\n    name: string;\n    displayName: string;\n    status: \"running\" | \"completed\" | \"failed\";\n    error?: string;\n    startedAt: Date;\n    completedAt?: Date;\n}\n\nconst agentTree = new Map<string, AgentNode>();\n\nsession.on((event) => {\n    if (event.type === \"subagent.started\") {\n        agentTree.set(event.data.toolCallId, {\n            toolCallId: event.data.toolCallId,\n            name: event.data.agentName,\n            displayName: event.data.agentDisplayName,\n            status: \"running\",\n            startedAt: new Date(event.timestamp),\n        });\n    }\n\n    if (event.type === \"subagent.completed\") {\n        const node = agentTree.get(event.data.toolCallId);\n        if (node) {\n            node.status = \"completed\";\n            node.completedAt = new Date(event.timestamp);\n        }\n    }\n\n    if (event.type === \"subagent.failed\") {\n        const node = agentTree.get(event.data.toolCallId);\n        if (node) {\n            node.status = \"failed\";\n            node.error = event.data.error;\n            node.completedAt = new Date(event.timestamp);\n        }\n    }\n\n    // Render your UI with the updated tree\n    renderAgentTree(agentTree);\n});\n```\n\n## Ferramentas de escopo por agente\n\nUse a `tools` propriedade para restringir quais ferramentas um agente pode acessar. Isso é essencial para a segurança e para manter os agentes focados:\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [\n        {\n            name: \"reader\",\n            description: \"Read-only exploration of the codebase\",\n            tools: [\"grep\", \"glob\", \"view\"],  // No write access\n            prompt: \"You explore and analyze code. Never suggest modifications directly.\",\n        },\n        {\n            name: \"writer\",\n            description: \"Makes code changes\",\n            tools: [\"view\", \"edit\", \"bash\"],   // Write access\n            prompt: \"You make precise code changes as instructed.\",\n        },\n        {\n            name: \"unrestricted\",\n            description: \"Full access agent for complex tasks\",\n            tools: null,                        // All tools available\n            prompt: \"You handle complex multi-step tasks using any available tools.\",\n        },\n    ],\n});\n```\n\n> \\[!NOTE]\n> 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.\n\n## Ferramentas exclusivas do agente\n\nUse 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.\n\nIsso é útil quando:\n\n* Determinadas ferramentas geram grandes quantidades de contexto que sobrecarregariam o agente principal\n* Você deseja que o agente principal atue como um orquestrador, delegando trabalho pesado a sub-agentes especializados\n* Você precisa de separação estrita entre orquestração e execução\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient, defineTool, approveAll } from \"@github/copilot-sdk\";\nimport { z } from \"zod\";\n\nconst heavyContextTool = defineTool(\"analyze-codebase\", {\n    description: \"Performs deep analysis of the codebase, generating extensive context\",\n    parameters: z.object({ query: z.string() }),\n    handler: async ({ query }) => {\n        // ... expensive analysis that returns lots of data\n        return { analysis: \"...\" };\n    },\n});\n\nconst session = await client.createSession({\n    tools: [heavyContextTool],\n    defaultAgent: {\n        excludedTools: [\"analyze-codebase\"],\n    },\n    customAgents: [\n        {\n            name: \"researcher\",\n            description: \"Deep codebase analysis agent with access to heavy-context tools\",\n            tools: [\"analyze-codebase\"],\n            prompt: \"You perform thorough codebase analysis using the analyze-codebase tool.\",\n        },\n    ],\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient\nfrom copilot.tools import Tool\n\nheavy_tool = Tool(\n    name=\"analyze-codebase\",\n    description=\"Performs deep analysis of the codebase\",\n    handler=analyze_handler,\n    parameters={\"type\": \"object\", \"properties\": {\"query\": {\"type\": \"string\"}}},\n)\n\nsession = await client.create_session(\n    tools=[heavy_tool],\n    default_agent={\"excluded_tools\": [\"analyze-codebase\"]},\n    custom_agents=[\n        {\n            \"name\": \"researcher\",\n            \"description\": \"Deep codebase analysis agent\",\n            \"tools\": [\"analyze-codebase\"],\n            \"prompt\": \"You perform thorough codebase analysis.\",\n        },\n    ],\n    on_permission_request=approve_all,\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n<!-- docs-validate: skip -->\n\n```golang\nsession, err := client.CreateSession(ctx, &copilot.SessionConfig{\n    Tools: []copilot.Tool{heavyTool},\n    DefaultAgent: &copilot.DefaultAgentConfig{\n        ExcludedTools: []string{\"analyze-codebase\"},\n    },\n    CustomAgents: []copilot.CustomAgentConfig{\n        {\n            Name:        \"researcher\",\n            Description: \"Deep codebase analysis agent\",\n            Tools:       []string{\"analyze-codebase\"},\n            Prompt:      \"You perform thorough codebase analysis.\",\n        },\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"csharp\" data-label=\"C#\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">C#</div>\n\n<!-- docs-validate: skip -->\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    Tools = [analyzeCodebaseTool],\n    DefaultAgent = new DefaultAgentConfig\n    {\n        ExcludedTools = [\"analyze-codebase\"],\n    },\n    CustomAgents =\n    [\n        new CustomAgentConfig\n        {\n            Name = \"researcher\",\n            Description = \"Deep codebase analysis agent\",\n            Tools = [\"analyze-codebase\"],\n            Prompt = \"You perform thorough codebase analysis.\",\n        },\n    ],\n});\n```\n\n</div>\n\n</div>\n\n### Como funciona\n\nFerramentas listadas em `defaultAgent.excludedTools`:\n\n1. **Estão registrados**– seus manipuladores estão disponíveis para execução\n2. **Estão ocultos** na lista de ferramentas do agente principal– a LLM não os verá nem os chamará diretamente\n3. **Permanecer disponível** para qualquer subagente personalizado que os inclua em sua `tools` matriz\n\n### Interação com outros filtros de ferramenta\n\n`defaultAgent.excludedTools` é ortogonal a `availableTools` e `excludedTools` no nível da sessão:\n\n| Filtro                       | Scope                    | Efeito                                                                                      |\n| ---------------------------- | ------------------------ | ------------------------------------------------------------------------------------------- |\n| `availableTools`             | Em toda a sessão         | Lista de permissões – somente essas ferramentas existem para qualquer pessoa                |\n| `excludedTools`              | Em toda a sessão         | Lista de bloqueios – essas ferramentas são bloqueadas para todos                            |\n| `defaultAgent.excludedTools` | Somente agente principal | Essas ferramentas estão ocultas do agente principal, mas estão disponíveis para sub-agentes |\n\nPrecedência:\n\n1. O nível `availableTools`/`excludedTools` da sessão é aplicado primeiro (globalmente)\n2. `defaultAgent.excludedTools` é aplicado na parte superior, restringindo ainda mais apenas o agente principal\n\n> \\[!NOTE]\n> 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.\n\n## Anexando servidores MCP a agentes\n\nCada agente personalizado pode ter seus próprios servidores MCP (Model Context Protocol), dando-lhe acesso a fontes de dados especializadas:\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [\n        {\n            name: \"db-analyst\",\n            description: \"Analyzes database schemas and queries\",\n            prompt: \"You are a database expert. Use the database MCP server to analyze schemas.\",\n            mcpServers: {\n                \"database\": {\n                    command: \"npx\",\n                    args: [\"-y\", \"@modelcontextprotocol/server-postgres\", \"postgresql://localhost/mydb\"],\n                },\n            },\n        },\n    ],\n});\n```\n\n## Padrões e melhores práticas\n\n### Emparelhar um pesquisador com um editor\n\nUm 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.\n\n```typescript\ncustomAgents: [\n    {\n        name: \"researcher\",\n        description: \"Analyzes code structure, finds patterns, and answers questions\",\n        tools: [\"grep\", \"glob\", \"view\"],\n        prompt: \"You are a code analyst. Thoroughly explore the codebase to answer questions.\",\n    },\n    {\n        name: \"implementer\",\n        description: \"Implements code changes based on analysis\",\n        tools: [\"view\", \"edit\", \"bash\"],\n        prompt: \"You make minimal, targeted code changes. Always verify changes compile.\",\n    },\n]\n```\n\n### Manter descrições de agente específicas\n\nO runtime usa o `description` para corresponder à intenção do usuário. Descrições vagas levam à má delegação:\n\n```typescript\n// ❌ Too vague — runtime can't distinguish from other agents\n{ description: \"Helps with code\" }\n\n// ✅ Specific — runtime knows when to delegate\n{ description: \"Analyzes Python test coverage and identifies untested code paths\" }\n```\n\n### Lidar com falhas de forma elegante\n\nSub-agentes podem falhar. Sempre ouça eventos `subagent.failed` e manipule-os em seu aplicativo:\n\n```typescript\nsession.on((event) => {\n    if (event.type === \"subagent.failed\") {\n        logger.error(`Agent ${event.data.agentName} failed: ${event.data.error}`);\n        // Show error in UI, retry, or fall back to parent agent\n    }\n});\n```"}