Path: blob/main/extensions/copilot/src/extension/intents/node/generateNewWorkspaceContent.ts
13399 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*--------------------------------------------------------------------------------------------*/45import type { CancellationToken } from 'vscode';6import { ChatFetchResponseType, ChatLocation } from '../../../platform/chat/common/commonTypes';7import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';8import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';9import { PromptRenderer } from '../../prompts/node/base/promptRenderer';10import { FileContentsPrompt, NewWorkspaceContentsPromptProps, ProjectSpecificationPrompt } from '../../prompts/node/panel/newWorkspace/newWorkspaceContents';111213abstract class NewWorkspaceContentGenerator {1415constructor(16private readonly promptType: typeof FileContentsPrompt | typeof ProjectSpecificationPrompt,17@IEndpointProvider private readonly endpointProvider: IEndpointProvider,18@IInstantiationService private readonly instantiationService: IInstantiationService,19) { }2021public async generate(promptArgs: NewWorkspaceContentsPromptProps, token: CancellationToken): Promise<string> {22const endpoint = await this.endpointProvider.getChatEndpoint('copilot-fast');23const promptRenderer = PromptRenderer.create(this.instantiationService, endpoint, this.promptType, promptArgs);24const prompt = await promptRenderer.render();2526const fetchResult = await endpoint27.makeChatRequest(28'newWorkspaceContentGenerator',29prompt.messages,30undefined,31token,32ChatLocation.Other,33undefined,34undefined,35);3637return fetchResult.type === ChatFetchResponseType.Success ?38(promptArgs.filePath ? this.parseContents(promptArgs.filePath, fetchResult.value) : fetchResult.value) :39'';40}4142protected abstract parseContents(filePath: string, chatResponse: string): string;43}4445export class ProjectSpecificationGenerator extends NewWorkspaceContentGenerator {46constructor(47@IEndpointProvider endpointProvider: IEndpointProvider,48@IInstantiationService instantiationService: IInstantiationService49) {50super(ProjectSpecificationPrompt, endpointProvider, instantiationService);51}5253protected override parseContents(chatResponse: string, filePath?: string | undefined): string {54throw new Error('Method not implemented.');55}56}5758export class FileContentsGenerator extends NewWorkspaceContentGenerator {59constructor(60@IEndpointProvider endpointProvider: IEndpointProvider,61@IInstantiationService instantiationService: IInstantiationService,62) {63super(FileContentsPrompt, endpointProvider, instantiationService);64}6566protected parseContents(filePath: string, chatResponse: string,): string {67function safeParse(str: string, regex: RegExp) {68try {69const match = regex.exec(str.trim());70if (match && match.length > 2) {71return match[2];72}73} catch (ex) {74console.error(ex);75}7677return str;78}7980if (filePath.endsWith('.md')) {81// If returned as a markdown codeblock, strip the codeblock markers82const fromCodeblock = safeParse(chatResponse, /^```([a-zA-Z]+)?\s*([\s\S]+?)\s*```$/);83// If returned as bare text, remove any text before the first header84const [preamble, ...withoutPreamble] = fromCodeblock.split('#');85if (preamble.length) {86return ['', ...withoutPreamble].join('#');87}88return fromCodeblock;89} else {90return safeParse(chatResponse, /```([^\n]+)?\s*\n([\s\S]+?)\s*```/g);91}92}93}949596