Skip to main content
Skip to content

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.

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.

StateO que acontece
Createsession_id Atribuído
AtivoEnviar prompts, chamadas de ferramenta, respostas
PausadoEstado salvo em disco
ResumeEstado 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

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

Retomando uma sessão

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

Permissões lembradas com o sistema de arquivos da sessão

Quando você configura um provedor personalizado sessionFs, as opções de permissões persistentes pertencentes ao runtime usam o armazenamento do provedor em vez da configuração do host de runtime. Os arquivos residem na sessionStatePath do provedor e mantêm seus formatos existentes:

  • permissions.json: um locations mapa de nível superior que mantém os campos allowed_directories e tool_approvals existentes
  • settings.json: Controle de nível superior allowedUrls para approve-permanently aprovação de URLs e sandbox para preferências de sandbox salvas
  • config.json: Nível superior trustedFolders para a confiança da pasta lembrada e sandboxOnboardingShown para a mensagem de sandbox de primeira habilitação

As chaves de localização são caminhos de diretório do provedor normalizados, como /workspace, sem um prefixo adicionado. O runtime os resolve lexicalmente usando convenções de caminho do provedor, sem inspecionar o sistema de arquivos do host ou descobrir repositórios Git do host. Uma aprovação salva para /workspace não é selecionada automaticamente quando o diretório de trabalho é /workspace/sub.

A confiança em pasta com suporte do provedor também usa caminhos léxicos: uma pasta confiável abrange a si mesma e seus descendentes, não worktrees do Git vinculadas em outros caminhos. Confie explicitamente nesses caminhos de worktree.

Não há nenhuma partição de ID de sessão adicional dentro desses arquivos. Sessões que acessam os mesmos arquivos subjacentes compartilham opções lembradas. Use namespaces de provedor separados quando sessões ou tenants não devem compartilhar permissões. Com um namespace por sessão, as opções permanentes sobrevivem às retomadas dessa sessão, mas não são transferidas automaticamente para novas sessões. Para restaurar as opções persistentes de uma sessão ao retomar, reconecte-a ao mesmo namespace.

As atualizações de consentimento são serializadas por endpoint e arquivo de cada provedor em um processo de runtime. Pontos de extremidade separados não bloqueiam uns aos outros. Se diferentes pontos de extremidade do provedor ou processos de runtime compartilharem arquivos subjacentes, o aplicativo deverá coordenar atualizações simultâneas; o runtime não pode inferir que esses arquivos são compartilhados.

Essas operações nunca importam, atualizam nem recorrem aos permissions-config.json, settings.json ou config.json do host, inclusive quando as leituras ou gravações do provedor falham. Os arquivos em formato existente fornecidos por meio do provedor são lidos diretamente.

Assim como acontece com a configuração do host, as aprovações de URL são lidas somente de settings.json. Um campo herdado allowedUrls em config.json é ignorado; config.json continua sendo o arquivo de estado global para a confiança de pasta lembrada e o marcador de integração da área restrita.

O roteamento de armazenamento não altera o tempo de vida da permissão, a precedência de negação de URL ou o comportamento da política de sessão. A aprovação única e a aprovação para a sessão não se tornam concessões permanentes.

As preferências de sandbox salvas são restauradas na criação e na retomada. Chamadas explícitas do SDK options.update posteriores podem alterar a configuração ativa do sandbox sem reescrever a preferência salva.

Sem sessionFs, os aplicativos SDK nos modos empty e copilot-cli mantêm a persistência existente com suporte de host. Isso inclui o comportamento existente em que o consentimento permanente de URL salva as configurações do host e concede acesso na sessão ao vivo, mas uma nova sessão do SDK não carrega automaticamente a lista de permissões da URL do host.

Consulte Multilocação e implantações de servidores para ver as responsabilidades de isolamento do provedor.

Recuperação de transcrição

A opção allowTranscriptRecovery de retomar controla a recuperação quando o runtime carrega um registro do armazenamento. O padrão é true em todos os modos. Com false, uma carga que descartaria registros danificados ou mover session.start falhará com erro JSON-RPC -32075 sem reescrever a transcrição. Um registro final intacto sem uma nova linha é aceito.

Os registros ignorados para compatibilidade com versões futuras ainda contam ao verificar a ordem persistente. Se esses registros precederem session.start, a recuperação deverá mover o registro inicial à frente deles. Uma transcrição que contém apenas registros ignorados não está vazia e não pode ser recuperada sem um session.start.

Quando a recuperação é permitida, a sessão retornada expõe transcriptRecovery, incluindo os números de linha inválidos, se session.start foi movido e um caminho de backup planejado por bytes exatos. O carregamento por si só não grava esse backup; o próximo acréscimo durável executa o reparo e o backup.

Observação

Essa opção se aplica a uma nova carga de transcrição, não ao tempo de vida de uma sessão. Reconectar-se a uma sessão já residente no runtime reutiliza seu histórico ao vivo sem revalidar o armazenamento ou rejeitar a recuperação autorizada por uma retomada anterior. O relatório de recuperação descreve a carga que executou a recuperação, e não toda reconexão subsequente.

Diagrama: Fluxograma mostrando o processo descrito.

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

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çãoDescription
modelAlterar o modelo da sessão retomada
systemMessageSubstituir ou estender o prompt do sistema
availableToolsRestringir quais ferramentas estão disponíveis
excludedToolsDesabilitar ferramentas específicas
providerFornecer novamente as credenciais BYOK (necessárias para sessões BYOK)
capi.autoTierSobrescrever a preferência persistente de roteamento Auto
capi.enableWebSocketResponsesEscolha o transporte da API Responses para a sessão retomada
reasoningEffortAjustar o nível de esforço de raciocínio
streamingHabilitar/desabilitar respostas de streaming
workingDirectoryAlterar o diretório de trabalho
configDirSobrescrever diretório de configuração
mcpServersConfigurar servidores MCP
customAgentsConfigurar agentes personalizados
agentPré-selecionar um agente personalizado pelo nome
skillDirectoriesDiretórios para carregar habilidades de
disabledSkillsFunções a desativar
infiniteSessionsConfigurar o comportamento de sessão infinita

Persistência de autoclassificação de camadas

Commodel: "auto", a configuração opcional capi.autoTier seleciona uma preferência de roteamento automático: efficiency, , balanceou intelligence``fast. Em Python, use capi={"auto_tier": "balance"}. Essa configuração se aplica ao roteamento automático V2; As solicitações automáticas V1 não são alteradas.

Quando o recurso desativado por padrão DYNAMIC_AUTO_TIERS do runtime está habilitado, o RPC da sessão model.list também retorna metadados opcionais auto do endpoint /meta do provedor. Use os descritores habilitados com type: "auto" para descobrir identificadores de camada com suporte adicionais, seus nomes de exibição, descrições e ordenação. Os métodos de seleção existentes e os campos JSON aceitam esses identificadores. Uma falha de descoberta não recorre a /models, e uma resposta bem-sucedida sem metadados auto não fornece níveis Auto selecionáveis.

Para preencher um seletor de modelo antes de qualquer sessão existir, habilite DYNAMIC_AUTO_TIERS no ambiente do runtime (por exemplo, a opção env de cliente). O RPC no nível models.list do servidor (client.rpc.models.list() em Node.js) retorna os mesmos auto metadados da mesma /meta resposta, com o mesmo comportamento de não fallback. A listagem no nível do servidor lê o sinalizador que o runtime detectou na inicialização, não sinalizadores de recursos por sessão nem atribuições de experimento, portanto, defina o sinalizador no ambiente em que o runtime é iniciado. Com o sinalizador desabilitado, auto permanece inalterado e omite models.list.

Trate os identificadores de nível como valores extensíveis, não uma enumeração fechada. Os valores nomeados existentes permanecem disponíveis; para identificadores adicionais, use cadeias de caracteres em Node.js e Python, AutoTier("premium-v2") em Go, new AutoTier("premium-v2") em .NET, AutoTier::Custom no Rust ou AutoTier.fromValue em Java. O defaultTier do provedor descreve seu roteamento padrão sem criar uma preferência de SDK gravada.

Se uma camada persistente for removida ou desabilitada, a retomada preserva a preferência explícita em vez de substituí-la pelo padrão do provedor. Selecione uma substituição disponível antes de ativar o roteamento automático.

A CLI também preserva as preferências derivadas de configurações durante a inicialização, mesmo quando um nível não está disponível ou a descoberta dinâmica está desabilitada. Em seguida, você pode selecionar um modelo substituto no seletor de modelo. As preferências explícitas de criação e retomada do SDK ainda são validadas antes que a operação seja bem-sucedida, e a ativação automática sempre valida a disponibilidade em relação ao modo de descoberta resolvido.

Quando uma solicitação de criação ou retomada inclui expAssignments, o runtime instala essas atribuições antes de validar uma preferência automática explícita. Validação, descoberta e ativação usam a mesma decisão de funcionalidade resolvida.

fast é uma predefinição de latência exclusiva para integradores, não uma preferência nativa de produto do GitHub Copilot. O Fast não é validado no catálogo de camadas /meta ao configurar uma sessão. O SDK não determina a elegibilidade ao Fast, não inspeciona a identidade do cliente, não o escolhe como padrão nem recorre a outra camada quando um ambiente de execução não oferece suporte a ele — um ambiente de execução mais antigo retorna o erro nativo inalterado.

O ambiente de execução mantém o nível selecionado, portanto os aplicativos não precisam reenviá-lo a cada retomada:

  • Omitir a camada ao criar uma sessão usa o comportamento de roteamento padrão do runtime.
  • Uma retomada a frio restaura a camada persistida. Fornecer uma camada explícita substitui o valor restaurado para a nova ativação.
  • Ao retomar uma sessão já residente no runtime, omitir a camada preserva a seleção atual e fornecer a mesma camada é um no-op. A disponibilização de um nível diferente requer uma alternância segura, que o runtime aplica após a retomada ser bem-sucedida; não é possível alterar um turno que já esteja em andamento.
  • Sessões mais antigas sem uma camada persistente mantêm o comportamento de roteamento padrão.

A seleção de nível não é uma operação de troca de modelo em tempo real. O SDK encaminha a preferência; o runtime possui persistência e validação.

Os eventos session.resume e session.start expõem a camada selecionada no campo opcional data.autoTier (data.auto_tier em Python). Quando nenhuma camada é selecionada, o campo é omitido.

Alterando o nível Auto durante uma sessão

Chame setAutoTier para alterar a preferência de roteamento em uma sessão ao vivo sem alterar o modelo selecionado. Passe null (PythonNone, Gonil) para retornar ao roteamento automático padrão do provedor.

const result = await session.setAutoTier("intelligence");
if (result.status === "pending") {
  // Accepted, but not yet in effect.
}

O runtime não aplica a preferência imediatamente. Ele registra a solicitação e só a efetiva quando, em uma interação posterior do usuário usando o modelo auto, obtém com êxito um modelo utilizável do provedor. Um status pending, portanto, confirma que a solicitação foi aceita, não que tenha entrado em vigor. Apenas a solicitação mais recente permanece: uma nova solicitação substitui qualquer uma anterior que ainda não tenha sido reivindicada por nenhum turno.

Se uma solicitação mais antiga ainda estiver validando quando uma solicitação ou redefinição de preferência mais recente chegar, a chamada mais antiga falhará com um erro de solicitação substituída por outra mais recente em vez de substituir a intenção mais recente.

Observe o resultado por meio destes eventos:

  • session.model_change quando a preferência for confirmada.
  • session.auto_tier_switch_failed quando isso não acontece. Esse evento é efêmero, portanto o runtime nunca o persiste nem o reproduz ao retomar. Seu reason campo é um de policy_rejected, request_failed, setup_failedou unsupported, e a preferência anteriormente efetiva permanece ativa.

Você também pode ler o estado autoritativo a qualquer momento por meio do método RPC da sessão model.getCurrent, que informa o autoTier confirmado, qualquer pendingAutoTier não reivindicado e o activatingAutoTier atualmente reivindicado por uma ativação em andamento.

SDKAlterar o nívelRetornar ao roteamento padrão do provedor
Node.jssession.setAutoTier("balance")session.setAutoTier(null)
Pythonsession.set_auto_tier("balance")session.set_auto_tier(None)
Gosession.SetAutoTier(ctx, &tier)session.SetAutoTier(ctx, nil)
.NETsession.SetAutoTierAsync(AutoTier.Balance)session.SetAutoTierAsync(null)
Rustsession.set_auto_tier(Some(AutoTier::Balance))session.set_auto_tier(None)
Javasession.setAutoTier(AutoTier.BALANCE)session.setAutoTier(null)

Para selecionar o modelo auto e sua preferência de roteamento em uma única chamada, em vez disso, defina o nível no seletor de modelo. O runtime rejeita essa opção quando o modelo é diferente de auto.

SDKConfigure um nível com o switchRedefinir para roteamento padrão do provedor
Node.jssetModel("auto", { autoTier: "balance" })setModel("auto", { autoTier: null })
Pythonset_model("auto", auto_tier="balance")set_model("auto", auto_tier=None)
GoSetModelOptions{AutoTier: &tier}SetModelOptions{ResetAutoTier: true}
.NETnew SetModelOptions { AutoTier = AutoTier.Balance }new SetModelOptions { ResetAutoTier = true }
RustSetModelOptions::default().with_auto_tier(AutoTier::Balance)SetModelOptions::default().with_reset_auto_tier()
Javanew SetModelOptions().setModel("auto").setAutoTier(AutoTier.BALANCE)new SetModelOptions().setModel("auto").setResetAutoTier(true)

Node.js, Python e Rust expressam os três estados em um único valor: Node.js e Python porque null/None é distinguível de um argumento omitido e Rust porque AutoTierPreference::Reset é uma variante distinta da mesma opção. Go, .NET e Java não têm como distinguir entre "resetado" e "não definido" em um mesmo valor, por isso usam um sinalizador separado de reset. Omitir ambos sempre significa "deixar a preferência atual em paz".

Transferência de respostas na retomada

A configuração opcional capi.enableWebSocketResponses escolhe o transporte para a API de Respostas CAPI. O padrão é true, de modo que o transporte WebSocket seja usado sempre que o modelo selecionado disponibilizar o endpoint ws:/responses. Ao defini-lo como false, o sistema volta a usar o transporte HTTP. Em Python, use capi={"enable_web_socket_responses": False}.

Forneça durante a chamada de retomada, quando necessário. Vale a pena configurar isso quando as conexões WebSocket falham ao passar por um proxy e quando uma sessão retomada indica 400 input item ID does not belong to this connection, o que é específico do transporte WebSocket.

const session = await client.resumeSession("user-123-task-456", {
  capi: { enableWebSocketResponses: false },
});

Definir isso como false é equivalente à variável de ambiente COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES, que tem a polaridade oposta.

Exemplo: alterar o modelo no currículo

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

// 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}/:

~/.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
DadosPersistiu?Notes
Histórico de conversas
✅ SimThread de mensagem completo
Resultados da chamada de ferramenta
✅ SimArmazenado em cache para contexto
Estado de planejamento do agente
✅ SimArquivo plan.md
Artefatos de sessão
✅ SimNo files/ diretório
Chaves de provedor/API
❌ NãoSegurança: deve ser fornecida novamente
Estado da ferramenta na memória
❌ NãoAs 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.

PatternExampleCaso de uso
❌abc123IDs aleatóriasDifícil de auditar, sem informações de propriedade
✅user-{userId}-{taskId}user-alice-pr-review-42Aplicativos multiusuários
✅tenant-{tenantId}-{workflow}tenant-acme-onboardingSaaS multilocatário
✅{userId}-{taskId}-{timestamp}alice-deploy-1706932800Limpeza 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

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"

Gerenciando o ciclo de vida da sessão

Listando sessões ativas

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

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:

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:

LinguagemPatternExample
TypeScriptSymbol.asyncDisposeawait using session = await client.createSession(config);
Pythonasync with gerenciador de contextoasync with await client.create_session(on_permission_request=handler) as session:
C#IAsyncDisposableawait using var session = await client.CreateSessionAsync(config);
Godeferdefer session.Disconnect()

Observação

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:

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

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.

Observação

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.

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:

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

Padrões de implantação

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

Diagrama: Fluxograma mostrando o processo descrito.

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

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

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

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:

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

Observação

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 para obter detalhes.

Limitações e considerações

LimitationDescriptionAtenuação
Autenticação de BYOKAs chaves de API não são mantidasArmazene chaves no gerenciador de segredos; fornecer ao retomar
Armazenamento gravável~/.copilot/session-state/ deve ser gravávelMontar volume persistente em contêineres
Nenhum bloqueio de sessãoO acesso simultâneo à mesma sessão é indefinidoImplementar bloqueio ou fila no nível do aplicativo
O estado da ferramenta não persistiuO estado da ferramenta na memória é perdidoFerramentas 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:

// 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ísticaComo usar
Criar sessão retomávelForneça seu próprio sessionId
Retomar sessãoclient.resumeSession(sessionId)
Resumo BYOKFornecer novamente a configuração provider
Listar sessõesclient.listSessions(filter?)
Desconectar-se da sessão ativasession.disconnect()— libera recursos na memória; os dados de sessão no disco são preservados para retomada
Excluir sessão permanentementeclient.deleteSession(sessionId)— remove permanentemente todos os dados de sessão do disco; não pode ser retomado
Implantação em contêineresMontar ~/.copilot/session-state/ no armazenamento persistente

Próximas Etapas