Files
openclaw/src/agents/bootstrap-cache.ts
Vincent Koc 015f7dc747 fix(agents): refresh bootstrap snapshot when workspace files change (#72406)
* fix(agents): refresh bootstrap snapshot when workspace files change

* fix(clownfish): address review for ghcrawl-207042-agentic-merge (1)
2026-04-26 23:39:33 -07:00

68 lines
1.8 KiB
TypeScript

import { loadWorkspaceBootstrapFiles, type WorkspaceBootstrapFile } from "./workspace.js";
type BootstrapSnapshot = {
workspaceDir: string;
files: WorkspaceBootstrapFile[];
};
const cache = new Map<string, BootstrapSnapshot>();
function bootstrapFilesEqual(
previous: WorkspaceBootstrapFile[],
next: WorkspaceBootstrapFile[],
): boolean {
if (previous.length !== next.length) {
return false;
}
return previous.every((file, index) => {
const updated = next[index];
return (
updated !== undefined &&
file.name === updated.name &&
file.path === updated.path &&
file.content === updated.content &&
file.missing === updated.missing
);
});
}
export async function getOrLoadBootstrapFiles(params: {
workspaceDir: string;
sessionKey: string;
}): Promise<WorkspaceBootstrapFile[]> {
const existing = cache.get(params.sessionKey);
// Refresh per turn so long-lived sessions pick up edits; loadWorkspaceBootstrapFiles
// handles unchanged file content through its guarded inode/mtime cache.
const files = await loadWorkspaceBootstrapFiles(params.workspaceDir);
if (
existing &&
existing.workspaceDir === params.workspaceDir &&
bootstrapFilesEqual(existing.files, files)
) {
return existing.files;
}
cache.set(params.sessionKey, { workspaceDir: params.workspaceDir, files });
return files;
}
export function clearBootstrapSnapshot(sessionKey: string): void {
cache.delete(sessionKey);
}
export function clearBootstrapSnapshotOnSessionRollover(params: {
sessionKey?: string;
previousSessionId?: string;
}): void {
if (!params.sessionKey || !params.previousSessionId) {
return;
}
clearBootstrapSnapshot(params.sessionKey);
}
export function clearAllBootstrapSnapshots(): void {
cache.clear();
}