mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-22 13:08:07 +00:00
fix(memory): write dream fallback without subagent runtime (#90121)
This commit is contained in:
@@ -1020,20 +1020,21 @@ describe("generateAndAppendDreamNarrative", () => {
|
||||
const storePath = path.join(sessionsDir, "sessions.json");
|
||||
const orphanPath = path.join(sessionsDir, "orphan.jsonl");
|
||||
const livePath = path.join(sessionsDir, "still-live.jsonl");
|
||||
const updatedAt = Date.now();
|
||||
await sessionStoreRuntimeModule.saveSessionStore(
|
||||
storePath,
|
||||
{
|
||||
"agent:main:dreaming-narrative-light-1": {
|
||||
sessionId: "missing",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
"agent:main:kept-session": {
|
||||
sessionId: "still-live",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
"agent:main:telegram:group:dreaming-narrative-room": {
|
||||
sessionId: "still-missing-non-dreaming",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
},
|
||||
{ skipMaintenance: true },
|
||||
@@ -1090,20 +1091,21 @@ describe("generateAndAppendDreamNarrative", () => {
|
||||
// A second dreaming row whose transcript is fresh (a live/just-started run)
|
||||
// must be preserved.
|
||||
const liveTranscript = path.join(sessionsDir, "live-dreaming.jsonl");
|
||||
const updatedAt = Date.now();
|
||||
await sessionStoreRuntimeModule.saveSessionStore(
|
||||
storePath,
|
||||
{
|
||||
"agent:main:dreaming-narrative-deep-orphan": {
|
||||
sessionId: "orphan-dreaming",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
"agent:main:dreaming-narrative-deep-live": {
|
||||
sessionId: "live-dreaming",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
"agent:main:kept-session": {
|
||||
sessionId: "still-live",
|
||||
updatedAt: Date.now(),
|
||||
updatedAt,
|
||||
},
|
||||
},
|
||||
{ skipMaintenance: true },
|
||||
|
||||
@@ -152,7 +152,7 @@ function buildRequestScopedFallbackNarrative(_data: NarrativePhaseData): string
|
||||
return "A memory trace surfaced, but details were unavailable in this run.";
|
||||
}
|
||||
|
||||
async function appendFallbackNarrativeEntry(params: {
|
||||
export async function appendFallbackNarrativeEntry(params: {
|
||||
workspaceDir: string;
|
||||
data: NarrativePhaseData;
|
||||
nowMs: number;
|
||||
|
||||
@@ -2341,6 +2341,57 @@ describe("short-term dreaming trigger", () => {
|
||||
expect(memoryText).toContain("Move backups to S3 Glacier.");
|
||||
});
|
||||
|
||||
it("writes fallback dream diary prose when managed cron has no subagent runtime", async () => {
|
||||
const logger = createLogger();
|
||||
const workspaceDir = await createTempWorkspace("memory-dreaming-cron-no-subagent-");
|
||||
await writeDailyMemoryNote(workspaceDir, "2026-04-02", ["Move backups to S3 Glacier."]);
|
||||
|
||||
await recordShortTermRecalls({
|
||||
workspaceDir,
|
||||
query: "backup policy",
|
||||
results: [
|
||||
{
|
||||
path: "memory/2026-04-02.md",
|
||||
startLine: 1,
|
||||
endLine: 1,
|
||||
score: 0.9,
|
||||
snippet: "Move backups to S3 Glacier.",
|
||||
source: "memory",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const result = await runShortTermDreamingPromotionIfTriggered({
|
||||
cleanedBody: constants.DREAMING_SYSTEM_EVENT_TEXT,
|
||||
trigger: "cron",
|
||||
workspaceDir,
|
||||
config: {
|
||||
enabled: true,
|
||||
cron: constants.DEFAULT_DREAMING_CRON_EXPR,
|
||||
limit: 10,
|
||||
minScore: 0,
|
||||
minRecallCount: 0,
|
||||
minUniqueQueries: 0,
|
||||
recencyHalfLifeDays: constants.DEFAULT_DREAMING_RECENCY_HALF_LIFE_DAYS,
|
||||
verboseLogging: false,
|
||||
},
|
||||
logger,
|
||||
});
|
||||
|
||||
expect(result?.handled).toBe(true);
|
||||
const memoryText = await fs.readFile(path.join(workspaceDir, "MEMORY.md"), "utf-8");
|
||||
expect(memoryText).toContain("Move backups to S3 Glacier.");
|
||||
const dreamsText = await fs.readFile(path.join(workspaceDir, "DREAMS.md"), "utf-8");
|
||||
expect(dreamsText).toContain("<!-- openclaw:dreaming:diary:start -->");
|
||||
expect(dreamsText).toContain(
|
||||
"A memory trace surfaced, but details were unavailable in this run.",
|
||||
);
|
||||
expect(dreamsText).not.toContain("Move backups to S3 Glacier.");
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
"memory-core: narrative generation used fallback for deep phase because subagent runtime is unavailable.",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps one-off recalls out of long-term memory under default thresholds", async () => {
|
||||
const logger = createLogger();
|
||||
const workspaceDir = await createTempWorkspace("memory-dreaming-strict-");
|
||||
|
||||
@@ -556,7 +556,7 @@ export async function runShortTermDreamingPromotionIfTriggered(params: {
|
||||
const detachNarratives = params.trigger === "cron";
|
||||
const [
|
||||
{ writeDeepDreamingReport },
|
||||
{ generateAndAppendDreamNarrative, runDetachedDreamNarrative },
|
||||
{ appendFallbackNarrativeEntry, generateAndAppendDreamNarrative, runDetachedDreamNarrative },
|
||||
{ runDreamingSweepPhases },
|
||||
{
|
||||
applyShortTermPromotions,
|
||||
@@ -652,13 +652,22 @@ export async function runShortTermDreamingPromotionIfTriggered(params: {
|
||||
storage: params.config.storage ?? { mode: "separate", separateReports: false },
|
||||
});
|
||||
// Generate dream diary narrative from promoted memories.
|
||||
if (params.subagent && (candidates.length > 0 || applied.applied > 0)) {
|
||||
if (candidates.length > 0 || applied.applied > 0) {
|
||||
const data: NarrativePhaseData = {
|
||||
phase: "deep",
|
||||
snippets: candidates.map((c) => c.snippet).filter(Boolean),
|
||||
promotions: applied.appliedCandidates.map((c) => c.snippet).filter(Boolean),
|
||||
};
|
||||
if (detachNarratives) {
|
||||
if (!params.subagent) {
|
||||
await appendFallbackNarrativeEntry({
|
||||
workspaceDir,
|
||||
data,
|
||||
nowMs: sweepNowMs,
|
||||
timezone: params.config.timezone,
|
||||
logger: params.logger,
|
||||
reason: "subagent runtime is unavailable",
|
||||
});
|
||||
} else if (detachNarratives) {
|
||||
runDetachedDreamNarrative({
|
||||
subagent: params.subagent,
|
||||
workspaceDir,
|
||||
|
||||
Reference in New Issue
Block a user