mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:10:45 +00:00
memory-core: precompute dreaming transcript lookup
This commit is contained in:
@@ -6,6 +6,8 @@ import type { OpenClawConfig, OpenClawPluginApi } from "openclaw/plugin-sdk/memo
|
||||
import {
|
||||
buildSessionEntry,
|
||||
listSessionFilesForAgent,
|
||||
loadDreamingNarrativeTranscriptPathSetForAgent,
|
||||
normalizeSessionTranscriptPathForComparison,
|
||||
parseUsageCountedSessionIdFromFileName,
|
||||
sessionPathForFile,
|
||||
} from "openclaw/plugin-sdk/memory-core-host-engine-qmd";
|
||||
@@ -688,13 +690,25 @@ async function collectSessionIngestionBatches(params: {
|
||||
const nextSeenMessages: Record<string, string[]> = { ...params.state.seenMessages };
|
||||
let changed = false;
|
||||
|
||||
const sessionFiles: Array<{ agentId: string; absolutePath: string; sessionPath: string }> = [];
|
||||
const sessionFiles: Array<{
|
||||
agentId: string;
|
||||
absolutePath: string;
|
||||
generatedByDreamingNarrative: boolean;
|
||||
sessionPath: string;
|
||||
}> = [];
|
||||
for (const agentId of agentIds) {
|
||||
const files = await listSessionFilesForAgent(agentId);
|
||||
const dreamingTranscriptPaths =
|
||||
files.length > 0
|
||||
? loadDreamingNarrativeTranscriptPathSetForAgent(agentId)
|
||||
: new Set<string>();
|
||||
for (const absolutePath of files) {
|
||||
sessionFiles.push({
|
||||
agentId,
|
||||
absolutePath,
|
||||
generatedByDreamingNarrative: dreamingTranscriptPaths.has(
|
||||
normalizeSessionTranscriptPathForComparison(absolutePath),
|
||||
),
|
||||
sessionPath: sessionPathForFile(absolutePath),
|
||||
});
|
||||
}
|
||||
@@ -751,7 +765,9 @@ async function collectSessionIngestionBatches(params: {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry = await buildSessionEntry(file.absolutePath);
|
||||
const entry = await buildSessionEntry(file.absolutePath, {
|
||||
generatedByDreamingNarrative: file.generatedByDreamingNarrative,
|
||||
});
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ export { extractKeywords, isQueryStopWordToken } from "./host/query-expansion.js
|
||||
export {
|
||||
buildSessionEntry,
|
||||
listSessionFilesForAgent,
|
||||
loadDreamingNarrativeTranscriptPathSetForAgent,
|
||||
normalizeSessionTranscriptPathForComparison,
|
||||
sessionPathForFile,
|
||||
type BuildSessionEntryOptions,
|
||||
type SessionFileEntry,
|
||||
} from "./host/session-files.js";
|
||||
export { parseUsageCountedSessionIdFromFileName } from "../config/sessions/artifacts.js";
|
||||
|
||||
@@ -25,6 +25,11 @@ export type SessionFileEntry = {
|
||||
generatedByDreamingNarrative?: boolean;
|
||||
};
|
||||
|
||||
export type BuildSessionEntryOptions = {
|
||||
/** Optional preclassification from a caller-managed dreaming transcript lookup. */
|
||||
generatedByDreamingNarrative?: boolean;
|
||||
};
|
||||
|
||||
function isDreamingNarrativeBootstrapRecord(record: unknown): boolean {
|
||||
if (!record || typeof record !== "object" || Array.isArray(record)) {
|
||||
return false;
|
||||
@@ -98,6 +103,10 @@ function normalizeComparablePath(pathname: string): string {
|
||||
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
||||
}
|
||||
|
||||
export function normalizeSessionTranscriptPathForComparison(pathname: string): string {
|
||||
return normalizeComparablePath(pathname);
|
||||
}
|
||||
|
||||
function resolveSessionStoreTranscriptPath(
|
||||
sessionsDir: string,
|
||||
entry: { sessionFile?: unknown; sessionId?: unknown } | undefined,
|
||||
@@ -115,21 +124,37 @@ function resolveSessionStoreTranscriptPath(
|
||||
return null;
|
||||
}
|
||||
|
||||
function isDreamingNarrativeTranscriptFromSessionStore(absPath: string): boolean {
|
||||
const sessionsDir = path.dirname(absPath);
|
||||
export function loadDreamingNarrativeTranscriptPathSetForSessionsDir(
|
||||
sessionsDir: string,
|
||||
): ReadonlySet<string> {
|
||||
const storePath = path.join(sessionsDir, "sessions.json");
|
||||
const normalizedAbsPath = normalizeComparablePath(absPath);
|
||||
const store = loadSessionStore(storePath);
|
||||
const dreamingTranscriptPaths = new Set<string>();
|
||||
for (const [sessionKey, entry] of Object.entries(store)) {
|
||||
if (!isDreamingNarrativeSessionStoreKey(sessionKey)) {
|
||||
continue;
|
||||
}
|
||||
const transcriptPath = resolveSessionStoreTranscriptPath(sessionsDir, entry);
|
||||
if (transcriptPath === normalizedAbsPath) {
|
||||
return true;
|
||||
if (transcriptPath) {
|
||||
dreamingTranscriptPaths.add(transcriptPath);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return dreamingTranscriptPaths;
|
||||
}
|
||||
|
||||
export function loadDreamingNarrativeTranscriptPathSetForAgent(
|
||||
agentId: string,
|
||||
): ReadonlySet<string> {
|
||||
return loadDreamingNarrativeTranscriptPathSetForSessionsDir(
|
||||
resolveSessionTranscriptsDirForAgent(agentId),
|
||||
);
|
||||
}
|
||||
|
||||
function isDreamingNarrativeTranscriptFromSessionStore(absPath: string): boolean {
|
||||
const sessionsDir = path.dirname(absPath);
|
||||
const normalizedAbsPath = normalizeComparablePath(absPath);
|
||||
const dreamingTranscriptPaths = loadDreamingNarrativeTranscriptPathSetForSessionsDir(sessionsDir);
|
||||
return dreamingTranscriptPaths.has(normalizedAbsPath);
|
||||
}
|
||||
|
||||
export async function listSessionFilesForAgent(agentId: string): Promise<string[]> {
|
||||
@@ -207,7 +232,10 @@ function parseSessionTimestampMs(
|
||||
return 0;
|
||||
}
|
||||
|
||||
export async function buildSessionEntry(absPath: string): Promise<SessionFileEntry | null> {
|
||||
export async function buildSessionEntry(
|
||||
absPath: string,
|
||||
opts: BuildSessionEntryOptions = {},
|
||||
): Promise<SessionFileEntry | null> {
|
||||
try {
|
||||
const stat = await fs.stat(absPath);
|
||||
const raw = await fs.readFile(absPath, "utf-8");
|
||||
@@ -215,7 +243,8 @@ export async function buildSessionEntry(absPath: string): Promise<SessionFileEnt
|
||||
const collected: string[] = [];
|
||||
const lineMap: number[] = [];
|
||||
const messageTimestampsMs: number[] = [];
|
||||
let generatedByDreamingNarrative = isDreamingNarrativeTranscriptFromSessionStore(absPath);
|
||||
let generatedByDreamingNarrative =
|
||||
opts.generatedByDreamingNarrative ?? isDreamingNarrativeTranscriptFromSessionStore(absPath);
|
||||
for (let jsonlIdx = 0; jsonlIdx < lines.length; jsonlIdx++) {
|
||||
const line = lines[jsonlIdx];
|
||||
if (!line.trim()) {
|
||||
|
||||
Reference in New Issue
Block a user