Memory: harden readFile ENOENT handling

This commit is contained in:
Vignesh Natarajan
2026-02-19 22:21:17 -08:00
committed by Vignesh
parent f3f47886ba
commit ec4198954a
3 changed files with 121 additions and 25 deletions

View File

@@ -1,11 +1,20 @@
import fs from "node:fs/promises";
import path from "node:path";
import type { Stats } from "node:fs";
import type { DatabaseSync } from "node:sqlite";
import { type FSWatcher } from "chokidar";
import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import fs from "node:fs/promises";
import path from "node:path";
import type { ResolvedMemorySearchConfig } from "../agents/memory-search.js";
import { resolveMemorySearchConfig } from "../agents/memory-search.js";
import type { OpenClawConfig } from "../config/config.js";
import type {
MemoryEmbeddingProbeResult,
MemoryProviderStatus,
MemorySearchManager,
MemorySearchResult,
MemorySource,
MemorySyncProgressUpdate,
} from "./types.js";
import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import { resolveMemorySearchConfig } from "../agents/memory-search.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import {
createEmbeddingProvider,
@@ -20,14 +29,6 @@ import { isMemoryPath, normalizeExtraMemoryPaths } from "./internal.js";
import { MemoryManagerEmbeddingOps } from "./manager-embedding-ops.js";
import { searchKeyword, searchVector } from "./manager-search.js";
import { extractKeywords } from "./query-expansion.js";
import type {
MemoryEmbeddingProbeResult,
MemoryProviderStatus,
MemorySearchManager,
MemorySearchResult,
MemorySource,
MemorySyncProgressUpdate,
} from "./types.js";
const SNIPPET_MAX_CHARS = 700;
const VECTOR_TABLE = "chunks_vec";
const FTS_TABLE = "chunks_fts";
@@ -36,6 +37,15 @@ const BATCH_FAILURE_LIMIT = 2;
const log = createSubsystemLogger("memory");
function isFileMissingError(err: unknown): err is NodeJS.ErrnoException & { code: "ENOENT" } {
return Boolean(
err &&
typeof err === "object" &&
"code" in err &&
(err as Partial<NodeJS.ErrnoException>).code === "ENOENT",
);
}
const INDEX_CACHE = new Map<string, MemoryIndexManager>();
export class MemoryIndexManager extends MemoryManagerEmbeddingOps implements MemorySearchManager {
@@ -437,15 +447,11 @@ export class MemoryIndexManager extends MemoryManagerEmbeddingOps implements Mem
if (!absPath.endsWith(".md")) {
throw new Error("path required");
}
let stat;
let stat: Stats;
try {
stat = await fs.lstat(absPath);
} catch (err: unknown) {
if (
err instanceof Error &&
"code" in err &&
(err as NodeJS.ErrnoException).code === "ENOENT"
) {
} catch (err) {
if (isFileMissingError(err)) {
return { text: "", path: relPath };
}
throw err;
@@ -453,7 +459,15 @@ export class MemoryIndexManager extends MemoryManagerEmbeddingOps implements Mem
if (stat.isSymbolicLink() || !stat.isFile()) {
throw new Error("path required");
}
const content = await fs.readFile(absPath, "utf-8");
let content: string;
try {
content = await fs.readFile(absPath, "utf-8");
} catch (err) {
if (isFileMissingError(err)) {
return { text: "", path: relPath };
}
throw err;
}
if (!params.from && !params.lines) {
return { text: content, path: relPath };
}