openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
537 lines (536 loc) • 24.6 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js";
import { i as formatErrorMessage } from "./errors-BXgSefBE.js";
import { _ as uniqueStrings } from "./string-normalization-WNUDCpXX.js";
import { B as MANAGED_MEMORY_DREAMING_CRON_TAG, G as resolveMemoryDeepDreamingConfig, V as MEMORY_DREAMING_SYSTEM_EVENT_TEXT, W as resolveMemoryCorePluginConfig, Y as resolveMemoryDreamingWorkspaces, z as MANAGED_MEMORY_DREAMING_CRON_NAME } from "./dreaming-SqhFI2Et.js";
import { c as peekSystemEventEntries } from "./system-events-C5WI3S5a.js";
import "./string-coerce-runtime-CEGJWkQ_.js";
import "./system-event-runtime-D80J5tzu.js";
import "./memory-core-host-status-DVjlVr90.js";
import { n as normalizeTrimmedString, t as includesSystemEventToken } from "./dreaming-shared-BChAYuyu.js";
//#region extensions/memory-core/src/dreaming.ts
const RUNTIME_CRON_RECONCILE_INTERVAL_MS = 6e4;
const STARTUP_CRON_RETRY_DELAY_MS = 5e3;
const STARTUP_CRON_RETRY_MAX_ATTEMPTS = 12;
const HEARTBEAT_ISOLATED_SESSION_SUFFIX = ":heartbeat";
function formatRepairSummary(repair) {
const actions = [];
if (repair.rewroteStore) {
const removedOverflowEntries = repair.removedOverflowEntries ?? 0;
const details = [repair.removedInvalidEntries > 0 ? `-${repair.removedInvalidEntries} invalid` : null, removedOverflowEntries > 0 ? `-${removedOverflowEntries} overflow` : null].filter(Boolean).join(", ");
actions.push(`rewrote recall store${details ? ` (${details})` : ""}`);
}
if (repair.removedStaleLock) actions.push("removed stale promotion lock");
return actions.join(", ");
}
function resolveManagedCronDescription(config) {
const recencyHalfLifeDays = config.recencyHalfLifeDays ?? 14;
return `${MANAGED_MEMORY_DREAMING_CRON_TAG} Promote weighted short-term recalls into MEMORY.md (limit=${config.limit}, minScore=${config.minScore.toFixed(3)}, minRecallCount=${config.minRecallCount}, minUniqueQueries=${config.minUniqueQueries}, recencyHalfLifeDays=${recencyHalfLifeDays}, maxAgeDays=${config.maxAgeDays ?? "none"}).`;
}
function buildManagedDreamingCronJob(config) {
return {
name: MANAGED_MEMORY_DREAMING_CRON_NAME,
description: resolveManagedCronDescription(config),
enabled: true,
schedule: {
kind: "cron",
expr: config.cron,
...config.timezone ? { tz: config.timezone } : {}
},
sessionTarget: "isolated",
wakeMode: "now",
payload: {
kind: "agentTurn",
message: MEMORY_DREAMING_SYSTEM_EVENT_TEXT,
lightContext: true
},
delivery: { mode: "none" }
};
}
function resolveManagedDreamingPayloadToken(payload) {
const payloadKind = normalizeLowercaseStringOrEmpty(normalizeTrimmedString(payload?.kind));
if (payloadKind === "systemevent") return normalizeTrimmedString(payload?.text);
if (payloadKind === "agentturn") return normalizeTrimmedString(payload?.message);
}
function isManagedDreamingJob(job) {
if (normalizeTrimmedString(job.description)?.includes("[managed-by=memory-core.short-term-promotion]")) return true;
const name = normalizeTrimmedString(job.name);
const payloadToken = resolveManagedDreamingPayloadToken(job.payload);
return name === "Memory Dreaming Promotion" && payloadToken === "__openclaw_memory_core_short_term_promotion_dream__";
}
function isLegacyPhaseDreamingJob(job) {
const description = normalizeTrimmedString(job.description);
if (description?.includes("[managed-by=memory-core.dreaming.light]") || description?.includes("[managed-by=memory-core.dreaming.rem]")) return true;
const name = normalizeTrimmedString(job.name);
const payloadText = normalizeTrimmedString(job.payload?.text);
if (name === "Memory Light Dreaming" && payloadText === "__openclaw_memory_core_light_sleep__") return true;
return name === "Memory REM Dreaming" && payloadText === "__openclaw_memory_core_rem_sleep__";
}
function compareOptionalStrings(a, b) {
return a === b;
}
async function migrateLegacyPhaseDreamingCronJobs(params) {
let migrated = 0;
for (const job of params.legacyJobs) try {
if ((await params.cron.remove(job.id)).removed === true) migrated += 1;
} catch (err) {
params.logger.warn(`memory-core: failed to migrate legacy phase dreaming cron job ${job.id}: ${formatErrorMessage(err)}`);
}
if (migrated > 0) if (params.mode === "enabled") params.logger.info(`memory-core: migrated ${migrated} legacy phase dreaming cron job(s) to the unified dreaming controller.`);
else params.logger.info(`memory-core: completed legacy phase dreaming cron migration while unified dreaming is disabled (${migrated} job(s) removed).`);
return migrated;
}
function buildManagedDreamingPatch(job, desired) {
const patch = {};
if (!compareOptionalStrings(normalizeTrimmedString(job.name), desired.name)) patch.name = desired.name;
if (!compareOptionalStrings(normalizeTrimmedString(job.description), desired.description)) patch.description = desired.description;
if (job.enabled !== true) patch.enabled = true;
const scheduleKind = normalizeLowercaseStringOrEmpty(normalizeTrimmedString(job.schedule?.kind));
const scheduleExpr = normalizeTrimmedString(job.schedule?.expr);
const scheduleTz = normalizeTrimmedString(job.schedule?.tz);
if (scheduleKind !== "cron" || !compareOptionalStrings(scheduleExpr, desired.schedule.expr) || !compareOptionalStrings(scheduleTz, desired.schedule.tz)) patch.schedule = desired.schedule;
if (normalizeLowercaseStringOrEmpty(normalizeTrimmedString(job.sessionTarget)) !== desired.sessionTarget) patch.sessionTarget = desired.sessionTarget;
if (normalizeLowercaseStringOrEmpty(normalizeTrimmedString(job.wakeMode)) !== "now") patch.wakeMode = "now";
const payloadKind = normalizeLowercaseStringOrEmpty(normalizeTrimmedString(job.payload?.kind));
const payloadToken = resolveManagedDreamingPayloadToken(job.payload);
const desiredPayloadToken = desired.payload.kind === "systemEvent" ? desired.payload.text : desired.payload.message;
if (payloadKind !== normalizeLowercaseStringOrEmpty(desired.payload.kind) || !compareOptionalStrings(payloadToken, desiredPayloadToken) || desired.payload.kind === "agentTurn" && job.payload?.lightContext !== desired.payload.lightContext) patch.payload = desired.payload;
if (normalizeLowercaseStringOrEmpty(normalizeTrimmedString(job.delivery?.mode)) !== "none") patch.delivery = desired.delivery;
return Object.keys(patch).length > 0 ? patch : null;
}
function sortManagedJobs(managed) {
return managed.toSorted((a, b) => {
const aCreated = typeof a.createdAtMs === "number" && Number.isFinite(a.createdAtMs) ? a.createdAtMs : Number.MAX_SAFE_INTEGER;
const bCreated = typeof b.createdAtMs === "number" && Number.isFinite(b.createdAtMs) ? b.createdAtMs : Number.MAX_SAFE_INTEGER;
if (aCreated !== bCreated) return aCreated - bCreated;
return a.id.localeCompare(b.id);
});
}
function resolveCronServiceFromCandidate(candidate) {
if (!candidate || typeof candidate !== "object") return null;
const cron = candidate;
if (typeof cron.list !== "function" || typeof cron.add !== "function" || typeof cron.update !== "function" || typeof cron.remove !== "function") return null;
return cron;
}
function resolveCronServiceFromGatewayContext(context) {
return resolveCronServiceFromCandidate(context?.getCron?.());
}
function resolveDreamingTriggerSessionKeys(sessionKey) {
const normalized = normalizeTrimmedString(sessionKey);
if (!normalized) return [];
const keys = [normalized];
if (normalized.endsWith(HEARTBEAT_ISOLATED_SESSION_SUFFIX)) {
const baseSessionKey = normalized.slice(0, -10).trim();
if (baseSessionKey) keys.push(baseSessionKey);
}
return uniqueStrings(keys);
}
function hasPendingManagedDreamingCronEvent(sessionKey) {
return resolveDreamingTriggerSessionKeys(sessionKey).some((candidateSessionKey) => peekSystemEventEntries(candidateSessionKey).some((event) => event.contextKey?.startsWith("cron:") === true && normalizeTrimmedString(event.text) === "__openclaw_memory_core_short_term_promotion_dream__"));
}
function resolveShortTermPromotionDreamingConfig(params) {
const resolved = resolveMemoryDeepDreamingConfig(params);
return {
enabled: resolved.enabled,
cron: resolved.cron,
...resolved.timezone ? { timezone: resolved.timezone } : {},
limit: resolved.limit,
minScore: resolved.minScore,
minRecallCount: resolved.minRecallCount,
minUniqueQueries: resolved.minUniqueQueries,
recencyHalfLifeDays: resolved.recencyHalfLifeDays,
...typeof resolved.maxAgeDays === "number" ? { maxAgeDays: resolved.maxAgeDays } : {},
maxPromotedSnippetTokens: resolved.maxPromotedSnippetTokens ?? 160,
verboseLogging: resolved.verboseLogging,
storage: resolved.storage,
...resolved.execution.model ? { execution: { model: resolved.execution.model } } : {}
};
}
async function reconcileShortTermDreamingCronJob(params) {
const cron = params.cron;
if (!cron) return {
status: "unavailable",
removed: 0
};
const allJobs = await cron.list({ includeDisabled: true });
const managed = allJobs.filter(isManagedDreamingJob);
const legacyPhaseJobs = allJobs.filter(isLegacyPhaseDreamingJob);
if (!params.config.enabled) {
let removed = await migrateLegacyPhaseDreamingCronJobs({
cron,
legacyJobs: legacyPhaseJobs,
logger: params.logger,
mode: "disabled"
});
for (const job of managed) try {
if ((await cron.remove(job.id)).removed === true) removed += 1;
} catch (err) {
params.logger.warn(`memory-core: failed to remove managed dreaming cron job ${job.id}: ${formatErrorMessage(err)}`);
}
if (removed > 0) params.logger.info(`memory-core: removed ${removed} managed dreaming cron job(s).`);
return {
status: "disabled",
removed
};
}
const desired = buildManagedDreamingCronJob(params.config);
if (managed.length === 0) {
await cron.add(desired);
const migratedLegacy = await migrateLegacyPhaseDreamingCronJobs({
cron,
legacyJobs: legacyPhaseJobs,
logger: params.logger,
mode: "enabled"
});
params.logger.info("memory-core: created managed dreaming cron job.");
return {
status: "added",
removed: migratedLegacy
};
}
const [primary, ...duplicates] = sortManagedJobs(managed);
let removed = await migrateLegacyPhaseDreamingCronJobs({
cron,
legacyJobs: legacyPhaseJobs,
logger: params.logger,
mode: "enabled"
});
for (const duplicate of duplicates) try {
if ((await cron.remove(duplicate.id)).removed === true) removed += 1;
} catch (err) {
params.logger.warn(`memory-core: failed to prune duplicate managed dreaming cron job ${duplicate.id}: ${formatErrorMessage(err)}`);
}
const patch = buildManagedDreamingPatch(primary, desired);
if (!patch) {
if (removed > 0) params.logger.info("memory-core: pruned duplicate managed dreaming cron jobs.");
return {
status: "noop",
removed
};
}
await cron.update(primary.id, patch);
params.logger.info("memory-core: updated managed dreaming cron job.");
return {
status: "updated",
removed
};
}
async function runShortTermDreamingPromotionIfTriggered(params) {
if (params.trigger !== "heartbeat" && params.trigger !== "cron") return;
if (!includesSystemEventToken(params.cleanedBody, "__openclaw_memory_core_short_term_promotion_dream__")) return;
if (!params.config.enabled) return {
handled: true,
reason: "memory-core: short-term dreaming disabled"
};
const recencyHalfLifeDays = params.config.recencyHalfLifeDays ?? 14;
const fallbackWorkspaceDir = normalizeTrimmedString(params.workspaceDir);
const workspaceCandidates = params.cfg ? resolveMemoryDreamingWorkspaces(params.cfg, {
primaryWorkspaceDir: fallbackWorkspaceDir,
primaryAgentId: "main"
}).map((entry) => entry.workspaceDir) : [];
const seenWorkspaces = /* @__PURE__ */ new Set();
const workspaces = workspaceCandidates.filter((workspaceDir) => {
if (seenWorkspaces.has(workspaceDir)) return false;
seenWorkspaces.add(workspaceDir);
return true;
});
if (workspaces.length === 0 && fallbackWorkspaceDir) workspaces.push(fallbackWorkspaceDir);
if (workspaces.length === 0) {
params.logger.warn("memory-core: dreaming promotion skipped because no memory workspace is available.");
return {
handled: true,
reason: "memory-core: short-term dreaming missing workspace"
};
}
if (params.config.limit === 0) {
params.logger.info("memory-core: dreaming promotion skipped because limit=0.");
return {
handled: true,
reason: "memory-core: short-term dreaming disabled by limit"
};
}
if (params.config.verboseLogging) params.logger.info(`memory-core: dreaming verbose enabled (cron=${params.config.cron}, limit=${params.config.limit}, minScore=${params.config.minScore.toFixed(3)}, minRecallCount=${params.config.minRecallCount}, minUniqueQueries=${params.config.minUniqueQueries}, recencyHalfLifeDays=${recencyHalfLifeDays}, maxAgeDays=${params.config.maxAgeDays ?? "none"}, workspaces=${workspaces.length}).`);
let totalCandidates = 0;
let totalApplied = 0;
let failedWorkspaces = 0;
const pluginConfig = params.cfg ? resolveMemoryCorePluginConfig(params.cfg) : void 0;
const detachNarratives = params.trigger === "cron";
const [{ writeDeepDreamingReport }, { appendFallbackNarrativeEntry, generateAndAppendDreamNarrative, runDetachedDreamNarrative }, { runDreamingSweepPhases }, { applyShortTermPromotions, repairShortTermPromotionArtifacts, rankShortTermPromotionCandidates }] = await Promise.all([
import("./dreaming-markdown-BHSC9aNz.js"),
import("./dreaming-narrative-Bdg-vPO_.js"),
import("./dreaming-phases-E8TN4rSj.js"),
import("./short-term-promotion-dT5KFZ8a.js")
]);
for (const workspaceDir of workspaces) try {
const sweepNowMs = Date.now();
await runDreamingSweepPhases({
workspaceDir,
pluginConfig,
cfg: params.cfg,
logger: params.logger,
subagent: params.subagent,
detachNarratives,
nowMs: sweepNowMs
});
const reportLines = [];
const repair = await repairShortTermPromotionArtifacts({ workspaceDir });
if (repair.changed) {
params.logger.info(`memory-core: normalized recall artifacts before dreaming (${formatRepairSummary(repair)}) [workspace=${workspaceDir}].`);
reportLines.push(`- Repaired recall artifacts: ${formatRepairSummary(repair)}.`);
}
const candidates = await rankShortTermPromotionCandidates({
workspaceDir,
limit: params.config.limit,
minScore: params.config.minScore,
minRecallCount: params.config.minRecallCount,
minUniqueQueries: params.config.minUniqueQueries,
recencyHalfLifeDays,
maxAgeDays: params.config.maxAgeDays,
nowMs: sweepNowMs
});
totalCandidates += candidates.length;
reportLines.push(`- Ranked ${candidates.length} candidate(s) for durable promotion.`);
if (params.config.verboseLogging) {
const candidateSummary = candidates.length > 0 ? candidates.map((candidate) => `${candidate.path}:${candidate.startLine}-${candidate.endLine} score=${candidate.score.toFixed(3)} recalls=${candidate.recallCount} queries=${candidate.uniqueQueries} components={freq=${candidate.components.frequency.toFixed(3)},rel=${candidate.components.relevance.toFixed(3)},div=${candidate.components.diversity.toFixed(3)},rec=${candidate.components.recency.toFixed(3)},cons=${candidate.components.consolidation.toFixed(3)},concept=${candidate.components.conceptual.toFixed(3)}}`).join(" | ") : "none";
params.logger.info(`memory-core: dreaming candidate details [workspace=${workspaceDir}] ${candidateSummary}`);
}
const applied = await applyShortTermPromotions({
workspaceDir,
candidates,
limit: params.config.limit,
minScore: params.config.minScore,
minRecallCount: params.config.minRecallCount,
minUniqueQueries: params.config.minUniqueQueries,
maxAgeDays: params.config.maxAgeDays,
maxPromotedSnippetTokens: params.config.maxPromotedSnippetTokens,
timezone: params.config.timezone,
nowMs: sweepNowMs
});
totalApplied += applied.applied;
reportLines.push(`- Promoted ${applied.applied} candidate(s) into MEMORY.md.`);
if (params.config.verboseLogging) {
const appliedSummary = applied.appliedCandidates.length > 0 ? applied.appliedCandidates.map((candidate) => `${candidate.path}:${candidate.startLine}-${candidate.endLine} score=${candidate.score.toFixed(3)} recalls=${candidate.recallCount}`).join(" | ") : "none";
params.logger.info(`memory-core: dreaming applied details [workspace=${workspaceDir}] ${appliedSummary}`);
}
await writeDeepDreamingReport({
workspaceDir,
bodyLines: reportLines,
nowMs: sweepNowMs,
timezone: params.config.timezone,
storage: params.config.storage ?? {
mode: "separate",
separateReports: false
}
});
if (candidates.length > 0 || applied.applied > 0) {
const data = {
phase: "deep",
snippets: candidates.map((c) => c.snippet).filter(Boolean),
promotions: applied.appliedCandidates.map((c) => c.snippet).filter(Boolean)
};
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,
data,
nowMs: sweepNowMs,
timezone: params.config.timezone,
model: params.config.execution?.model,
logger: params.logger
});
else await generateAndAppendDreamNarrative({
subagent: params.subagent,
workspaceDir,
data,
nowMs: sweepNowMs,
timezone: params.config.timezone,
model: params.config.execution?.model,
logger: params.logger
});
}
} catch (err) {
failedWorkspaces += 1;
params.logger.error(`memory-core: dreaming promotion failed for workspace ${workspaceDir}: ${formatErrorMessage(err)}`);
}
params.logger.info(`memory-core: dreaming promotion complete (workspaces=${workspaces.length}, candidates=${totalCandidates}, applied=${totalApplied}, failed=${failedWorkspaces}).`);
return {
handled: true,
reason: "memory-core: short-term dreaming processed"
};
}
function registerShortTermPromotionDreaming(api) {
let resolveStartupCron = null;
let gatewayContext = null;
let unavailableCronWarningEmitted = false;
let lastRuntimeReconcileAtMs = 0;
let lastRuntimeConfigKey = null;
let lastRuntimeCronRef = null;
let startupCronRetryTimer = null;
let runtimeCronReconcileTimer = null;
let startupCronRetryAttempts = 0;
let disposed = false;
const resolveCurrentConfig = () => api.runtime.config?.current?.() ?? api.config;
const clearStartupCronRetry = () => {
if (startupCronRetryTimer) {
clearTimeout(startupCronRetryTimer);
startupCronRetryTimer = null;
}
startupCronRetryAttempts = 0;
};
const hasStartupCron = () => {
try {
return Boolean(resolveStartupCron?.());
} catch {
return false;
}
};
const hasCronManagementContext = () => Boolean(resolveStartupCron || gatewayContext?.getCron);
const disposeStartupCronRetry = () => {
disposed = true;
clearStartupCronRetry();
if (runtimeCronReconcileTimer) {
clearInterval(runtimeCronReconcileTimer);
runtimeCronReconcileTimer = null;
}
gatewayContext = null;
resolveStartupCron = null;
};
const runtimeConfigKey = (config) => [
config.enabled ? "enabled" : "disabled",
config.cron,
config.timezone ?? "",
String(config.limit),
String(config.minScore),
String(config.minRecallCount),
String(config.minUniqueQueries),
String(config.recencyHalfLifeDays ?? ""),
String(config.maxAgeDays ?? ""),
config.verboseLogging ? "verbose" : "quiet",
config.storage?.mode ?? "",
config.storage?.separateReports ? "separate" : "inline"
].join("|");
const reconcileManagedDreamingCron = async (params) => {
const startupCfg = params.reason === "startup" ? params.startupConfig ?? api.config : resolveCurrentConfig();
const config = resolveShortTermPromotionDreamingConfig({
pluginConfig: params.reason === "startup" ? resolveMemoryCorePluginConfig(startupCfg) ?? resolveMemoryCorePluginConfig(api.config) ?? api.pluginConfig : resolveMemoryCorePluginConfig(startupCfg),
cfg: startupCfg
});
if (params.reason === "startup") resolveStartupCron = params.startupCron ?? null;
let cron = resolveStartupCron?.() ?? null;
if (!cron && params.reason !== "startup" && gatewayContext) try {
cron = resolveCronServiceFromGatewayContext(gatewayContext);
if (cron) resolveStartupCron = () => cron;
} catch {}
const configKey = runtimeConfigKey(config);
if (!cron && config.enabled && !unavailableCronWarningEmitted) if (params.reason === "startup" || params.reason === "startup_retry") api.logger.debug?.("memory-core: cron service not yet available at gateway_start; deferring to runtime reconciliation.");
else {
api.logger.warn("memory-core: managed dreaming cron could not be reconciled (cron service unavailable).");
unavailableCronWarningEmitted = true;
}
if (cron) {
unavailableCronWarningEmitted = false;
clearStartupCronRetry();
}
if (!cron && params.reason === "startup_retry") return config;
if (params.reason === "runtime") {
const now = Date.now();
if (now - lastRuntimeReconcileAtMs < RUNTIME_CRON_RECONCILE_INTERVAL_MS && lastRuntimeConfigKey === configKey && lastRuntimeCronRef === cron) return config;
lastRuntimeReconcileAtMs = now;
lastRuntimeConfigKey = configKey;
lastRuntimeCronRef = cron;
}
await reconcileShortTermDreamingCronJob({
cron,
config,
logger: api.logger
});
return config;
};
const scheduleStartupCronRetry = () => {
if (disposed || hasStartupCron()) {
clearStartupCronRetry();
return;
}
if (startupCronRetryTimer || startupCronRetryAttempts >= STARTUP_CRON_RETRY_MAX_ATTEMPTS) return;
startupCronRetryTimer = setTimeout(() => {
startupCronRetryTimer = null;
if (disposed) return;
startupCronRetryAttempts += 1;
reconcileManagedDreamingCron({ reason: "startup_retry" }).then(async () => {
if (disposed || hasStartupCron()) {
clearStartupCronRetry();
return;
}
if (startupCronRetryAttempts >= STARTUP_CRON_RETRY_MAX_ATTEMPTS) {
await reconcileManagedDreamingCron({ reason: "runtime" });
return;
}
scheduleStartupCronRetry();
}).catch((err) => {
if (disposed) return;
api.logger.error(`memory-core: deferred dreaming cron retry failed: ${formatErrorMessage(err)}`);
scheduleStartupCronRetry();
});
}, STARTUP_CRON_RETRY_DELAY_MS);
};
const startRuntimeCronReconcileTimer = () => {
if (runtimeCronReconcileTimer) return;
runtimeCronReconcileTimer = setInterval(() => {
reconcileManagedDreamingCron({ reason: "runtime" }).catch((err) => {
api.logger.error(`memory-core: dreaming cron reconcile failed: ${formatErrorMessage(err)}`);
});
}, RUNTIME_CRON_RECONCILE_INTERVAL_MS);
runtimeCronReconcileTimer.unref?.();
};
api.on("gateway_start", async (_event, ctx) => {
disposed = false;
gatewayContext = ctx;
try {
await reconcileManagedDreamingCron({
reason: "startup",
startupConfig: ctx.config,
startupCron: () => resolveCronServiceFromGatewayContext(ctx)
});
startRuntimeCronReconcileTimer();
scheduleStartupCronRetry();
} catch (err) {
api.logger.error(`memory-core: dreaming startup reconciliation failed: ${formatErrorMessage(err)}`);
}
});
api.on("gateway_stop", () => {
disposeStartupCronRetry();
});
api.on("before_agent_reply", async (event, ctx) => {
try {
if (ctx.trigger !== "heartbeat" && ctx.trigger !== "cron") return;
const currentConfig = resolveCurrentConfig();
const hasManagedDreamingToken = includesSystemEventToken(event.cleanedBody, MEMORY_DREAMING_SYSTEM_EVENT_TEXT);
const isManagedHeartbeatTrigger = ctx.trigger === "heartbeat" && hasPendingManagedDreamingCronEvent(ctx.sessionKey);
const isManagedCronTrigger = ctx.trigger === "cron";
const shouldHandleManagedDreaming = hasManagedDreamingToken && (isManagedHeartbeatTrigger || isManagedCronTrigger);
if (!shouldHandleManagedDreaming && !hasCronManagementContext()) return;
const config = await reconcileManagedDreamingCron({ reason: "runtime" });
if (!shouldHandleManagedDreaming) return;
return await runShortTermDreamingPromotionIfTriggered({
cleanedBody: event.cleanedBody,
trigger: ctx.trigger,
workspaceDir: ctx.workspaceDir,
cfg: currentConfig,
config,
logger: api.logger,
subagent: config.enabled ? api.runtime?.subagent : void 0
});
} catch (err) {
api.logger.error(`memory-core: dreaming trigger failed: ${formatErrorMessage(err)}`);
return;
}
});
}
//#endregion
export { resolveShortTermPromotionDreamingConfig as n, registerShortTermPromotionDreaming as t };