What happened?
create_file builds its success message purely from the length of the input string. It never checks that the file actually persisted. A write that never landed still reports success, and the model — reasonably — believes it.
packages/api/src/agents/handlers.ts L2944 (current dev):
const summary = `${action} ${filePath} (${content.length} chars).`;
content.length is the input the model supplied. Nothing between this line and the response confirms the file exists.
The same pattern appears at L3582, L3641, L3730 and L3816 — five sites, so a fix probably wants to be a shared helper rather than five edits.
Why this matters
This is the reporting layer on top of the sandbox's per-execution statelessness, and it turns a recoverable situation into a confusing one.
A user reported this to us as "the agent says it created the file but ls doesn't show it, then it writes the file again and reports something different each time." The underlying cause was benign (the file appears on the next call). But because create_file reports success unconditionally, the model has no way to tell that apart from a genuine failure, so it produces contradictory narration and sometimes rewrites the file repeatedly.
We have also seen a genuine infrastructure failure where generated files were silently discarded — the code API pruned every file from the response because it could not reach the file server. In that state create_file still reported "Created … (N chars)" for every write. The success string cannot distinguish "written" from "silently dropped", which is exactly when a user most needs it to.
Related: LibreChat-AI/agents#274 documents create_file returning "Created" while the file is genuinely absent. That fixed the session routing; this issue is that the success string cannot detect such a failure at all.
Suggested fix
Either would help, roughly in order of value:
- Verify the write before reporting success — the
/exec response already carries files[]; assert the written path appears in it, and report an error if not.
- If verification isn't practical on every path, make the message reflect what is actually known — e.g. state that the file is registered and will be available to the next call, rather than asserting it was created.
Steps to reproduce
The clearest reproduction is the infrastructure-failure case, since the benign one still ends with the file present:
- Put the code API in a state where generated files cannot be uploaded (e.g. the in-guest API cannot reach the file server; the response then returns
files: []).
- Ask an agent to
create_file /mnt/data/probe.txt.
- The tool reports
Created /mnt/data/probe.txt (7 chars).
- The file is never persisted; it is absent on this and every subsequent call.
Version
v0.8.7 and v0.8.8-rc2; the pattern is unchanged on current dev.
Environment
Self-hosted, Docker, self-hosted code interpreter (ClickHouse/code-interpreter), Anthropic via Google Vertex AI.
What happened?
create_filebuilds its success message purely from the length of the input string. It never checks that the file actually persisted. A write that never landed still reports success, and the model — reasonably — believes it.packages/api/src/agents/handlers.tsL2944 (currentdev):content.lengthis the input the model supplied. Nothing between this line and the response confirms the file exists.The same pattern appears at L3582, L3641, L3730 and L3816 — five sites, so a fix probably wants to be a shared helper rather than five edits.
Why this matters
This is the reporting layer on top of the sandbox's per-execution statelessness, and it turns a recoverable situation into a confusing one.
A user reported this to us as "the agent says it created the file but
lsdoesn't show it, then it writes the file again and reports something different each time." The underlying cause was benign (the file appears on the next call). But becausecreate_filereports success unconditionally, the model has no way to tell that apart from a genuine failure, so it produces contradictory narration and sometimes rewrites the file repeatedly.We have also seen a genuine infrastructure failure where generated files were silently discarded — the code API pruned every file from the response because it could not reach the file server. In that state
create_filestill reported "Created … (N chars)" for every write. The success string cannot distinguish "written" from "silently dropped", which is exactly when a user most needs it to.Related: LibreChat-AI/agents#274 documents
create_filereturning "Created" while the file is genuinely absent. That fixed the session routing; this issue is that the success string cannot detect such a failure at all.Suggested fix
Either would help, roughly in order of value:
/execresponse already carriesfiles[]; assert the written path appears in it, and report an error if not.Steps to reproduce
The clearest reproduction is the infrastructure-failure case, since the benign one still ends with the file present:
files: []).create_file /mnt/data/probe.txt.Created /mnt/data/probe.txt (7 chars).Version
v0.8.7 and v0.8.8-rc2; the pattern is unchanged on current
dev.Environment
Self-hosted, Docker, self-hosted code interpreter (ClickHouse/code-interpreter), Anthropic via Google Vertex AI.