Skip to content

feat: allow textEditor to overwrite existing files with create command #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 11, 2025
Merged
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
90 changes: 90 additions & 0 deletions packages/agent/src/tools/io/textEditor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,94 @@ describe('textEditor', () => {
);
}).rejects.toThrow(/Found 2 occurrences/);
});

it('should overwrite an existing file with create command', async () => {
const initialContent = 'Initial content';
const newContent = 'New content that overwrites the file';
const testPath = join(testDir, `${randomUUID()}.txt`);

// Create initial file
await textEditorTool.execute(
{
command: 'create',
path: testPath,
file_text: initialContent,
description: 'test',
},
toolContext,
);

// Verify initial content
let content = await readFile(testPath, 'utf8');
expect(content).toBe(initialContent);

// Overwrite the file using create command
const result = await textEditorTool.execute(
{
command: 'create',
path: testPath,
file_text: newContent,
description: 'test',
},
toolContext,
);

// Verify return value
expect(result.success).toBe(true);
expect(result.message).toContain('File overwritten');

// Verify content has been updated
content = await readFile(testPath, 'utf8');
expect(content).toBe(newContent);
});

it('should be able to undo file overwrite', async () => {
const initialContent = 'Initial content that will be restored';
const overwrittenContent = 'This content will be undone';
const testPath = join(testDir, `${randomUUID()}.txt`);

// Create initial file
await textEditorTool.execute(
{
command: 'create',
path: testPath,
file_text: initialContent,
description: 'test',
},
toolContext,
);

// Overwrite the file
await textEditorTool.execute(
{
command: 'create',
path: testPath,
file_text: overwrittenContent,
description: 'test',
},
toolContext,
);

// Verify overwritten content
let content = await readFile(testPath, 'utf8');
expect(content).toBe(overwrittenContent);

// Undo the overwrite
const result = await textEditorTool.execute(
{
command: 'undo_edit',
path: testPath,
description: 'test',
},
toolContext,
);

// Verify return value
expect(result.success).toBe(true);
expect(result.message).toContain('Successfully reverted');

// Verify content is back to initial
content = await readFile(testPath, 'utf8');
expect(content).toBe(initialContent);
});
});
31 changes: 19 additions & 12 deletions packages/agent/src/tools/io/textEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,29 +160,36 @@ export const textEditorTool: Tool<Parameters, ReturnType> = {
}

case 'create': {
// Check if file already exists
if (fsSync.existsSync(absolutePath)) {
throw new Error(
`File already exists: ${filePath}. Use str_replace to modify it.`,
);
}

if (!file_text) {
throw new Error('file_text parameter is required for create command');
}

// Create parent directories if they don't exist
await fs.mkdir(path.dirname(absolutePath), { recursive: true });

// Create the file
await fs.writeFile(absolutePath, file_text, 'utf8');
// Check if file already exists
const fileExists = fsSync.existsSync(absolutePath);

// Store initial state for undo
fileStateHistory[absolutePath] = [file_text];
if (fileExists) {
// Save current state for undo if file exists
const currentContent = await fs.readFile(absolutePath, 'utf8');
if (!fileStateHistory[absolutePath]) {
fileStateHistory[absolutePath] = [];
}
fileStateHistory[absolutePath].push(currentContent);
} else {
// Initialize history for new files
fileStateHistory[absolutePath] = [];
}

// Create or overwrite the file
await fs.writeFile(absolutePath, file_text, 'utf8');

return {
success: true,
message: `File created: ${filePath}`,
message: fileExists
? `File overwritten: ${filePath}`
: `File created: ${filePath}`,
};
}

Expand Down
Loading