From dd95b765019c53afebb802e0eadf43b5ad684305 Mon Sep 17 00:00:00 2001 From: pei711 <199601925+pei711@users.noreply.github.com> Date: Tue, 27 Oct 2026 09:20:58 +0800 Subject: [PATCH] fix(tools): reject empty content in terminal write_file (#478) --- backend/pkg/tools/terminal.go | 3 +++ backend/pkg/tools/terminal_test.go | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/backend/pkg/tools/terminal.go b/backend/pkg/tools/terminal.go index 021851a6f..f68dc35c3 100644 --- a/backend/pkg/tools/terminal.go +++ b/backend/pkg/tools/terminal.go @@ -495,6 +495,9 @@ func (t *terminal) WriteFile(ctx context.Context, flowID int64, content string, if err := validateFilePath(path); err != nil { return "", err } + if content == "" { + return "", fmt.Errorf("content is required and cannot be empty") + } if err := t.writeFileToContainer(ctx, flowID, path, content); err != nil { return "", err diff --git a/backend/pkg/tools/terminal_test.go b/backend/pkg/tools/terminal_test.go index 0fe4de7ae..e624fe53b 100644 --- a/backend/pkg/tools/terminal_test.go +++ b/backend/pkg/tools/terminal_test.go @@ -325,6 +325,23 @@ func TestTerminal_WriteFile_RefusesANameTheArchiveCannotCarry(t *testing.T) { } } +func TestTerminal_WriteFile_RefusesEmptyContent(t *testing.T) { + mock := &fakeDockerClient{isRunning: true} + tlp := &recordingTermLog{} + term := terminalFor(mock, tlp) + + result, err := term.Handle(t.Context(), FileToolName, + mustJSON(map[string]any{"action": "write_file", "path": "/work/probe.txt", "content": "", "message": "test"})) + + require.NoError(t, err, "a tool failure is a soft (nil-error) response") + assert.Equal(t, "terminal tool 'file' handled with error: content is required and cannot be empty", result) + assert.Zero(t, mock.copies, "nothing may be copied into the sandbox") + + _, writeErr := term.WriteFile(t.Context(), 1, "", "/work/probe.txt") + require.Error(t, writeErr) + assert.Equal(t, "content is required and cannot be empty", writeErr.Error()) +} + func TestTerminal_EditFile_AppliesTheDiff(t *testing.T) { big := terminalLargeFileContent(2000) const firstLine = "line 00000: the quick brown fox jumps over the lazy dog"