Примечание.
Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.
Кастомные агенты — это лёгкие определения агента, которые вы прикрепляете к сессии. У каждого агента есть собственный системный запрос, ограничения инструментов и опциональные MCP-серверы. Когда запрос пользователя совпадает с экспертизой агента, Второй пилот SDK среда выполнения автоматически делегирует данные этому агенту как подагенту — запуская его в изолированном контексте и транслируя события жизненного цикла обратно в родительскую сессию. Для визуального обзора процесса делегирования см. репозиторийgithub/copilot-sdk.
| Концепция | Описание |
|---|
**Таможенный агент** | Конфиг именованного агента с собственной подсказкой и набором инструментов |
| Субагент | Пользовательский агент, вызванный временем выполнения для обработки части задачи | | Вывод | Возможность работы автоматически выбирать агент на основе намерений пользователя | | Родительская сессия | Сессия, породившая субагента; принимает все события жизненного цикла |
Определение пользовательских агентов
Проходите customAgents при создании сессии. Минимум каждому агенту нужно и name``prompt.
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-4.1",
customAgents: [
{
name: "researcher",
displayName: "Research Agent",
description: "Explores codebases and answers questions using read-only tools",
tools: ["grep", "glob", "view"],
prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
name: "editor",
displayName: "Editor Agent",
description: "Makes targeted code changes",
tools: ["view", "edit", "bash"],
prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
},
],
onPermissionRequest: async () => ({ kind: "approved" }),
});
Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Справочник по конфигурации
| Недвижимость | Тип | Обязательный | Описание |
|---|---|---|---|
name | string | ✅ | Уникальный идентификатор агента |
displayName | string | ||
| Имя, читаемое человеком в событиях | |||
description | string | ||
| То, что делает агент — помогает процессу выполнения выбрать его | |||
tools |
`string[]` или `null` |
| Названия инструментов, которые агент может использовать.
null или опущено = все инструменты |
| prompt | string | ✅ | Системный запрос для агента |
| mcpServers | object |
| Конфигурации серверов MCP, специфичные для этого агента |
| infer | boolean |
| Может ли среда выполнения автоматически выбирать этот агент (по умолчанию: true) |
Совет
Хороший description помогает во время выполнения сопоставить пользовательские намерения с нужным агентом. Будьте конкретны в отношении экспертизы и возможностей агента.
Помимо настройки для каждого агента, вы можете заранее agent выбрать в конфигурации сессии заранее выбрать, какой пользовательский агент будет активен при старте сессии.
| Свойство конфигурации сессии | Тип | Описание |
|---|---|---|
agent | string | Имя пользовательского агента для предварительного выбора при создании сессии. Должно совпадать с a name в customAgents. |
Выбор агента при создании сессии
Вы можете ввести agent конфигурацию сессии, чтобы предопределить, какой пользовательский агент должен быть активен при старте сессии. Значение должно совпадать name с значением одного из агентов, определённых в customAgents.
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
});
Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Как работает делегирование субагентов
Когда вы отправляете запрос в сессию с пользовательскими агентами, среда выполнения оценивает, стоит ли делегировать подагенту:
-
**Сопоставление намерений** — Runtime анализирует подсказки пользователя по сравнению с запросами `name` каждого агента и `description` -
**Выбор агента** — если совпадение найдено, `infer` но нет `false`, время выполнения выбирает агента -
**Изолированное выполнение** — подагент работает со своим собственным подсказкой и набором ограниченных инструментов -
**Потоковая трансляция событий** — события жизненного цикла (`subagent.started`, `subagent.completed`и т.д.) возвращаются в родительскую сессию -
**Интеграция результатов** — выход субагента интегрируется в ответ родительского агента
Контролирующий вывод
По умолчанию все пользовательские агенты доступны для автоматического выбора (infer: true). Настройте infer: false так, чтобы предотвращать автоматический выбор агента во время выполнения — полезно для агентов, которые вы хотите вызвать только через явные пользовательские запросы:
{
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
}
Прослушивание событий субагентов
Когда работает субагент, родительская сессия генерирует события жизненного цикла. Подпишитесь на эти события, чтобы создавать интерфейсы, визуализирующие активность агентов.
Типы событий
| Event | Излучается, когда | Данные |
|---|---|---|
subagent.selected | Runtime выбирает агента для задачи |
`agentName`, , `agentDisplayName``tools` |
| subagent.started | Субагент начинает исполнение |
toolCallId, , agentName``agentDisplayName``agentDescription |
| subagent.completed | Субагент успешно завершает |
toolCallId, , agentName``agentDisplayName |
| subagent.failed | Субагент сталкивается с ошибкой |
toolCallId, , agentName``agentDisplayName``error |
| subagent.deselected | Runtime переключается от субагента | — |
Подписка на события
session.on((event) => {
switch (event.type) {
case "subagent.started":
console.log(`▶ Sub-agent started: ${event.data.agentDisplayName}`);
console.log(` Description: ${event.data.agentDescription}`);
console.log(` Tool call ID: ${event.data.toolCallId}`);
break;
case "subagent.completed":
console.log(`✅ Sub-agent completed: ${event.data.agentDisplayName}`);
break;
case "subagent.failed":
console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);
console.log(` Error: ${event.data.error}`);
break;
case "subagent.selected":
console.log(`🎯 Agent selected: ${event.data.agentDisplayName}`);
console.log(` Tools: ${event.data.tools?.join(", ") ?? "all"}`);
break;
case "subagent.deselected":
console.log("↩ Agent deselected, returning to parent");
break;
}
});
const response = await session.sendAndWait({
prompt: "Research how authentication works in this codebase",
});
Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Создание интерфейса дерева агентов
События субагента включают toolCallId поля, позволяющие восстановить дерево исполнения. Вот схема отслеживания активности агентов:
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);
});
Инструменты для определения обхвата для каждого агента
Используйте tools это свойство, чтобы ограничить, к какому инструменту может получить доступ агент. Это важно для безопасности и для поддержания концентрации агентов:
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.",
},
],
});
Примечание.
Когда tools есть null или нет, агент наследует доступ ко всем инструментам, настроенным на сессии. Используйте явные списки инструментов для соблюдения принципа наименьшей привилегии.
Подключение MCP-серверов к агентам
Каждый пользовательский агент может иметь собственные серверы MCP (Model Context Protocol), что даёт доступ к специализированным источникам данных:
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"],
},
},
},
],
});
Шаблоны и рекомендации
Объедините исследователя с редактором
Распространённый шаблон — определить агент-исследователь только для чтения и агент редактора с способностью записи. В процессе выполнения задачи по исследованию поручены исследователю, а задачи по модификации — редактору:
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.",
},
]
Держите описание агентов конкретными
В процессе description выполнения используется функция, чтобы соответствовать намерению пользователя. Расплывчатые описания приводят к плохому делегированию:
// ❌ 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" }
Корректная обработка сбоев
Субагенты могут провалиться. Всегда прислушивайтесь к subagent.failed событиям и решайте их в вашем приложении:
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
}
});