Skip to content

セッション switch/fork/import

源码版本v0.73.1

AgentSessionRuntimeAgentSession の外側のラッパーで、「セッション差し替え」を管轄する。実行中のプロセス内で AgentSession インスタンスは何度も差し替えられ得る:/new で新規セッション、/resume で旧セッションに切替、/fork で特定メッセージから分岐、/import で外部 jsonl を取り込み。毎回の差し替えで旧 session を解体し、新サービスを作り、拡張を再バインドし、イベント購読を復元する。このファイルはその差し替えフローを入れる容器だ。

責務

  1. 現在 session の保持:_session_services フィールドが現在生きているインスタンスを格納し、session/services/cwd getter で晒す。packages/coding-agent/src/core/agent-session-runtime.ts:67-97 参照。
  2. new / switch / fork / import:4 つの差し替えメソッド。まず before イベント (拡張が cancel 可能) を送り、次に teardownCurrent、その後に apply で新 runtime を当てる。packages/coding-agent/src/core/agent-session-runtime.ts:175-198packages/coding-agent/src/core/agent-session-runtime.ts:200-232packages/coding-agent/src/core/agent-session-runtime.ts:234-320packages/coding-agent/src/core/agent-session-runtime.ts:329-364 参照。
  3. イベントフック:session_before_switch / session_before_fork / session_shutdown の 3 種の拡張イベント。拡張が差し替えを cancel できる。packages/coding-agent/src/core/agent-session-runtime.ts:115-147 参照。
  4. rebind コールバック:host (InteractiveMode か rpc-mode) は setRebindSession で、session 差し替え後に呼ばれるコールバックを登録する。これで拡張 UI を再バインドし、イベントを再購読する。packages/coding-agent/src/core/agent-session-runtime.ts:99-113packages/coding-agent/src/core/agent-session-runtime.ts:166-173 参照。
  5. ファクトリ再利用:createRuntime クロージャは createAgentSessionRuntime 時に渡し、以降の差し替えすべてで同じファクトリを再利用し、cwd/agentDir/拡張パスが一致するようにする。packages/coding-agent/src/core/agent-session-runtime.ts:382-400 参照。

設計動機

なぜ直接 this.session = new AgentSession(...) しないのか? 差し替えは 3 つのことを含むからだ:旧 session は shutdown イベントを送って拡張にリソース解放させないといけない。新 session は同じパスからサービス (settings、auth、resource loader) を読み込まないといけない。UI 層はイベントを再購読し、拡張コマンドコンテキストを再バインドしないといけない。この 3 つの順序が肝で——拡張が shutdown を受け取ってから dispose しないと、拡張が持つ参照がダangling pointer になる。teardownCurrentapplyfinishSessionReplacement の三段式はこの順序の硬保証だ。

createRuntime ファクトリの再利用も語る価値がある:差し替えごとに cwdagentDir、拡張パスを再解析するのは重すぎるし、パラメータがドリフトする。クロージャが CLI で一度解析した設定を捕捉し、以降の差し替えはすべて同じものを使う。これで何度 /resume しても拡張パスが突然無効になったりしない。

主要ファイル

差し替え三段式:

typescript
// packages/coding-agent/src/core/agent-session-runtime.ts:149-164
private async teardownCurrent(reason: SessionShutdownEvent["reason"], targetSessionFile?: string): Promise<void> {
	await emitSessionShutdownEvent(this.session.extensionRunner, {
		type: "session_shutdown",
		reason,
		targetSessionFile,
	});
	this.beforeSessionInvalidate?.();
	this.session.dispose();
}

private apply(result: CreateAgentSessionRuntimeResult): void {
	this._session = result.session;
	this._services = result.services;
	this._diagnostics = result.diagnostics;
	this._modelFallbackMessage = result.modelFallbackMessage;
}

forkposition: "at" の時、選択されたエントリをそのまま分岐点とし、before の時は親エントリを取り、ユーザーメッセージのテキストを抽出してエディタに戻す:

typescript
// packages/coding-agent/src/core/agent-session-runtime.ts:251-258
if (position === "at") {
	targetLeafId = selectedEntry.id;
} else {
	if (selectedEntry.type !== "message" || selectedEntry.message.role !== "user") {
		throw new Error("Invalid entry ID for forking");
	}
	targetLeafId = selectedEntry.parentId;
	selectedText = extractUserMessageText(selectedEntry.message.content);
}

データフロー

session 差し替えの統一フロー:

境界と失敗

小ねた

AgentSessionRuntime はセッション差し替えを統一三段式に抽象化する:teardown → apply → rebind。4 つの入り口 (new/switch/fork/import) が同じ teardown とファクトリクロージャを共用し、拡張は before イベントで cancel できる。組み立てファクトリ内部の詳細は createAgentSession 装配、差し替え対象の session 自身は AgentSession オーケストレーション層 参照。