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 teardownCurrentapplyfinishSessionReplacement 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.