# Retomada e persistência da sessão

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.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## Como funcionam as sessões

Quando 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.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-0.png)

| State                  | O que acontece                                    |
| ---------------------- | ------------------------------------------------- |
| **Create**             |                                                   |
| `session_id` Atribuído |                                                   |
| **Ativo**              | Enviar prompts, chamadas de ferramenta, respostas |
| **Pausado**            | Estado salvo em disco                             |
| **Resume**             | Estado carregado do disco                         |

## Início rápido: criando uma sessão retomável

A 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.

### TypeScript

```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

```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

```golang
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)

```csharp
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
```

## Retomando uma sessão

Mais tarde — minutos, horas ou até mesmo dias — você pode retomar a sessão de onde parou.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-1.png)

### TypeScript

```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

```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

```golang
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)

```csharp
// 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?" });
```

## Opções de retomada

Ao 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.

| Opção              | Description                                                            |
| ------------------ | ---------------------------------------------------------------------- |
| `model`            | Alterar o modelo da sessão retomada                                    |
| `systemMessage`    | Substituir ou estender o prompt do sistema                             |
| `availableTools`   | Restringir quais ferramentas estão disponíveis                         |
| `excludedTools`    | Desabilitar ferramentas específicas                                    |
| `provider`         | Fornecer novamente as credenciais BYOK (necessárias para sessões BYOK) |
| `reasoningEffort`  | Ajustar o nível de esforço de raciocínio                               |
| `streaming`        | Habilitar/desabilitar respostas de streaming                           |
| `workingDirectory` | Alterar o diretório de trabalho                                        |
| `configDir`        | Sobrescrever diretório de configuração                                 |
| `mcpServers`       | Configurar servidores MCP                                              |
| `customAgents`     | Configurar agentes personalizados                                      |
| `agent`            | Pré-selecionar um agente personalizado pelo nome                       |
| `skillDirectories` | Diretórios para carregar habilidades de                                |
| `disabledSkills`   | Funções a desativar                                                    |
| `infiniteSessions` | Configurar o comportamento de sessão infinita                          |

### Exemplo: alterar o modelo no currículo

```typescript
// 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
});
```

## Usando BYOK (traga sua própria chave) com sessões retomadas

Ao 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.

```typescript
// 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",
  },
});
```

## O que é persistente?

O estado da sessão é salvo em `~/.copilot/session-state/{sessionId}/`:

```text
~/.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
```

| Dados                               | Persistiu?                              | Notes |
| ----------------------------------- | --------------------------------------- | ----- |
| Histórico de conversas              |                                         |       |
| ✅ Sim                               | Thread de mensagem completo             |       |
| Resultados da chamada de ferramenta |                                         |       |
| ✅ Sim                               | Armazenado em cache para contexto       |       |
| Estado de planejamento do agente    |                                         |       |
| ✅ Sim                               | Arquivo `plan.md`                       |       |
| Artefatos de sessão                 |                                         |       |
| ✅ Sim                               | No `files/` diretório                   |       |
| Chaves de provedor/API              |                                         |       |
| ❌ Não                               | Segurança: deve ser fornecida novamente |       |
| Estado da ferramenta na memória     |                                         |       |
| ❌ Não                               | As ferramentas devem ser sem estado     |       |

## Práticas recomendadas de ID de sessão

Escolha IDs de sessão que codificam a propriedade e a finalidade. Isso facilita muito a auditoria e a limpeza.

| Pattern                         | Example                                            | Caso de uso |
| ------------------------------- | -------------------------------------------------- | ----------- |
| ❌                               |                                                    |             |
| `abc123`                        |                                                    |             |
| IDs aleatórias                  | Difícil de auditar, sem informações de propriedade |             |
| ✅                               |                                                    |             |
| `user-{userId}-{taskId}`        |                                                    |             |
| `user-alice-pr-review-42`       | Aplicativos multiusuários                          |             |
| ✅                               |                                                    |             |
| `tenant-{tenantId}-{workflow}`  |                                                    |             |
| `tenant-acme-onboarding`        | SaaS multilocatário                                |             |
| ✅                               |                                                    |             |
| `{userId}-{taskId}-{timestamp}` |                                                    |             |
| `alice-deploy-1706932800`       | Limpeza baseada em tempo                           |             |

**Benefícios das IDs estruturadas:**

* Fácil de auditar: "Mostrar todas as sessões para o usuário alice"
* Fácil de limpar: "Excluir todas as sessões mais antigas que X"
* Controle de acesso integrado: analisar a ID do usuário a partir da ID da sessão

### Exemplo: gerando IDs de sessão

```typescript
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
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"
```

## Gerenciando o ciclo de vida da sessão

### Listando sessões ativas

```typescript
// 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" });
```

### Limpar sessões antigas

```typescript
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);
```

### Desconectando de uma sessão (`disconnect`)

Quando 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:

```typescript
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;
}
```

Cada SDK também fornece padrões de limpeza automática idiomática:

| Linguagem                            | Pattern                                                                             | Example                                                              |
| ------------------------------------ | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **TypeScript**                       | `Symbol.asyncDispose`                                                               | `await using session = await client.createSession(config);`          |
| **Python**                           |                                                                                     |                                                                      |
| `async with` gerenciador de contexto | `async with await client.create_session(on_permission_request=handler) as session:` |                                                                      |
| **C#**                               | `IAsyncDisposable`                                                                  | `await using var session = await client.CreateSessionAsync(config);` |
| **Go**                               | `defer`                                                                             | `defer session.Disconnect()`                                         |

> \[!NOTE]
> `destroy()` foi descontinuado em favor de `disconnect()`. O código existente que usa `destroy()` continuará funcionando, mas deve ser migrado.

### Excluindo permanentemente uma sessão (`deleteSession`)

Para 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:

```typescript
// Permanently remove session data
await client.deleteSession("user-123-task-456");
```

> **`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.

## Limpeza automática: tempo de inatividade

Por 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`:

```typescript
const client = new CopilotClient({
  sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes
});
```

Quando um tempo limite é configurado, as sessões sem atividade para essa duração são limpas automaticamente. Defina como `0` ou omita para desabilitar.

> \[!NOTE]
> 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.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-2.png)

Sessõ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.

Detecte eventos de inatividade para reagir à inatividade da sessão:

```typescript
session.on("session.idle", (event) => {
  console.log(`Session idle for ${event.idleDurationMs}ms`);
});
```

## Padrões de implantação

### Padrão 1: um servidor da CLI por usuário (recomendado)

Melhor para: isolamento forte, ambientes multilocatários e Sessões Dinâmicas do Azure.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-3.png)

\*\*Benefícios:\*\*✅ Isolamento completo | ✅ Segurança simples | ✅ Dimensionamento fácil

### Padrão 2: servidor da CLI compartilhada (eficiente em recursos)

Melhor para: ferramentas internas, ambientes confiáveis, configurações restritas a recursos.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-4.png)

**Requisitos:**

* ⚠️ IDs de sessão exclusivas por usuário
* ⚠️ Controle de acesso no nível do aplicativo
* ⚠️ Validação da ID da sessão antes das operações

```typescript
// 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 sessões dinâmicas

Para implantações sem servidor/contêiner em que os contêineres podem reiniciar ou migrar:

### Montar armazenamento persistente

O diretório de estado da sessão deve ser montado no armazenamento persistente:

```yaml
# 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
```

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/features-session-persistence-diagram-5.png)

**A sessão sobrevive às reinicializações de contêiner!**

## Sessões infinitas para fluxos de trabalho de execução longa

Para fluxos de trabalho que podem exceder os limites de contexto, habilite sessões infinitas com compactação automática:

```typescript
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
  },
});
```

> \[!NOTE]
> 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.

## Limitações e considerações

| Limitation                                    | Description                                     | Atenuação                                                                     |
| --------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------- |
| **Autenticação de BYOK**                      | As chaves de API não são mantidas               | Armazene chaves no gerenciador de segredos; fornecer ao retomar               |
| **Armazenamento gravável**                    |                                                 |                                                                               |
| `~/.copilot/session-state/` deve ser gravável | Montar volume persistente em contêineres        |                                                                               |
| **Nenhum bloqueio de sessão**                 | O acesso simultâneo à mesma sessão é indefinido | Implementar bloqueio ou fila no nível do aplicativo                           |
| **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 |

### Manipulando o acesso simultâneo

O SDK não fornece bloqueio de sessão interno. Se vários clientes puderem acessar a mesma sessão:

```typescript
// 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" });
});
```

## Resumo

| Característica                                                                                                     | Como usar                                                       |
| ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------- |
| **Criar sessão retomável**                                                                                         | Forneça seu próprio `sessionId`                                 |
| **Retomar sessão**                                                                                                 | `client.resumeSession(sessionId)`                               |
| **Resumo BYOK**                                                                                                    | Fornecer novamente a configuração `provider`                    |
| **Listar sessões**                                                                                                 | `client.listSessions(filter?)`                                  |
| **Desconectar-se da sessão ativa**                                                                                 |                                                                 |
| `session.disconnect()`— libera recursos na memória; os dados de sessão no disco são preservados para retomada      |                                                                 |
| **Excluir sessão permanentemente**                                                                                 |                                                                 |
| `client.deleteSession(sessionId)`— remove permanentemente todos os dados de sessão do disco; não pode ser retomado |                                                                 |
| **Implantação em contêineres**                                                                                     | Montar `~/.copilot/session-state/` no armazenamento persistente |

## Próximas Etapas 

* [Ganchos de sessão](/pt/copilot/how-tos/copilot-sdk/hooks/hooks-overview) – Personalizar o comportamento da sessão com ganchos
* [Compatibilidade do SDK e da CLI](/pt/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) – Comparação de recursos do SDK vs CLI
* [Guia de depuração](/pt/copilot/how-tos/copilot-sdk/troubleshooting/debugging) – Solucionar problemas de sessão