{"meta":{"title":"Возобновление сессии и сохранение","intro":"Это руководство проведёт вас через возможности сохранения сессий SDK — как поставить работу на паузу, возобновить её позже и управлять сессиями в производственных средах.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/enterprise-cloud@latest/copilot","title":"GitHub Copilot"},{"href":"/ru/enterprise-cloud@latest/copilot/how-tos","title":"Инструкции"},{"href":"/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk","title":"Второй пилот SDK"},{"href":"/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features","title":"Возможности"},{"href":"/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/session-persistence","title":"Сохранение сессии"}],"documentType":"article"},"body":"# Возобновление сессии и сохранение\n\nЭто руководство проведёт вас через возможности сохранения сессий SDK — как поставить работу на паузу, возобновить её позже и управлять сессиями в производственных средах.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Как работают сеансы\n\nКогда вы создаёте сессию, CLI Copilot сохраняет историю разговоров, состояние инструмента и контекст планирования. По умолчанию это состояние остаётся в памяти и исчезает после окончания сессии. С включенной устойчивостью вы можете возобновлять сессии при перезапусках, миграциях контейнеров или даже в разных клиентских инстансах.\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-0.png)\n\n| Государство            | Что происходит                                        |\n| ---------------------- | ----------------------------------------------------- |\n| **Создать**            |                                                       |\n| `session_id` Назначено |                                                       |\n| **Активный**           | Отправляйте подсказки, призывы к инструментам, ответы |\n| **Приостановлено**     | Состояние сохранено на диск                           |\n| **Резюме**             | Состояние, загруженное с диска                        |\n\n## Быстрый старт: создание возобновляемой сессии\n\nКлюч к возобновляемым сессиям — это предоставление собственных `session_id`. Без этого SDK генерирует случайный идентификатор, и сессию нельзя возобновить позже.\n\n### TypeScript\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\n\n// Create a session with a meaningful ID\nconst session = await client.createSession({\n  sessionId: \"user-123-task-456\",\n  model: \"gpt-5.2-codex\",\n});\n\n// Do some work...\nawait session.sendAndWait({ prompt: \"Analyze my codebase\" });\n\n// Session state is automatically persisted\n// You can safely close the client\n```\n\n### Python\n\n```python\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\n\nclient = CopilotClient()\nawait client.start()\n\n# Create a session with a meaningful ID\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"gpt-5.2-codex\", session_id=\"user-123-task-456\")\n\n# Do some work...\nawait session.send_and_wait(\"Analyze my codebase\")\n\n# Session state is automatically persisted\n```\n\n### Go\n\n```golang\nctx := context.Background()\nclient := copilot.NewClient(nil)\n\n// Create a session with a meaningful ID\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    SessionID: \"user-123-task-456\",\n    Model:     \"gpt-5.2-codex\",\n})\n\n// Do some work...\nsession.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"Analyze my codebase\"})\n\n// Session state is automatically persisted\n```\n\n### C# (.NET)\n\n```csharp\nusing GitHub.Copilot;\n\nvar client = new CopilotClient();\n\n// Create a session with a meaningful ID\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    SessionId = \"user-123-task-456\",\n    Model = \"gpt-5.2-codex\",\n});\n\n// Do some work...\nawait session.SendAndWaitAsync(new MessageOptions { Prompt = \"Analyze my codebase\" });\n\n// Session state is automatically persisted\n```\n\n## Возобновление сессии\n\nПозже — через минуты, часы или даже дни — вы сможете продолжить сессию с того места, где остановились.\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-1.png)\n\n### TypeScript\n\n```typescript\n// Resume from a different client instance (or after restart)\nconst session = await client.resumeSession(\"user-123-task-456\");\n\n// Continue where you left off\nawait session.sendAndWait({ prompt: \"What did we discuss earlier?\" });\n```\n\n### Python\n\n```python\n# Resume from a different client instance (or after restart)\nsession = await client.resume_session(\"user-123-task-456\", on_permission_request=PermissionHandler.approve_all)\n\n# Continue where you left off\nawait session.send_and_wait(\"What did we discuss earlier?\")\n```\n\n### Go\n\n```golang\nctx := context.Background()\n\n// Resume from a different client instance (or after restart)\nsession, _ := client.ResumeSession(ctx, \"user-123-task-456\", nil)\n\n// Continue where you left off\nsession.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"What did we discuss earlier?\"})\n```\n\n### C# (.NET)\n\n```csharp\n// Resume from a different client instance (or after restart)\nvar session = await client.ResumeSessionAsync(\"user-123-task-456\");\n\n// Continue where you left off\nawait session.SendAndWaitAsync(new MessageOptions { Prompt = \"What did we discuss earlier?\" });\n```\n\n## Варианты резюме\n\nПри возобновлении сессии вы можете опционально перенастроить несколько настроек. Это полезно, когда нужно изменить модель, обновить конфигурацию инструментов или изменить поведение.\n\n| Опция              | Description                                                              |\n| ------------------ | ------------------------------------------------------------------------ |\n| `model`            | Измените модель для возобновлённой сессии                                |\n| `systemMessage`    | Отменить или расширить системный запрос                                  |\n| `availableTools`   | Ограничьте доступные инструменты                                         |\n| `excludedTools`    | Отключите определённые инструменты                                       |\n| `provider`         | Повторное предоставление учетных данных BYOK (требуется для сессий BYOK) |\n| `reasoningEffort`  | Корректируйте уровень усилий по рассуждению                              |\n| `streaming`        | Включить/отключить потоковые ответы                                      |\n| `workingDirectory` | Изменить рабочий каталог                                                 |\n| `configDir`        | Каталог конфигурации Override                                            |\n| `mcpServers`       | Настройка MCP-серверов                                                   |\n| `customAgents`     | Настройка пользовательских агентов                                       |\n| `agent`            | Предварительный выбор пользовательского агента по имени                  |\n| `skillDirectories` | Каталоги для загрузки навыков                                            |\n| `disabledSkills`   | Навыки для отключения                                                    |\n| `infiniteSessions` | Настройка поведения бесконечных сессий                                   |\n\n### Пример: изменение модели в резюме\n\n```typescript\n// Resume with a different model\nconst session = await client.resumeSession(\"user-123-task-456\", {\n  model: \"claude-sonnet-4\",  // Switch to a different model\n  reasoningEffort: \"high\",   // Increase reasoning effort\n});\n```\n\n## Использование BYOK (принеси свой ключ) с возобновленными сессиями\n\nПри использовании собственных API-ключей при возобновлении работы необходимо повторно указать конфигурацию провайдера. API-ключи никогда не сохраняются на диске по соображениям безопасности.\n\n```typescript\n// Original session with BYOK\nconst session = await client.createSession({\n  sessionId: \"user-123-task-456\",\n  model: \"gpt-5.2-codex\",\n  provider: {\n    type: \"azure\",\n    endpoint: \"https://my-resource.openai.azure.com\",\n    apiKey: process.env.AZURE_OPENAI_KEY,\n    deploymentId: \"my-gpt-deployment\",\n  },\n});\n\n// When resuming, you MUST re-provide the provider config\nconst resumed = await client.resumeSession(\"user-123-task-456\", {\n  provider: {\n    type: \"azure\",\n    endpoint: \"https://my-resource.openai.azure.com\",\n    apiKey: process.env.AZURE_OPENAI_KEY,  // Required again\n    deploymentId: \"my-gpt-deployment\",\n  },\n});\n```\n\n## Что настаивает?\n\nСостояние сессии сохраняется в `~/.copilot/session-state/{sessionId}/`виде:\n\n```text\n~/.copilot/session-state/\n└── user-123-task-456/\n    ├── checkpoints/           # Conversation history snapshots\n    │   ├── 001.json          # Initial state\n    │   ├── 002.json          # After first interaction\n    │   └── ...               # Incremental checkpoints\n    ├── plan.md               # Agent's planning state (if any)\n    └── files/                # Session artifacts\n        ├── analysis.md       # Files the agent created\n        └── notes.txt         # Working documents\n```\n\n| Данные                         | Продолжался?                                   | Notes |\n| ------------------------------ | ---------------------------------------------- | ----- |\n| История беседы                 |                                                |       |\n| ✅ Да                           | Полный поток сообщений                         |       |\n| Результаты вызова инструментов |                                                |       |\n| ✅ Да                           | Кэшировано для контекста                       |       |\n| Состояние планирования агента  |                                                |       |\n| ✅ Да                           | Файл `plan.md`                                 |       |\n| Артефакты сессии               |                                                |       |\n| ✅ Да                           | В `files/` справочнике                         |       |\n| Ключи провайдера/API           |                                                |       |\n| ❌ Нет                          | Безопасность: необходимо повторно предоставить |       |\n| Состояние инструмента в памяти |                                                |       |\n| ❌ Нет                          | Инструменты должны быть безсостоятельными      |       |\n\n## Лучшие практики идентификатора сессии\n\nВыбирайте идентификаторы сессий, которые кодируют принадлежность и назначение. Это значительно облегчает аудит и уборку.\n\n| Pattern                         | Пример                                          | Вариант использования |\n| ------------------------------- | ----------------------------------------------- | --------------------- |\n| ❌                               |                                                 |                       |\n| `abc123`                        |                                                 |                       |\n| Случайные идентификаторы        | Сложно аудитировать, нет информации о владельце |                       |\n| ✅                               |                                                 |                       |\n| `user-{userId}-{taskId}`        |                                                 |                       |\n| `user-alice-pr-review-42`       | Многопользовательские приложения                |                       |\n| ✅                               |                                                 |                       |\n| `tenant-{tenantId}-{workflow}`  |                                                 |                       |\n| `tenant-acme-onboarding`        | Многопользовательский SaaS                      |                       |\n| ✅                               |                                                 |                       |\n| `{userId}-{taskId}-{timestamp}` |                                                 |                       |\n| `alice-deploy-1706932800`       | Очистка по времени                              |                       |\n\n**Преимущества структурированных ID:**\n\n* Легко аудитировать: «Показать все сессии для пользователя Alice»\n* Простое исправление: «Удалить все сессии старше X»\n* Естественный контроль доступа: разбор user ID из session ID\n\n### Пример: генерация идентификаторов сессий\n\n```typescript\nfunction createSessionId(userId: string, taskType: string): string {\n  const timestamp = Date.now();\n  return `${userId}-${taskType}-${timestamp}`;\n}\n\nconst sessionId = createSessionId(\"alice\", \"code-review\");\n// → \"alice-code-review-1706932800000\"\n```\n\n```python\nimport time\n\ndef create_session_id(user_id: str, task_type: str) -> str:\n    timestamp = int(time.time())\n    return f\"{user_id}-{task_type}-{timestamp}\"\n\nsession_id = create_session_id(\"alice\", \"code-review\")\n# → \"alice-code-review-1706932800\"\n```\n\n## Управление жизненным циклом сессии\n\n### Список активных сессий\n\n```typescript\n// List all sessions\nconst sessions = await client.listSessions();\nconsole.log(`Found ${sessions.length} sessions`);\n\nfor (const session of sessions) {\n  console.log(`- ${session.sessionId} (created: ${session.createdAt})`);\n}\n\n// Filter sessions by repository\nconst repoSessions = await client.listSessions({ repository: \"owner/repo\" });\n```\n\n### Уборка старых сессий\n\n```typescript\nasync function cleanupExpiredSessions(maxAgeMs: number) {\n  const sessions = await client.listSessions();\n  const now = Date.now();\n  \n  for (const session of sessions) {\n    const age = now - new Date(session.createdAt).getTime();\n    if (age > maxAgeMs) {\n      await client.deleteSession(session.sessionId);\n      console.log(`Deleted expired session: ${session.sessionId}`);\n    }\n  }\n}\n\n// Clean up sessions older than 24 hours\nawait cleanupExpiredSessions(24 * 60 * 60 * 1000);\n```\n\n### Отключение от сессии (`disconnect`)\n\nКогда задача завершена, явно отключайтесь от сессии, а не ждите тайм-аутов. Это освобождает ресурсы в памяти, но **сохраняет данные сессии на диске**, так что сессию можно возобновить позже:\n\n```typescript\ntry {\n  // Do work...\n  await session.sendAndWait({ prompt: \"Complete the task\" });\n  \n  // Task complete — release in-memory resources (session can be resumed later)\n  await session.disconnect();\n} catch (error) {\n  // Clean up even on error\n  await session.disconnect();\n  throw error;\n}\n```\n\nКаждый SDK также предоставляет идиоматические автоматические шаблоны очистки:\n\n| Язык                              | Pattern                                                                             | Пример                                                               |\n| --------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |\n| **TypeScript**                    | `Symbol.asyncDispose`                                                               | `await using session = await client.createSession(config);`          |\n| **Python**                        |                                                                                     |                                                                      |\n| `async with` диспетчер контекстов | `async with await client.create_session(on_permission_request=handler) as session:` |                                                                      |\n| **C#**                            | `IAsyncDisposable`                                                                  | `await using var session = await client.CreateSessionAsync(config);` |\n| **Go**                            | `defer`                                                                             | `defer session.Disconnect()`                                         |\n\n> \\[!NOTE]\n> Вместо <code>PackageIconUrl</code> теперь используется <code>PackageIcon</code>. Существующий код, использующий `destroy()` его, продолжит работать, но его следует перевести.\n\n### Постоянное удаление сессии (`deleteSession`)\n\nЧтобы навсегда удалить сессию и все её данные с диска (история разговоров, состояние планирования, артефакты), используйте `deleteSession`. Это необратимо — сессия **не** может быть возобновлена после удаления:\n\n```typescript\n// Permanently remove session data\nawait client.deleteSession(\"user-123-task-456\");\n```\n\n> **`disconnect()` VS `deleteSession()`:**`disconnect()` освобождает ресурсы в памяти, но сохраняет данные сессии на диске для последующего возобновления. `deleteSession()` Навсегда удаляет всё, включая файлы с диска.\n\n## Автоматическая очистка: тайм-аут на холостом ходу\n\nПо умолчанию сессии **не имеют тайм-аута в простое** и живут бесконечно, пока не будут явно отключены или удалены. По желанию вы можете настроить серверный тайм-аут простоя с помощью `CopilotClientOptions.sessionIdleTimeoutSeconds`следующих методов:\n\n```typescript\nconst client = new CopilotClient({\n  sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes\n});\n```\n\nКогда тайм-аут настроен, сессии без активности в течение этого времени автоматически очищаются. Настройте или `0` пропустите, чтобы отключить.\n\n> \\[!NOTE]\n> Эта опция действует только тогда, когда SDK запускает процесс выполнения. При подключении к существующему серверу через `cliUrl`, применяется собственная тайм-аут сервера.\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-2.png)\n\nСессии с активной работой (выполняющие команды, фоновые агенты) всегда защищены от очистки в режиме простоя, независимо от настройки тайм-аута.\n\nПрислушивайтесь к событиям простоя, которые могут реагировать на неактивность сессии:\n\n```typescript\nsession.on(\"session.idle\", (event) => {\n  console.log(`Session idle for ${event.idleDurationMs}ms`);\n});\n```\n\n## Шаблоны развертывания\n\n### Шаблон 1: один CLI-сервер на пользователя (рекомендуется)\n\nЛучше всего для: сильной изоляции, многоарендных сред, динамических сессий Azure.\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-3.png)\n\n\\*\\*Преимущества:\\*\\*✅ Полная изоляция | ✅ Простая безопасность | ✅ Простое масштабирование\n\n### Шаблон 2: общий CLI-сервер (ресурсоэффективный)\n\nЛучше всего для: внутренних инструментов, доверенных сред, ограниченных ресурсами конфигураций.\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-4.png)\n\n**Требования:**\n\n* ⚠️ Уникальные идентификаторы сессий для каждого пользователя\n* ⚠️ Управление доступом на уровне приложений\n* ⚠️ Проверка идентификатора сессии перед операциями\n\n```typescript\n// Application-level access control for shared CLI\nasync function resumeSessionWithAuth(\n  client: CopilotClient,\n  sessionId: string,\n  currentUserId: string\n): Promise<Session> {\n  // Parse user from session ID\n  const [sessionUserId] = sessionId.split(\"-\");\n  \n  if (sessionUserId !== currentUserId) {\n    throw new Error(\"Access denied: session belongs to another user\");\n  }\n  \n  return client.resumeSession(sessionId);\n}\n```\n\n## динамические сеансы Azure\n\nДля серверных/контейнерных развертываний, где контейнеры могут перезапускаться или мигрировать:\n\n### Монтирование постоянного хранения\n\nКаталог состояния сессии должен быть смонтирован в постоянное хранилище:\n\n```yaml\n# Azure Container Instance example\ncontainers:\n  - name: copilot-agent\n    image: my-agent:latest\n    volumeMounts:\n      - name: session-storage\n        mountPath: /home/app/.copilot/session-state\n\nvolumes:\n  - name: session-storage\n    azureFile:\n      shareName: copilot-sessions\n      storageAccountName: myaccount\n```\n\n![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-5.png)\n\n**Сессия переживает запуск в контейнере!**\n\n## Бесконечные сессии для долгосрочных рабочих процессов\n\nДля рабочих процессов, которые могут превышать ограничения контекста, включайте бесконечные сессии с автоматической компрессией:\n\n```typescript\nconst session = await client.createSession({\n  sessionId: \"long-workflow-123\",\n  infiniteSessions: {\n    enabled: true,\n    backgroundCompactionThreshold: 0.80,  // Start compaction at 80% context\n    bufferExhaustionThreshold: 0.95,      // Block at 95% if needed\n  },\n});\n```\n\n> \\[!NOTE]\n> Пороги — это коэффициенты использования контекста (0,0-1,0), а не абсолютное количество токенов. Подробности смотрите [в АВТОЗАГОЛОВКЕ](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) .\n\n## Ограничения и рекомендации\n\n| Limitation                                       | Description                                              | Смягчение последствий                                                                                   |\n| ------------------------------------------------ | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |\n| **Повторная аутентификация BYOK**                | Ключи API не сохраняются                                 | Ключи от хранилища в вашем секретном менеджере; Указывайте в резюме                                     |\n| **Регистрируемое хранилище**                     |                                                          |                                                                                                         |\n| `~/.copilot/session-state/` должно быть записано | Монтировать постоянный объём в контейнеры                |                                                                                                         |\n| **Нет блокировки сессии**                        | Параллельный доступ к одной и той же сессии не определен | Реализовать блокировку или очередь на уровне приложения                                                 |\n| **Состояние инструмента не сохраняется**         | Состояние инструмента в памяти теряется                  | Проектируйте инструменты так, чтобы они были безсостоятельными или сохраняли своё собственное состояние |\n\n### Обработка параллельного доступа\n\nSDK не обеспечивает встроенную блокировку сессий. Если несколько клиентов могут получить доступ к одной и той же сессии:\n\n```typescript\n// Option 1: Application-level locking with Redis\nimport Redis from \"ioredis\";\n\nconst redis = new Redis();\n\nasync function withSessionLock<T>(\n  sessionId: string,\n  fn: () => Promise<T>\n): Promise<T> {\n  const lockKey = `session-lock:${sessionId}`;\n  const acquired = await redis.set(lockKey, \"locked\", \"NX\", \"EX\", 300);\n  \n  if (!acquired) {\n    throw new Error(\"Session is in use by another client\");\n  }\n  \n  try {\n    return await fn();\n  } finally {\n    await redis.del(lockKey);\n  }\n}\n\n// Usage\nawait withSessionLock(\"user-123-task-456\", async () => {\n  const session = await client.resumeSession(\"user-123-task-456\");\n  await session.sendAndWait({ prompt: \"Continue the task\" });\n});\n```\n\n## Сводка\n\n| Функция                                                                                                  | Использование                                                    |\n| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |\n| **Создать вособновляемую сессию**                                                                        | Предоставляйте свои собственные `sessionId`                      |\n| **Сессия резюме**                                                                                        | `client.resumeSession(sessionId)`                                |\n| **Резюме BYOK**                                                                                          | Повторное предоставление `provider` конфигурации                 |\n| **Перечисление сеансов**                                                                                 | `client.listSessions(filter?)`                                   |\n| **Отключение от активной сессии**                                                                        |                                                                  |\n| `session.disconnect()`— выпускает ресурсы в памяти; Данные сессии на диске сохраняются для возобновления |                                                                  |\n| **Навсегда удалить сессию**                                                                              |                                                                  |\n| `client.deleteSession(sessionId)`—навсегда удаляет все данные сессии с диска; возобновить не может       |                                                                  |\n| **Контейнерное развертывание**                                                                           | Монтирование `~/.copilot/session-state/` на постоянное хранилище |\n\n## Дальнейшие действия\n\n* [Сессионные хуки](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks/hooks-overview) — Настройка поведения сессии с помощью хуков\n* [Совместимость SDK и CLI](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) — сравнение функций SDK и CLI\n* [Руководство по отладке](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/troubleshooting/debugging) - Проблемы с диагностикой сессии"}