fix: scan full cortex history for conversation matches

This commit is contained in:
Junebugg1214 2026-03-12 22:47:19 -04:00
parent bb27f35319
commit a2b0d03cbb
2 changed files with 96 additions and 31 deletions

View File

@ -86,4 +86,47 @@ describe("cortex capture history", () => {
expect(syncEntry?.timestamp).toBe(2_000);
expect(syncEntry?.syncPlatforms).toEqual(["claude-code", "cursor", "copilot"]);
});
it("finds an older matching conversation entry even when newer unrelated entries exceed 100", async () => {
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cortex-history-scan-"));
vi.stubEnv("OPENCLAW_STATE_DIR", stateDir);
await appendCortexCaptureHistory({
agentId: "main",
sessionId: "session-target",
channelId: "channel-target",
captured: true,
score: 0.8,
reason: "target conversation capture",
timestamp: 1_000,
});
for (let index = 0; index < 150; index += 1) {
await appendCortexCaptureHistory({
agentId: "main",
sessionId: `session-${index}`,
channelId: `channel-${index}`,
captured: true,
score: 0.5,
reason: `other capture ${index}`,
timestamp: 2_000 + index,
});
}
const asyncEntry = await getLatestCortexCaptureHistoryEntry({
agentId: "main",
sessionId: "session-target",
channelId: "channel-target",
});
const syncEntry = getLatestCortexCaptureHistoryEntrySync({
agentId: "main",
sessionId: "session-target",
channelId: "channel-target",
});
expect(asyncEntry?.reason).toBe("target conversation capture");
expect(asyncEntry?.timestamp).toBe(1_000);
expect(syncEntry?.reason).toBe("target conversation capture");
expect(syncEntry?.timestamp).toBe(1_000);
});
});

View File

@ -18,6 +18,50 @@ export type CortexCaptureHistoryEntry = {
const latestCortexCaptureHistoryByKey = new Map<string, CortexCaptureHistoryEntry>();
function matchesHistoryEntry(
entry: CortexCaptureHistoryEntry,
params: {
agentId: string;
sessionId?: string;
channelId?: string;
},
): boolean {
return (
entry.agentId === params.agentId &&
(params.sessionId ? entry.sessionId === params.sessionId : true) &&
(params.channelId ? entry.channelId === params.channelId : true)
);
}
function parseLatestMatchingHistoryEntry(
raw: string,
params: {
agentId: string;
sessionId?: string;
channelId?: string;
},
): CortexCaptureHistoryEntry | null {
const lines = raw
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
for (let index = lines.length - 1; index >= 0; index -= 1) {
const line = lines[index];
if (!line) {
continue;
}
try {
const entry = JSON.parse(line) as CortexCaptureHistoryEntry;
if (matchesHistoryEntry(entry, params)) {
return entry;
}
} catch {
continue;
}
}
return null;
}
function buildHistoryCacheKey(params: {
agentId: string;
sessionId?: string;
@ -91,29 +135,7 @@ export function getLatestCortexCaptureHistoryEntrySync(params: {
} catch {
return null;
}
const lines = raw
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
for (let index = lines.length - 1; index >= 0; index -= 1) {
const line = lines[index];
if (!line) {
continue;
}
try {
const entry = JSON.parse(line) as CortexCaptureHistoryEntry;
if (
entry.agentId === params.agentId &&
(params.sessionId ? entry.sessionId === params.sessionId : true) &&
(params.channelId ? entry.channelId === params.channelId : true)
) {
return entry;
}
} catch {
continue;
}
}
return null;
return parseLatestMatchingHistoryEntry(raw, params);
}
export function getCachedLatestCortexCaptureHistoryEntry(params: {
@ -138,14 +160,14 @@ export async function getLatestCortexCaptureHistoryEntry(params: {
channelId?: string;
env?: NodeJS.ProcessEnv;
}): Promise<CortexCaptureHistoryEntry | null> {
const recent = await readRecentCortexCaptureHistory({ limit: 100, env: params.env });
const match =
recent.find(
(entry) =>
entry.agentId === params.agentId &&
(params.sessionId ? entry.sessionId === params.sessionId : true) &&
(params.channelId ? entry.channelId === params.channelId : true),
) ?? null;
const historyPath = resolveHistoryPath(params.env);
let raw: string;
try {
raw = await fsp.readFile(historyPath, "utf8");
} catch {
return null;
}
const match = parseLatestMatchingHistoryEntry(raw, params);
if (match) {
cacheHistoryEntry(match);
}