Skip to main content

Wiederaufnahme und Persistenz der Sitzung

Dieses Handbuch führt Sie durch die Sitzungspersistenzfunktionen des SDK – wie Sie die Arbeit anhalten, später fortsetzen und Sitzungen in Produktionsumgebungen verwalten können.

Funktionsweise von Sitzungen

Wenn Sie eine Sitzung erstellen, speichert die Copilot CLI den Konversationsverlauf, den Status der Tools und den Planungskontext. Dieser Zustand befindet sich standardmäßig im Arbeitsspeicher und verschwindet, wenn die Sitzung endet. Mit aktivierter Persistenz können Sie Sitzungen über Neustarts, Containermigrationen oder sogar unterschiedliche Clientinstanzen hinweg fortsetzen.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

StateWas ist los
Erstellen
session_id Zugewiesen
AktivSenden von Eingabeaufforderungen, Toolanrufen, Antworten
PausiertAuf dem Datenträger gespeicherter Zustand
ResumeVom Datenträger geladener Zustand

Schnellstart: Erstellen einer reaktivierbaren Sitzung

Der Schlüssel zu wiederaufnehmbaren Sitzungen ist, dass Sie Ihre eigene session_id bereitstellen. Ohne eine generiert das SDK eine zufällige ID, und die Sitzung kann später nicht fortgesetzt werden.

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

package main

import (
    "context"
    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)

    session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
        SessionID: "user-123-task-456",
        Model:     "gpt-5.2-codex",
        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })

    session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Analyze my codebase"})
    _ = session
}
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

Fortsetzen einer Sitzung

Später – Minuten, Stunden oder sogar Tage – können Sie die Sitzung fortsetzen, von wo Sie aufgehört haben.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

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

package main

import (
    "context"
    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)

    session, _ := client.ResumeSession(ctx, "user-123-task-456", nil)

    session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What did we discuss earlier?"})
    _ = session
}
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)

using GitHub.Copilot;
using GitHub.Copilot.Rpc;

public static class ResumeSessionExample
{
    public static async Task Main()
    {
        await using var client = new CopilotClient();

        var session = await client.ResumeSessionAsync("user-123-task-456", new ResumeSessionConfig
        {
            OnPermissionRequest = (req, inv) =>
                Task.FromResult(PermissionDecision.ApproveOnce()),
        });

        await session.SendAndWaitAsync(new MessageOptions { Prompt = "What did we discuss earlier?" });
    }
}
// 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?" });

Optionen für "Fortsetzen"

Beim Fortsetzen einer Sitzung können Sie optional viele Einstellungen neu konfigurieren. Dies ist nützlich, wenn Sie das Modell ändern, Toolkonfigurationen aktualisieren oder das Verhalten ändern müssen.

AuswahlDescription
modelÄndern des Modells für die fortgesetzte Sitzung
systemMessageÜberschreiben oder Erweitern der Systemaufforderung
availableToolsEinschränken der verfügbaren Tools
excludedToolsDeaktivieren bestimmter Tools
providerErneutes Bereitstellen von BYOK-Anmeldeinformationen (erforderlich für BYOK-Sitzungen)
reasoningEffortAnpassen der Aufwandsstufe für die Begründung
streamingAktivieren oder Deaktivieren von Streaming-Antworten
workingDirectoryÄndern des Arbeitsverzeichnisses
configDirKonfigurationsverzeichnis außer Kraft setzen
mcpServersMCP-Server konfigurieren
customAgentsKonfigurieren von benutzerdefinierten Agents
agentVorauswahl eines benutzerdefinierten Agents anhand des Namens
skillDirectoriesVerzeichnisse, aus denen Fähigkeiten geladen werden
disabledSkillsZu deaktivierende Fähigkeiten
infiniteSessionsKonfigurieren des unendlichen Sitzungsverhaltens

Beispiel: Modellwechsel bei der Fortsetzung

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

Verwendung von BYOK (bring your own key) mit wiederaufgenommenen Sitzungen

Wenn Sie Ihre eigenen API-Schlüssel verwenden, müssen Sie die Anbieterkonfiguration beim Fortsetzen erneut bereitstellen. API-Schlüssel werden aus Sicherheitsgründen niemals auf dem Datenträger beibehalten.

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

Was wird beibehalten?

Der Sitzungsstatus wird gespeichert in ~/.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
DatenPersistiert?Hinweise
Aufgezeichnete Unterhaltungen
✅ JaVollständiger Nachrichtenthread
Ergebnisse des Toolaufrufs
✅ JaIm Cache gespeichert für Kontext
Planungsstatus des Agenten
✅ Ja
plan.md-Datei
Sitzungsartefakte
✅ JaIm files/ Verzeichnis
Anbieter-/API-Schlüssel
❌ NeinSicherheit: muss erneut bereitgestellt werden
Status des Arbeitsspeicher-Tools
❌ NeinWerkzeuge sollten zustandslos sein

Bewährte Methoden für Sitzungs-ID

Wählen Sie Sitzungs-IDs aus, die Besitz und Zweck codieren. Dies erleichtert die Überwachung und Bereinigung.

PatternExampleAnwendungsfall
abc123
Zufällige IDsSchwer zu überwachen, keine Besitzinformationen
user-{userId}-{taskId}
user-alice-pr-review-42Apps mit mehreren Benutzern
tenant-{tenantId}-{workflow}
tenant-acme-onboardingMehrinstanzenfähige SaaS
{userId}-{taskId}-{timestamp}
alice-deploy-1706932800Zeitbasierte Bereinigung

Vorteile strukturierter IDs:

  • Einfach zu überwachen: "Alle Sitzungen für Benutzer alice anzeigen"
  • Einfach zu bereinigen: "Alle Sitzungen löschen, die älter als X sind"
  • Natürliche Zugriffskontrolle: Parsen der Benutzer-ID aus der Sitzungs-ID

Beispiel: Generieren von Sitzungs-IDs

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"

Verwalten des Sitzungslebenszyklus

Auflisten aktiver Sitzungen

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

Bereinigen von alten Sitzungen

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

Die Verbindung zu einer Sitzung trennen (disconnect)

Wenn eine Aufgabe abgeschlossen ist, trennen Sie die Verbindung mit der Sitzung explizit, anstatt auf Timeouts zu warten. Dadurch werden Speicherressourcen freigegeben, sitzungsdaten jedoch auf dem Datenträger beibehalten, sodass die Sitzung später noch fortgesetzt werden kann:

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

Jedes SDK stellt außerdem idiomatische automatische Bereinigungsmuster bereit:

SprachePatternExample
TypeScriptSymbol.asyncDisposeawait using session = await client.createSession(config);
Python
async with Kontext-Managerasync with await client.create_session(on_permission_request=handler) as session:
C#IAsyncDisposableawait using var session = await client.CreateSessionAsync(config);
Godeferdefer session.Disconnect()

Hinweis

destroy() ist zugunsten von disconnect() veraltet. Bestehender Code funktioniert destroy() weiterhin, sollte jedoch migriert werden.

Dauerhaftes Löschen einer Sitzung (deleteSession)

Um eine Sitzung und alle zugehörigen Daten dauerhaft vom Datenträger zu entfernen (Aufgezeichnete Unterhaltungen, Planungszustand, Artefakte), verwenden Sie deleteSession. Dies ist unumkehrbar – die Sitzung kann nach dem Löschen nicht fortgesetzt werden:

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

disconnect() vs deleteSession():disconnect() veröffentlicht Speicherressourcen, behält jedoch Sitzungsdaten auf dem Datenträger für die spätere Wiederaufnahme bei. deleteSession() Entfernt dauerhaft alles, einschließlich Dateien auf dem Datenträger.

Automatische Bereinigung: Leerlaufzeitüberschreitung

Standardmäßig haben Sitzungen kein Leerlauftimeout und bleiben unbegrenzt bestehen, bis sie explizit getrennt oder gelöscht werden. Optional können Sie über CopilotClientOptions.sessionIdleTimeoutSeconds ein serverweites Leerlauf-Timeout konfigurieren:

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

Wenn ein Timeout konfiguriert ist, werden Sitzungen ohne Aktivität für diese Dauer automatisch bereinigt. Auf 0 setzen oder weglassen, um die Funktion zu deaktivieren.

Hinweis

Diese Option gilt nur dann, wenn das SDK den Laufzeitprozess startet. Beim Herstellen einer Verbindung mit einem vorhandenen Server über cliUrlgilt die eigene Timeoutkonfiguration des Servers.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

Sitzungen mit aktiven Prozessen (laufende Befehle, Hintergrund-Agenten) werden unabhängig von der Timeouteinstellung immer vor einer Bereinigung aufgrund von Inaktivität geschützt.

Lauschen Sie auf Leerlaufereignisse, um auf Sitzungsinaktivität zu reagieren:

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

Bereitstellungsmuster

Am besten geeignet für: Starke Isolation, Mehrinstanzenumgebungen, Azure dynamische Sitzungen.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

**Vorteile:**✅ Vollständige Isolation | ✅ Einfache Sicherheit | ✅ Einfache Skalierung

Muster 2: gemeinsam genutzter CLI-Server (ressourceneffizient)

Am besten geeignet für: Interne Tools, vertrauenswürdige Umgebungen, ressourcenbeschränkte Setups.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

Anforderungen:

  • ⚠️ Eindeutige Sitzungs-IDs pro Benutzer
  • ⚠️ Zugriffssteuerung auf Anwendungsebene
  • ⚠️ Sitzungs-ID-Überprüfung vor Vorgängen
// 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);
}

dynamische Sitzungen Azure

Für Serverlose/Containerbereitstellungen, bei denen Container neu gestartet oder migriert werden können:

Persistenten Speicher einbinden

Das Sitzungsstatusverzeichnis muss an beständigen Speicher bereitgestellt werden:

# 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

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

Die Sitzung bleibt auch nach Container-Neustarts erhalten!

Fortlaufende Sitzungen für langandauernde Workflows

Aktivieren Sie für Workflows, die Kontextbeschränkungen überschreiten könnten, dauerhafte Sitzungen mit automatischer Datenkomprimierung.

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

Hinweis

Schwellenwerte sind Kontextauslastungsverhältnisse (0,0-1,0), keine absolute Tokenanzahl. Weitere Einzelheiten finden Sie unter SDK- und CLI-Kompatibilität.

Einschränkungen und Überlegungen

EinschränkungDescriptionAbschwächung
BYOK-Erneute AuthentifizierungAPI-Schlüssel werden nicht beibehaltenSchlüssel in Ihrem geheimen Manager speichern; "On Resume" bereitstellen
Schreibbarer Speicher
~/.copilot/session-state/ muss schreibbar seinBereitstellen persistenter Volumes in Containern
Keine SitzungssperreGleichzeitiger Zugriff auf dieselbe Sitzung ist nicht definiertImplementieren der Sperrung oder Warteschlange auf Anwendungsebene
Der Toolstatus wurde nicht beibehalten.Der Status des In-Memory-Tools geht verloren.Entwerfen Sie Werkzeuge, die zustandslos sind oder ihren eigenen Zustand speichern

Verwaltung gleichzeitigen Zugriffs

Das SDK bietet keine integrierte Sitzungssperre. Wenn mehrere Clients möglicherweise auf dieselbe Sitzung zugreifen:

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

Zusammenfassung

FunktionVerwendung
Reaktivierbare Sitzung erstellenStellen Sie Ihre eigene sessionId
Sitzung fortsetzenclient.resumeSession(sessionId)
BYOK fortsetzenKonfiguration erneut bereitstellen provider
Sitzungen auflistenclient.listSessions(filter?)
Verbindung mit der aktiven Sitzung trennen
session.disconnect()— gibt Speicherressourcen frei; Sitzungsdaten auf dem Datenträger werden für die Wiederaufnahme beibehalten.
Sitzung dauerhaft löschen
client.deleteSession(sessionId)— entfernt dauerhaft alle Sitzungsdaten vom Datenträger; Kann nicht fortgesetzt werden
Containerisierte BereitstellungZum persistenten Speicher einbinden ~/.copilot/session-state/

Nächste Schritte