diff --git a/packages/ai-chat/src/common/chat-model.ts b/packages/ai-chat/src/common/chat-model.ts index a5a8950bb4772..1e1672746c6a1 100644 --- a/packages/ai-chat/src/common/chat-model.ts +++ b/packages/ai-chat/src/common/chat-model.ts @@ -570,6 +570,12 @@ export class ChangeSetImpl implements ChangeSet { return true; } + addOrReplaceElement(element: ChangeSetElement): void { + if (!this.replaceElement(element)) { + this.addElement(element); + } + } + removeElement(index: number): void { this._elements.splice(index, 1); this.notifyChange(); diff --git a/packages/ai-workspace-agent/src/browser/file-changeset-functions.ts b/packages/ai-workspace-agent/src/browser/file-changeset-functions.ts index d80af2f1206ff..3eeb309ef91ed 100644 --- a/packages/ai-workspace-agent/src/browser/file-changeset-functions.ts +++ b/packages/ai-workspace-agent/src/browser/file-changeset-functions.ts @@ -41,7 +41,7 @@ export class WriteChangeToFileProvider implements ToolProvider { description: `Proposes writing content to a file. If the file exists, it will be overwritten with the provided content.\n If the file does not exist, it will be created. This tool will automatically create any directories needed to write the file.\n If the new content is empty, the file will be deleted. To move a file, delete it and re-create it at the new location.\n - The proposed changes will be applied when the user accepts.`, + The proposed changes will be applied when the user accepts. If called again for the same file, previously proposed changes will be overridden.`, parameters: { type: 'object', properties: { @@ -76,7 +76,7 @@ export class WriteChangeToFileProvider implements ToolProvider { } catch (error) { type = 'add'; } - changeSet.addElement( + changeSet.addOrReplaceElement( this.fileChangeFactory({ uri: uri, type: type as 'modify' | 'add' | 'delete', @@ -117,7 +117,8 @@ export class ReplaceContentInFileProvider implements ToolProvider { name: ReplaceContentInFileProvider.ID, description: `Request to replace sections of content in an existing file by providing a list of tuples with old content to be matched and replaced. Only the first matched instance of each old content in the tuples will be replaced. For deletions, use an empty new content in the tuple.\n - Make sure you use the same line endings and whitespace as in the original file content. The proposed changes will be applied when the user accepts.`, + Make sure you use the same line endings and whitespace as in the original file content. The proposed changes will be applied when the user accepts.\n + If called again for the same file, it will override previously proposed changes.`, parameters: { type: 'object', properties: { @@ -165,7 +166,7 @@ export class ReplaceContentInFileProvider implements ToolProvider { ctx.session.setChangeSet(changeSet); } - changeSet.addElement( + changeSet.addOrReplaceElement( this.fileChangeFactory({ uri: fileUri, type: 'modify',