🗂️ refactor: Clarify Code Sandbox File Guidance (#13236)

This commit is contained in:
Danny Avila 2026-05-21 21:13:06 -04:00 committed by GitHub
parent a865d40431
commit b9d4a595b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 36 additions and 24 deletions

View file

@ -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!');

View file

@ -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.
*/
/**

View file

@ -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/<sid>` 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/<sid>`. 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`,
{

View file

@ -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}');

View file

@ -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',