Skip to content

Commit 277d8fe

Browse files
authored
fix: quiet missing daily memory reads
Closes #82928
1 parent 026cfb6 commit 277d8fe

3 files changed

Lines changed: 74 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai
1616
### Fixes
1717

1818
- Gateway: keep session-only Control UI tool-start mirrors flowing during diagnostic queue pressure instead of silently dropping non-terminal tool updates.
19+
- Agents/memory: return optional not-found context for missing date-only daily memory reads instead of logging benign first-run `ENOENT` failures. Fixes #82928. Thanks @galiniliev.
1920
- Gateway: avoid sending duplicate tool-event frames to Control UI connections that are subscribed by both run and session.
2021
- Discord/OpenAI voice: accept longer leading wake-name mistranscripts such as "Open Club" for OpenClaw.
2122
- Agents/OpenAI-compatible: stop ModelStudio-compatible chat requests before sending system/tool-only payloads that have no usable user or assistant turn. (#86177) Thanks @TurboTheTurtle.

src/agents/pi-tools.read.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type ReadTruncationDetails = {
6060
const OFFSET_BEYOND_EOF_RE = /^Offset \d+ is beyond end of file \(\d+ lines total\)$/;
6161
const READ_CONTINUATION_NOTICE_RE =
6262
/\n\n\[(?:Showing lines [^\]]*?Use offset=\d+ to continue\.|\d+ more lines in file\. Use offset=\d+ to continue\.)\]\s*$/;
63+
const DAILY_MEMORY_PATH_RE = /^memory\/\d{4}-\d{2}-\d{2}\.md$/;
6364

6465
function clamp(value: number, min: number, max: number): number {
6566
return Math.max(min, Math.min(max, value));
@@ -218,6 +219,40 @@ function emptyReadResult(): AgentToolResult<unknown> {
218219
return { content: [textBlock], details: undefined };
219220
}
220221

222+
function missingDailyMemoryReadResult(relativePath: string): AgentToolResult<unknown> {
223+
return {
224+
content: [
225+
{
226+
type: "text",
227+
text: `No daily memory file exists yet at ${relativePath}.`,
228+
},
229+
],
230+
details: {
231+
status: "not_found",
232+
path: relativePath,
233+
optional: true,
234+
},
235+
};
236+
}
237+
238+
function normalizeDailyMemoryReadPath(value: unknown): string | undefined {
239+
if (typeof value !== "string") {
240+
return undefined;
241+
}
242+
const normalized = value.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
243+
return DAILY_MEMORY_PATH_RE.test(normalized) ? normalized : undefined;
244+
}
245+
246+
function isNotFoundError(error: unknown): boolean {
247+
if (typeof (error as NodeJS.ErrnoException | undefined)?.code === "string") {
248+
return (error as NodeJS.ErrnoException).code === "ENOENT";
249+
}
250+
if (!(error instanceof Error)) {
251+
return false;
252+
}
253+
return /\bENOENT\b|no such file or directory|file not found/i.test(error.message);
254+
}
255+
221256
async function executeReadPage(params: {
222257
base: AnyAgentTool;
223258
toolCallId: string;
@@ -230,6 +265,10 @@ async function executeReadPage(params: {
230265
if (isOffsetBeyondEof(error, params.args)) {
231266
return emptyReadResult();
232267
}
268+
const missingDailyMemoryPath = normalizeDailyMemoryReadPath(params.args.path);
269+
if (missingDailyMemoryPath && isNotFoundError(error)) {
270+
return missingDailyMemoryReadResult(missingDailyMemoryPath);
271+
}
233272
throw error;
234273
}
235274
}

src/agents/pi-tools.workspace-only-false.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,40 @@ describe("FS tools with workspaceOnly=false", () => {
165165
expect(JSON.stringify(result.content)).toContain("test read content");
166166
});
167167

168+
it("returns optional not-found context for missing date-only daily memory reads", async () => {
169+
const result = await runFsTool(
170+
"read",
171+
"test-call-missing-daily-memory",
172+
{
173+
path: "memory/2026-05-15.md",
174+
},
175+
undefined,
176+
);
177+
expect(result).toStrictEqual({
178+
content: [
179+
{
180+
type: "text",
181+
text: "No daily memory file exists yet at memory/2026-05-15.md.",
182+
},
183+
],
184+
details: {
185+
status: "not_found",
186+
path: "memory/2026-05-15.md",
187+
optional: true,
188+
},
189+
});
190+
});
191+
192+
it("still throws for ordinary missing read paths", async () => {
193+
const readTool = requireTool(toolsFor(undefined), "read");
194+
195+
await expect(
196+
readTool.execute("test-call-missing-ordinary-file", {
197+
path: "notes/missing.md",
198+
}),
199+
).rejects.toThrow(/ENOENT|no such file|not found/i);
200+
});
201+
168202
it("should allow write outside workspace when workspaceOnly is unset", async () => {
169203
const outsideUnsetFile = path.join(tmpDir, "outside-unset-write.txt");
170204
await runFsTool(

0 commit comments

Comments
 (0)