diff --git a/integrations/openclaw/__tests__/e2e/test_sessionCapture.ts b/integrations/openclaw/__tests__/e2e/test_sessionCapture.ts index 21911c17..454916f6 100644 --- a/integrations/openclaw/__tests__/e2e/test_sessionCapture.ts +++ b/integrations/openclaw/__tests__/e2e/test_sessionCapture.ts @@ -28,7 +28,7 @@ function resetMockImplementations(): void { type HookHandler = (event: unknown, ctx: unknown) => Promise | unknown; -function createApi() { +function createApi(pluginConfig: Record = {}) { const handlers = new Map(); const api = { id: "cognee-openclaw", @@ -41,6 +41,7 @@ function createApi() { enableSessions: true, captureSession: true, datasetName: "testds", + ...pluginConfig, }, runtime: {}, logger: { info: jest.fn(), warn: jest.fn(), debug: jest.fn() }, @@ -189,6 +190,26 @@ describe("session capture (traces + QA)", () => { }); describe("session_end final chain", () => { + it("does not persist clean or crashed sessions when persistence is disabled", async () => { + const { emit } = createApi({ persistSessionsAfterEnd: false }); + + await emit("gateway_start", { port: 1 }, {}); + await flush(); + await emit("before_prompt_build", { prompt: "hello there" }, { agentId: "will", sessionId: "s1" }); + await flush(); + + expect(spawnExitWatcher).toHaveBeenCalledWith(expect.objectContaining({ + datasetName: undefined, + cogneeSessionId: undefined, + })); + + await emit("session_end", { sessionId: "s1", messageCount: 1 }, { agentId: "will", sessionId: "s1" }); + await flush(30); + + expect(mockImprove).not.toHaveBeenCalled(); + expect(mockUnregisterAgent).toHaveBeenCalledWith({ agentSessionName: "s1-will" }); + }); + it("improves before unregistering and returns without blocking", async () => { const { emit } = createApi(); diff --git a/integrations/openclaw/src/plugin.ts b/integrations/openclaw/src/plugin.ts index e12f207a..99f31509 100644 --- a/integrations/openclaw/src/plugin.ts +++ b/integrations/openclaw/src/plugin.ts @@ -1474,11 +1474,11 @@ const memoryCogneePlugin = { baseUrl: cfg.baseUrl, apiKey: resolvedApiKey || cfg.apiKey, pidfilePath: exitWatcherPidfilePath(agentSessionName), - // On unclean gateway death, bridge this session's cache into the - // graph before unregistering. The gateway anchor watcher has no - // session and stays unregister-only. - datasetName: captureDatasetName(ctx.agentId), - cogneeSessionId: cogneeSessionId(ctx.sessionId), + // On unclean gateway death, bridge this session's cache only when + // session persistence is enabled. The gateway anchor watcher has + // no session and stays unregister-only. + datasetName: cfg.persistSessionsAfterEnd ? captureDatasetName(ctx.agentId) : undefined, + cogneeSessionId: cfg.persistSessionsAfterEnd ? cogneeSessionId(ctx.sessionId) : undefined, logger: api.logger, }).catch(() => {}); } catch (e: unknown) { @@ -1985,7 +1985,7 @@ const memoryCogneePlugin = { // into THIS session's agent dataset. Must complete BEFORE unregister: // unregister can drop activeAgents to 0 and, in COGNEE_AGENT_MODE, // shut the server down mid-pipeline. - if (cfg.improveOnSessionEnd && endSessionId) { + if (cfg.persistSessionsAfterEnd && cfg.improveOnSessionEnd && endSessionId) { // Let this session's in-flight capture writes land first; improve // only bridges what is already in the session cache. await awaitPendingStores(endSessionId);