From 39385f2f7b18cde5efc4820aa444a888c447473d Mon Sep 17 00:00:00 2001 From: spebl Date: Tue, 10 Dec 2024 11:54:52 -0800 Subject: [PATCH 01/10] Use propsed content exclusion extensions for vscode language model --- Extension/package.json | 5 ++++- .../LanguageServer/Providers/CopilotHoverProvider.ts | 10 ++++++++++ Extension/src/LanguageServer/client.ts | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index cfdc2a73d7..eb51597af0 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -38,7 +38,10 @@ "Snippets" ], "enabledApiProposals": [ - "terminalDataWriteEvent" + "terminalDataWriteEvent", + "chatVariableResolver", + "chatParticipantPrivate", + "chatParticipantAdditions" ], "capabilities": { "untrustedWorkspaces": { diff --git a/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts b/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts index a6d052895b..cc5fda9266 100644 --- a/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts +++ b/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts @@ -107,6 +107,16 @@ export class CopilotHoverProvider implements vscode.HoverProvider { try { const response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken); requestInfo = response.content; + if (response.files) { + for (const file of response.files) { + const fileUri = vscode.Uri.parse(file); + const token = this.currentCancellationToken ?? new vscode.CancellationTokenSource().token; + if (await vscode.lm.fileIsIgnored(fileUri, token)) { + return ""; + } + } + } + } catch (e: any) { if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { throw new vscode.CancellationError(); diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 8ee0e22f6a..d56f1c29d9 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -541,6 +541,7 @@ export interface GetCopilotHoverInfoParams { interface GetCopilotHoverInfoResult { content: string; + files: string[]; } export interface ChatContextResult { From 26396c72266ce8b14795c98b37e5ce019a5775dd Mon Sep 17 00:00:00 2001 From: spebl Date: Mon, 13 Jan 2025 10:44:00 -0800 Subject: [PATCH 02/10] get back files used for copilot context generation. --- .../Providers/CopilotHoverProvider.ts | 21 +++++-------------- Extension/src/LanguageServer/client.ts | 2 +- Extension/src/LanguageServer/extension.ts | 14 +++++++++++-- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts b/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts index cc5fda9266..05a5ecb8c7 100644 --- a/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts +++ b/Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { Position, ResponseError } from 'vscode-languageclient'; import * as nls from 'vscode-nls'; -import { DefaultClient, GetCopilotHoverInfoParams, GetCopilotHoverInfoRequest } from '../client'; +import { DefaultClient, GetCopilotHoverInfoParams, GetCopilotHoverInfoRequest, GetCopilotHoverInfoResult } from '../client'; import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings } from '../settings'; @@ -92,8 +92,8 @@ export class CopilotHoverProvider implements vscode.HoverProvider { return this.currentCancellationToken; } - public async getRequestInfo(document: vscode.TextDocument, position: vscode.Position): Promise { - let requestInfo = ""; + public async getRequestInfo(document: vscode.TextDocument, position: vscode.Position): Promise { + let response: GetCopilotHoverInfoResult; const params: GetCopilotHoverInfoParams = { textDocument: { uri: document.uri.toString() }, position: Position.create(position.line, position.character) @@ -105,18 +105,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider { } try { - const response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken); - requestInfo = response.content; - if (response.files) { - for (const file of response.files) { - const fileUri = vscode.Uri.parse(file); - const token = this.currentCancellationToken ?? new vscode.CancellationTokenSource().token; - if (await vscode.lm.fileIsIgnored(fileUri, token)) { - return ""; - } - } - } - + response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken); } catch (e: any) { if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { throw new vscode.CancellationError(); @@ -124,7 +113,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider { throw e; } - return requestInfo; + return response; } public isCancelled(document: vscode.TextDocument, position: vscode.Position): boolean { diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index d56f1c29d9..912fde2125 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -539,7 +539,7 @@ export interface GetCopilotHoverInfoParams { position: Position; } -interface GetCopilotHoverInfoResult { +export interface GetCopilotHoverInfoResult { content: string; files: string[]; } diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 642831c25c..6d828b8791 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -11,7 +11,7 @@ import * as StreamZip from 'node-stream-zip'; import * as os from 'os'; import * as path from 'path'; import * as vscode from 'vscode'; -import { Range } from 'vscode-languageclient'; +import { CancellationToken, Range } from 'vscode-languageclient'; import * as nls from 'vscode-nls'; import { TargetPopulation } from 'vscode-tas-client'; import * as which from 'which'; @@ -1430,7 +1430,17 @@ async function onCopilotHover(): Promise { // Gather the content for the query from the client. const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition); - if (requestInfo.length === 0) { + for (const file of requestInfo.files) { + // TODO: make uri from file string. + const fileUri = vscode.Uri.file(file); + if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { + // Context is not available for this file. + telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for this file." }); + await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available for this file.")); + return; + } + } + if (requestInfo.content.length === 0) { // Context is not available for this symbol. telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for this symbol." }); await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available for this symbol.")); From 9d4088238a7c7f34a81b68365f6af99c6bcf5e9c Mon Sep 17 00:00:00 2001 From: spebl Date: Mon, 13 Jan 2025 11:22:12 -0800 Subject: [PATCH 03/10] update message to use the right content --- Extension/src/LanguageServer/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 6d828b8791..8d6f529cd0 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1451,7 +1451,7 @@ async function onCopilotHover(): Promise { const messages = [ vscode.LanguageModelChatMessage - .User(requestInfo + locale)]; + .User(requestInfo.content + locale)]; const [model] = await vscodelm.selectChatModels(modelSelector); From 8a76de95ea0225447e8b45ad6f5d730aad26dc70 Mon Sep 17 00:00:00 2001 From: spebl Date: Mon, 13 Jan 2025 13:39:51 -0800 Subject: [PATCH 04/10] remove old comment --- Extension/src/LanguageServer/extension.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 8d6f529cd0..a429530301 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1431,7 +1431,6 @@ async function onCopilotHover(): Promise { // Gather the content for the query from the client. const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition); for (const file of requestInfo.files) { - // TODO: make uri from file string. const fileUri = vscode.Uri.file(file); if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { // Context is not available for this file. From bca1d45abaae5708b825c687f9dd61667fb28c8e Mon Sep 17 00:00:00 2001 From: spebl Date: Mon, 13 Jan 2025 15:37:13 -0800 Subject: [PATCH 05/10] update displayed error to better convey content exclusion --- Extension/src/LanguageServer/extension.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index a429530301..bcf96fae2b 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1434,15 +1434,16 @@ async function onCopilotHover(): Promise { const fileUri = vscode.Uri.file(file); if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { // Context is not available for this file. - telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for this file." }); - await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available for this file.")); + telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for definition or declaration." }); + await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available." + "\n\n" + + localize("copilot.hover.excluded", "The file containing this symbol's defintion or declaration has been excluded from use with Copilot."))); return; } } if (requestInfo.content.length === 0) { // Context is not available for this symbol. telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for this symbol." }); - await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available for this symbol.")); + await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable.symbol", "Copilot summary is not available for this symbol.")); return; } From 2262010c0447c5a6a8d6e6c71049d14455e79771 Mon Sep 17 00:00:00 2001 From: spebl Date: Tue, 14 Jan 2025 12:27:43 -0800 Subject: [PATCH 06/10] fix parens for localize calls --- Extension/src/LanguageServer/extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index bcf96fae2b..279465cf1f 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1435,8 +1435,8 @@ async function onCopilotHover(): Promise { if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { // Context is not available for this file. telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for definition or declaration." }); - await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available." + "\n\n" + - localize("copilot.hover.excluded", "The file containing this symbol's defintion or declaration has been excluded from use with Copilot."))); + await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available.") + "\n\n" + + localize("copilot.hover.excluded", "The file containing this symbol's defintion or declaration has been excluded from use with Copilot.")); return; } } From 7f4cde94b376646202816d49dfeef6bd0ccbc227 Mon Sep 17 00:00:00 2001 From: spebl Date: Wed, 15 Jan 2025 12:01:03 -0800 Subject: [PATCH 07/10] fix typo and update telemetry for content exclusion case --- Extension/src/LanguageServer/extension.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 279465cf1f..5e759f06d8 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1433,10 +1433,9 @@ async function onCopilotHover(): Promise { for (const file of requestInfo.files) { const fileUri = vscode.Uri.file(file); if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { - // Context is not available for this file. - telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for definition or declaration." }); + telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available due to content exclusion." }); await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available.") + "\n\n" + - localize("copilot.hover.excluded", "The file containing this symbol's defintion or declaration has been excluded from use with Copilot.")); + localize("copilot.hover.excluded", "The file containing this symbol's definition or declaration has been excluded from use with Copilot.")); return; } } From 00e9a546169d407a523f6a20265f28642747442c Mon Sep 17 00:00:00 2001 From: spebl Date: Wed, 15 Jan 2025 12:43:33 -0800 Subject: [PATCH 08/10] update proposals needed and update build scripts to not force download dev dependencies --- Extension/package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index a53f882597..ebee813ba0 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -39,8 +39,6 @@ ], "enabledApiProposals": [ "terminalDataWriteEvent", - "chatVariableResolver", - "chatParticipantPrivate", "chatParticipantAdditions" ], "capabilities": { @@ -6530,6 +6528,7 @@ "lint": "yarn install && eslint -c .eslintrc.js --report-unused-disable-directives src test ui .scripts", "compile": "yarn install && (yarn verify prep --quiet || yarn prep) && yarn build", "watch": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build tsconfig.json --watch", + "watch-dev": "yarn install && yarn prep:dts-dev && tsc --build tsconfig.json --watch", "rebuild": "yarn install && yarn clean && yarn prep && yarn build", "vsix-prepublish": "yarn install && yarn clean && yarn webpack", "webpack": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build ui.tsconfig.json && webpack --mode production --env vscode_nls", @@ -6540,8 +6539,10 @@ "translations-generate": "set NODE_OPTIONS=--no-experimental-fetch && gulp translations-generate", "translations-import": "gulp translations-import", "import-edge-strings": "ts-node -T ./.scripts/import_edge_strings.ts", - "prep:dts": "yarn verify dts --quiet || (npx @vscode/dts dev && npx @vscode/dts main)", - "build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json" + "prep:dts": "yarn verify dts --quiet || npx @vscode/dts main", + "prep:dts-dev": "yarn verify dts --quiet || (npx @vscode/dts main && npx @vscode/dts dev)", + "build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json", + "build-dev": "yarn prep:dts-dev && echo [Building TypeScript code with dev dependencies] && tsc --build tsconfig.json" }, "devDependencies": { "@octokit/rest": "^20.1.1", From 792d8f9801b7d43252f722dfaa9afa9228155918 Mon Sep 17 00:00:00 2001 From: spebl Date: Wed, 15 Jan 2025 13:55:19 -0800 Subject: [PATCH 09/10] update scripts to delete problematic development proposal --- Extension/.scripts/common.ts | 18 +++++++++++++++--- Extension/.scripts/verify.ts | 11 ++++++++++- Extension/package.json | 7 ++----- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Extension/.scripts/common.ts b/Extension/.scripts/common.ts index 598ff97e8f..91adc0e302 100644 --- a/Extension/.scripts/common.ts +++ b/Extension/.scripts/common.ts @@ -48,7 +48,7 @@ export const Git = async (...args: Parameters>) => (awa export const GitClean = async (...args: Parameters>) => (await new Command(await git, 'clean'))(...args); export async function getModifiedIgnoredFiles() { - const {code, error, stdio } = await GitClean('-Xd', '-n'); + const { code, error, stdio } = await GitClean('-Xd', '-n'); if (code) { throw new Error(`\n${error.all().join('\n')}`); } @@ -65,11 +65,11 @@ export async function rimraf(...paths: string[]) { } if (await filepath.isFolder(each)) { verbose(`Removing folder ${red(each)}`); - all.push(rm(each, {recursive: true, force: true})); + all.push(rm(each, { recursive: true, force: true })); continue; } verbose(`Removing file ${red(each)}`); - all.push(rm(each, {force: true})); + all.push(rm(each, { force: true })); } await Promise.all(all); } @@ -345,3 +345,15 @@ export async function checkBinaries() { } return failing; } + +export async function checkProposals() { + let failing = false; + + await rm(`${$root}/vscode.proposed.chatParticipantAdditions.d.ts`); + failing = await assertAnyFile('vscode.proposed.chatParticipantAdditions.d.ts') && (quiet || warn(`The VSCode import file '${$root}/vscode.proposed.chatParticipantAdditions.d.ts' should not be present.`)) || failing; + + if (!failing) { + verbose('VSCode proposals appear to be in place.'); + } + return failing; +} diff --git a/Extension/.scripts/verify.ts b/Extension/.scripts/verify.ts index d6ed9896d3..ccfaac49d8 100644 --- a/Extension/.scripts/verify.ts +++ b/Extension/.scripts/verify.ts @@ -3,7 +3,7 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import { checkBinaries, checkCompiled, checkDTS, checkPrep, error, green } from './common'; +import { checkBinaries, checkCompiled, checkDTS, checkPrep, checkProposals, error, green } from './common'; const quiet = process.argv.includes('--quiet'); export async function main() { @@ -50,3 +50,12 @@ export async function dts() { process.exit(1); } } + +export async function proposals() { + let failing = false; + failing = (await checkProposals() && (quiet || error(`Issue with VSCode proposals. Run ${green('yarn prep')} to fix it.`))) || failing; + + if (failing) { + process.exit(1); + } +} diff --git a/Extension/package.json b/Extension/package.json index ebee813ba0..e115e09d0e 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -6528,7 +6528,6 @@ "lint": "yarn install && eslint -c .eslintrc.js --report-unused-disable-directives src test ui .scripts", "compile": "yarn install && (yarn verify prep --quiet || yarn prep) && yarn build", "watch": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build tsconfig.json --watch", - "watch-dev": "yarn install && yarn prep:dts-dev && tsc --build tsconfig.json --watch", "rebuild": "yarn install && yarn clean && yarn prep && yarn build", "vsix-prepublish": "yarn install && yarn clean && yarn webpack", "webpack": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build ui.tsconfig.json && webpack --mode production --env vscode_nls", @@ -6539,10 +6538,8 @@ "translations-generate": "set NODE_OPTIONS=--no-experimental-fetch && gulp translations-generate", "translations-import": "gulp translations-import", "import-edge-strings": "ts-node -T ./.scripts/import_edge_strings.ts", - "prep:dts": "yarn verify dts --quiet || npx @vscode/dts main", - "prep:dts-dev": "yarn verify dts --quiet || (npx @vscode/dts main && npx @vscode/dts dev)", - "build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json", - "build-dev": "yarn prep:dts-dev && echo [Building TypeScript code with dev dependencies] && tsc --build tsconfig.json" + "prep:dts": "yarn verify dts --quiet || (npx @vscode/dts main && npx @vscode/dts dev && yarn verify proposals)", + "build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json" }, "devDependencies": { "@octokit/rest": "^20.1.1", From 43cb8556b46173b11092cef868c8d857afa1d408 Mon Sep 17 00:00:00 2001 From: spebl Date: Wed, 15 Jan 2025 16:20:24 -0800 Subject: [PATCH 10/10] wrap proposed API call in try/catch --- Extension/src/LanguageServer/extension.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 5e759f06d8..87ac5d6e57 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -1430,14 +1430,21 @@ async function onCopilotHover(): Promise { // Gather the content for the query from the client. const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition); - for (const file of requestInfo.files) { - const fileUri = vscode.Uri.file(file); - if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { - telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available due to content exclusion." }); - await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available.") + "\n\n" + - localize("copilot.hover.excluded", "The file containing this symbol's definition or declaration has been excluded from use with Copilot.")); - return; + try { + for (const file of requestInfo.files) { + const fileUri = vscode.Uri.file(file); + if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) { + telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available due to content exclusion." }); + await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available.") + "\n\n" + + localize("copilot.hover.excluded", "The file containing this symbol's definition or declaration has been excluded from use with Copilot.")); + return; + } } + } catch (err) { + if (err instanceof Error) { + await reportCopilotFailure(copilotHoverProvider, hoverDocument, hoverPosition, err.message); + } + return; } if (requestInfo.content.length === 0) { // Context is not available for this symbol.