Support Content Exclusion for Copilot Hover (#13143)

* Use propsed content exclusion APIs
This commit is contained in:
Spencer Bloom
2025-01-16 12:13:41 -08:00
committed by GitHub
parent 9e96d6383c
commit 5d32121787
6 changed files with 55 additions and 17 deletions
+15 -3
View File
@@ -48,7 +48,7 @@ export const Git = async (...args: Parameters<Awaited<CommandFunction>>) => (awa
export const GitClean = async (...args: Parameters<Awaited<CommandFunction>>) => (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;
}
+10 -1
View File
@@ -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);
}
}
+3 -2
View File
@@ -38,7 +38,8 @@
"Snippets"
],
"enabledApiProposals": [
"terminalDataWriteEvent"
"terminalDataWriteEvent",
"chatParticipantAdditions"
],
"capabilities": {
"untrustedWorkspaces": {
@@ -6537,7 +6538,7 @@
"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)",
"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": {
@@ -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<string> {
let requestInfo = "";
public async getRequestInfo(document: vscode.TextDocument, position: vscode.Position): Promise<GetCopilotHoverInfoResult> {
let response: GetCopilotHoverInfoResult;
const params: GetCopilotHoverInfoParams = {
textDocument: { uri: document.uri.toString() },
position: Position.create(position.line, position.character)
@@ -105,8 +105,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
}
try {
const response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken);
requestInfo = response.content;
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();
@@ -114,7 +113,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
throw e;
}
return requestInfo;
return response;
}
public isCancelled(document: vscode.TextDocument, position: vscode.Position): boolean {
+2 -1
View File
@@ -540,8 +540,9 @@ export interface GetCopilotHoverInfoParams {
position: Position;
}
interface GetCopilotHoverInfoResult {
export interface GetCopilotHoverInfoResult {
content: string;
files: string[];
}
export interface ChatContextResult {
+20 -4
View File
@@ -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,10 +1430,26 @@ async function onCopilotHover(): Promise<void> {
// Gather the content for the query from the client.
const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition);
if (requestInfo.length === 0) {
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.name);
}
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;
}
@@ -1441,7 +1457,7 @@ async function onCopilotHover(): Promise<void> {
const messages = [
vscode.LanguageModelChatMessage
.User(requestInfo + locale)];
.User(requestInfo.content + locale)];
const [model] = await vscodelm.selectChatModels(modelSelector);