From b9d4a595b93bb485c6e08f92c2b8d7d79db6046b Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Thu, 21 May 2026 21:13:06 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=82=EF=B8=8F=20refactor:=20Clarify=20C?= =?UTF-8?q?ode=20Sandbox=20File=20Guidance=20(#13236)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/api/src/agents/cleanup.spec.ts | 16 ++++++++++++++++ packages/api/src/agents/cleanup.ts | 18 ++++++++++-------- packages/api/src/agents/handlers.ts | 10 +++++----- packages/api/src/agents/tools.spec.ts | 4 +++- packages/api/src/agents/tools.ts | 12 ++---------- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/api/src/agents/cleanup.spec.ts b/packages/api/src/agents/cleanup.spec.ts index 077007de3b..563b5a67d3 100644 --- a/packages/api/src/agents/cleanup.spec.ts +++ b/packages/api/src/agents/cleanup.spec.ts @@ -77,6 +77,22 @@ describe('cleanCodeToolOutput', () => { expect(output).toMatch(/- \/mnt\/data\/test_folder\/\.dirkeep/); }); + it('preserves the compact session-file summary', () => { + const summary = + 'Session files: 4 persisted file(s) are available in /mnt/data, including 1 image(s). ' + + 'Use known /mnt/data paths directly in later code-tool calls. ' + + 'The app displays files/images automatically; do not invent download links or wrap generated images in Markdown.'; + const input = [ + 'stdout:', + 'Report generated', + '', + 'Generated files:', + summary, + ].join('\n'); + const output = cleanCodeToolOutput(input); + expect(output).toBe(input); + }); + it('passes through output that contains no boilerplate (no false positives)', () => { const input = 'stdout:\nHello, world!\n'; expect(cleanCodeToolOutput(input)).toBe('stdout:\nHello, world!'); diff --git a/packages/api/src/agents/cleanup.ts b/packages/api/src/agents/cleanup.ts index 9025d2ea7c..ffb051901c 100644 --- a/packages/api/src/agents/cleanup.ts +++ b/packages/api/src/agents/cleanup.ts @@ -3,8 +3,8 @@ * tool output before LibreChat re-injects it into the assistant's * conversation history. * - * The bash executor in `@librechat/agents` appends two kinds of noise - * to every successful run: + * Older bash executor output from `@librechat/agents` appended two + * kinds of noise to successful runs: * * 1. **Trailing "Note:" paragraphs** — long behavioral hints repeating * rules the agent already has via its system prompt @@ -21,12 +21,14 @@ * per-file annotations are redundant *and* phrased inconsistently * ("downloaded" vs. "displayed" vs. "known to the user"). * - * Stripping happens in LibreChat (this file), not upstream, so the - * cleaning is reversible — pin to a specific upstream version and the - * patterns adjust here without releasing a new agents build. The - * patterns are anchored conservatively: only the documented forms are - * matched, so a future upstream string change leaves user-authored - * `Note:` lines (or legitimate `|`-delimited filenames) untouched. + * Newer compact summaries under `Generated files:` intentionally do + * not list `- /...` paths and pass through unchanged. Stripping happens + * in LibreChat (this file), not upstream, so the cleaning is reversible + * — pin to a specific upstream version and the patterns adjust here + * without releasing a new agents build. The patterns are anchored + * conservatively: only the documented forms are matched, so a future + * upstream string change leaves user-authored `Note:` lines (or + * legitimate `|`-delimited filenames) untouched. */ /** diff --git a/packages/api/src/agents/handlers.ts b/packages/api/src/agents/handlers.ts index 4690cf73e4..51fed861be 100644 --- a/packages/api/src/agents/handlers.ts +++ b/packages/api/src/agents/handlers.ts @@ -1179,11 +1179,11 @@ export function createToolExecuteHandler(options: ToolExecuteOptions): EventHand * call. Almost always means the seeding chain * (primeCodeFiles → initialSessions → * CodeSessionContext) dropped the file upstream. - * `session_id` is still emitted; agents falls - * through to the `/files/` legacy fetch - * which is post-cutover broken (returns 400). - * Pair with `[primeCodeFiles]` traces below to - * locate the layer that lost the ref. */ + * `session_id` is still emitted for continuity, but + * concrete file refs must arrive through + * `_injected_files`; agents no longer falls back to + * `/files/`. Pair with `[primeCodeFiles]` + * traces below to locate the layer that lost the ref. */ logger.warn( `[code-env:inject] tool=${tc.name} _injected_files=0 — sandbox will see no input files`, { diff --git a/packages/api/src/agents/tools.spec.ts b/packages/api/src/agents/tools.spec.ts index 2ad9c30db9..0643259847 100644 --- a/packages/api/src/agents/tools.spec.ts +++ b/packages/api/src/agents/tools.spec.ts @@ -211,8 +211,10 @@ describe('registerCodeExecutionTools', () => { const readFile = result.toolDefinitions.find((d) => d.name === 'read_file'); expect(readFile?.description).toContain('code-execution sandbox'); expect(readFile?.description).toContain('/mnt/data/'); + expect(readFile?.description).toContain('Do not run ls/find'); + expect(readFile?.description).toContain('/tmp is per-call scratch'); expect(readFile?.description).toContain('truncated around 256KB'); - expect(readFile?.description).toContain('may return an error'); + expect(readFile?.description).toContain('true filesystem discovery'); expect(readFile?.description).not.toContain('{skillName}'); expect(readFile?.description).not.toContain('SKILL.md'); expect(JSON.stringify(readFile?.parameters)).not.toContain('{skillName}'); diff --git a/packages/api/src/agents/tools.ts b/packages/api/src/agents/tools.ts index 268b7df01a..59c7ade5d8 100644 --- a/packages/api/src/agents/tools.ts +++ b/packages/api/src/agents/tools.ts @@ -100,17 +100,9 @@ const READ_FILE_DEF: LCTool = Object.freeze({ responseFormat: ReadFileToolDefinition.responseFormat, }) as LCTool; -const CODE_READ_FILE_DESCRIPTION = `Read the contents of a file from the code-execution sandbox or from prior code-execution output. Returns text content with line numbers for easy reference. +const CODE_READ_FILE_DESCRIPTION = `Read a known text file from the code-execution sandbox. Returns line-numbered text; large files may be truncated around 256KB. -BEHAVIOR: -- Text files: returned with numbered lines. -- Large text files are truncated around 256KB with a note to use bash_tool for the full content. -- Binary files and formats that are not safe to serialize as text may return an error. Use bash_tool to inspect or process them. - -CONSTRAINTS: -- Only files produced by code execution or attached to the code-execution sandbox are accessible. -- Use paths returned by tool output or paths under /mnt/data/. -- Do not guess file paths. Use bash_tool to inspect available sandbox files when needed.`; +Use for text, CSV, JSON, Markdown, logs, and small source files at paths returned by tool output, just written, or under /mnt/data/. Do not run ls/find just to rediscover known paths. Use bash_tool for binary files, large files, transforms, metadata, or true filesystem discovery. /tmp is per-call scratch and unavailable later.`; const CODE_READ_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object',