Как работают сеансы
Когда вы создаёте сессию, CLI Copilot сохраняет историю разговоров, состояние инструмента и контекст планирования. По умолчанию это состояние остаётся в памяти и исчезает после окончания сессии. С включенной устойчивостью вы можете возобновлять сессии при перезапусках, миграциях контейнеров или даже в разных клиентских инстансах.

| Государство | Что происходит |
|---|---|
| Создать | session_id Назначено |
| Активный | Отправляйте подсказки, призывы к инструментам, ответы |
| Приостановлено | Состояние сохранено на диск |
| Резюме | Состояние, загруженное с диска |
Быстрый старт: создание возобновляемой сессии
Ключ к возобновляемым сессиям — это предоставление собственных session_id. Без этого SDK генерирует случайный идентификатор, и сессию нельзя возобновить позже.
TypeScript
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
from copilot import CopilotClient
from copilot.session import PermissionHandler
client = CopilotClient()
await client.start()
# Create a session with a meaningful ID
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5.2-codex", session_id="user-123-task-456")
# Do some work...
await session.send_and_wait("Analyze my codebase")
# Session state is automatically persisted
Go
ctx := context.Background()
client := copilot.NewClient(nil)
// Create a session with a meaningful ID
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
SessionID: "user-123-task-456",
Model: "gpt-5.2-codex",
})
// Do some work...
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Analyze my codebase"})
// Session state is automatically persisted
C# (.NET)
using GitHub.Copilot;
var client = new CopilotClient();
// Create a session with a meaningful ID
var session = await client.CreateSessionAsync(new SessionConfig
{
SessionId = "user-123-task-456",
Model = "gpt-5.2-codex",
});
// Do some work...
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Analyze my codebase" });
// Session state is automatically persisted
Возобновление сессии
Позже — через минуты, часы или даже дни — вы сможете продолжить сессию с того места, где остановились.

TypeScript
// 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
# Resume from a different client instance (or after restart)
session = await client.resume_session("user-123-task-456", on_permission_request=PermissionHandler.approve_all)
# Continue where you left off
await session.send_and_wait("What did we discuss earlier?")
Go
ctx := context.Background()
// Resume from a different client instance (or after restart)
session, _ := client.ResumeSession(ctx, "user-123-task-456", nil)
// Continue where you left off
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What did we discuss earlier?"})
C# (.NET)
// Resume from a different client instance (or after restart)
var session = await client.ResumeSessionAsync("user-123-task-456");
// Continue where you left off
await session.SendAndWaitAsync(new MessageOptions { Prompt = "What did we discuss earlier?" });
Варианты резюме
При возобновлении сессии вы можете опционально перенастроить несколько настроек. Это полезно, когда нужно изменить модель, обновить конфигурацию инструментов или изменить поведение.
| Опция | Description |
|---|---|
model | Измените модель для возобновлённой сессии |
systemMessage | Отменить или расширить системный запрос |
availableTools | Ограничьте доступные инструменты |
excludedTools | Отключите определённые инструменты |
provider | Повторное предоставление учетных данных BYOK (требуется для сессий BYOK) |
capi.autoTier | Переопределите сохраненные параметры автоматической маршрутизации |
capi.enable | Выбор транспорта API ответов для возобновленного сеанса |
reasoningEffort | Корректируйте уровень усилий по рассуждению |
streaming | Включить/отключить потоковые ответы |
workingDirectory | Изменить рабочий каталог |
configDir | Каталог конфигурации Override |
mcpServers | Настройка MCP-серверов |
customAgents | Настройка пользовательских агентов |
agent | Предварительный выбор пользовательского агента по имени |
skillDirectories | Каталоги для загрузки навыков |
disabledSkills | Навыки для отключения |
infiniteSessions | Настройка поведения бесконечных сессий |
Сохраняемость автоуровневого уровня
При model: "auto"использовании необязательный capi.autoTier параметр выбирает параметр автоматической маршрутизации: efficiency, , balance``intelligenceили fast. В Python используйте capi={"auto_tier": "balance"}. Этот параметр применяется к автоматической маршрутизации версии 2; Автоматические запросы версии 1 не изменяются.
fast— это предустановка задержки только для интегратора, а не сторонняя GitHub Copilot предпочтения продукта. Пакет SDK не принимает решения о быстрой доступности, проверяет удостоверение клиента, выбирает его в качестве значения по умолчанию или возвращается на другой уровень, если среда выполнения не поддерживает ее, старая среда выполнения возвращает собственную ошибку без изменений.
Среда выполнения сохраняет выбранный уровень, поэтому приложениям не нужно повторно отправлять его в каждом возобновлении:
- Пропуская уровень при создании сеанса, использует поведение маршрутизации по умолчанию среды выполнения.
- Холодное возобновление восстанавливает сохраненный уровень. При предоставлении явного уровня переопределяет восстановленное значение для новой активации.
- При возобновлении сеанса, который уже находится в среде выполнения, опустите уровень сохранения текущего выбора и предоставления того же уровня является no-op. Предоставление другого уровня запрашивает безопасный коммутатор, который среда выполнения применяется после успешного возобновления; Он не может изменить поворот, который уже находится в полете.
- Старые сеансы без сохраняемого уровня сохраняют поведение маршрутизации по умолчанию.
Выбор уровня не является операцией динамического коммутатора модели. Пакет SDK перенаправит предпочтения; среда выполнения владеет сохраняемостью и проверкой.
session.resume События session.start предоставляют выбранный уровень в необязательном data.autoTier поле (data.auto_tierв Python). Если уровень не выбран, поле опущено.
Изменение уровня "Авто" во время сеанса
Вызов setAutoTier для изменения предпочтения маршрутизации в динамическом сеансе без изменения выбранной модели. Передайте null (PythonNone, Gonil), чтобы вернуться к автоматической маршрутизации поставщика по умолчанию.
const result = await session.setAutoTier("intelligence");
if (result.status === "pending") {
// Accepted, but not yet in effect.
}
Среда выполнения немедленно не применяет предпочтения. Он записывает запрос и фиксирует его только в том случае, если последующий поворот пользователя с помощью auto модели успешно получает используемую модель от поставщика. Таким pending образом, состояние подтверждает, что запрос был принят, а не вступил в силу. Только последний запрос выживает: новый запрос заменяет любой более ранний, который еще не утверждался.
Следите за результатом с помощью следующих событий:
session.model_changeпри фиксации предпочтения.session.auto_tier_switch_failedесли это не так. Это событие является временным, поэтому среда выполнения никогда не сохраняет или воспроизводит его в возобновлении. Егоreasonполе является одним изpolicy_rejected,request_failed``setup_failedили , иunsupportedранее действующие предпочтения остаются активными.
Вы также можете прочитать авторитетное состояние в любое время с помощью метода RPC сеанса model.getCurrent , который сообщает об фиксации autoTier, любой неисключаемой pendingAutoTierи activatingAutoTier в настоящее время утверждается активацией во время выполнения.
| SDK | Изменение уровня | Возврат к маршрутизации по умолчанию поставщика |
|---|---|---|
| Node.js | session.set | session.set |
| Python | session.set_auto_tier("balance") | session.set_auto_tier(None) |
| Go | session.Set | session.Set |
| .NET | session.Set | session.Set |
| Rust | session.set_auto_tier(Some(Auto | session.set_auto_tier(None) |
| Java | session.set | session.set |
Чтобы выбрать модель и ее предпочтения маршрутизации в одном вызове, наведите auto уровень на коммутаторе модели. Среда выполнения отклоняет этот параметр, если модель не является любой autoдругой.
| SDK | Этап уровня с помощью коммутатора | Сброс маршрутизации по умолчанию для поставщика |
|---|---|---|
| Node.js | setModel("auto", { autoTier: "balance" }) | setModel("auto", { autoTier: null }) |
| Python | set_model("auto", auto_tier="balance") | set_model("auto", auto_tier=None) |
| Go | Set | Set |
| .NET | new SetModelOptions { AutoTier = AutoTier.Balance } | new SetModelOptions { ResetAutoTier = true } |
| Rust | Set | Set |
| Java | new Set | new Set |
Node.js, Python и Rust выражают все три состояния в одном значении: Node.js и Python, так как отличается от опущенного аргумента, и Rust, так как null/None``AutoTierPreference::Reset это отдельный вариант одного и того же параметра. Go, .NET и Java не имеют способа отличить "сброс" от "unset" в одном значении, поэтому они несут отдельный флаг сброса. Опущение обоих всегда означает "оставить текущее предпочтение в одиночку".
Перенос ответов на возобновление
Необязательный capi.enableWebSocketResponses параметр выбирает транспорт для API ответов CAPI. По умолчанию trueиспользуется транспорт WebSocket всякий раз, когда выбранная модель объявляет конечную точку ws:/responses . Если он возвращается false к транспорту HTTP. В Python используйте capi={"enable_web_socket_responses": False}.
При необходимости укажите его в вызове резюме. Следует задать, когда подключения WebSocket завершаются сбоем за прокси-сервером и когда возобновляются отчеты 400 input item ID does not belong to this connectionсеанса, относящиеся к транспорту WebSocket.
const session = await client.resumeSession("user-123-task-456", {
capi: { enableWebSocketResponses: false },
});
Установка этого false значения эквивалентна переменной COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES среды, которая имеет противоположное полярность.
Пример: изменение модели в резюме
// 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
| Данные | Продолжался? | Notes |
|---|---|---|
| История беседы | ||
| ✅ Да | Полный поток сообщений | |
| Результаты вызова инструментов | ||
| ✅ Да | Кэшировано для контекста | |
| Состояние планирования агента | ||
| ✅ Да | Файл plan.md | |
| Артефакты сессии | ||
| ✅ Да | В files/ справочнике | |
| Ключи провайдера/API | ||
| ❌ Нет | Безопасность: необходимо повторно предоставить | |
| Состояние инструмента в памяти | ||
| ❌ Нет | Инструменты должны быть безсостоятельными |
Лучшие практики идентификатора сессии
Выбирайте идентификаторы сессий, которые кодируют принадлежность и назначение. Это значительно облегчает аудит и уборку.
| Pattern | Пример | Вариант использования |
|---|---|---|
❌abc123 | Случайные идентификаторы | Сложно аудитировать, нет информации о владельце |
✅user-{user | user-alice-pr-review-42 | Многопользовательские приложения |
✅tenant-{tenant | tenant-acme-onboarding | Многопользовательский SaaS |
✅{user | 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"
import time
def create_session_id(user_id: str, task_type: str) -> str:
timestamp = int(time.time())
return f"{user_id}-{task_type}-{timestamp}"
session_id = create_session_id("alice", "code-review")
# → "alice-code-review-1706932800"
Управление жизненным циклом сессии
Список активных сессий
// 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);
Отключение от сессии (disconnect)
Когда задача завершена, явно отключайтесь от сессии, а не ждите тайм-аутов. Это освобождает ресурсы в памяти, но сохраняет данные сессии на диске, так что сессию можно возобновить позже:
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 также предоставляет идиоматические автоматические шаблоны очистки:
| Язык | Pattern | Пример |
|---|---|---|
| TypeScript | Symbol.async | await using session = await client.create |
| Python | async with диспетчер контекстов | async with await client.create_session(on_ |
| C# | IAsyncDisposable | await using var session = await client.Create |
| Go | defer | defer session.Disconnect() |
Примечание.
Вместо PackageIconUrl теперь используется PackageIcon. Существующий код, использующий destroy() его, продолжит работать, но его следует перевести.
Постоянное удаление сессии (deleteSession)
Чтобы навсегда удалить сессию и все её данные с диска (история разговоров, состояние планирования, артефакты), используйте deleteSession. Это необратимо — сессия не может быть возобновлена после удаления:
// Permanently remove session data
await client.deleteSession("user-123-task-456");
disconnect()VSdeleteSession():disconnect()освобождает ресурсы в памяти, но сохраняет данные сессии на диске для последующего возобновления.deleteSession()Навсегда удаляет всё, включая файлы с диска.
Автоматическая очистка: тайм-аут на холостом ходу
По умолчанию сессии не имеют тайм-аута в простое и живут бесконечно, пока не будут явно отключены или удалены. По желанию вы можете настроить серверный тайм-аут простоя с помощью CopilotClientOptions.sessionIdleTimeoutSecondsследующих методов:
const client = new CopilotClient({
sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes
});
Когда тайм-аут настроен, сессии без активности в течение этого времени автоматически очищаются. Настройте или 0 пропустите, чтобы отключить.
Примечание.
Эта опция действует только тогда, когда SDK запускает процесс выполнения. При подключении к существующему серверу через cliUrl, применяется собственная тайм-аут сервера.

Сессии с активной работой (выполняющие команды, фоновые агенты) всегда защищены от очистки в режиме простоя, независимо от настройки тайм-аута.
Прислушивайтесь к событиям простоя, которые могут реагировать на неактивность сессии:
session.on("session.idle", (event) => {
console.log(`Session idle for ${event.idleDurationMs}ms`);
});
Шаблоны развертывания
Шаблон 1: один CLI-сервер на пользователя (рекомендуется)
Лучше всего для: сильной изоляции, многоарендных сред, динамических сессий Azure.

**Преимущества:**✅ Полная изоляция | ✅ Простая безопасность | ✅ Простое масштабирование
Шаблон 2: общий CLI-сервер (ресурсоэффективный)
Лучше всего для: внутренних инструментов, доверенных сред, ограниченных ресурсами конфигураций.

Требования:
- ⚠️ Уникальные идентификаторы сессий для каждого пользователя
- ⚠️ Управление доступом на уровне приложений
- ⚠️ Проверка идентификатора сессии перед операциями
// 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
Для серверных/контейнерных развертываний, где контейнеры могут перезапускаться или мигрировать:
Монтирование постоянного хранения
Каталог состояния сессии должен быть смонтирован в постоянное хранилище:
# 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

Сессия переживает запуск в контейнере!
Бесконечные сессии для долгосрочных рабочих процессов
Для рабочих процессов, которые могут превышать ограничения контекста, включайте бесконечные сессии с автоматической компрессией:
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), а не абсолютное количество токенов. Подробности смотрите в АВТОЗАГОЛОВКЕ .
Ограничения и рекомендации
| Limitation | Description | Смягчение последствий |
|---|---|---|
| Повторная аутентификация BYOK | Ключи API не сохраняются | Ключи от хранилища в вашем секретном менеджере; Указывайте в резюме |
| Регистрируемое хранилище | ~/ должно быть записано | Монтировать постоянный объём в контейнеры |
| Нет блокировки сессии | Параллельный доступ к одной и той же сессии не определен | Реализовать блокировку или очередь на уровне приложения |
| Состояние инструмента не сохраняется | Состояние инструмента в памяти теряется | Проектируйте инструменты так, чтобы они были безсостоятельными или сохраняли своё собственное состояние |
Обработка параллельного доступа
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.resume |
| Резюме BYOK | Повторное предоставление provider конфигурации |
| Перечисление сеансов | client.list |
| Отключение от активной сессии | session.disconnect()— выпускает ресурсы в памяти; Данные сессии на диске сохраняются для возобновления |
| Навсегда удалить сессию | client.delete—навсегда удаляет все данные сессии с диска; возобновить не может |
| Контейнерное развертывание | Монтирование ~/ на постоянное хранилище |
Дальнейшие действия
- Сессионные хуки — Настройка поведения сессии с помощью хуков
- Совместимость SDK и CLI — сравнение функций SDK и CLI
- Руководство по отладке - Проблемы с диагностикой сессии