Skip to main content

Copilot SDK でのセッション永続化

再起動とデプロイの間で、 Copilot SDK セッションを一時停止、再開、および管理します。

この機能を使用できるユーザーについて

GitHub Copilot SDK は、すべての Copilot プランで使用できます。

メモ

          Copilot SDK は現在 テクニカル プレビューです。 機能と可用性は変更される場合があります。

セッションを作成すると、 Copilot SDK は会話履歴、ツールの状態、および計画コンテキストを維持します。 既定では、この状態はメモリ内に存在し、セッションが終了すると消えます。 永続化を有効にすると、再起動、コンテナーの移行、または異なるクライアント インスタンス間でセッションを再開できます。 セッション状態のライフサイクルの視覚的な概要については、 github/copilot-sdk リポジトリを参照してください。

状態何が起きるか
          **Create** | 
          `sessionId` が割り当てられた |

| アクティブです | プロンプト、ツール呼び出し、応答を送信する | | 一時停止 | ディスクに保存された状態 | | [再開] | ディスクから読み込まれた状態 |

クイック スタート: 再開可能なセッションの作成

再開可能なセッションの鍵は、独自の sessionId を提供することです (他の SDK では session_id使用できます)。 1 つがないと、SDK によってランダムな ID が生成され、後でセッションを再開することはできません。

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、Go、C# の例については、 github/copilot-sdkrepository を参照してください。

セッションの再開

セッションは、終了した場所 (分、時間、または数日後) から再開できます。 クライアント間セッション再開の視覚的な概要については、 github/copilot-sdk リポジトリを参照してください。

// 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、Go、C# の例については、 github/copilot-sdk リポジトリを参照してください。

再開オプション

セッションを再開するときに、必要に応じて多くの設定を再構成できます。 これは、モデルの変更、ツール構成の更新、または動作の変更が必要な場合に便利です。

オプション説明
model再開されたセッションのモデルを変更する
systemMessageシステム プロンプトをオーバーライドまたは拡張する
availableTools使用できるツールを制限する
excludedTools特定のツールを無効にする
providerBYOK 資格情報を再入力する (BYOK セッションに必要)
reasoningEffort推論作業レベルを調整する
streamingストリーミング応答を有効または無効にする
workingDirectory作業ディレクトリを変更する
configDir構成ディレクトリをオーバーライドする
mcpServersMCP サーバーの構成
customAgentsカスタム エージェントを構成する
agent名前でカスタム エージェントを事前に選択する
skillDirectoriesスキルを読み込むためのディレクトリ
disabledSkills無効にするスキル
infiniteSessions無限セッション動作を構成する

例: 履歴書上のモデルの変更

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

再開されたセッションでの BYOK の使用

独自の API キーを使用する場合は、再開時にプロバイダー構成を再指定する必要があります。 API キーは、セキュリティ上の理由からディスクに保持されることはありません。

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

永続化される内容

セッション状態は ~/.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
データ永続化しましたか?メモ
会話履歴
          ✅ はい | メッセージ全体のスレッド |

| ツール呼び出しの結果 | ✅ はい | コンテキスト用にキャッシュ | | エージェントの計画状態 | ✅ はい | plan.md ファイル | | セッション成果物 | ✅ はい | files/ ディレクトリ内 | | プロバイダー/API キー | ❌ いいえ | セキュリティ: 再提供する必要があります | | メモリ内ツールの状態 | ❌ いいえ | ツールはステートレスにする必要がある |

セッション ID のベスト プラクティス

所有権と目的をエンコードするセッション ID を選択します。 これにより、監査とクリーンアップがはるかに簡単になります。

パターン利用シーン
          ❌
          `abc123`
         | ランダム ID | 監査が難しく、所有権情報がない |

| ✅ user-{userId}-{taskId} | user-alice-pr-review-42 | マルチユーザー アプリ | | ✅ tenant-{tenantId}-{workflow} | tenant-acme-onboarding | マルチテナント SaaS | | ✅ {userId}-{taskId}-{timestamp} | alice-deploy-1706932800 | 時間ベースのクリーンアップ |

構造化 ID の利点:

  • 監査が簡単: "ユーザー alice のすべてのセッションを表示する"
  • クリーンアップが簡単: "X より前のすべてのセッションを削除する"
  • 自然アクセス制御: セッション ID からユーザー ID を解析する

例: セッション ID の生成

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 の例については、 github/copilot-sdk リポジトリを参照してください。

セッション ライフサイクルの管理

アクティブなセッションの一覧表示

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

古いセッションのクリーンアップ

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

セッションからの切断

タスクが完了したら、タイムアウトを待機するのではなく、セッションから明示的に切断します。 これによりメモリ内リソースは解放されますが、 ディスク上のセッション データは保持されるため、セッションは後で再開できます。

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

各 SDK には、慣用的な自動クリーンアップ パターンが用意されています。

Languageパターン
          **TypeScript** | `Symbol.asyncDispose` | `await using session = await client.createSession(config);` |

| Python | async with コンテキストマネージャー | async with await client.create_session(config) as session: | | C# | IAsyncDisposable | await using var session = await client.CreateSessionAsync(config); | | 進む | defer | defer session.Disconnect() |

メモ

          `destroy()` は `disconnect()` に置き換えられ、今後のリリースで削除される予定です。 
          `destroy()`を使用する既存のコードは引き続き機能しますが、移行する必要があります。

セッションを完全に削除する

セッションとそのすべてのデータ (会話履歴、計画状態、成果物) を完全に削除するには、 deleteSessionを使用します。 これは元に戻せません。削除後にセッションを再開 することはできません

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

ヒント

          `disconnect()` はメモリ内リソースを解放しますが、後で再開できるようにセッション データをディスクに保持します。 
          `deleteSession()` ディスク上のファイルを含め、すべてを完全に削除します。

自動整理: 待機タイムアウト

SDK には、30 分間のアイドル タイムアウトが組み込まれています。 アクティビティのないセッションは自動的にクリーンアップされます。 アイドル タイムアウト フローの視覚的な概要については、 github/copilot-sdk リポジトリを参照してください。

アイドル状態のイベントを監視して、作業の完了タイミングを確認します。

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

デプロイ パターン

最適な方法は、強力な分離、マルチテナント環境、Azure 動的セッションです。 視覚的な図については、 github/copilot-sdk リポジトリを参照してください。

メリット:

  • 完全な分離
  • シンプルなセキュリティ
  • 簡単なスケーリング

パターン 2: 共有 CLI サーバー (リソース効率)

最適な方法は、内部ツール、信頼できる環境、リソースに制約のあるセットアップです。 視覚的な図については、 github/copilot-sdk リポジトリを参照してください。

必要条件:

  • ユーザーごとの一意のセッション ID
  • アプリケーション レベルのアクセス制御
  • 操作前のセッション ID 検証
// 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 動的セッション

コンテナーを再起動または移行できるサーバーレス/コンテナーデプロイの場合、セッション状態ディレクトリを永続ストレージにマウントする必要があります。

# 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

コンテナーの再起動の永続化の視覚的な図については、 github/copilot-sdk リポジトリを参照してください。

実行時間の長いワークフローの無限セッション

コンテキストの制限を超える可能性があるワークフローの場合は、自動圧縮で無限セッションを有効にします。

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

メモ

しきい値は、絶対トークン数ではなく、コンテキスト使用率の比率 (0.0 ~ 1.0) です。

制限事項と考慮事項

制限事項説明緩和策
          **BYOK の再認証** | API キーが永続化されない | シークレット マネージャーにキーを格納する。再開時に指定する |

| 書き込み可能ストレージ | ~/.copilot/session-state/ 書き込み可能である必要があります | コンテナーに永続ボリュームをマウントする | | セッションロックなし | 同じセッションへの同時アクセスは未定義です | アプリケーション レベルのロックまたはキューを実装する | | ツールの状態が保持されない | メモリ内ツールの状態が失われる | ステートレスであるか、独自の状態を保持するようにツールを設計する |

同時実行アクセスの処理

SDK では、組み込みのセッション ロックは提供されません。 複数のクライアントが同じセッションにアクセスする可能性がある場合は、ハイジャックを防ぐために各セッションがロックされていることを確認する必要があります。

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

まとめ

特徴使用方法
          **再開可能なセッションを作成する** | 独自のサービスを提供する `sessionId` |

| セッションを再開する | client.resumeSession(sessionId) | | BYOK の再開 | provider コンフィグを指定し直す | | セッションの一覧 | client.listSessions(filter?) | | アクティブなセッションから切断する | session.disconnect()—メモリ内リソースを解放します。ディスク上のセッション データは再開のために保持されます | | セッションを完全に削除する | client.deleteSession(sessionId)—ディスクからすべてのセッション データを完全に削除します。再開できません | | コンテナー化されたデプロイ | 永続的ストレージに ~/.copilot/session-state/ をマウントする |