Session switch/fork/import
AgentSessionRuntime ist der äußere Wrapper um AgentSession und zuständig für "Session-Austausch". In einem laufenden Prozess kann die AgentSession-Instanz mehrfach ausgetauscht werden: /new öffnet eine neue Session, /resume schaltet auf eine alte, /fork zweigt von einer Nachricht ab, /import importiert eine externe jsonl. Bei jedem Austausch muss die alte Session abgerissen, neue Services erzeugt, Extensions neu gebunden und Event-Subscriptions wiederhergestellt werden. Diese Datei ist der Container für diesen Austausch-Prozess.
Verantwortung
- Aktuelle Session halten:
_sessionund_servicesspeichern die aktuell lebenden Instanzen, übersession/services/cwd-Getter freigegeben. Siehepackages/coding-agent/src/core/agent-session-runtime.ts:67-97. - new / switch / fork / import: Vier Austausch-Methoden, senden zuerst ein before-Event (Extensions können abbrechen), dann
teardownCurrent, dannapplyder neuen Runtime. Siehepackages/coding-agent/src/core/agent-session-runtime.ts:175-198,packages/coding-agent/src/core/agent-session-runtime.ts:200-232,packages/coding-agent/src/core/agent-session-runtime.ts:234-320,packages/coding-agent/src/core/agent-session-runtime.ts:329-364. - Event-Hooks: Drei Extension-Events
session_before_switch/session_before_fork/session_shutdown, Extensions können den Austausch abbrechen. Siehepackages/coding-agent/src/core/agent-session-runtime.ts:115-147. - rebind-Callback: Der Host (InteractiveMode oder rpc-Modus) registriert über
setRebindSessioneinen Callback, der nach dem Session-Austausch aufgerufen wird, um Extension-UI neu zu binden und Events neu zu abonnieren. Siehepackages/coding-agent/src/core/agent-session-runtime.ts:99-113,packages/coding-agent/src/core/agent-session-runtime.ts:166-173. - Fabrik-Wiederverwendung: Das
createRuntime-Closure wird beimcreateAgentSessionRuntimeübergeben und bei jedem Austausch wiederverwendet, um cwd/agentDir/Extension-Pfade konsistent zu halten. Siehepackages/coding-agent/src/core/agent-session-runtime.ts:382-400.
Entwurfsmotivation
Warum nicht einfach this.session = new AgentSession(...)? Weil der Austausch drei Dinge berührt: Die alte Session muss ein shutdown-Event senden, damit Extensions Ressourcen freigeben; die neue Session muss Services aus demselben Pfad laden (settings, auth, resource loader); die UI-Schicht muss Events neu abonnieren und Extension-Befehlskontexte neu binden. Die Reihenfolge dieser drei ist kritisch - Extensions müssen shutdown empfangen, bevor sie disposed werden, sonst werden ihre Referenzen zu wilden Pointern. Die dreiteilige Sequenz teardownCurrent → apply → finishSessionReplacement ist die harte Garantie für diese Reihenfolge.
Die Wiederverwendung der createRuntime-Fabrik ist auch erwähnenswert: Bei jedem Austausch cwd, agentDir und Extension-Pfade neu aufzulösen wäre zu schwer und die Parameter würden driften. Das Closure fängt die einmal vom CLI geparste Konfiguration ein, spätere Austausche verwenden dieselbe, damit nach mehreren /resume die Extension-Pfade nicht plötzlich ungültig werden.
Wichtige Dateien
packages/coding-agent/src/core/agent-session-runtime.ts:67-97—class AgentSessionRuntimeFelder und Getter.packages/coding-agent/src/core/agent-session-runtime.ts:149-164—teardownCurrentundapply, die zwei Kernschritten des Austauschs.packages/coding-agent/src/core/agent-session-runtime.ts:166-173—finishSessionReplacement, löst den rebind-Callback des Hosts aus.packages/coding-agent/src/core/agent-session-runtime.ts:175-198—switchSession, resume einer existierenden jsonl.packages/coding-agent/src/core/agent-session-runtime.ts:200-232—newSession, unterstütztparentSessionfür einen Verzweigungsbaum.packages/coding-agent/src/core/agent-session-runtime.ts:234-320—fork, positionbefore/atals zwei Semantiken.packages/coding-agent/src/core/agent-session-runtime.ts:329-364—importFromJsonl, kopiert externe jsonl in sessionDir und switcht.packages/coding-agent/src/core/agent-session-runtime.ts:382-400—createAgentSessionRuntime, Eingang der initialen Runtime-Fabrik.
Die dreiteilige Austausch-Sequenz:
// 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;
}fork nimmt bei position: "at" den ausgewählten Eintrag direkt als Verzweigungspunkt, bei before den Eltern-Eintrag und extrahiert den User-Nachricht-Text zum Zurückfüllen in den Editor:
// 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);
}Datenfluss
Der einheitliche Ablauf eines Session-Austauschs:
Grenzen und Fehler
- fork auf Nicht-User-Nachricht: Bei
position: "before"kann nur von einer User-Nachricht verzweigt werden, sonst wirftInvalid entry ID for forking, siehepackages/coding-agent/src/core/agent-session-runtime.ts:254-256. - fork-Fehler-Rollback: Wenn
sourceManager.createBranchedSessionnull zurückgibt, wirft esFailed to create forked session, aber die alte Session ist schon disposed, der Aufrufer muss diesen "Zwischenzustand"-Fehler behandeln, siehepackages/coding-agent/src/core/agent-session-runtime.ts:286-288. - import-Datei fehlt:
existsSync-Prüfung wirftSessionImportFileNotFoundError, schlägt nicht still fehl, siehepackages/coding-agent/src/core/agent-session-runtime.ts:330-333. - import cwd fehlt:
assertSessionCwdExistsprüft, ob das cwd der importierten jsonl noch zugänglich ist, im interaktiven Modus poppingt es einen Prompt, in dem der Nutzer neu wählt, siehepackages/coding-agent/src/core/agent-session-runtime.ts:351-352. - dispose-Reihenfolge: Der
quit-Reason geht ebenfalls durch denteardownCurrent-Ablauf, damit Extensions beim Prozess-Ende das shutdown-Event empfangen.
Zusammenfassung
AgentSessionRuntime abstrahiert den Session-Austausch als einheitliche dreiteilige Sequenz: teardown → apply → rebind. Die vier Eingänge (new/switch/fork/import) teilen sich denselben teardown und dasselbe Fabrik-Closure, Extensions können über before-Events abbrechen. Wie die Zusammenbau-Fabrik intern arbeitet, siehe createAgentSession Zusammenbau; die ausgetauschte Session selbst siehe AgentSession Orchestrierungsschicht.