Примечание.
Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.
Когда вы создаёте сессию, Второй пилот SDK сохраняется история разговоров, состояние инструмента и контекст планирования. По умолчанию это состояние остаётся в памяти и исчезает после окончания сессии. С включенной устойчивостью вы можете возобновлять сессии при перезапусках, миграциях контейнеров или даже в разных клиентских инстансах. Для визуального обзора жизненного цикла состояния сессии см. репозиторийgithub/copilot-sdk.
| Государство | Что происходит |
|---|
**Создать** |
`sessionId` Назначено |
| Активный | Отправляйте подсказки, призывы к инструментам, ответы | | Приостановлено | Состояние сохранено на диск | | Резюме | Состояние, загруженное с диска |
Быстрый старт: создание возобновляемой сессии
Ключ к вособновляемым сессиям — это предоставление своих собственных sessionId сессий (другие SDK могут использовать session_id). Без этого SDK генерирует случайный идентификатор, и сессию нельзя возобновить позже.
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
// Create a session with a meaningful ID
const session = await client.createSession({
sessionId: "user-123-task-456",
model: "gpt-5.2-codex",
});
// Do some work...
await session.sendAndWait({ prompt: "Analyze my codebase" });
// Session state is automatically persisted
// You can safely close the client
Для примеров в Python, Go и C# см. репозиторийgithub/copilot-sdk.
Возобновление сессии
Вы можете продолжить сессию с того места, где она закончилась (через минуты, часы или даже дни). Для визуального обзора возобновления сессий между клиентами см. репозиторийgithub/copilot-sdk.
// Resume from a different client instance (or after restart)
const session = await client.resumeSession("user-123-task-456");
// Continue where you left off
await session.sendAndWait({ prompt: "What did we discuss earlier?" });
Для примеров в Python, Go и C# см. репозиторийgithub/copilot-sdk.
Варианты резюме
При возобновлении сессии вы можете опционально перенастроить несколько настроек. Это полезно, когда нужно изменить модель, обновить конфигурацию инструментов или изменить поведение.
| Опция | Описание |
|---|---|
model | Измените модель для возобновлённой сессии |
systemMessage | Отменить или расширить системный запрос |
availableTools | Ограничьте доступные инструменты |
excludedTools | Отключите определённые инструменты |
provider | Повторное предоставление учетных данных BYOK (требуется для сессий BYOK) |
reasoningEffort | Корректируйте уровень усилий по рассуждению |
streaming | Включить/отключить потоковые ответы |
workingDirectory | Изменить рабочий каталог |
configDir | Каталог конфигурации Override |
mcpServers | Настройка MCP-серверов |
customAgents | Настройка пользовательских агентов |
agent | Предварительный выбор пользовательского агента по имени |
skillDirectories | Каталоги для загрузки навыков |
disabledSkills | Навыки для отключения |
infiniteSessions | Настройка поведения бесконечных сессий |
Пример: Изменение модели в резюме
// Resume with a different model
const session = await client.resumeSession("user-123-task-456", {
model: "claude-sonnet-4", // Switch to a different model
reasoningEffort: "high", // Increase reasoning effort
});
Использование BYOK с возобновлёнными сессиями
При использовании собственных API-ключей при возобновлении работы необходимо повторно указать конфигурацию провайдера. API-ключи никогда не сохраняются на диске по соображениям безопасности.
// Original session with BYOK
const session = await client.createSession({
sessionId: "user-123-task-456",
model: "gpt-5.2-codex",
provider: {
type: "azure",
endpoint: "https://my-resource.openai.azure.com",
apiKey: process.env.AZURE_OPENAI_KEY,
deploymentId: "my-gpt-deployment",
},
});
// When resuming, you MUST re-provide the provider config
const resumed = await client.resumeSession("user-123-task-456", {
provider: {
type: "azure",
endpoint: "https://my-resource.openai.azure.com",
apiKey: process.env.AZURE_OPENAI_KEY, // Required again
deploymentId: "my-gpt-deployment",
},
});
Что сохраняется
Состояние сессии сохраняется в ~/.copilot/session-state/{sessionId}/виде:
~/.copilot/session-state/
└── user-123-task-456/
├── checkpoints/ # Conversation history snapshots
│ ├── 001.json # Initial state
│ ├── 002.json # After first interaction
│ └── ... # Incremental checkpoints
├── plan.md # Agent's planning state (if any)
└── files/ # Session artifacts
├── analysis.md # Files the agent created
└── notes.txt # Working documents
| Данные | Продолжался? | Примечания |
|---|---|---|
| История беседы |
✅ Да | Полный поток сообщений |
| Результаты вызова инструментов |
✅ Да | Кэшировано для контекста |
| Состояние планирования агента |
✅ Да | Файл plan.md |
| Артефакты сессии |
✅ Да | В files/ справочнике |
| Ключи провайдера/API |
❌ Нет | Безопасность: необходимо повторно предоставить |
| Состояние инструмента в памяти |
❌ Нет | Инструменты должны быть безсостоятельными |
Лучшие практики идентификатора сессии
Выбирайте идентификаторы сессий, которые кодируют принадлежность и назначение. Это значительно облегчает аудит и уборку.
| Рисунок | Пример | Сценарий использования |
|---|
❌
`abc123`
| Случайные идентификаторы | Сложно аудитировать, нет информации о владельце |
|
✅
user-{userId}-{taskId}
| user-alice-pr-review-42 | Многопользовательские приложения |
|
✅
tenant-{tenantId}-{workflow}
| tenant-acme-onboarding | Многопользовательский SaaS |
|
✅
{userId}-{taskId}-{timestamp}
| alice-deploy-1706932800 | Очистка по времени |
Преимущества структурированных ID:
- Легко аудитировать: «Показать все сессии для пользователя Alice»
- Простое исправление: «Удалить все сессии старше X»
- Естественный контроль доступа: разбор user ID из session ID
Пример: Генерация идентификаторов сессий
function createSessionId(userId: string, taskType: string): string {
const timestamp = Date.now();
return `${userId}-${taskType}-${timestamp}`;
}
const sessionId = createSessionId("alice", "code-review");
// → "alice-code-review-1706932800000"
Для примера в Python см. github/copilot-sdk репозиторий.
Управление жизненным циклом сессии
Список активных сессий
// List all sessions
const sessions = await client.listSessions();
console.log(`Found ${sessions.length} sessions`);
for (const session of sessions) {
console.log(`- ${session.sessionId} (created: ${session.createdAt})`);
}
// Filter sessions by repository
const repoSessions = await client.listSessions({ repository: "owner/repo" });
Уборка старых сессий
async function cleanupExpiredSessions(maxAgeMs: number) {
const sessions = await client.listSessions();
const now = Date.now();
for (const session of sessions) {
const age = now - new Date(session.createdAt).getTime();
if (age > maxAgeMs) {
await client.deleteSession(session.sessionId);
console.log(`Deleted expired session: ${session.sessionId}`);
}
}
}
// Clean up sessions older than 24 hours
await cleanupExpiredSessions(24 * 60 * 60 * 1000);
Отключение от сессии
Когда задача завершена, явно отключайтесь от сессии, а не ждите тайм-аутов. Это освобождает ресурсы в памяти, но сохраняет данные сессии на диске, так что сессию можно возобновить позже:
try {
// Do work...
await session.sendAndWait({ prompt: "Complete the task" });
// Task complete — release in-memory resources (session can be resumed later)
await session.disconnect();
} catch (error) {
// Clean up even on error
await session.disconnect();
throw error;
}
Каждый SDK предоставляет идиоматические автоматические шаблоны очистки:
| Язык | Рисунок | Пример |
|---|
**TypeScript** | `Symbol.asyncDispose` | `await using session = await client.createSession(config);` |
|
Python |
async with диспетчер контекстов | async with await client.create_session(config) as session: |
|
C# | IAsyncDisposable | await using var session = await client.CreateSessionAsync(config); |
|
Вперед | defer | defer session.Disconnect() |
Примечание.
`destroy()` была заменена и `disconnect()` будет удалена в одном из будущих релизов. Существующий код, использующий `destroy()` его, продолжит работать, но его следует перевести.
Постоянное удаление сессии
Чтобы навсегда удалить сессию и все её данные с диска (история разговоров, состояние планирования, артефакты), используйте deleteSession. Это необратимо — сессия не может быть возобновлена после удаления:
// Permanently remove session data
await client.deleteSession("user-123-task-456");
Совет
`disconnect()` выпускает ресурсы в памяти, но сохраняет данные сессии на диске для дальнейшего возобновления.
`deleteSession()` Навсегда удаляет всё, включая файлы с диска.
Автоматическая очистка: тайм-аут на холостом ходу
SDK имеет встроенный тайм-аут на 30 минут. Сессии без активности автоматически очищаются. Для визуального обзора потока тайм-аута в режиме простоя смотрите github/copilot-sdk репозиторий.
Слушайте случайные события, чтобы знать, когда работа заканчивается:
session.on("session.idle", (event) => {
console.log(`Session idle for ${event.idleDurationMs}ms`);
});
Шаблоны развертывания
Шаблон 1: Один CLI-сервер на пользователя (рекомендуется)
Лучше всего для: сильной изоляции, мульти-арендных сред, динамических сессий Azure. Для визуальной схемы см. репозиторийgithub/copilot-sdk.
Преимущества:
- Полная изоляция
- Простая безопасность
- Простое масштабирование
Шаблон 2: Общий CLI-сервер (ресурсоэффективный)
Лучшие для: внутренних инструментов, доверенных сред, ограниченных ресурсами конфигураций. Для визуальной схемы см. репозиторийgithub/copilot-sdk.
Требования:
- Уникальные идентификаторы сессий для каждого пользователя
- Управление доступом на уровне приложений
- Проверка идентификатора сессии перед операциями
// Application-level access control for shared CLI
async function resumeSessionWithAuth(
client: CopilotClient,
sessionId: string,
currentUserId: string
): Promise<Session> {
// Parse user from session ID
const [sessionUserId] = sessionId.split("-");
if (sessionUserId !== currentUserId) {
throw new Error("Access denied: session belongs to another user");
}
return client.resumeSession(sessionId);
}
Azure Dynamic Sessions
Для серверных или контейнерных развертываний, где контейнеры могут перезапускаться или мигрировать, каталог состояния сессии должен быть монтирован в постоянное хранилище:
# Azure Container Instance example
containers:
- name: copilot-agent
image: my-agent:latest
volumeMounts:
- name: session-storage
mountPath: /home/app/.copilot/session-state
volumes:
- name: session-storage
azureFile:
shareName: copilot-sessions
storageAccountName: myaccount
Для визуальной схемы сохранения перезапуска контейнера см. репозиторийgithub/copilot-sdk.
Бесконечные сессии для долгосрочных рабочих процессов
Для рабочих процессов, которые могут превышать ограничения контекста, включайте бесконечные сессии с автоматической компрессией:
const session = await client.createSession({
sessionId: "long-workflow-123",
infiniteSessions: {
enabled: true,
backgroundCompactionThreshold: 0.80, // Start compaction at 80% context
bufferExhaustionThreshold: 0.95, // Block at 95% if needed
},
});
Примечание.
Пороги — это коэффициенты использования контекста (0,0–1,0), а не абсолютное количество токенов.
Ограничения и рекомендации
| Ограничение | Описание | Смягчение последствий |
|---|
**Повторная аутентификация BYOK** | Ключи API не сохраняются | Ключи от хранилища в вашем секретном менеджере; Указывайте в резюме |
|
Регистрируемое хранилище |
~/.copilot/session-state/ должно быть записано | Монтировать постоянный объём в контейнеры |
|
Нет блокировки сессии | Параллельный доступ к одной и той же сессии не определен | Реализовать блокировку или очередь на уровне приложения |
|
Состояние инструмента не сохраняется | Состояние инструмента в памяти теряется | Проектируйте инструменты так, чтобы они были безсостоятельными или сохраняли своё собственное состояние |
Обработка параллельного доступа
SDK не обеспечивает встроенную блокировку сессий. Если несколько клиентов могут получить доступ к одной и той же сессии, убедитесь, что каждая сессия заблокирована, чтобы избежать захвата:
// Option 1: Application-level locking with Redis
import Redis from "ioredis";
const redis = new Redis();
async function withSessionLock<T>(
sessionId: string,
fn: () => Promise<T>
): Promise<T> {
const lockKey = `session-lock:${sessionId}`;
const acquired = await redis.set(lockKey, "locked", "NX", "EX", 300);
if (!acquired) {
throw new Error("Session is in use by another client");
}
try {
return await fn();
} finally {
await redis.del(lockKey);
}
}
// Usage
await withSessionLock("user-123-task-456", async () => {
const session = await client.resumeSession("user-123-task-456");
await session.sendAndWait({ prompt: "Continue the task" });
});
Сводка
| Функция | Использование |
|---|
**Создать вособновляемую сессию** | Предоставляйте свои собственные `sessionId` |
|
Сессия резюме | client.resumeSession(sessionId) |
|
Резюме BYOK | Повторное предоставление provider конфигурации |
|
Перечисление сеансов | client.listSessions(filter?) |
|
Отключение от активной сессии |
session.disconnect()— выпускает ресурсы в памяти; Данные сессии на диске сохраняются для возобновления |
|
Навсегда удалить сессию |
client.deleteSession(sessionId)—навсегда удаляет все данные сессии с диска; возобновить не может |
|
Контейнерное развертывание | Монтирование ~/.copilot/session-state/ на постоянное хранилище |