mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 14:44:57 +00:00
fix(memory): handle ENOENT gracefully in readFile instead of throwing
When a memory file doesn't exist yet (e.g. daily log `2026-02-19.md`),
`readFile` now returns `{ text: "", path }` instead of propagating the
ENOENT error. This prevents noisy error responses from the memory read
tool and aligns with the "graceful degradation" recommendation in #9307.
Closes #9307
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ let searchImpl: () => Promise<unknown[]> = async () => [
|
|||||||
source: "memory" as const,
|
source: "memory" as const,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let readFileImpl: () => Promise<string> = async () => "";
|
let readFileImpl: () => Promise<unknown> = async () => "";
|
||||||
|
|
||||||
const stubManager = {
|
const stubManager = {
|
||||||
search: vi.fn(async () => await searchImpl()),
|
search: vi.fn(async () => await searchImpl()),
|
||||||
@@ -59,7 +59,7 @@ beforeEach(() => {
|
|||||||
source: "memory" as const,
|
source: "memory" as const,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
readFileImpl = async () => "";
|
readFileImpl = async () => ""; // default: return empty string
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,4 +189,23 @@ describe("memory tools", () => {
|
|||||||
error: "path required",
|
error: "path required",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("returns empty text without error when file does not exist (ENOENT)", async () => {
|
||||||
|
readFileImpl = async () => {
|
||||||
|
return { text: "", path: "memory/2026-02-19.md" };
|
||||||
|
};
|
||||||
|
|
||||||
|
const cfg = { agents: { list: [{ id: "main", default: true }] } };
|
||||||
|
const tool = createMemoryGetTool({ config: cfg });
|
||||||
|
expect(tool).not.toBeNull();
|
||||||
|
if (!tool) {
|
||||||
|
throw new Error("tool missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await tool.execute("call_enoent", { path: "memory/2026-02-19.md" });
|
||||||
|
expect(result.details).toEqual({
|
||||||
|
text: "",
|
||||||
|
path: "memory/2026-02-19.md",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -437,7 +437,19 @@ export class MemoryIndexManager extends MemoryManagerEmbeddingOps implements Mem
|
|||||||
if (!absPath.endsWith(".md")) {
|
if (!absPath.endsWith(".md")) {
|
||||||
throw new Error("path required");
|
throw new Error("path required");
|
||||||
}
|
}
|
||||||
const stat = await fs.lstat(absPath);
|
let stat;
|
||||||
|
try {
|
||||||
|
stat = await fs.lstat(absPath);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
if (
|
||||||
|
err instanceof Error &&
|
||||||
|
"code" in err &&
|
||||||
|
(err as NodeJS.ErrnoException).code === "ENOENT"
|
||||||
|
) {
|
||||||
|
return { text: "", path: relPath };
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
if (stat.isSymbolicLink() || !stat.isFile()) {
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
||||||
throw new Error("path required");
|
throw new Error("path required");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user