Merge PR #6432: fix(session): clear session-scoped tool state (@roboomp)

This commit is contained in:
can1357
2026-07-24 02:24:15 +02:00
7 changed files with 149 additions and 3 deletions
@@ -1399,6 +1399,7 @@ export class AgentSession {
finishBashSessionTransition: (transition, success) => this.#bash.finishSessionTransition(transition, success),
cancelOwnAsyncJobs: () => this.#cancelOwnAsyncJobs(),
clearCheckpointRuntimeState: () => this.#clearCheckpointRuntimeState(),
clearSessionScopedToolState: () => this.#clearSessionScopedToolState(),
clearFreshProviderSessionId: () => {
this.#freshProviderSessionId = undefined;
},
@@ -4023,6 +4024,12 @@ export class AgentSession {
this.#rewoundToolResultIds.clear();
}
/** Drop mutable tool decisions and directives owned by the previous logical session. */
#clearSessionScopedToolState(): void {
this.#toolChoiceQueue.clear();
this.#tools.clearAcpPermissionDecisions();
}
/**
* Rebuild checkpoint/rewind runtime state from the current branch. Handles two
* cases surfaced by session resume, `switchSession()` reloading the same file,
@@ -5699,6 +5706,7 @@ export class AgentSession {
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
}
this.#clearSessionScopedToolState();
this.#clearCheckpointRuntimeState();
this.setTodoPhases([]);
this.#freshProviderSessionId = undefined;
@@ -6819,6 +6827,9 @@ export class AgentSession {
if (switchingToDifferentSession) {
await this.#memory.resetContextForNewTranscript();
}
if (switchingToDifferentSession) {
this.#clearSessionScopedToolState();
}
this.#reconnectToAgent();
try {
await this.#sessionSwitchReconciler?.();
@@ -6941,6 +6952,7 @@ export class AgentSession {
} finally {
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
}
this.#clearSessionScopedToolState();
this.#rehydrateCheckpointRewindState();
this.#todo.syncFromBranch();
this.#freshProviderSessionId = undefined;
@@ -7038,6 +7050,8 @@ export class AgentSession {
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
}
this.#clearSessionScopedToolState();
this.#rehydrateCheckpointRewindState();
this.sessionManager.appendMessage({
role: "user",
@@ -56,6 +56,7 @@ export interface SessionHandoffHost {
finishBashSessionTransition(transition: BashSessionTransition, success: boolean): void;
cancelOwnAsyncJobs(): void;
clearCheckpointRuntimeState(): void;
clearSessionScopedToolState(): void;
clearFreshProviderSessionId(): void;
syncAgentSessionId(): void;
rekeyMemoryForCurrentSessionId(): void;
@@ -236,6 +237,8 @@ export class SessionHandoff {
this.#host.finishBashSessionTransition(bashTransition, sessionTransitioned);
}
this.#host.clearSessionScopedToolState();
this.#host.clearCheckpointRuntimeState();
// agent.reset() clears the core steering/follow-up queues. Preserve any queued
// steers/follow-ups (RPC/SDK steer()/followUp() issued during the handoff, or a
@@ -158,6 +158,11 @@ export class SessionTools {
return this.#skillsSettings;
}
/** Drops cached per-session ACP `allow_always`/`reject_always` decisions. */
clearAcpPermissionDecisions(): void {
this.#acpPermissionDecisions.clear();
}
/** Re-wraps active and mounted tools after the ACP client changes. */
refreshAcpPermissionGates(): void {
this.#acpPermissionDecisions.clear();