From d9b7b41d26ec4111b32c1aedf75296442cca6396 Mon Sep 17 00:00:00 2001 From: doudouOUC Date: Wed, 22 Jul 2026 10:44:01 +0800 Subject: [PATCH] test(core): cover Shell truncation without an artifact Co-authored-by: Qwen-Coder --- packages/core/src/tools/shell.test.ts | 26 ++++++++++++++++++++++++++ packages/core/src/tools/tools.ts | 10 ++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/core/src/tools/shell.test.ts b/packages/core/src/tools/shell.test.ts index efd02880937..7bc5d3a7bed 100644 --- a/packages/core/src/tools/shell.test.ts +++ b/packages/core/src/tools/shell.test.ts @@ -2725,6 +2725,32 @@ describe('ShellTool', () => { expect(result.error?.type).toBe(ToolErrorType.SHELL_EXECUTE_ERROR); }); + it('retains shell truncation without an artifact and records the persistence decision', async () => { + const originalOutput = 'A'.repeat(30_001); + const shortenedContent = + 'Tool output was too large and has been truncated.\n[mocked truncated body]\n[Note: Could not save full output to file]'; + const truncationModule = await import('../utils/truncation.js'); + const spy = vi + .spyOn(truncationModule, 'truncateToolOutput') + .mockResolvedValue({ content: shortenedContent }); + + try { + const invocation = shellTool.build({ + command: 'large-output-cmd', + is_background: false, + }); + const promise = invocation.execute(mockAbortSignal); + resolveShellExecution({ output: originalOutput, exitCode: 0 }); + const result = await promise; + + expect(result.llmContent).toContain(shortenedContent); + expect(result.llmContent).not.toContain(originalOutput); + expect(result.persistedOutputFiles).toEqual([]); + } finally { + spy.mockRestore(); + } + }); + describe('long-running foreground hint', () => { // Auto-bg advisory. Threshold = effectiveTimeout / 2 — for the // default 120s timeout that's 60_000ms, which the tests below diff --git a/packages/core/src/tools/tools.ts b/packages/core/src/tools/tools.ts index f5105fddb27..23d0e8efb0c 100644 --- a/packages/core/src/tools/tools.ts +++ b/packages/core/src/tools/tools.ts @@ -493,8 +493,14 @@ export interface ToolResult { llmContent: PartListUnion; /** - * Producer output artifacts persisted before final aggregation. - * Internal runtimes use these paths to avoid writing the same output again. + * Internal runtime metadata recording the producer persistence decision + * before final aggregation. + * `undefined` means no decision was made; `[]` means a decision was made but + * no reusable artifact exists; a non-empty array lists reusable producer + * artifact paths. Downstream finalization treats any defined value as a + * completed decision for this producer output and does not persist it again. + * Other artifact channels remain independent and may still be aggregated + * later. */ persistedOutputFiles?: string[];