Skip to content

Session switch/fork/import ​

源码版本v0.73.1

AgentSessionRuntime est l'enveloppe extérieure d'AgentSession, responsable du « remplacement de session ». Dans un processus en cours, l'instance AgentSession peut être échangée plusieurs fois : /new ouvre une nouvelle session, /resume bascule sur une ancienne, /fork crée une branche depuis un message donné, /import importe un jsonl externe. Chaque remplacement implique de démonter l'ancienne session, de créer de nouveaux services, de re-lier les extensions et de restaurer les abonnements aux événements. Ce fichier est le conteneur de ce flux de remplacement.

Responsabilités ​

  1. Détention de la session courante : les champs _session et _services stockent les instances vivantes, exposées via les getters session/services/cwd. Voir packages/coding-agent/src/core/agent-session-runtime.ts:67-97.
  2. new / switch / fork / import : quatre méthodes de remplacement — elles émettent d'abord un événement before (que les extensions peuvent cancel), puis teardownCurrent, puis apply du nouveau runtime. Voir packages/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 et packages/coding-agent/src/core/agent-session-runtime.ts:329-364.
  3. Hooks d'événements : trois types d'événements d'extension — session_before_switch / session_before_fork / session_shutdown — permettent aux extensions d'annuler le remplacement. Voir packages/coding-agent/src/core/agent-session-runtime.ts:115-147.
  4. Callback de rebind : l'host (InteractiveMode ou rpc-mode) enregistre via setRebindSession un callback appelé après le remplacement de la session, pour re-lier l'UI des extensions et ré-abonner les événements. Voir packages/coding-agent/src/core/agent-session-runtime.ts:99-113 et packages/coding-agent/src/core/agent-session-runtime.ts:166-173.
  5. Réutilisation de factory : la closure createRuntime est passée à createAgentSessionRuntime, puis réutilisée à chaque remplacement — garantit la cohérence des cwd/agentDir/chemins d'extensions. Voir packages/coding-agent/src/core/agent-session-runtime.ts:382-400.

Motivation de design ​

Pourquoi ne pas faire directement this.session = new AgentSession(...) ? Parce que le remplacement touche à trois choses : l'ancienne session doit émettre un événement shutdown pour que les extensions nettoient leurs ressources ; la nouvelle session doit charger ses services depuis le même chemin (settings, auth, resource loader) ; l'UI doit se ré-abonner aux événements et re-lier le context des commandes d'extension. L'ordre de ces trois étapes est critique — les extensions doivent recevoir shutdown avant le dispose, sinon leurs références deviennent des pointeurs fous. La séquence en trois temps teardownCurrent → apply → finishSessionReplacement est la garantie dure de cet ordre.

La réutilisation de la factory createRuntime mérite aussi une explication : re-parser cwd, agentDir et les chemins d'extensions à chaque remplacement est lourd, et les paramètres dérivent. La closure capture la configuration résolue une fois au CLI, et les remplacements ultérieurs utilisent la même copie, garantissant qu'après plusieurs /resume le chemin d'extensions ne tombe pas soudainement en panne.

Fichiers clés ​

Le triptyque de remplacement :

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

Pour fork en position: "at", on prend directement l'entrée sélectionnée comme point de branche ; en before, on prend l'entrée parente, et on extrait le texte du message utilisateur pour pré-remplir l'éditeur :

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

Flux de données ​

Le flux unifié de remplacement de session :

Limites et échecs ​

Résumé ​

AgentSessionRuntime abstrait le remplacement de session en un triptyque unifié : teardown → apply → rebind. Les quatre entrées (new/switch/fork/import) partagent la même logique teardown et la même closure factory ; les extensions peuvent cancel via l'événement before. Pour les détails internes de la factory d'assemblage, voir Assemblage createAgentSession ; pour la session elle-même qui est remplacée, voir AgentSession : couche d'orchestration.