diff --git a/src/agent/prompts.ts b/src/agent/prompts.ts index 749cfc4e4..42cf388ff 100644 --- a/src/agent/prompts.ts +++ b/src/agent/prompts.ts @@ -78,7 +78,7 @@ export function buildHarnessFacts( "- Shell file-writes and deletions are blocked; never use echo/heredoc/sed/rm as a substitute for product tools. Path tools are the DIY surface.", ]), "- Use the provided tools for file reads/searches instead of shelling out as a substitute.", - "- read_file accepts a filesystem path or a tool-output:///{callId} URI from a prior tool result when the harness exposes one; prefer the URI over re-reading huge blobs.", + "- read_file accepts a filesystem path or a tool-output:///{callId} URI from a prior tool result when the harness exposes one. Only read_file a tool-output:// URI if the truncation notice on that result named one; do not re-read a complete inline result.", "- run_shell has no default timeout; pass timeout for builds, tests, and other long commands. Prefer background:true for builds, test suites, and dev servers: it returns a shell_id at once, the result is delivered when the process finishes (foreground runs hold steers; background runs do not), and shell_collect collects or cancels later. background does not change the retained shell cwd.", "- Shell find, rg, and grep -r are blocked — they can walk huge trees and OOM the host. Prefer the bounded grep/search_files tools, and do not substitute another unbounded walk (fd, ls -R, scripted os.walk).", ...(subAgent @@ -226,7 +226,7 @@ export function buildPromptDisciplineBlock( const TOOL_SUMMARIES: Record = { read_file: - "read a file or tool-output:///{callId} from a prior tool result (prefer over cat/head/tail in the shell)", + "read a file or tool-output:///{callId} from a prior tool result (prefer over cat/head/tail in the shell). Only read_file a tool-output:// URI if the truncation notice named one", write_file: "create or overwrite a file (never shell redirects or heredocs)", edit_file: "make a surgical edit (exact old_string match, or start_line/end_line line-range mode; never include read_file's NNNNNN\\t line prefix; substring failures include nearby file text; prefer over sed/awk in the shell)", diff --git a/src/prompts.test.ts b/src/prompts.test.ts index ab52289ba..5e2df2f6a 100644 --- a/src/prompts.test.ts +++ b/src/prompts.test.ts @@ -87,6 +87,26 @@ test("harness facts state only the non-derivable tool and safety rules", () => { expect(facts).not.toContain("Tool results already render richly"); }); +test("harness facts gate tool-output URI reads on a named truncation notice", () => { + const facts = buildHarnessFacts(); + expect(facts).toContain("read_file"); + expect(facts).toMatch(/filesystem path/i); + expect(facts).toMatch(/tool-output:\/\//); + expect(facts).toContain("truncation notice on that result named one"); + expect(facts).toContain("do not re-read a complete inline result"); + expect(facts).not.toMatch(/prefer the URI/i); + expect(facts).not.toMatch(/re-reading huge blobs/i); +}); + +test("read_file catalog summary gates tool-output URI reads on truncation", () => { + const listed = buildAvailableTools(["read_file"]); + expect(listed).toContain("read_file"); + expect(listed).toMatch(/tool-output:\/\//); + expect(listed).toContain("truncation notice named one"); + expect(listed).toContain("cat/head/tail"); + expect(listed).not.toMatch(/prefer the URI/i); +}); + test("harness facts name skill_search as a resident catalog tool", () => { const facts = buildHarnessFacts(); expect(facts).toMatch(