openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
118 lines (117 loc) • 4.69 kB
JavaScript
import { D as resolveMemoryRemDreamingConfig, x as resolveMemoryDeepDreamingConfig } from "./dreaming-DmJZL5-O.js";
import "./memory-core-host-status-DAqa4uMk.js";
import { n as previewGroundedRemMarkdown } from "./rem-evidence-DwmnIkoF.js";
import { l as filterLiveShortTermRecallEntries, t as rankShortTermPromotionCandidates, u as readShortTermRecallEntries } from "./short-term-promotion-BWqNnYfM.js";
import { n as previewRemDreaming, t as filterRecallEntriesWithinLookback } from "./dreaming-phases-Bq-h-wp2.js";
import path from "node:path";
import fs from "node:fs/promises";
//#region extensions/memory-core/src/rem-harness.ts
const DAILY_MEMORY_FILE_NAME_RE = /^\d{4}-\d{2}-\d{2}(?:-[^/]+)?\.md$/i;
function normalizeOptionalPositiveLimit(value) {
if (typeof value !== "number" || !Number.isFinite(value)) return;
return Math.max(1, Math.floor(value));
}
function resolveRemPreviewLimit(configLimit, cap) {
if (configLimit <= 0) return 0;
if (typeof cap !== "number" || !Number.isFinite(cap)) return configLimit;
return Math.max(0, Math.min(configLimit, Math.floor(cap)));
}
function createSkippedRemPreview() {
return {
sourceEntryCount: 0,
reflections: [],
candidateTruths: [],
candidateKeys: [],
bodyLines: []
};
}
async function listWorkspaceDailyFiles(workspaceDir, limit) {
const memoryDir = path.join(workspaceDir, "memory");
let entries;
try {
entries = (await fs.readdir(memoryDir, { withFileTypes: true })).filter((entry) => entry.isFile() && DAILY_MEMORY_FILE_NAME_RE.test(entry.name)).map((entry) => entry.name);
} catch (err) {
if (err?.code === "ENOENT") return [];
throw err;
}
const files = entries.map((name) => path.join(memoryDir, name)).toSorted((left, right) => left.localeCompare(right));
if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0 || files.length <= limit) return files;
return files.slice(-Math.floor(limit));
}
function resolveGroundedFileLimit(configLimit, cap) {
if (typeof cap !== "number" || !Number.isFinite(cap)) return configLimit;
const normalizedCap = Math.max(1, Math.floor(cap));
return configLimit > 0 ? Math.min(configLimit, normalizedCap) : normalizedCap;
}
async function previewRemHarness(params) {
const nowMs = Number.isFinite(params.nowMs) ? params.nowMs : Date.now();
const remConfig = resolveMemoryRemDreamingConfig({
pluginConfig: params.pluginConfig,
cfg: params.cfg
});
const deepConfig = resolveMemoryDeepDreamingConfig({
pluginConfig: params.pluginConfig,
cfg: params.cfg
});
const allRecallEntries = await readShortTermRecallEntries({
workspaceDir: params.workspaceDir,
nowMs
});
const recallEntries = await filterLiveShortTermRecallEntries({
workspaceDir: params.workspaceDir,
entries: filterRecallEntriesWithinLookback({
entries: allRecallEntries,
nowMs,
lookbackDays: remConfig.lookbackDays
})
});
const remPreviewLimit = resolveRemPreviewLimit(remConfig.limit, params.remPreviewLimit);
const remSkipped = remConfig.limit <= 0 || remPreviewLimit <= 0;
const rem = remSkipped ? createSkippedRemPreview() : previewRemDreaming({
entries: recallEntries,
limit: remPreviewLimit,
minPatternStrength: remConfig.minPatternStrength
});
let groundedInputPaths = params.groundedInputPaths ?? [];
let grounded = null;
if (params.grounded) {
if (groundedInputPaths.length === 0) groundedInputPaths = await listWorkspaceDailyFiles(params.workspaceDir, resolveGroundedFileLimit(remConfig.limit, params.groundedFileLimit));
grounded = groundedInputPaths.length > 0 ? await previewGroundedRemMarkdown({
workspaceDir: params.workspaceDir,
inputPaths: groundedInputPaths
}) : null;
}
const candidateLimit = normalizeOptionalPositiveLimit(params.candidateLimit);
const rankedCandidates = await rankShortTermPromotionCandidates({
workspaceDir: params.workspaceDir,
minScore: 0,
minRecallCount: 0,
minUniqueQueries: 0,
includePromoted: Boolean(params.includePromoted),
recencyHalfLifeDays: deepConfig.recencyHalfLifeDays,
maxAgeDays: deepConfig.maxAgeDays,
nowMs,
...candidateLimit ? { limit: candidateLimit + 1 } : {}
});
const truncated = typeof candidateLimit === "number" && rankedCandidates.length > candidateLimit;
const candidates = typeof candidateLimit === "number" ? rankedCandidates.slice(0, candidateLimit) : rankedCandidates;
return {
workspaceDir: params.workspaceDir,
nowMs,
remConfig,
deepConfig,
recallEntryCount: recallEntries.length,
remSkipped,
rem,
groundedInputPaths,
grounded,
deep: {
...candidateLimit ? { candidateLimit } : {},
candidateCount: candidates.length,
truncated,
candidates
}
};
}
//#endregion
export { previewRemHarness as t };