diff --git a/package.json b/package.json index 297b834512..09c3d91e16 100644 --- a/package.json +++ b/package.json @@ -3323,7 +3323,7 @@ "type": "string", "description": "The repo in which the issue/PR is located" }, - "unreadComments": { + "comments": { "type": "array", "items": { "type": "object", @@ -3380,13 +3380,15 @@ }, "required": [ "title", - "unreadComments", + "comments", "lastUpdatedAt", "unread", "threadId", "notificationKey", "owner", - "repo" + "repo", + "itemNumber", + "itemType" ] }, "when": "config.githubPullRequests.experimental.chat" diff --git a/src/lm/tools/fetchNotificationTool.ts b/src/lm/tools/fetchNotificationTool.ts index 6b691a73e7..5cf88a62fe 100644 --- a/src/lm/tools/fetchNotificationTool.ts +++ b/src/lm/tools/fetchNotificationTool.ts @@ -25,17 +25,17 @@ export interface FetchNotificationResult { unread: boolean; title: string; body: string; - unreadComments: { + comments?: { author: string; body: string; }[]; owner: string; repo: string; - itemNumber: string; - itemType: 'issue' | 'pr'; + itemNumber?: string; + itemType?: 'issue' | 'pr'; fileChanges?: FileChange[]; - threadId: number, - notificationKey: string + threadId?: number, + notificationKey?: string } export class FetchNotificationTool extends RepoToolBase { @@ -73,20 +73,20 @@ export class FetchNotificationTool extends RepoToolBase { + const itemComments = issueOrPR.item.comments ?? []; + let comments: { body: string; author: string }[]; + if (lastReadAt !== undefined && itemComments) { + comments = itemComments.filter(comment => { return comment.createdAt > lastReadAt; }).map(comment => { return { body: comment.body, author: comment.author.login }; }); } else { - unreadComments = comments.map(comment => { return { body: comment.body, author: comment.author.login }; }); + comments = itemComments.map(comment => { return { body: comment.body, author: comment.author.login }; }); } const result: FetchNotificationResult = { lastReadAt, lastUpdatedAt, unread, - unreadComments, + comments, threadId, notificationKey, title: issueOrPR.title, diff --git a/src/lm/tools/summarizeNotificationsTool.ts b/src/lm/tools/summarizeNotificationsTool.ts index 165e27e746..9eb08426ea 100644 --- a/src/lm/tools/summarizeNotificationsTool.ts +++ b/src/lm/tools/summarizeNotificationsTool.ts @@ -13,6 +13,11 @@ export class NotificationSummarizationTool implements vscode.LanguageModelTool): Promise { const parameters = options.parameters; + if (!parameters.itemType || !parameters.itemNumber) { + return { + invocationMessage: vscode.l10n.t('Summarizing notification') + }; + } const type = parameters.itemType === 'issue' ? 'issues' : 'pull'; const url = `https://github.com/${parameters.owner}/${parameters.repo}/${type}/${parameters.itemNumber}`; return { @@ -44,47 +49,48 @@ Patch: ${fileChange.patch} } } - const unreadComments = options.parameters.unreadComments; - if (unreadComments.length > 0) { + const unreadComments = options.parameters.comments; + if (unreadComments && unreadComments.length > 0) { notificationInfo += ` The following are the unread comments of the thread: `; - } - for (const [index, comment] of unreadComments.entries()) { - notificationInfo += ` + for (const [index, comment] of unreadComments.entries()) { + notificationInfo += ` Comment ${index} : Author: ${comment.author} Body: ${comment.body} `; + } } const models = await vscode.lm.selectChatModels({ vendor: 'copilot', family: 'gpt-4o' }); const model = models[0]; - const markAsReadCommand: vscode.Command = { - title: 'Mark As Read', - command: 'notification.markAsRead', - arguments: [{ - threadId: options.parameters.threadId, - notificationKey: options.parameters.notificationKey - }] - }; + const content: vscode.LanguageModelTextPart[] = []; + const threadId = options.parameters.threadId; + const notificationKey = options.parameters.notificationKey; + if (threadId && notificationKey) { + const markAsReadCommand = { + title: 'Mark As Read', + command: 'notification.markAsRead', + arguments: [{ threadId, notificationKey }] + }; + content.push(new vscode.LanguageModelTextPart(TOOL_COMMAND_RESULT)); + content.push(new vscode.LanguageModelTextPart(JSON.stringify(markAsReadCommand))); + } if (model) { const messages = [vscode.LanguageModelChatMessage.User(this.summarizeInstructions(options.parameters.owner, options.parameters.repo))]; messages.push(vscode.LanguageModelChatMessage.User(`The notification information is as follows:`)); messages.push(vscode.LanguageModelChatMessage.User(notificationInfo)); const response = await model.sendRequest(messages, {}); const responseText = await concatAsyncIterable(response.text); - - return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(TOOL_COMMAND_RESULT), - new vscode.LanguageModelTextPart(JSON.stringify(markAsReadCommand)), - new vscode.LanguageModelTextPart(responseText)]); + content.push(new vscode.LanguageModelTextPart(responseText)); } else { - return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(TOOL_COMMAND_RESULT), - new vscode.LanguageModelTextPart(JSON.stringify(markAsReadCommand)), - new vscode.LanguageModelTextPart(notificationInfo)]); + content.push(new vscode.LanguageModelTextPart(notificationInfo)); } + content.push(new vscode.LanguageModelTextPart('Above is a summary of the notification. Extract and output this notification summary directly as is to the user. Do not output the result from the call to the fetch notification tool.')); + return new vscode.LanguageModelToolResult(content); } private summarizeInstructions(owner: string, repo: string): string {