{"meta":{"title":"Retomada e persistência da sessão","intro":"Este guia orienta você pelos recursos de persistência de sessão do SDK: como pausar o trabalho, retomá-lo mais tarde e gerenciar sessões em ambientes de produção.","product":"GitHub Copilot","breadcrumbs":[{"href":"/pt/copilot","title":"GitHub Copilot"},{"href":"/pt/copilot/how-tos","title":"Instruções"},{"href":"/pt/copilot/how-tos/copilot-sdk","title":"SDK do Copilot"},{"href":"/pt/copilot/how-tos/copilot-sdk/features","title":"Features"},{"href":"/pt/copilot/how-tos/copilot-sdk/features/session-persistence","title":"Persistência da sessão"}],"documentType":"article"},"body":"# Retomada e persistência da sessão\n\nEste guia orienta você pelos recursos de persistência de sessão do SDK: como pausar o trabalho, retomá-lo mais tarde e gerenciar sessões em ambientes de produção.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Como funcionam as sessões\n\nQuando você cria uma sessão, a CLI do Copilot mantém o histórico da conversa, o estado da ferramenta e o contexto de planejamento. Por padrão, esse estado reside na memória e desaparece quando a sessão termina. Com a persistência habilitada, você pode retomar sessões entre reinicializações, migrações de contêiner ou até mesmo instâncias de cliente diferentes.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-0.png)\n\n| State                  | O que acontece                                    |\n| ---------------------- | ------------------------------------------------- |\n| **Create**             |                                                   |\n| `session_id` Atribuído |                                                   |\n| **Ativo**              | Enviar prompts, chamadas de ferramenta, respostas |\n| **Pausado**            | Estado salvo em disco                             |\n| **Resume**             | Estado carregado do disco                         |\n\n## Início rápido: criando uma sessão retomável\n\nA chave para sessões que podem ser retomadas é fornecer sua própria `session_id`. Sem um, o SDK gera uma ID aleatória e a sessão não pode ser retomada mais tarde.\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## Retomando uma sessão\n\nMais tarde — minutos, horas ou até mesmo dias — você pode retomar a sessão de onde parou.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/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## Opções de retomada\n\nAo retomar uma sessão, opcionalmente, você pode reconfigurar muitas configurações. Isso é útil quando você precisa alterar o modelo, atualizar as configurações da ferramenta ou modificar o comportamento.\n\n| Opção              | Description                                                            |\n| ------------------ | ---------------------------------------------------------------------- |\n| `model`            | Alterar o modelo da sessão retomada                                    |\n| `systemMessage`    | Substituir ou estender o prompt do sistema                             |\n| `availableTools`   | Restringir quais ferramentas estão disponíveis                         |\n| `excludedTools`    | Desabilitar ferramentas específicas                                    |\n| `provider`         | Fornecer novamente as credenciais BYOK (necessárias para sessões BYOK) |\n| `reasoningEffort`  | Ajustar o nível de esforço de raciocínio                               |\n| `streaming`        | Habilitar/desabilitar respostas de streaming                           |\n| `workingDirectory` | Alterar o diretório de trabalho                                        |\n| `configDir`        | Sobrescrever diretório de configuração                                 |\n| `mcpServers`       | Configurar servidores MCP                                              |\n| `customAgents`     | Configurar agentes personalizados                                      |\n| `agent`            | Pré-selecionar um agente personalizado pelo nome                       |\n| `skillDirectories` | Diretórios para carregar habilidades de                                |\n| `disabledSkills`   | Funções a desativar                                                    |\n| `infiniteSessions` | Configurar o comportamento de sessão infinita                          |\n\n### Exemplo: alterar o modelo no currículo\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## Usando BYOK (traga sua própria chave) com sessões retomadas\n\nAo usar suas próprias chaves de API, você deve fornecer novamente a configuração do provedor ao retomar. As chaves de API nunca são mantidas no disco por motivos de segurança.\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## O que é persistente?\n\nO estado da sessão é salvo em `~/.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| Dados                               | Persistiu?                              | Notes |\n| ----------------------------------- | --------------------------------------- | ----- |\n| Histórico de conversas              |                                         |       |\n| ✅ Sim                               | Thread de mensagem completo             |       |\n| Resultados da chamada de ferramenta |                                         |       |\n| ✅ Sim                               | Armazenado em cache para contexto       |       |\n| Estado de planejamento do agente    |                                         |       |\n| ✅ Sim                               | Arquivo `plan.md`                       |       |\n| Artefatos de sessão                 |                                         |       |\n| ✅ Sim                               | No `files/` diretório                   |       |\n| Chaves de provedor/API              |                                         |       |\n| ❌ Não                               | Segurança: deve ser fornecida novamente |       |\n| Estado da ferramenta na memória     |                                         |       |\n| ❌ Não                               | As ferramentas devem ser sem estado     |       |\n\n## Práticas recomendadas de ID de sessão\n\nEscolha IDs de sessão que codificam a propriedade e a finalidade. Isso facilita muito a auditoria e a limpeza.\n\n| Pattern                         | Example                                            | Caso de uso |\n| ------------------------------- | -------------------------------------------------- | ----------- |\n| ❌                               |                                                    |             |\n| `abc123`                        |                                                    |             |\n| IDs aleatórias                  | Difícil de auditar, sem informações de propriedade |             |\n| ✅                               |                                                    |             |\n| `user-{userId}-{taskId}`        |                                                    |             |\n| `user-alice-pr-review-42`       | Aplicativos multiusuários                          |             |\n| ✅                               |                                                    |             |\n| `tenant-{tenantId}-{workflow}`  |                                                    |             |\n| `tenant-acme-onboarding`        | SaaS multilocatário                                |             |\n| ✅                               |                                                    |             |\n| `{userId}-{taskId}-{timestamp}` |                                                    |             |\n| `alice-deploy-1706932800`       | Limpeza baseada em tempo                           |             |\n\n**Benefícios das IDs estruturadas:**\n\n* Fácil de auditar: \"Mostrar todas as sessões para o usuário alice\"\n* Fácil de limpar: \"Excluir todas as sessões mais antigas que X\"\n* Controle de acesso integrado: analisar a ID do usuário a partir da ID da sessão\n\n### Exemplo: gerando IDs de sessão\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## Gerenciando o ciclo de vida da sessão\n\n### Listando sessões ativas\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### Limpar sessões antigas\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### Desconectando de uma sessão (`disconnect`)\n\nQuando uma tarefa é concluída, desconecte-se da sessão explicitamente em vez de aguardar o time-out. Isso libera recursos na memória, mas **preserva os dados de sessão no disco**, portanto, a sessão ainda pode ser retomada mais tarde:\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\nCada SDK também fornece padrões de limpeza automática idiomática:\n\n| Linguagem                            | Pattern                                                                             | Example                                                              |\n| ------------------------------------ | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |\n| **TypeScript**                       | `Symbol.asyncDispose`                                                               | `await using session = await client.createSession(config);`          |\n| **Python**                           |                                                                                     |                                                                      |\n| `async with` gerenciador de contexto | `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> `destroy()` foi descontinuado em favor de `disconnect()`. O código existente que usa `destroy()` continuará funcionando, mas deve ser migrado.\n\n### Excluindo permanentemente uma sessão (`deleteSession`)\n\nPara remover permanentemente uma sessão e todos os seus dados do disco (histórico de conversa, estado de planejamento, artefatos), use `deleteSession`. Isso é irreversível: a sessão **não pode** ser retomada após a exclusão:\n\n```typescript\n// Permanently remove session data\nawait client.deleteSession(\"user-123-task-456\");\n```\n\n> **`disconnect()` vs `deleteSession()`:**`disconnect()` libera recursos na memória, mas mantém os dados de sessão no disco para retomada posterior. `deleteSession()` remove permanentemente tudo, incluindo arquivos em disco.\n\n## Limpeza automática: tempo de inatividade\n\nPor padrão, as sessões **não têm tempo limite ocioso** e vivem indefinidamente até serem explicitamente desconectadas ou excluídas. Opcionalmente, você pode configurar um tempo limite de inatividade para todo o servidor por meio de `CopilotClientOptions.sessionIdleTimeoutSeconds`:\n\n```typescript\nconst client = new CopilotClient({\n  sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes\n});\n```\n\nQuando um tempo limite é configurado, as sessões sem atividade para essa duração são limpas automaticamente. Defina como `0` ou omita para desabilitar.\n\n> \\[!NOTE]\n> Essa opção só se aplica quando o SDK gera o processo de runtime. Ao se conectar a um servidor existente por meio de `cliUrl`, aplica-se a configuração de tempo limite do próprio servidor.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-2.png)\n\nSessões com trabalho ativo (comandos em execução, agentes em segundo plano) são sempre protegidas contra limpeza ociosa, independentemente da configuração de tempo limite.\n\nDetecte eventos de inatividade para reagir à inatividade da sessão:\n\n```typescript\nsession.on(\"session.idle\", (event) => {\n  console.log(`Session idle for ${event.idleDurationMs}ms`);\n});\n```\n\n## Padrões de implantação\n\n### Padrão 1: um servidor da CLI por usuário (recomendado)\n\nMelhor para: isolamento forte, ambientes multilocatários e Sessões Dinâmicas do Azure.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-3.png)\n\n\\*\\*Benefícios:\\*\\*✅ Isolamento completo | ✅ Segurança simples | ✅ Dimensionamento fácil\n\n### Padrão 2: servidor da CLI compartilhada (eficiente em recursos)\n\nMelhor para: ferramentas internas, ambientes confiáveis, configurações restritas a recursos.\n\n![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-4.png)\n\n**Requisitos:**\n\n* ⚠️ IDs de sessão exclusivas por usuário\n* ⚠️ Controle de acesso no nível do aplicativo\n* ⚠️ Validação da ID da sessão antes das operações\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 sessões dinâmicas\n\nPara implantações sem servidor/contêiner em que os contêineres podem reiniciar ou migrar:\n\n### Montar armazenamento persistente\n\nO diretório de estado da sessão deve ser montado no armazenamento persistente:\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![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-5.png)\n\n**A sessão sobrevive às reinicializações de contêiner!**\n\n## Sessões infinitas para fluxos de trabalho de execução longa\n\nPara fluxos de trabalho que podem exceder os limites de contexto, habilite sessões infinitas com compactação automática:\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> Os limites são taxas de utilização de contexto (0,0-1,0), não contagens absolutas de token. Consulte o [Compatibilidade do SDK e da CLI](/pt/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) para obter detalhes.\n\n## Limitações e considerações\n\n| Limitation                                    | Description                                     | Atenuação                                                                     |\n| --------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------- |\n| **Autenticação de BYOK**                      | As chaves de API não são mantidas               | Armazene chaves no gerenciador de segredos; fornecer ao retomar               |\n| **Armazenamento gravável**                    |                                                 |                                                                               |\n| `~/.copilot/session-state/` deve ser gravável | Montar volume persistente em contêineres        |                                                                               |\n| **Nenhum bloqueio de sessão**                 | O acesso simultâneo à mesma sessão é indefinido | Implementar bloqueio ou fila no nível do aplicativo                           |\n| **O estado da ferramenta não persistiu**      | O estado da ferramenta na memória é perdido     | Ferramentas de design para serem sem estado ou persistirem seu próprio estado |\n\n### Manipulando o acesso simultâneo\n\nO SDK não fornece bloqueio de sessão interno. Se vários clientes puderem acessar a mesma sessão:\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## Resumo\n\n| Característica                                                                                                     | Como usar                                                       |\n| ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------- |\n| **Criar sessão retomável**                                                                                         | Forneça seu próprio `sessionId`                                 |\n| **Retomar sessão**                                                                                                 | `client.resumeSession(sessionId)`                               |\n| **Resumo BYOK**                                                                                                    | Fornecer novamente a configuração `provider`                    |\n| **Listar sessões**                                                                                                 | `client.listSessions(filter?)`                                  |\n| **Desconectar-se da sessão ativa**                                                                                 |                                                                 |\n| `session.disconnect()`— libera recursos na memória; os dados de sessão no disco são preservados para retomada      |                                                                 |\n| **Excluir sessão permanentemente**                                                                                 |                                                                 |\n| `client.deleteSession(sessionId)`— remove permanentemente todos os dados de sessão do disco; não pode ser retomado |                                                                 |\n| **Implantação em contêineres**                                                                                     | Montar `~/.copilot/session-state/` no armazenamento persistente |\n\n## Próximas Etapas \n\n* [Ganchos de sessão](/pt/copilot/how-tos/copilot-sdk/hooks/hooks-overview) – Personalizar o comportamento da sessão com ganchos\n* [Compatibilidade do SDK e da CLI](/pt/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) – Comparação de recursos do SDK vs CLI\n* [Guia de depuração](/pt/copilot/how-tos/copilot-sdk/troubleshooting/debugging) – Solucionar problemas de sessão"}