Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/pkg/tools/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions backend/pkg/tools/terminal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down