diff --git a/src/commands/agents.command-shared.ts b/src/commands/agents.command-shared.ts index 8b69f50070d..4597bd9d86a 100644 --- a/src/commands/agents.command-shared.ts +++ b/src/commands/agents.command-shared.ts @@ -1,3 +1,4 @@ +import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { resolveStorePath, updateSessionStore } from "../config/sessions.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { resolveStoredSessionOwnerAgentId } from "../gateway/session-store-key.js"; @@ -28,13 +29,18 @@ export async function purgeAgentSessionStoreEntries( ): Promise { try { const normalizedAgentId = normalizeAgentId(agentId); + const storeConfig = cfg.session?.store; + const storeAgentId = + typeof storeConfig === "string" && storeConfig.includes("{agentId}") + ? normalizedAgentId + : normalizeAgentId(resolveDefaultAgentId(cfg)); const storePath = resolveStorePath(cfg.session?.store, { agentId: normalizedAgentId }); await updateSessionStore(storePath, (store) => { for (const key of Object.keys(store)) { if ( resolveStoredSessionOwnerAgentId({ cfg, - agentId: normalizedAgentId, + agentId: storeAgentId, sessionKey: key, }) === normalizedAgentId ) { diff --git a/src/commands/agents.delete.test.ts b/src/commands/agents.delete.test.ts index 605dd5c6e5d..9492adfd1ea 100644 --- a/src/commands/agents.delete.test.ts +++ b/src/commands/agents.delete.test.ts @@ -116,4 +116,43 @@ describe("agents delete command", () => { }); }); }); + + it("preserves shared-store legacy default keys when deleting another agent", async () => { + await withStateDirEnv("openclaw-agents-delete-shared-store-", async ({ stateDir }) => { + const cfg: OpenClawConfig = { + session: { store: path.join(stateDir, "sessions.json") }, + agents: { + list: [ + { id: "main", default: true, workspace: path.join(stateDir, "workspace-main") }, + { id: "ops", workspace: path.join(stateDir, "workspace-ops") }, + ], + }, + }; + const storePath = resolveStorePath(cfg.session?.store, { agentId: "ops" }); + await saveSessionStore(storePath, { + main: { sessionId: "sess-main", updatedAt: 1 }, + "discord:direct:u1": { sessionId: "sess-main-direct", updatedAt: 2 }, + "agent:ops:main": { sessionId: "sess-ops-main", updatedAt: 3 }, + "agent:ops:discord:direct:u2": { sessionId: "sess-ops-direct", updatedAt: 4 }, + }); + await fs.mkdir(path.join(stateDir, "workspace-ops"), { recursive: true }); + await fs.mkdir(path.join(stateDir, "agents", "ops", "agent"), { recursive: true }); + + configMocks.readConfigFileSnapshot.mockResolvedValue({ + ...baseConfigSnapshot, + config: cfg, + runtimeConfig: cfg, + sourceConfig: cfg, + resolved: cfg, + }); + + await agentsDeleteCommand({ id: "ops", force: true, json: true }, runtime); + + expect(runtime.exit).not.toHaveBeenCalled(); + expect(loadSessionStore(storePath, { skipCache: true })).toEqual({ + main: { sessionId: "sess-main", updatedAt: 1 }, + "discord:direct:u1": { sessionId: "sess-main-direct", updatedAt: 2 }, + }); + }); + }); });