mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:10:45 +00:00
fix(memory-core): prevent dreaming-narrative session leaks (GitHub #66358)
Root cause: `runDreamingSweepPhases` passed `params.nowMs` through to each phase without normalizing it first. Each phase recomputed `Date.now()` at call time, producing a slightly different timestamp than the session key used by `generateAndAppendDreamNarrative`. The resulting session key mismatch meant the `deleteSession` call cleaned up a different (or non-existent) key than the one that was created. Fix: - Normalize `nowMs` once at the top of `runDreamingSweepPhases` and pass the consistent value to all phases. - Add a defensive `deleteSession` call in `runDreamingSweepPhases` for each phase after `runLightDreaming`/`runRemDreaming` completes. This acts as a safety net even if the narrative function's primary cleanup is skipped. - Guard the `finally` block in `generateAndAppendDreamNarrative` with `if (params.subagent)` to prevent TypeError if the subagent runtime becomes unavailable mid-flight. This fixes the observed session list pollution where `dreaming-narrative-*-<timestamp>` entries accumulated indefinitely.
This commit is contained in:
@@ -911,7 +911,7 @@ export async function generateAndAppendDreamNarrative(params: {
|
||||
`memory-core: narrative generation failed for ${params.data.phase} phase: ${formatErrorMessage(err)}`,
|
||||
);
|
||||
} finally {
|
||||
if (runId && waitStatus === "timeout") {
|
||||
if (params.subagent && runId && waitStatus === "timeout") {
|
||||
try {
|
||||
const settle = await params.subagent.waitForRun({
|
||||
runId,
|
||||
@@ -929,12 +929,15 @@ export async function generateAndAppendDreamNarrative(params: {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await params.subagent.deleteSession({ sessionKey });
|
||||
} catch (cleanupErr) {
|
||||
params.logger.warn(
|
||||
`memory-core: narrative session cleanup failed for ${params.data.phase} phase: ${formatErrorMessage(cleanupErr)}`,
|
||||
);
|
||||
// Guard against subagent becoming unavailable mid-flight (throws TypeError without this).
|
||||
if (params.subagent) {
|
||||
try {
|
||||
await params.subagent.deleteSession({ sessionKey });
|
||||
} catch (cleanupErr) {
|
||||
params.logger.warn(
|
||||
`memory-core: narrative session cleanup failed for ${params.data.phase} phase: ${formatErrorMessage(cleanupErr)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await scrubDreamingNarrativeArtifacts(params.logger).catch((scrubErr: unknown) => {
|
||||
|
||||
@@ -1641,6 +1641,9 @@ export async function runDreamingSweepPhases(params: {
|
||||
subagent?: Parameters<typeof generateAndAppendDreamNarrative>[0]["subagent"];
|
||||
nowMs?: number;
|
||||
}): Promise<void> {
|
||||
// Normalize nowMs once so all phase timestamps and narrative session keys are consistent.
|
||||
const sweepNowMs = Number.isFinite(params.nowMs) ? params.nowMs : Date.now();
|
||||
|
||||
const light = resolveMemoryLightDreamingConfig({
|
||||
pluginConfig: params.pluginConfig,
|
||||
cfg: params.cfg,
|
||||
@@ -1652,8 +1655,18 @@ export async function runDreamingSweepPhases(params: {
|
||||
config: light,
|
||||
logger: params.logger,
|
||||
subagent: params.subagent,
|
||||
nowMs: params.nowMs,
|
||||
nowMs: sweepNowMs,
|
||||
});
|
||||
// Defensive cleanup: ensure the light-phase narrative session is deleted even if
|
||||
// generateAndAppendDreamNarrative's primary cleanup was skipped due to an error.
|
||||
if (params.subagent) {
|
||||
const lightSessionKey = `dreaming-narrative-light-${sweepNowMs}`;
|
||||
await params.subagent
|
||||
.deleteSession({ sessionKey: lightSessionKey })
|
||||
.catch(() => {
|
||||
// Swallow errors — this is best-effort cleanup.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const rem = resolveMemoryRemDreamingConfig({
|
||||
@@ -1667,8 +1680,17 @@ export async function runDreamingSweepPhases(params: {
|
||||
config: rem,
|
||||
logger: params.logger,
|
||||
subagent: params.subagent,
|
||||
nowMs: params.nowMs,
|
||||
nowMs: sweepNowMs,
|
||||
});
|
||||
// Defensive cleanup: ensure the REM-phase narrative session is deleted.
|
||||
if (params.subagent) {
|
||||
const remSessionKey = `dreaming-narrative-rem-${sweepNowMs}`;
|
||||
await params.subagent
|
||||
.deleteSession({ sessionKey: remSessionKey })
|
||||
.catch(() => {
|
||||
// Swallow errors — this is best-effort cleanup.
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user