Skip to content

Commit 18e94f6

Browse files
committed
Move status checks into a separate tool
1 parent 98e8b9a commit 18e94f6

File tree

5 files changed

+140
-33
lines changed

5 files changed

+140
-33
lines changed

package.json

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,12 +3935,58 @@
39353935
],
39363936
"toolReferenceName": "activePullRequest",
39373937
"displayName": "%languageModelTools.github-pull-request_activePullRequest.displayName%",
3938-
"modelDescription": "Get comprehensive information about the active GitHub pull request (PR). The active PR is the one that is currently checked out. This includes the PR title, full description, list of changed files, review comments, PR state, and status checks/CI results. For PRs created by Copilot, it also includes the session logs which indicate the development process and decisions made by the coding agent. When asked about the active or current pull request, do this first! Use this tool for any request related to \"current changes,\" \"pull request details,\" \"what changed,\" \"PR status,\" or similar queries even if the user does not explicitly mention \"pull request.\" When asked to use this tool, ALWAYS use it.",
3938+
"modelDescription": "Get comprehensive information about the active GitHub pull request (PR). The active PR is the one that is currently checked out. This includes the PR title, full description, list of changed files, review comments, and PR state. For PRs created by Copilot, it also includes the session logs which indicate the development process and decisions made by the coding agent. Does NOT include status checks/CI results; use the pullRequestStatusChecks tool instead. When asked about the active or current pull request, do this first! Use this tool for any request related to \"current changes,\" \"pull request details,\" \"what changed,\" or similar queries even if the user does not explicitly mention \"pull request.\" When asked to use this tool, ALWAYS use it.",
39393939
"icon": "$(git-pull-request)",
39403940
"canBeReferencedInPrompt": true,
39413941
"userDescription": "%languageModelTools.github-pull-request_activePullRequest.description%",
39423942
"when": "config.githubPullRequests.experimental.chat"
39433943
},
3944+
{
3945+
"name": "github-pull-request_pullRequestStatusChecks",
3946+
"tags": [
3947+
"github",
3948+
"pull request",
3949+
"ci",
3950+
"status checks"
3951+
],
3952+
"toolReferenceName": "pullRequestStatusChecks",
3953+
"displayName": "%languageModelTools.github-pull-request_pullRequestStatusChecks.displayName%",
3954+
"modelDescription": "Get the status checks and CI failures for a GitHub pull request (PR). This includes check run statuses, workflow names, failure logs, and review requirements (approvals needed, current approvals, requested changes). Use this tool when the user asks about CI status/failures, build results, check runs, status checks, whether a PR is ready to merge, or similar queries. Requires a pull request number.",
3955+
"icon": "$(check-all)",
3956+
"canBeReferencedInPrompt": true,
3957+
"inputSchema": {
3958+
"type": "object",
3959+
"properties": {
3960+
"repo": {
3961+
"type": "object",
3962+
"description": "The repository to get the pull request status checks from.",
3963+
"properties": {
3964+
"owner": {
3965+
"type": "string",
3966+
"description": "The owner of the repository."
3967+
},
3968+
"name": {
3969+
"type": "string",
3970+
"description": "The name of the repository."
3971+
}
3972+
},
3973+
"required": [
3974+
"owner",
3975+
"name"
3976+
]
3977+
},
3978+
"pullRequestNumber": {
3979+
"type": "number",
3980+
"description": "The number of the pull request to get status checks for."
3981+
}
3982+
},
3983+
"required": [
3984+
"pullRequestNumber"
3985+
]
3986+
},
3987+
"userDescription": "%languageModelTools.github-pull-request_pullRequestStatusChecks.description%",
3988+
"when": "config.githubPullRequests.experimental.chat"
3989+
},
39443990
{
39453991
"name": "github-pull-request_openPullRequest",
39463992
"tags": [
@@ -3949,7 +3995,7 @@
39493995
],
39503996
"toolReferenceName": "openPullRequest",
39513997
"displayName": "%languageModelTools.github-pull-request_openPullRequest.displayName%",
3952-
"modelDescription": "Get comprehensive information about the GitHub pull request (PR) which is currently visible, but not necessarily checked out. This is the pull request that the user is currently viewing. This includes the PR title, full description, list of changed files, review comments, PR state, and status checks/CI results. For PRs created by Copilot, it also includes the session logs which indicate the development process and decisions made by the coding agent. When asked about the currently open pull request, do this first! Use this tool for any request related to \"pull request details,\" \"what changed,\" \"PR status,\" or similar queries even if the user does not explicitly mention \"pull request.\" When asked to use this tool, ALWAYS use it.",
3998+
"modelDescription": "Get comprehensive information about the GitHub pull request (PR) which is currently visible, but not necessarily checked out. This is the pull request that the user is currently viewing. This includes the PR title, full description, list of changed files, review comments, and PR state. For PRs created by Copilot, it also includes the session logs which indicate the development process and decisions made by the coding agent. Does NOT include status checks/CI results; use the pullRequestStatusChecks tool instead. When asked about the currently open pull request, do this first! Use this tool for any request related to \"pull request details,\" \"what changed,\" or similar queries even if the user does not explicitly mention \"pull request.\" When asked to use this tool, ALWAYS use it.",
39533999
"icon": "$(git-pull-request)",
39544000
"canBeReferencedInPrompt": true,
39554001
"userDescription": "%languageModelTools.github-pull-request_openPullRequest.description%",

package.nls.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,9 @@
434434
"languageModelTools.github-pull-request_doSearch.description": "Search for GitHub issues and pull requests.",
435435
"languageModelTools.github-pull-request_renderIssues.displayName": "Render issue items in a markdown table",
436436
"languageModelTools.github-pull-request_activePullRequest.displayName": "Active Pull Request",
437-
"languageModelTools.github-pull-request_activePullRequest.description": "Get information about the active GitHub pull request. This information includes: comments, files changed, pull request title + description, pull request state, and pull request status checks/CI.",
437+
"languageModelTools.github-pull-request_activePullRequest.description": "Get information about the active GitHub pull request. This information includes: comments, files changed, pull request title + description, and pull request state.",
438+
"languageModelTools.github-pull-request_pullRequestStatusChecks.displayName": "Pull Request Status Checks",
439+
"languageModelTools.github-pull-request_pullRequestStatusChecks.description": "Get the status checks and CI results for a GitHub pull request.",
438440
"languageModelTools.github-pull-request_openPullRequest.displayName": "Open Pull Request",
439-
"languageModelTools.github-pull-request_openPullRequest.description": "Get information about the open GitHub pull request. This information includes: comments, files changed, pull request title + description, pull request state, and pull request status checks/CI."
441+
"languageModelTools.github-pull-request_openPullRequest.description": "Get information about the open GitHub pull request. This information includes: comments, files changed, pull request title + description, and pull request state."
440442
}

src/lm/tools/activePullRequestTool.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
import * as vscode from 'vscode';
88
import { FetchIssueResult } from './fetchIssueTool';
99
import { GitChangeType, InMemFileChange } from '../../common/file';
10-
import Logger from '../../common/logger';
1110
import { CommentEvent, EventType, ReviewEvent } from '../../common/timelineEvent';
12-
import { CheckState } from '../../github/interface';
1311
import { PullRequestModel } from '../../github/pullRequestModel';
1412
import { RepositoriesManager } from '../../github/repositoriesManager';
1513

@@ -51,27 +49,6 @@ export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchI
5149
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('There is no active pull request')]);
5250
}
5351

54-
const status = await pullRequest.getStatusChecks();
55-
const statuses = status[0]?.statuses ?? [];
56-
57-
// Fetch logs for failed check runs in parallel
58-
const statusChecks = await Promise.all(statuses.map(async (s) => {
59-
const entry: Record<string, any> = {
60-
context: s.context,
61-
description: s.description,
62-
state: s.state,
63-
name: s.workflowName,
64-
targetUrl: s.targetUrl,
65-
};
66-
if (s.state === CheckState.Failure && s.isCheckRun && s.databaseId) {
67-
try {
68-
entry.logs = await pullRequest.githubRepository.getCheckRunLogs(s.databaseId);
69-
} catch (e) {
70-
Logger.error(`Failed to fetch check run logs for ${s.context}: ${e}`, 'PullRequestTool');
71-
}
72-
}
73-
return entry;
74-
}));
7552
const timeline = (pullRequest.timelineEvents && pullRequest.timelineEvents.length > 0) ? pullRequest.timelineEvents : await pullRequest.getTimelineEvents();
7653
const pullRequestInfo = {
7754
title: pullRequest.title,
@@ -94,12 +71,6 @@ export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchI
9471
};
9572
}),
9673
state: pullRequest.state,
97-
statusChecks,
98-
reviewRequirements: {
99-
approvalsNeeded: status[1]?.count ?? 0,
100-
currentApprovals: status[1]?.approvals.length ?? 0,
101-
areChangesRequested: (status[1]?.requestedChanges.length ?? 0) > 0,
102-
},
10374
isDraft: pullRequest.isDraft ? 'is a draft and cannot be merged until marked as ready for review' : 'false',
10475
changes: (await pullRequest.getFileChangesInfo()).map(change => {
10576
if (change instanceof InMemFileChange) {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
'use strict';
6+
7+
import * as vscode from 'vscode';
8+
import { RepoToolBase } from './toolsUtils';
9+
import Logger from '../../common/logger';
10+
import { CheckState } from '../../github/interface';
11+
import { PullRequestModel } from '../../github/pullRequestModel';
12+
13+
interface StatusChecksToolParameters {
14+
pullRequestNumber: number;
15+
repo?: {
16+
owner?: string;
17+
name?: string;
18+
};
19+
}
20+
21+
export class PullRequestStatusChecksTool extends RepoToolBase<StatusChecksToolParameters> {
22+
public static readonly toolId = 'github-pull-request_pullRequestStatusChecks';
23+
24+
async prepareInvocation(options: vscode.LanguageModelToolInvocationPrepareOptions<StatusChecksToolParameters>): Promise<vscode.PreparedToolInvocation> {
25+
if (!options.input.pullRequestNumber) {
26+
return {
27+
invocationMessage: vscode.l10n.t('Fetching status checks from GitHub'),
28+
};
29+
}
30+
const { owner, name } = await this.getRepoInfo({ owner: options.input.repo?.owner, name: options.input.repo?.name });
31+
const url = (owner && name) ? `https://github.com/${owner}/${name}/pull/${options.input.pullRequestNumber}` : undefined;
32+
const message = url
33+
? new vscode.MarkdownString(vscode.l10n.t('Fetching status checks for [#{0}]({1}) from GitHub', options.input.pullRequestNumber, url))
34+
: vscode.l10n.t('Fetching status checks for #{0} from GitHub', options.input.pullRequestNumber);
35+
return {
36+
invocationMessage: message,
37+
};
38+
}
39+
40+
async invoke(options: vscode.LanguageModelToolInvocationOptions<StatusChecksToolParameters>, _token: vscode.CancellationToken): Promise<vscode.LanguageModelToolResult> {
41+
const pullRequestNumber = options.input.pullRequestNumber;
42+
if (!pullRequestNumber) {
43+
throw new Error('No pull request number provided.');
44+
}
45+
const { owner, name, folderManager } = await this.getRepoInfo({ owner: options.input.repo?.owner, name: options.input.repo?.name });
46+
const issueOrPullRequest = await folderManager.resolveIssueOrPullRequest(owner, name, pullRequestNumber);
47+
if (!(issueOrPullRequest instanceof PullRequestModel)) {
48+
throw new Error(`No pull request found for ${owner}/${name}#${pullRequestNumber}. Make sure the pull request exists.`);
49+
}
50+
51+
const pullRequest = issueOrPullRequest;
52+
const status = await pullRequest.getStatusChecks();
53+
const statuses = status[0]?.statuses ?? [];
54+
const failures = statuses.filter(s => s.state === CheckState.Failure);
55+
56+
// Fetch logs for failed check runs in parallel
57+
const failedChecks = await Promise.all(failures.map(async (s) => {
58+
const entry: Record<string, any> = {
59+
context: s.context,
60+
description: s.description,
61+
state: s.state,
62+
name: s.workflowName,
63+
targetUrl: s.targetUrl,
64+
};
65+
if (s.isCheckRun && s.databaseId) {
66+
try {
67+
entry.logs = await pullRequest.githubRepository.getCheckRunLogs(s.databaseId);
68+
} catch (e) {
69+
Logger.error(`Failed to fetch check run logs for ${s.context}: ${e}`, 'PullRequestStatusChecksTool');
70+
}
71+
}
72+
return entry;
73+
}));
74+
75+
const statusChecksInfo = {
76+
failedChecks,
77+
reviewRequirements: {
78+
approvalsNeeded: status[1]?.count ?? 0,
79+
currentApprovals: status[1]?.approvals.length ?? 0,
80+
areChangesRequested: (status[1]?.requestedChanges.length ?? 0) > 0,
81+
},
82+
};
83+
84+
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(JSON.stringify(statusChecksInfo))]);
85+
}
86+
}

src/lm/tools/tools.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { FetchIssueTool } from './fetchIssueTool';
1010
import { FetchLabelsTool } from './fetchLabelsTool';
1111
import { FetchNotificationTool } from './fetchNotificationTool';
1212
import { OpenPullRequestTool } from './openPullRequestTool';
13+
import { PullRequestStatusChecksTool } from './pullRequestStatusChecksTool';
1314
import { SearchTool } from './searchTools';
1415
import { CredentialStore } from '../../github/credentials';
1516
import { RepositoriesManager } from '../../github/repositoriesManager';
@@ -19,6 +20,7 @@ export function registerTools(context: vscode.ExtensionContext, credentialStore:
1920
registerSearchTools(context, credentialStore, repositoriesManager);
2021
context.subscriptions.push(vscode.lm.registerTool(ActivePullRequestTool.toolId, new ActivePullRequestTool(repositoriesManager)));
2122
context.subscriptions.push(vscode.lm.registerTool(OpenPullRequestTool.toolId, new OpenPullRequestTool(repositoriesManager)));
23+
context.subscriptions.push(vscode.lm.registerTool(PullRequestStatusChecksTool.toolId, new PullRequestStatusChecksTool(credentialStore, repositoriesManager)));
2224
}
2325

2426
function registerFetchingTools(context: vscode.ExtensionContext, credentialStore: CredentialStore, repositoriesManager: RepositoriesManager) {

0 commit comments

Comments
 (0)