diff --git a/extensions/copilot/src/extension/inlineChat/vscode-node/inlineChatCommands.ts b/extensions/copilot/src/extension/inlineChat/vscode-node/inlineChatCommands.ts index 72b37550a6d..43d1c5dab22 100644 --- a/extensions/copilot/src/extension/inlineChat/vscode-node/inlineChatCommands.ts +++ b/extensions/copilot/src/extension/inlineChat/vscode-node/inlineChatCommands.ts @@ -332,6 +332,9 @@ function fetchSuggestion(accessor: ServicesAccessor, thread: vscode.CommentThrea const instantiationService = accessor.get(IInstantiationService); const comment = reviewService.findReviewComment(thread); if (!comment || comment.suggestion || comment.skipSuggestion) { + if (comment?.suggestion && 'edits' in comment.suggestion && comment.suggestion.edits.length && thread.contextValue?.includes('hasNoSuggestion')) { + thread.contextValue = updateContextValue(thread.contextValue, 'hasSuggestion', 'hasNoSuggestion'); + } return; } comment.suggestion = (async () => { diff --git a/extensions/copilot/src/extension/review/node/doReview.ts b/extensions/copilot/src/extension/review/node/doReview.ts index 5e2ae10d5d2..d17060012be 100644 --- a/extensions/copilot/src/extension/review/node/doReview.ts +++ b/extensions/copilot/src/extension/review/node/doReview.ts @@ -181,6 +181,7 @@ async function doReview( const canUseGitHubAgent = copilotToken.isCopilotCodeReviewEnabled; result = canUseGitHubAgent ? await githubReview(logService, gitExtensionService, authService, capiClientService, domainService, fetcherService, envService, ignoreService, workspaceService, customInstructionsService, group, editor, progress, tokenSource.token) : await review(instantiationService, gitExtensionService, workspaceService, typeof group === 'object' && 'group' in group ? group.group : group, editor, progress, tokenSource.token); } catch (err) { + logService.error(err, 'Error during code review'); result = { type: 'error', reason: err.message, severity: err.severity }; } finally { if (tokenSource === inProgress) { diff --git a/extensions/copilot/src/extension/review/node/githubReviewAgent.ts b/extensions/copilot/src/extension/review/node/githubReviewAgent.ts index 2c3a17220b8..dafba8eabf6 100644 --- a/extensions/copilot/src/extension/review/node/githubReviewAgent.ts +++ b/extensions/copilot/src/extension/review/node/githubReviewAgent.ts @@ -212,7 +212,9 @@ function createReviewComment(ghComment: ResponseComment | ExcludedComment, reque const range = new Range(fromLine.lineNumber, fromLine.firstNonWhitespaceCharacterIndex, fromLine.lineNumber, lastNonWhitespaceCharacterIndex); const raw = ghComment.data.body; // Remove suggestion because that interfers with our own suggestion rendering later. - const content = removeSuggestion(raw); + const { content, suggestions } = removeSuggestion(raw); + const startLine = typeof ghComment.data.start_line === 'number' ? ghComment.data.start_line : ghComment.data.line; + const suggestionRange = new Range(startLine - 1, 0, ghComment.data.line, 0); const comment: ReviewComment = { request, document: TextDocumentSnapshot.create(document), @@ -224,13 +226,32 @@ function createReviewComment(ghComment: ResponseComment | ExcludedComment, reque severity: 'medium', originalIndex: index, actionCount: 0, + skipSuggestion: true, + suggestion: { + markdown: '', + edits: suggestions.map(suggestion => { + const oldText = document.getText(suggestionRange); + return { + range: suggestionRange, + newText: suggestion, + oldText, + }; + }), + }, }; return comment; } const SUGGESTION_EXPRESSION = /```suggestion(\u0020*(\r\n|\n))((?[\s\S]*?)(\r\n|\n))?```/g; function removeSuggestion(body: string) { - return body.replaceAll(SUGGESTION_EXPRESSION, ''); + const suggestions: string[] = []; + const content = body.replaceAll(SUGGESTION_EXPRESSION, (_match, _ws, _nl, suggestion) => { + if (suggestion) { + suggestions.push(suggestion); + } + return ''; + }); + return { content, suggestions }; } // Represents the "before" or "after" state of a file, sent to the agent @@ -279,6 +300,7 @@ interface ResponseComment { line: number; // The body of the comment, including a ```suggestion block if there is a suggested change body: string; + start_line?: number; }; } @@ -288,6 +310,7 @@ interface ExcludedComment { path: string; line: number; body: string; + start_line?: number; exclusion_reason: 'denylisted_type' | 'unknown'; }; }