diff --git a/extensions/copilot/src/extension/tools/node/abstractReplaceStringTool.tsx b/extensions/copilot/src/extension/tools/node/abstractReplaceStringTool.tsx index 708f19c0c5a..4042bae46b7 100644 --- a/extensions/copilot/src/extension/tools/node/abstractReplaceStringTool.tsx +++ b/extensions/copilot/src/extension/tools/node/abstractReplaceStringTool.tsx @@ -28,7 +28,7 @@ import { ResourceMap, ResourceSet } from '../../../util/vs/base/common/map'; import { isDefined } from '../../../util/vs/base/common/types'; import { URI } from '../../../util/vs/base/common/uri'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; -import { ChatRequestEditorData, ChatResponseTextEditPart, EndOfLine, Position as ExtPosition, LanguageModelPromptTsxPart, LanguageModelToolResult, TextEdit } from '../../../vscodeTypes'; +import { ChatRequestEditorData, ChatResponseTextEditPart, EndOfLine, ExtendedLanguageModelToolResult, Position as ExtPosition, LanguageModelPromptTsxPart, LanguageModelToolResult, TextEdit } from '../../../vscodeTypes'; import { IBuildPromptContext } from '../../prompt/common/intents'; import { renderPromptElementJSON } from '../../prompts/node/base/promptRenderer'; import { CellOrNotebookEdit, processFullRewriteNotebookEdits } from '../../prompts/node/codeMapper/codeMapper'; @@ -39,7 +39,7 @@ import { IToolsService } from '../common/toolsService'; import { ActionType } from './applyPatch/parser'; import { CorrectedEditResult, healReplaceStringParams } from './editFileHealing'; import { EditFileResult, IEditedFile } from './editFileToolResult'; -import { EditError, NoChangeError, NoMatchError, applyEdit, canExistingFileBeEdited, createEditConfirmation, formatDiffAsUnified, logEditToolResult, openDocumentAndSnapshot } from './editFileToolUtils'; +import { applyEdit, canExistingFileBeEdited, createEditConfirmation, EditError, formatDiffAsUnified, logEditToolResult, NoChangeError, NoMatchError, openDocumentAndSnapshot } from './editFileToolUtils'; import { sendEditNotebookTelemetry } from './editNotebookTool'; import { assertFileNotContentExcluded, resolveToolInputPath } from './toolUtils'; @@ -308,7 +308,7 @@ export abstract class AbstractReplaceStringTool f.error); + return result; } private async generateEdit(uri: URI, document: TextDocumentSnapshot | NotebookDocumentSnapshot, options: vscode.LanguageModelToolInvocationOptions | vscode.LanguageModelToolInvocationPrepareOptions, input: IAbstractReplaceStringInput, didHealRef: { healed?: IAbstractReplaceStringInput }, token: vscode.CancellationToken) { diff --git a/extensions/copilot/src/extension/tools/node/applyPatchTool.tsx b/extensions/copilot/src/extension/tools/node/applyPatchTool.tsx index 8dfe38428ef..841e60f2596 100644 --- a/extensions/copilot/src/extension/tools/node/applyPatchTool.tsx +++ b/extensions/copilot/src/extension/tools/node/applyPatchTool.tsx @@ -31,7 +31,7 @@ import { ResourceMap, ResourceSet } from '../../../util/vs/base/common/map'; import { isDefined } from '../../../util/vs/base/common/types'; import { URI } from '../../../util/vs/base/common/uri'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; -import { ChatRequestEditorData, ChatResponseTextEditPart, LanguageModelPromptTsxPart, LanguageModelTextPart, LanguageModelToolResult, Position, Range, WorkspaceEdit } from '../../../vscodeTypes'; +import { ChatRequestEditorData, ChatResponseTextEditPart, ExtendedLanguageModelToolResult, LanguageModelPromptTsxPart, LanguageModelTextPart, LanguageModelToolResult, Position, Range, WorkspaceEdit } from '../../../vscodeTypes'; import { IBuildPromptContext } from '../../prompt/common/intents'; import { ApplyPatchFormatInstructions } from '../../prompts/node/agent/defaultAgentInstructions'; import { PromptRenderer, renderPromptElementJSON } from '../../prompts/node/base/promptRenderer'; @@ -417,7 +417,7 @@ export class ApplyPatchTool implements ICopilotTool { const isInlineChat = this._promptContext.request?.location2 instanceof ChatRequestEditorData; const isNotebook = editEntires.length === 1 ? handledNotebookUris.size === 1 : undefined; this.sendApplyPatchTelemetry('success', options, undefined, !!healed, isNotebook); - return new LanguageModelToolResult([ + const result = new ExtendedLanguageModelToolResult([ new LanguageModelPromptTsxPart( await renderPromptElementJSON( this.instantiationService, @@ -431,13 +431,17 @@ export class ApplyPatchTool implements ICopilotTool { ), ) ]); + result.hasError = files.some(f => f.error); + return result; } catch (error) { const isNotebook = Object.values(docText).length === 1 ? (!!mapFindFirst(Object.values(docText), v => v.notebookUri)) : undefined; // TODO parser.ts could annotate DiffError with a telemetry detail if we want this.sendApplyPatchTelemetry('error', options, undefined, false, isNotebook, error); - return new LanguageModelToolResult([ + const result = new ExtendedLanguageModelToolResult([ new LanguageModelTextPart('Applying patch failed with error: ' + error.message), ]); + result.hasError = true; + return result; } } diff --git a/extensions/copilot/src/extension/vscode.proposed.chatParticipantPrivate.d.ts b/extensions/copilot/src/extension/vscode.proposed.chatParticipantPrivate.d.ts index 398dce07fdd..9f9d0a4b6a9 100644 --- a/extensions/copilot/src/extension/vscode.proposed.chatParticipantPrivate.d.ts +++ b/extensions/copilot/src/extension/vscode.proposed.chatParticipantPrivate.d.ts @@ -248,6 +248,8 @@ declare module 'vscode' { toolResultMessage?: string | MarkdownString; toolResultDetails?: Array; toolMetadata?: unknown; + /** Whether there was an error calling the tool. The tool may still have partially succeeded. */ + hasError?: boolean; } // #region Chat participant detection