{"meta":{"title":"Angepasste Agents und Orchestrierung von Unteragenten","intro":"Definieren Sie spezialisierte Agents mit bereichsbezogenen Tools und Eingabeaufforderungen, und lassen Sie Copilot sie innerhalb einer einzigen Sitzung als Unter-Agents koordinieren. Zum parallelen Ausführen mehrerer Sub-Agents siehe Flottenmodus.","product":"GitHub Copilot","breadcrumbs":[{"href":"/de/copilot","title":"GitHub Copilot"},{"href":"/de/copilot/how-tos","title":"Vorgehensweisen"},{"href":"/de/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/de/copilot/how-tos/copilot-sdk/features","title":"Funktionen"},{"href":"/de/copilot/how-tos/copilot-sdk/features/custom-agents","title":"Benutzerdefinierte Agenten"}],"documentType":"article"},"body":"# Angepasste Agents und Orchestrierung von Unteragenten\n\nDefinieren Sie spezialisierte Agents mit bereichsbezogenen Tools und Eingabeaufforderungen, und lassen Sie Copilot sie innerhalb einer einzigen Sitzung als Unter-Agents koordinieren. Zum parallelen Ausführen mehrerer Sub-Agents siehe Flottenmodus.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Übersicht\n\nAngepasste Agents sind schlanke Agent-Definitionen, die Sie einer Sitzung zuordnen. Jeder Agent verfügt über eine eigene Systemaufforderung, Tooleinschränkungen und optionale MCP-Server. Wenn die Anfrage eines Benutzers mit dem Fachwissen eines Agenten übereinstimmt, delegiert die Copilot-Laufzeit automatisch an diesen Agenten als **Unter-Agenten** und führt ihn in einem isolierten Kontext aus, während Lebenszyklusereignisse an die übergeordnete Sitzung zurückgesendet werden.\n\n![Diagramm: Flussdiagramm mit dem beschriebenen Prozess.](/assets/images/help/copilot/copilot-sdk/features-custom-agents-diagram-0.png)\n\n| Konzept                       | Description                                                                                                     |\n| ----------------------------- | --------------------------------------------------------------------------------------------------------------- |\n| **Benutzerdefinierter Agent** | Eine benannte Agent-Konfiguration mit einer eigenen Eingabeaufforderung und einem eigenen Toolsatz              |\n| **Unter-Agent**               | Ein benutzerdefinierter Agent, der von der Laufzeit aufgerufen wird, um einen Teil einer Aufgabe zu verarbeiten |\n| **Schlussfolgerung**          | Die Fähigkeit der Runtime zur automatischen Auswahl eines Agents auf der Grundlage des Intents des Benutzers    |\n| **Übergeordnete Sitzung**     | Die Sitzung, die den Teilagent erzeugte, empfängt alle Lebenszyklus-Ereignisse                                  |\n\n## Definieren von benutzerdefinierten Agents\n\nÜbergeben Sie `customAgents` beim Erstellen einer Sitzung. Jeder Agent benötigt mindestens ein `name` und ein `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## Konfigurationsreferenz\n\n| Eigentum                                                                                                                                                                                                                            | Typ        | Erforderlich | Description                          |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------ | ------------------------------------ |\n| `name`                                                                                                                                                                                                                              | `string`   | ✅            | Eindeutiger Bezeichner für den Agent |\n| `displayName`                                                                                                                                                                                                                       | `string`   |              |                                      |\n| Lesbarer Name, der in Ereignissen angezeigt wird                                                                                                                                                                                    |            |              |                                      |\n| `description`                                                                                                                                                                                                                       | `string`   |              |                                      |\n| Was der Agent tut - hilft der Runtime bei der Auswahl des Agenten                                                                                                                                                                   |            |              |                                      |\n| `tools`                                                                                                                                                                                                                             |            |              |                                      |\n| `string[]` oder `null`                                                                                                                                                                                                              |            |              |                                      |\n| Toolnamen, die der Agent verwenden kann.                                                                                                                                                                                            |            |              |                                      |\n| `null` oder weggelassen = alle Tools                                                                                                                                                                                                |            |              |                                      |\n| `prompt`                                                                                                                                                                                                                            | `string`   | ✅            | Systemaufforderung für den Agent     |\n| `mcpServers`                                                                                                                                                                                                                        | `object`   |              |                                      |\n| MCP-Serverkonfigurationen, die für diesen Agent spezifisch sind                                                                                                                                                                     |            |              |                                      |\n| `infer`                                                                                                                                                                                                                             | `boolean`  |              |                                      |\n| Gibt an, ob die Laufzeit diesen Agent automatisch auswählen kann (Standard: `true`)                                                                                                                                                 |            |              |                                      |\n| `skills`                                                                                                                                                                                                                            | `string[]` |              |                                      |\n| Skill-Namen, die beim Start in den Kontext des Agents vorgeladen werden                                                                                                                                                             |            |              |                                      |\n| `model`                                                                                                                                                                                                                             | `string`   |              |                                      |\n| Modellbezeichner, der verwendet werden soll, während dieser Agent ausgeführt wird                                                                                                                                                   |            |              |                                      |\n| `reasoningEffort`                                                                                                                                                                                                                   | `string`   |              |                                      |\n| Überlegungsaufwand, der während der Ausführung dieses Agents verwendet werden soll. Wenn dies weggelassen wird, sendet das SDK keine Agent-spezifische Überschreibung, und die Laufzeit löst den Aufwand auf (siehe Hinweis unten). |            |              |                                      |\n\n> \\[!TIP]\n> Ein gutes `description` hilft der Laufzeit, den Intent des Benutzers dem richtigen Agenten zuzuordnen. Seien Sie spezifisch für das Fachwissen und die Fähigkeiten des Agenten.\n\nLegen Sie `model` und `reasoningEffort` fest, um die Modelleinstellungen der übergeordneten Sitzung zu überschreiben, während ein benutzerdefinierter Agent ausgeführt wird. Wenn `reasoningEffort` nicht angegeben wird, sendet das SDK keine agentenspezifische Überschreibung, und die Laufzeit bestimmt den Aufwand anhand ihrer eigenen Prioritätsreihenfolge: Eine Clientoption pro Aufruf, die Standardeinstellung des aufgelösten Modells oder die Agentdefinition haben jeweils Vorrang; andernfalls übernimmt die Laufzeit den Aufwand der übergeordneten Sitzung nur dann, wenn der Subagent dasselbe Modell wie die übergeordnete Sitzung verwendet. Wenn der Subagent zu einem anderen Modell aufgelöst wird, greift er auf den Standardwert des Modells zurück, anstatt den Aufwand des übergeordneten Elements zu erben. Python verwendet `reasoning_effort`, .NET verwendet `ReasoningEffort`, Go verwendet `ReasoningEffort`, Java verwendet `setReasoningEffort`, und Rust verwendet `with_reasoning_effort`.\n\nZusätzlich zur oben aufgeführten Konfiguration pro Agent können Sie für die `agent` selbst festlegen\\*\\*\\*\\*, dass sie vorwählt, welcher benutzerdefinierte Agent aktiv ist, wenn die Sitzung gestartet wird. Siehe [\"Auswählen eines Agents bei der Sitzungserstellung](#selecting-an-agent-at-session-creation) \" weiter unten.\n\n| Sitzungskonfigurationseigenschaft | Typ      | Description                                                                                                                                               |\n| --------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `agent`                           | `string` | Name des benutzerdefinierten Agents, der bei der Sitzungserstellung vorab ausgewählt werden soll. Muss mit einem `name` in `customAgents` übereinstimmen. |\n\n## Fähigkeiten pro Agent\n\nSie können Fähigkeiten mithilfe der `skills` Eigenschaft in den Kontext eines Agents vorab laden. Wenn angegeben, wird der **vollständige Inhalt** jeder aufgeführten Fähigkeit beim Start eifrig in den Kontext des Agenten eingefügt – der Agent muss kein Fähigkeitstool aufrufen; die Anweisungen sind bereits vorhanden. Fähigkeiten sind **optional**: Agent erhalten standardmäßig keine Fähigkeiten, und Unteragenten erben keine Fähigkeiten vom übergeordneten Agenten. Qualifikationsnamen werden auf Sitzungsebene `skillDirectories`aufgelöst.\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\nIn diesem Beispiel startet `security-auditor` mit `security-scan` und `dependency-check`, die bereits in seinen Kontext injiziert wurden, während `docs-writer` mit `markdown-lint` startet. Ein Agent ohne Feld `skills` erhält keinen Qualifikationsinhalt.\n\n## Auswählen eines Agents bei der Sitzungserstellung\n\nSie können `agent` in die Sitzungskonfiguration einfügen, um vorab auszuwählen, welcher benutzerdefinierte Agent aktiv sein soll, wenn die Sitzung beginnt. Der Wert muss mit dem `name` eines der in `customAgents` definierten Agenten übereinstimmen.\n\nDies entspricht dem Aufrufen `session.rpc.agent.select()` nach der Erstellung, vermeidet aber den zusätzlichen API-Aufruf und stellt sicher, dass der Agent von der ersten Eingabeaufforderung aus aktiv ist.\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## Funktionsweise der Sub-Agent-Delegierung\n\nWenn Sie eine Eingabeaufforderung an eine Sitzung mit benutzerdefinierten Agents senden, wertet die Laufzeit aus, ob sie an einen Unter-Agent delegiert werden soll:\n\n1. **Intent-Abgleich**-Die Runtime analysiert den Prompt des Benutzers mit den `name` und `description`Agenten\n2. **-Agentenauswahl**-Wenn eine Übereinstimmung gefunden wird und `infer` nicht `false` ist, wählt die Runtime den Agenten aus\n3. **Isolierte Ausführung** – Der Unter-Agent wird mit einer eigenen Eingabeaufforderung und einem eingeschränkten Toolsatz ausgeführt.\n4. **Ereignisstreaming** – Lebenszyklusereignisse (`subagent.started`, `subagent.completed`usw.) werden zurück zur übergeordneten Sitzung gestreamt\n5. **Ergebnisintegration** – Die Ausgabe des Unter-Agents wird in die Antwort des übergeordneten Agents integriert.\n\n### Steuern von Rückschlüssen\n\nStandardmäßig sind alle benutzerdefinierten Agents für die automatische Auswahl (`infer: true`) verfügbar. Um zu verhindern, dass die Laufzeit automatisch einen Agenten auswählt – nützlich für Agenten, die nur über explizite Benutzeranforderungen aufgerufen werden sollen, legen Sie `infer: false` fest:\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## Abhören von Sub-Agent-Ereignissen\n\nWenn ein Sub-Agent ausgeführt wird, sendet die übergeordnete Sitzung Lebenszyklusereignisse aus. Abonnieren Sie diese Ereignisse, um UIs zu erstellen, die Agentaktivitäten visualisieren.\n\nVon Unter-Agents stammende Sitzungsereignisse nutzen den Stream der übergeordneten Sitzung gemeinsam und enthalten `agentId` auf Umschlagebene. Stamm-/Haupt-Agent-Ereignisse und Ereignisse auf Sitzungsebene lassen `agentId` weg, sodass Renderer die übergeordnete Antwort von Unter-Agent-Ablaufverfolgungen getrennt halten können, indem sie den Ereignisumschlag überprüfen.\n\n### Ereignistypen\n\n| Event                                                                                                                | Wird ausgegeben, wenn                           | Daten |\n| -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ----- |\n| `subagent.selected`                                                                                                  | Runtime wählt einen Agenten für die Aufgabe aus |       |\n| `agentName`, `agentDisplayName``tools`                                                                               |                                                 |       |\n| `subagent.started`                                                                                                   | Der Unter-Agent beginnt mit der Ausführung.     |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, `agentDescription`, , `model?`                                        |                                                 |       |\n| `subagent.completed`                                                                                                 | Sub-Agent schließt erfolgreich ab               |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, `model?`, `durationMs?`, , `totalTokens?`, `totalToolCalls?`          |                                                 |       |\n| `subagent.failed`                                                                                                    | Bei einem Unteragent tritt ein Fehler auf.      |       |\n| `toolCallId`, `agentName`, `agentDisplayName`, `error`, , `model?`, `durationMs?`, `totalTokens?`, `totalToolCalls?` |                                                 |       |\n| `subagent.deselected`                                                                                                | Runtime schaltet weg vom Sub-Agenten            | —     |\n\n### Abonnieren von Ereignissen\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## Erstellen einer Agentstruktur-UI\n\nSub-Agent-Ereignisse umfassen `toolCallId` Felder, mit denen Sie den Ausführungsbaum rekonstruieren können. Hier ist ein Muster für die Nachverfolgung von Agentaktivitäten:\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## Scoping Tools pro Agent\n\nVerwenden Sie die `tools` Eigenschaft, um einzuschränken, auf welche Tools ein Agent zugreifen kann. Dies ist wesentlich für die Sicherheit und dafür, dass Agenten fokussiert bleiben.\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> Wenn `tools``null` ist oder weggelassen wird, erbt der Agent den Zugriff auf alle in der Sitzung konfigurierten Tools. Verwenden Sie explizite Toollisten, um das Prinzip der geringsten Berechtigungen zu erzwingen.\n\n## Exklusive Tools für Agenten\n\nVerwenden Sie die Eigenschaft `defaultAgent` in der Sitzungskonfiguration, um bestimmte Tools für den Standard-Agent auszublenden (den integrierten Agent, der die Interaktionsrunden verarbeitet, wenn kein benutzerdefinierter Agent ausgewählt ist). Dadurch wird der Haupt-Agent gezwungen, sich an Unter-Agents zu delegieren, wenn die Funktionen dieser Tools benötigt werden, damit der Kontext des Haupt-Agents sauber bleibt.\n\nDiese Möglichkeit ist in folgenden Situationen nützlich:\n\n* Bestimmte Tools generieren große Kontextmengen, die den Hauptagenten überwältigen würden\n* Sie möchten, dass der Hauptagent als Orchestrator fungiert und schwere Arbeit an spezialisierte Sub-Agents delegiert.\n* Sie benötigen eine strikte Trennung zwischen Orchestrierung und Ausführung\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### So funktioniert es\n\nIn `defaultAgent.excludedTools` aufgeführte Tools:\n\n1. **Sind registriert** – ihre Handler sind für die Ausführung verfügbar.\n2. **Sind** in der Toolliste des Haupt-Agents ausgeblendet – die LLM wird sie nicht direkt sehen oder anrufen.\n3. **Bleiben Sie** für jeden benutzerdefinierten Unter-Agent verfügbar, der sie in das `tools` Array einschließt.\n\n### Interaktion mit anderen Toolfiltern\n\n`defaultAgent.excludedTools` ist orthogonal zu `availableTools` und `excludedTools` auf Sitzungsebene:\n\n| Filter                       | Geltungsbereich | Auswirkung                                                                           |\n| ---------------------------- | --------------- | ------------------------------------------------------------------------------------ |\n| `availableTools`             | Sitzungsweit    | Zulassungsliste – nur diese Tools sind für jeden vorhanden                           |\n| `excludedTools`              | Sitzungsweit    | Sperrliste – diese Tools werden für alle blockiert.                                  |\n| `defaultAgent.excludedTools` | Nur Hauptagent  | Diese Werkzeuge sind für den Hauptagenten verborgen, aber für Unteragenten verfügbar |\n\nVorrang:\n\n1. Sitzungsebene `availableTools`/`excludedTools` wird zuerst (global) angewendet\n2. `defaultAgent.excludedTools` wird zusätzlich angewendet, wodurch nur der Hauptagent weiter eingeschränkt wird\n\n> \\[!NOTE]\n> Wenn sich ein Tool sowohl in `excludedTools` (auf Sitzungsebene) als auch in `defaultAgent.excludedTools` befindet, hat der Ausschluss auf Sitzungsebene Vorrang – das Tool ist für niemanden verfügbar.\n\n## Anfügen von MCP-Servern an Agenten\n\nJeder benutzerdefinierte Agent kann über eigene MCP-Server (Model Context Protocol) verfügen, sodass er Zugriff auf spezialisierte Datenquellen erhält:\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## Muster und bewährte Methoden\n\n### Koppeln eines Forschers mit einem Editor\n\nEin gängiges Muster ist die Definition eines schreibgeschützten Recherche-Agenten und eines schreibfähigen Editor-Agenten. Die Laufzeit delegiert Explorationsaufgaben an den Forscher und Änderungsaufgaben an den 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### Agentbeschreibungen spezifisch beibehalten\n\nDie Laufzeit verwendet `description`, um die Absicht des Benutzers zu erkennen. Vage Beschreibungen führen zu einer schlechten Aufgabenzuweisung.\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### Fehler geschickt bewältigen\n\nUnter-Agents können fehlschlagen. Hören Sie immer auf `subagent.failed`-Ereignisse und behandeln Sie diese in Ihrer Anwendung:\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```"}