test(core): Support tool-result cleanup in the eval stub workspace (no-changelog) (#37202)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaakko Husso
2026-08-27 12:47:15 +00:00
committed by GitHub
parent b9342a5bb8
commit a7661cb4f4
2 changed files with 52 additions and 2 deletions
@@ -28,6 +28,35 @@ describe('createStubWorkspace', () => {
await expect(filesystem().readFile('missing.ts')).rejects.toThrow('No such file');
});
// The runtime offloads oversized tool results to `tool-results/runs/<hash>/`
// and clears that directory at the end of every run, calling the filesystem
// directly rather than through the exposed tools.
describe('tool-result cleanup', () => {
const runDirectory = 'tool-results/runs/run-hash';
it('reports a directory as existing once a file sits under it', async () => {
const fs = filesystem();
await fs.writeFile(`${runDirectory}/call.result.json`, '{}');
await expect(fs.exists(runDirectory)).resolves.toBe(true);
});
it('reports a directory that was never written as missing', async () => {
await expect(filesystem().exists(runDirectory)).resolves.toBe(false);
});
it('removes every file under the directory it is given, and nothing else', async () => {
const fs = filesystem();
await fs.writeFile(`${runDirectory}/call.result.json`, '{}');
await fs.writeFile('tool-results/runs/other-hash/call.result.json', '{}');
await fs.rmdir(runDirectory);
await expect(fs.exists(runDirectory)).resolves.toBe(false);
await expect(fs.exists('tool-results/runs/other-hash')).resolves.toBe(true);
});
});
it('offers only the tools production exposes', () => {
expect(
createStubWorkspace()
@@ -4,6 +4,11 @@
// Without a workspace, `build-workflow` fails its source read with a
// `code_fixable` remediation telling the agent to write the file with
// `workspace_write_file` — a tool that only exists when a workspace is attached.
//
// Tool exposure is filtered to CORE_WORKSPACE_TOOL_NAMES, but the runtime also
// calls the filesystem directly for its own bookkeeping — offloading oversized
// tool results and clearing them at the end of every run — so those operations
// are implemented rather than rejected.
// ---------------------------------------------------------------------------
import {
@@ -58,13 +63,29 @@ class InMemoryWorkspaceFilesystem implements WorkspaceFilesystem {
await Promise.resolve();
}
async exists(path: string): Promise<boolean> {
const key = relativePath(path);
if (this.files.has(key)) return await Promise.resolve(true);
const prefix = `${key}/`;
for (const file of this.files.keys()) {
if (file.startsWith(prefix)) return await Promise.resolve(true);
}
return await Promise.resolve(false);
}
async rmdir(path: string): Promise<void> {
const prefix = `${relativePath(path)}/`;
for (const file of this.files.keys()) {
if (file.startsWith(prefix)) this.files.delete(file);
}
await Promise.resolve();
}
appendFile = unreachable;
deleteFile = unreachable;
copyFile = unreachable;
moveFile = unreachable;
rmdir = unreachable;
readdir = unreachable;
exists = unreachable;
stat = unreachable;
}