fix(coding-agent): add session_shutdown reasons closes #2863
This commit is contained in:
@@ -2,7 +2,7 @@ import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
||||
import { basename, join, resolve } from "node:path";
|
||||
import type { AgentSession } from "./agent-session.js";
|
||||
import type { AgentSessionRuntimeDiagnostic, AgentSessionServices } from "./agent-session-services.js";
|
||||
import type { SessionStartEvent } from "./extensions/index.js";
|
||||
import type { SessionShutdownEvent, SessionStartEvent } from "./extensions/index.js";
|
||||
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
||||
import type { CreateAgentSessionResult } from "./sdk.js";
|
||||
import { assertSessionCwdExists } from "./session-cwd.js";
|
||||
@@ -127,8 +127,12 @@ export class AgentSessionRuntime {
|
||||
return { cancelled: result?.cancel === true };
|
||||
}
|
||||
|
||||
private async teardownCurrent(): Promise<void> {
|
||||
await emitSessionShutdownEvent(this.session.extensionRunner);
|
||||
private async teardownCurrent(reason: SessionShutdownEvent["reason"], targetSessionFile?: string): Promise<void> {
|
||||
await emitSessionShutdownEvent(this.session.extensionRunner, {
|
||||
type: "session_shutdown",
|
||||
reason,
|
||||
targetSessionFile,
|
||||
});
|
||||
this.session.dispose();
|
||||
}
|
||||
|
||||
@@ -148,7 +152,7 @@ export class AgentSessionRuntime {
|
||||
const previousSessionFile = this.session.sessionFile;
|
||||
const sessionManager = SessionManager.open(sessionPath, undefined, cwdOverride);
|
||||
assertSessionCwdExists(sessionManager, this.cwd);
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("resume", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: sessionManager.getCwd(),
|
||||
@@ -176,7 +180,7 @@ export class AgentSessionRuntime {
|
||||
sessionManager.newSession({ parentSession: options.parentSession });
|
||||
}
|
||||
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("new", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: this.cwd,
|
||||
@@ -229,7 +233,7 @@ export class AgentSessionRuntime {
|
||||
if (!targetLeafId) {
|
||||
const sessionManager = SessionManager.create(this.cwd, sessionDir);
|
||||
sessionManager.newSession({ parentSession: currentSessionFile });
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("fork", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: this.cwd,
|
||||
@@ -247,7 +251,7 @@ export class AgentSessionRuntime {
|
||||
throw new Error("Failed to create forked session");
|
||||
}
|
||||
const sessionManager = SessionManager.open(forkedSessionPath, sessionDir);
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("fork", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: sessionManager.getCwd(),
|
||||
@@ -265,7 +269,7 @@ export class AgentSessionRuntime {
|
||||
} else {
|
||||
sessionManager.createBranchedSession(targetLeafId);
|
||||
}
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("fork", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: this.cwd,
|
||||
@@ -308,7 +312,7 @@ export class AgentSessionRuntime {
|
||||
|
||||
const sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);
|
||||
assertSessionCwdExists(sessionManager, this.cwd);
|
||||
await this.teardownCurrent();
|
||||
await this.teardownCurrent("resume", sessionManager.getSessionFile());
|
||||
this.apply(
|
||||
await this.createRuntime({
|
||||
cwd: sessionManager.getCwd(),
|
||||
@@ -321,7 +325,10 @@ export class AgentSessionRuntime {
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
await emitSessionShutdownEvent(this.session.extensionRunner);
|
||||
await emitSessionShutdownEvent(this.session.extensionRunner, {
|
||||
type: "session_shutdown",
|
||||
reason: "quit",
|
||||
});
|
||||
this.session.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ import {
|
||||
type TurnStartEvent,
|
||||
wrapRegisteredTools,
|
||||
} from "./extensions/index.js";
|
||||
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
||||
import type { BashExecutionMessage, CustomMessage } from "./messages.js";
|
||||
import type { ModelRegistry } from "./model-registry.js";
|
||||
import { expandPromptTemplate, type PromptTemplate } from "./prompt-templates.js";
|
||||
@@ -2372,7 +2373,7 @@ export class AgentSession {
|
||||
|
||||
async reload(): Promise<void> {
|
||||
const previousFlagValues = this._extensionRunner.getFlagValues();
|
||||
await this._extensionRunner.emit({ type: "session_shutdown" });
|
||||
await emitSessionShutdownEvent(this._extensionRunner, { type: "session_shutdown", reason: "reload" });
|
||||
await this.settingsManager.reload();
|
||||
resetApiProviders();
|
||||
await this._resourceLoader.reload();
|
||||
|
||||
@@ -45,6 +45,7 @@ import type {
|
||||
SessionBeforeForkResult,
|
||||
SessionBeforeSwitchResult,
|
||||
SessionBeforeTreeResult,
|
||||
SessionShutdownEvent,
|
||||
ToolCallEvent,
|
||||
ToolCallEventResult,
|
||||
ToolResultEvent,
|
||||
@@ -168,11 +169,12 @@ export type ShutdownHandler = () => void;
|
||||
* Helper function to emit session_shutdown event to extensions.
|
||||
* Returns true if the event was emitted, false if there were no handlers.
|
||||
*/
|
||||
export async function emitSessionShutdownEvent(extensionRunner: ExtensionRunner): Promise<boolean> {
|
||||
export async function emitSessionShutdownEvent(
|
||||
extensionRunner: ExtensionRunner,
|
||||
event: SessionShutdownEvent,
|
||||
): Promise<boolean> {
|
||||
if (extensionRunner.hasHandlers("session_shutdown")) {
|
||||
await extensionRunner.emit({
|
||||
type: "session_shutdown",
|
||||
});
|
||||
await extensionRunner.emit(event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -512,9 +512,12 @@ export interface SessionCompactEvent {
|
||||
fromExtension: boolean;
|
||||
}
|
||||
|
||||
/** Fired on graceful process shutdown paths such as Ctrl+C, Ctrl+D, SIGHUP, and SIGTERM. */
|
||||
/** Fired before an extension runtime is torn down due to quit, reload, or session replacement. */
|
||||
export interface SessionShutdownEvent {
|
||||
type: "session_shutdown";
|
||||
reason: "quit" | "reload" | "new" | "resume" | "fork";
|
||||
/** Destination session file when shutting down due to session replacement. */
|
||||
targetSessionFile?: string;
|
||||
}
|
||||
|
||||
/** Preparation data for tree navigation */
|
||||
|
||||
Reference in New Issue
Block a user