Path: blob/main/extensions/copilot/test/simulation/panelCodeMapperSimulator.ts
13388 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import type { ChatPromptReference, ChatResponseStream } from 'vscode';5import { isCodeBlockWithResource } from '../../src/extension/codeBlocks/node/codeBlockProcessor';6import { ITabsAndEditorsService } from '../../src/platform/tabs/common/tabsAndEditorsService';7import { TestingServiceCollection } from '../../src/platform/test/node/services';8import { isLocation } from '../../src/util/common/types';9import { URI } from '../../src/util/vs/base/common/uri';10import { ServicesAccessor } from '../../src/util/vs/platform/instantiation/common/instantiation';11import { ChatLocation, Location, Uri } from '../../src/vscodeTypes';12import { EditingSimulationHost, EditingSimulationHostResponseProcessor, simulateEditingScenario } from './inlineChatSimulator';13import { EditTestStrategy, IScenario, IScenarioQuery, OutcomeAnnotation } from './types';1415export type EditTestStrategyPanel = EditTestStrategy.Agent | EditTestStrategy.Edits;1617export async function simulatePanelCodeMapper(18testingServiceCollection: TestingServiceCollection,19scenario: IScenario,20strategy?: EditTestStrategyPanel,21spyOnStream?: (stream: ChatResponseStream) => ChatResponseStream22): Promise<void> {23const overrideCommand = strategy === undefined ? undefined :24strategy === EditTestStrategy.Edits ? '/edit' :25'/editAgent';26const ensureSlashEdit = (query: string) => {27if (!overrideCommand) {28return query;29}3031return query.startsWith(overrideCommand) ? query : `${overrideCommand} ${query}`;32};33const prependEditToUserQueries = (queries: IScenarioQuery[]) => {34return queries.map(scenarioQuery => {35return {36...scenarioQuery,37query: ensureSlashEdit(scenarioQuery.query),38};39});40};41const massagedScenario = { ...scenario, queries: prependEditToUserQueries(scenario.queries) };424344const host: EditingSimulationHost = {45prepareChatRequestLocation: (accessor: ServicesAccessor) => {46return {47location: ChatLocation.Panel,48location2: undefined,49};50},5152contributeAdditionalReferences: (accessor: ServicesAccessor, existingReferences: readonly ChatPromptReference[]) => {53const tabsAndEditorsService = accessor.get(ITabsAndEditorsService);54const activeTextEditor = tabsAndEditorsService.activeTextEditor;55if (activeTextEditor) {56const existingReference = existingReferences.find(ref => _extractUri(ref.value)?.toString() === activeTextEditor.document.uri.toString());57if (!existingReference) {58const varWithArg = `file:${activeTextEditor.document.uri.path}`;59return [{60id: `copilot.file`,61name: varWithArg,62value: new Location(63activeTextEditor.document.uri,64activeTextEditor.selection,65)66}];67}68}69return [];7071function _extractUri(something: Uri | Location | unknown | undefined): Uri | undefined {72if (isLocation(something)) {73return something.uri;74}75if (URI.isUri(something)) {76return something;77}78return undefined;79}80},8182provideResponseProcessor: (_query: IScenarioQuery): EditingSimulationHostResponseProcessor => {83return {84spyOnStream: (stream: ChatResponseStream): ChatResponseStream => {85return spyOnStream ? spyOnStream(stream) : stream;86},87postProcess: async (accessor, workspace, stream, chatResult): Promise<OutcomeAnnotation[]> => {88const annotations: OutcomeAnnotation[] = [];89if (strategy === EditTestStrategy.Edits) {90if (chatResult?.errorDetails) {91annotations.push({92severity: 'error',93label: 'chat-error',94message: `Chat request failed: ${chatResult.errorDetails.message}`,95});96return annotations;97}9899const codeBlocks = chatResult?.metadata?.codeBlocks;100if (!Array.isArray(codeBlocks)) {101throw new Error('No codeblocks in chat result metadata');102}103for (const codeBlock of codeBlocks) {104if (!isCodeBlockWithResource(codeBlock)) {105annotations.push({106severity: 'error',107label: 'missing-path-in-code-block',108message: 'Code block without a file path',109});110}111}112}113return annotations;114}115};116}117};118119return simulateEditingScenario(120testingServiceCollection,121massagedScenario,122host123);124}125126127