Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/e2e/testHelper.ts
13388 views
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
6
import type { ChatLanguageModelToolReference, ChatPromptReference } from 'vscode';
7
import { IToolsService } from '../../src/extension/tools/common/toolsService';
8
import { ITestingServicesAccessor } from '../../src/platform/test/node/services';
9
import { SimulationWorkspace } from '../../src/platform/test/node/simulationWorkspace';
10
import { basename } from '../../src/util/vs/base/common/resources';
11
import { Location, Uri } from '../../src/vscodeTypes';
12
import { IConversationTestCase } from './scenarioLoader';
13
14
export interface IParsedQuery {
15
query: string;
16
participantName: string | undefined;
17
command?: string;
18
variables: ChatPromptReference[];
19
toolReferences: ChatLanguageModelToolReference[];
20
}
21
22
/**
23
* This has to recreate some of the variable parsing logic in VS Code so that we can write tests easily with variables
24
* as strings, but then provide the extension code with the parsed variables in the extension API format.
25
*/
26
export async function parseQueryForScenarioTest(accessor: ITestingServicesAccessor, testCase: IConversationTestCase, simulationWorkspace: SimulationWorkspace): Promise<IParsedQuery> {
27
const query = await parseQueryForTest(accessor, testCase.question, simulationWorkspace);
28
29
// Simulate implicit context enablement
30
const activeTextEditor = simulationWorkspace.activeTextEditor;
31
if (activeTextEditor) {
32
const selection = activeTextEditor.selections?.[0];
33
if (selection) {
34
query.variables.push({
35
id: 'vscode.implicit',
36
name: `file:${basename(activeTextEditor.document.uri)}`,
37
value: new Location(activeTextEditor.document.uri, selection),
38
modelDescription: `User's active selection`
39
});
40
} else {
41
query.variables.push({
42
id: 'vscode.implicit',
43
name: `file:${basename(activeTextEditor.document.uri)}`,
44
value: activeTextEditor.document.uri,
45
modelDescription: `User's active file`
46
});
47
}
48
}
49
50
return query;
51
}
52
53
export function createWorkingSetFileVariable(uri: Uri) {
54
return {
55
id: 'copilot.file',
56
name: `file:${basename(uri)}`,
57
value: uri,
58
};
59
}
60
61
export function parseQueryForTest(accessor: ITestingServicesAccessor, query: string, simulationWorkspace: SimulationWorkspace): IParsedQuery {
62
const variableReg = /#([\w_\-]+)(?::(\S+))?(?=(\s|$|\b))/ig;
63
64
const toolsService = accessor.get(IToolsService);
65
66
const match = query.match(/(?:@(\S+))?\s*(?:\/(\S+))?(.*)/);
67
let command: string | undefined;
68
let participantName: string | undefined;
69
if (match) {
70
participantName = match[1];
71
command = match[2];
72
query = match[3]?.trim() || '';
73
}
74
75
const variables: ChatPromptReference[] = [];
76
const toolReferences: ChatLanguageModelToolReference[] = [];
77
let varMatch: RegExpMatchArray | null;
78
while (varMatch = variableReg.exec(query)) {
79
const [_, varName, arg] = varMatch;
80
const range: [number, number] = [varMatch.index!, varMatch.index! + varMatch[0].length];
81
if (varName === 'file') {
82
const value = parseFileVariables(simulationWorkspace, arg);
83
const varWithArg = `${varName}:${arg}`;
84
variables.push({ id: `copilot.${varName}`, name: varWithArg, range, value });
85
} else {
86
const tool = toolsService.getToolByToolReferenceName(varName);
87
if (tool) {
88
toolReferences.push(tool);
89
}
90
}
91
}
92
93
variables.sort((a, b) => (b.range?.[0] ?? 0) - (a.range?.[0] ?? 0));
94
95
return {
96
query,
97
participantName,
98
command,
99
variables,
100
toolReferences
101
};
102
}
103
104
function parseFileVariables(simulationWorkspace: SimulationWorkspace, filePath: string): Uri {
105
for (const doc of simulationWorkspace.documents) {
106
if (basename(doc.document.uri) === filePath) {
107
return doc.document.uri;
108
}
109
}
110
return Uri.joinPath(simulationWorkspace.workspaceFolders[0], filePath);
111
}
112
113