Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { SmartExtractor, createExtractionRateLimiter } from "./src/smart-extract
import { compressTexts, estimateConversationValue } from "./src/session-compressor.js";
import { NoisePrototypeBank } from "./src/noise-prototypes.js";
import { createLlmClient } from "./src/llm-client.js";
import { createDreamingEngine, type DreamingEngine, type DreamingConfig } from "./src/dreaming-engine.js";
import { createDecayEngine, DEFAULT_DECAY_CONFIG } from "./src/decay-engine.js";
import { createTierManager, DEFAULT_TIER_CONFIG } from "./src/tier-manager.js";
import { createMemoryUpgrader } from "./src/memory-upgrader.js";
Expand Down Expand Up @@ -225,6 +226,7 @@ interface PluginConfig {
skipLowValue?: boolean;
maxExtractionsPerHour?: number;
};
dreaming?: DreamingConfig;
}

type ReflectionThinkLevel = "off" | "minimal" | "low" | "medium" | "high";
Expand Down Expand Up @@ -254,7 +256,9 @@ function resolveEnvVars(value: string): string {
return value.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
const envValue = process.env[envVar];
if (!envValue) {
throw new Error(`Environment variable ${envVar} is not set`);
// Return empty string instead of throwing β€” the feature using this value
// will simply be unavailable (e.g., reranking disabled).
return '';
}
return envValue;
});
Expand Down Expand Up @@ -3606,6 +3610,7 @@ const memoryLanceDBProPlugin = {
// ========================================================================

let backupTimer: ReturnType<typeof setInterval> | null = null;
let dreamingTimer: ReturnType<typeof setInterval> | null = null;
const BACKUP_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours

async function runBackup() {
Expand Down Expand Up @@ -3749,12 +3754,70 @@ const memoryLanceDBProPlugin = {
// Run initial backup after a short delay, then schedule daily
setTimeout(() => void runBackup(), 60_000); // 1 min after start
backupTimer = setInterval(() => void runBackup(), BACKUP_INTERVAL_MS);

// ========================================================================
// Dreaming Engine
// ========================================================================
let dreamingEngine: DreamingEngine | null = null;
dreamingTimer = null;

const dreamingConfig = config.dreaming as DreamingConfig | undefined;
if (dreamingConfig?.enabled) {
try {
dreamingEngine = createDreamingEngine({
store,
decayEngine,
tierManager,
config: dreamingConfig,
log: (msg: string) => api.logger.info(msg),
debugLog: (msg: string) => api.logger.debug(msg),
});

// Run first dreaming cycle after 5 minutes, then every 6 hours
const DREAMING_INTERVAL_MS = 6 * 60 * 60 * 1000;
setTimeout(async () => {
try {
const report = await dreamingEngine!.run();
api.logger.info(
`memory-lancedb-pro: dreaming cycle complete β€” ` +
`light: ${report.phases.light.scanned} scanned, ${report.phases.light.transitions.length} transitions; ` +
`deep: ${report.phases.deep.promoted}/${report.phases.deep.candidates} promoted; ` +
`rem: ${report.phases.rem.patterns.length} patterns, ${report.phases.rem.reflectionsCreated} reflections`,
);
} catch (err) {
api.logger.warn(`memory-lancedb-pro: dreaming cycle failed: ${String(err)}`);
}
}, 5 * 60 * 1000);

dreamingTimer = setInterval(async () => {
try {
const report = await dreamingEngine!.run();
api.logger.info(
`memory-lancedb-pro: dreaming cycle complete β€” ` +
`light: ${report.phases.light.scanned} scanned, ${report.phases.light.transitions.length} transitions; ` +
`deep: ${report.phases.deep.promoted}/${report.phases.deep.candidates} promoted; ` +
`rem: ${report.phases.rem.patterns.length} patterns, ${report.phases.rem.reflectionsCreated} reflections`,
);
} catch (err) {
api.logger.warn(`memory-lancedb-pro: dreaming cycle failed: ${String(err)}`);
}
}, DREAMING_INTERVAL_MS);

api.logger.info("memory-lancedb-pro: dreaming engine initialized (interval: 6h)");
} catch (err) {
api.logger.warn(`memory-lancedb-pro: dreaming init failed: ${String(err)}`);
}
}
},
stop: async () => {
if (backupTimer) {
clearInterval(backupTimer);
backupTimer = null;
}
if (dreamingTimer) {
clearInterval(dreamingTimer);
dreamingTimer = null;
}
api.logger.info("memory-lancedb-pro: stopped");
},
});
Expand Down Expand Up @@ -4040,6 +4103,7 @@ export function parsePluginConfig(value: unknown): PluginConfig {
: 30,
}
: { skipLowValue: false, maxExtractionsPerHour: 30 },
dreaming: cfg.dreaming as DreamingConfig | undefined,
};
}

Expand Down
178 changes: 178 additions & 0 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,135 @@
"description": "Maximum number of auto-capture extractions allowed per hour"
}
}
},
"dreaming": {
"type": "object",
"additionalProperties": false,
"description": "Dreaming: periodic memory consolidation and promotion from short-term to long-term storage. Bridges LanceDB Pro's tier-manager, decay-engine, and smart-extraction into OpenClaw's dreaming lifecycle.",
"properties": {
"enabled": {
"type": "boolean",
"default": false,
"description": "Enable dreaming memory consolidation cycles"
},
"cron": {
"type": "string",
"default": "",
"description": "Custom cron expression for dreaming schedule. Leave empty for managed scheduling."
},
"timezone": {
"type": "string",
"default": "UTC",
"description": "Timezone for cron scheduling (IANA format)"
},
"storageMode": {
"type": "string",
"enum": ["inline", "separate", "both"],
"default": "inline",
"description": "How dream insights are stored: inline (metadata), separate (dedicated collection), or both"
},
"separateReports": {
"type": "boolean",
"default": false,
"description": "Generate separate dream reports per phase"
},
"verboseLogging": {
"type": "boolean",
"default": false,
"description": "Enable verbose logging for dreaming cycles"
},
"phases": {
"type": "object",
"additionalProperties": false,
"description": "Dreaming phase configuration",
"properties": {
"light": {
"type": "object",
"additionalProperties": false,
"description": "Light phase: collect candidate memories for consolidation",
"properties": {
"lookbackDays": {
"type": "integer",
"minimum": 1,
"maximum": 365,
"default": 7,
"description": "How many days of recent memories to scan"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 500,
"default": 50,
"description": "Maximum candidate memories per light phase"
}
}
},
"deep": {
"type": "object",
"additionalProperties": false,
"description": "Deep phase: evaluate and score memories for promotion using tier-manager and decay-engine",
"properties": {
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20,
"description": "Maximum memories to process per deep phase"
},
"minScore": {
"type": "number",
"minimum": 0,
"maximum": 1,
"default": 0.5,
"description": "Minimum composite score for promotion consideration"
},
"minRecallCount": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"default": 2,
"description": "Minimum recall count for promotion"
},
"recencyHalfLifeDays": {
"type": "integer",
"minimum": 1,
"maximum": 365,
"default": 14,
"description": "Recency weighting half-life for scoring"
}
}
},
"rem": {
"type": "object",
"additionalProperties": false,
"description": "REM phase: theme reflection and pattern detection across promoted memories",
"properties": {
"lookbackDays": {
"type": "integer",
"minimum": 1,
"maximum": 365,
"default": 30,
"description": "Lookback window for pattern analysis"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 10,
"description": "Maximum patterns to detect per REM phase"
},
"minPatternStrength": {
"type": "number",
"minimum": 0,
"maximum": 1,
"default": 0.6,
"description": "Minimum strength for detected patterns"
}
}
}
}
}
}
}
}
},
Expand Down Expand Up @@ -1376,6 +1505,55 @@
"label": "Max Extractions Per Hour",
"help": "Rate limit for auto-capture extractions. Prevents excessive LLM calls during rapid-fire sessions.",
"advanced": true
},
"dreaming.enabled": {
"label": "Enable Dreaming",
"help": "Enable periodic memory consolidation and promotion cycles using tier-manager and decay-engine"
},
"dreaming.cron": {
"label": "Dreaming Cron",
"help": "Custom cron expression for dreaming schedule. Leave empty for managed scheduling.",
"advanced": true
},
"dreaming.timezone": {
"label": "Dreaming Timezone",
"help": "IANA timezone for cron scheduling",
"advanced": true
},
"dreaming.storageMode": {
"label": "Dream Storage Mode",
"help": "inline (metadata), separate (dedicated collection), or both",
"advanced": true
},
"dreaming.verboseLogging": {
"label": "Verbose Dreaming",
"help": "Enable verbose logging for dreaming cycles",
"advanced": true
},
"dreaming.phases.light.lookbackDays": {
"label": "Light Phase Lookback",
"help": "Days of recent memories to scan in light phase",
"advanced": true
},
"dreaming.phases.light.limit": {
"label": "Light Phase Limit",
"help": "Max candidate memories per light phase",
"advanced": true
},
"dreaming.phases.deep.minScore": {
"label": "Deep Phase Min Score",
"help": "Minimum composite score for promotion consideration",
"advanced": true
},
"dreaming.phases.deep.minRecallCount": {
"label": "Deep Phase Min Recalls",
"help": "Minimum recall count for promotion",
"advanced": true
},
"dreaming.phases.rem.minPatternStrength": {
"label": "REM Min Pattern Strength",
"help": "Minimum strength for detected patterns",
"advanced": true
}
}
}
Loading