fix: share session purge across CLI and gateway agent delete paths (#65524)

This commit is contained in:
bittoby
2026-04-16 15:56:31 +02:00
committed by Gustavo Madeira Santana
parent ae17248040
commit b87d619072
3 changed files with 34 additions and 31 deletions

View File

@@ -1,4 +1,7 @@
import { resolveStorePath, updateSessionStore } from "../config/sessions.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { getLogger } from "../logging/logger.js";
import { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import {
requireValidConfigFileSnapshot as requireValidConfigFileSnapshotBase,
@@ -16,3 +19,22 @@ export async function requireValidConfigFileSnapshot(runtime: RuntimeEnv) {
export async function requireValidConfig(runtime: RuntimeEnv): Promise<OpenClawConfig | null> {
return await requireValidConfigSnapshot(runtime);
}
/** Purge session store entries for a deleted agent (#65524). Best-effort. */
export async function purgeAgentSessionStoreEntries(
cfg: OpenClawConfig,
agentId: string,
): Promise<void> {
try {
const storePath = resolveStorePath(cfg.session?.store, { agentId });
await updateSessionStore(storePath, (store) => {
for (const key of Object.keys(store)) {
if (resolveAgentIdFromSessionKey(key) === agentId) {
delete store[key];
}
}
});
} catch (err) {
getLogger().debug("session store purge skipped during agent delete", err);
}
}

View File

@@ -1,22 +1,16 @@
import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import { replaceConfigFile } from "../config/config.js";
import { logConfigUpdated } from "../config/logging.js";
import {
loadSessionStore,
resolveSessionTranscriptsDirForAgent,
resolveStorePath,
updateSessionStore,
} from "../config/sessions.js";
import { getLogger } from "../logging/logger.js";
import {
DEFAULT_AGENT_ID,
normalizeAgentId,
resolveAgentIdFromSessionKey,
} from "../routing/session-key.js";
import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js";
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../routing/session-key.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { createClackPrompter } from "../wizard/clack-prompter.js";
import { createQuietRuntime, requireValidConfigFileSnapshot } from "./agents.command-shared.js";
import {
createQuietRuntime,
purgeAgentSessionStoreEntries,
requireValidConfigFileSnapshot,
} from "./agents.command-shared.js";
import { findAgentEntryIndex, listAgentEntries, pruneAgentConfig } from "./agents.config.js";
import { moveToTrash } from "./onboard-helpers.js";
@@ -91,24 +85,7 @@ export async function agentsDeleteCommand(
}
// Purge session store entries for this agent so orphaned sessions cannot be targeted (#65524).
try {
const storePath = resolveStorePath(cfg.session?.store, { agentId });
const store = loadSessionStore(storePath);
const hasEntries = Object.keys(store).some(
(key) => resolveAgentIdFromSessionKey(key) === agentId,
);
if (hasEntries) {
await updateSessionStore(storePath, (s) => {
for (const key of Object.keys(s)) {
if (resolveAgentIdFromSessionKey(key) === agentId) {
delete s[key];
}
}
});
}
} catch (err) {
getLogger().debug("session store purge skipped during agent delete", err);
}
await purgeAgentSessionStoreEntries(cfg, agentId);
const quietRuntime = opts.json ? createQuietRuntime(runtime) : runtime;
await moveToTrash(workspaceDir, quietRuntime);

View File

@@ -20,6 +20,7 @@ import {
ensureAgentWorkspace,
isWorkspaceSetupCompleted,
} from "../../agents/workspace.js";
import { purgeAgentSessionStoreEntries } from "../../commands/agents.command-shared.js";
import {
applyAgentConfig,
findAgentEntryIndex,
@@ -650,6 +651,9 @@ export const agentsHandlers: GatewayRequestHandlers = {
const result = pruneAgentConfig(cfg, agentId);
await writeConfigFile(result.config);
// Purge session store entries so orphaned sessions cannot be targeted (#65524).
await purgeAgentSessionStoreEntries(cfg, agentId);
if (deleteFiles) {
await Promise.all([
moveToTrashBestEffort(workspaceDir),