Skip to content
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
14 changes: 13 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3794,6 +3794,9 @@
},
{
"path": "./src/lm/skills/show-github-search-result/SKILL.md"
},
{
"path": "./src/lm/skills/address-pr-comments/SKILL.md"
}
],
"languageModelTools": [
Expand Down Expand Up @@ -3963,7 +3966,16 @@
"icon": "$(git-pull-request)",
"canBeReferencedInPrompt": true,
"userDescription": "%languageModelTools.github-pull-request_activePullRequest.description%",
"when": "config.githubPullRequests.experimental.chat"
"when": "config.githubPullRequests.experimental.chat",
"inputSchema": {
"type": "object",
"properties": {
"refresh": {
"type": "boolean",
"description": "Whether to fetch fresh data from GitHub or return cached data. Set to true to ensure the most up-to-date information, especially after recent changes. Set to false to improve performance when up-to-date information is not critical."
}
}
}
},
{
"name": "github-pull-request_pullRequestStatusChecks",
Expand Down
65 changes: 65 additions & 0 deletions src/lm/skills/address-pr-comments/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
name: address-pr-comments
description: "Address review comments (including Copilot comments) on the active pull request. Use when: responding to PR feedback, fixing review comments, resolving PR threads, implementing requested changes from reviewers, addressing code review, fixing PR issues."
argument-hint: "Optionally specify a reviewer name or file to focus on"
---

# Address PR Review Comments

Read the active pull request, identify unresolved review comments and feedback, implement the requested changes, and resolve the threads.

## When to Use

- A reviewer has left comments or change requests on the active PR
- You need to systematically work through all open review threads
- You want to respond to or implement reviewer feedback

## Procedure

### 1. Read the Active PR

Call the `github-pull-request_activePullRequest` tool.

**Refresh logic**: Check whether a refresh is needed before reading:
- Call the tool once *without* `refresh` to get the cached state
- Inspect the `lastUpdatedAt` field in the result
- If the timestamp is **less than 3 minutes ago**, the PR is actively changing - call the tool again with `refresh: true` to ensure you have the latest comments and state
- If the timestamp is older than 3 minutes, proceed with the cached data

### 2. Identify Unresolved Comments

From the tool result, collect all feedback that needs action:

- **`comments`** array: inline review thread comments where `commentState` is `"unresolved"`
- **`timelineComments`** array: general PR comments and reviews where `commentType` is `"CHANGES_REQUESTED"` or `"COMMENTED"`

Group related comments by file (`file` field) to handle them efficiently.

### 3. Plan Changes

Before modifying any files:
1. Read each unresolved comment carefully
2. Identify the file and location each comment refers to
3. Determine the minimal correct fix for each, if a fix is needed (not all comments are worthy of a change)
4. Note dependencies between comments (e.g., a rename that affects multiple files)

### 4. Implement Changes

Work through the grouped comments file by file:
- Read the relevant file section before editing
- Apply the requested change
- Do not refactor or modify code outside the scope of each comment
- If a comment is unclear or contradictory, note it for a follow-up reply rather than guessing

### 5. Verify

After all changes are made:
- Review that each originally unresolved comment has a corresponding code change or a note about why no code change was needed.
- Ensure no unrelated code was modified

### 6. Summarize

Provide a concise summary of:
- Which comments were addressed and what changes were made
- Any comments that were intentionally skipped (with reasoning)
- Any follow-up questions for the reviewer
17 changes: 15 additions & 2 deletions src/lm/tools/activePullRequestTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { CommentEvent, EventType, ReviewEvent } from '../../common/timelineEvent
import { PullRequestModel } from '../../github/pullRequestModel';
import { RepositoriesManager } from '../../github/repositoriesManager';

interface PullRequestToolParams {
refresh?: boolean;
}

export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchIssueResult> {
constructor(
protected readonly folderManagers: RepositoriesManager
Expand Down Expand Up @@ -42,13 +46,21 @@ export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchI
};
}

async invoke(_options: vscode.LanguageModelToolInvocationOptions<any>, _token: vscode.CancellationToken): Promise<vscode.ExtendedLanguageModelToolResult | undefined> {
async invoke(options: vscode.LanguageModelToolInvocationOptions<any>, _token: vscode.CancellationToken): Promise<vscode.ExtendedLanguageModelToolResult | undefined> {
let pullRequest = this._findActivePullRequest();

if (!pullRequest) {
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('There is no active pull request')]);
}

if ((options.input as PullRequestToolParams | undefined)?.refresh) {
await Promise.all([
pullRequest.githubRepository.getPullRequest(pullRequest.number),
pullRequest.getTimelineEvents(),
pullRequest.initializeReviewThreadCacheAndReviewComments(),
]);
}

const timeline = (pullRequest.timelineEvents && pullRequest.timelineEvents.length > 0) ? pullRequest.timelineEvents : await pullRequest.getTimelineEvents();
const reviewAndCommentEvents = timeline.filter((event): event is ReviewEvent | CommentEvent => event.event === EventType.Reviewed || event.event === EventType.Commented);

Expand Down Expand Up @@ -85,7 +97,8 @@ export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchI
} else {
return `File: ${change.fileName} was ${change.status === GitChangeType.ADD ? 'added' : change.status === GitChangeType.DELETE ? 'deleted' : 'modified'}.`;
}
})
}),
lastUpdatedAt: new Date(pullRequest.updatedAt).toLocaleString()
};

const result = new vscode.ExtendedLanguageModelToolResult([new vscode.LanguageModelTextPart(JSON.stringify(pullRequestInfo))]);
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const webpack = require('webpack');
async function resolveTSConfig(configFile) {
const data = await new Promise((resolve, reject) => {
execFile(
'yarn',
'npx',
['tsc', `-p ${configFile}`, '--showConfig'],
{ cwd: __dirname, encoding: 'utf8', shell: true },
function (error, stdout, stderr) {
Expand Down
Loading