Path: blob/main/extensions/copilot/src/extension/prompts/node/panel/promptFile.tsx
13405 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 { BasePromptElementProps, PromptElement, PromptReference, PromptSizing } from '@vscode/prompt-tsx';6import type { ChatLanguageModelToolReference } from 'vscode';7import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';8import { ILogService } from '../../../../platform/log/common/logService';9import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';10import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';11import { URI } from '../../../../util/vs/base/common/uri';12import { PromptVariable } from '../../../prompt/common/chatVariablesCollection';13import { IPromptVariablesService } from '../../../prompt/node/promptVariablesService';14import { EmbeddedInsideUserMessage } from '../base/promptElement';15import { Tag } from '../base/tag';1617export interface PromptFileProps extends BasePromptElementProps, EmbeddedInsideUserMessage {18readonly variable: PromptVariable;19readonly omitReferences?: boolean;20}2122export class PromptFile extends PromptElement<PromptFileProps, void> {2324constructor(25props: PromptFileProps,26@IPromptVariablesService private readonly promptVariablesService: IPromptVariablesService,27@ILogService private readonly logService: ILogService,28@IPromptPathRepresentationService private readonly promptPathRepresentationService: IPromptPathRepresentationService,29@IIgnoreService private readonly ignoreService: IIgnoreService,30@IWorkspaceService private readonly workspaceService: IWorkspaceService,31) {32super(props);33}3435override async render(state: void, sizing: PromptSizing) {36const variable = this.props.variable.reference;37const uri = variable.value;38if (!URI.isUri(uri)) {39this.logService.debug(`Prompt file variable does not have a URI value: ${variable.value}`);40return undefined;41}4243if (await this.ignoreService.isCopilotIgnored(uri)) {44return <ignoredFiles value={[uri]} />;45}4647const content = await this.getBodyContent(uri, variable.toolReferences);48const attrs: Record<string, string> = {};49attrs.id = variable.name;50attrs.filePath = this.promptPathRepresentationService.getFilePath(uri);51return <Tag name='attachment' attrs={attrs}>52{!this.props.omitReferences && <references value={[new PromptReference(uri, undefined)]} />}53Prompt instructions file:<br />54{content}55</Tag>;56}5758private async getBodyContent(fileUri: URI, toolReferences: readonly ChatLanguageModelToolReference[] | undefined): Promise<string | undefined> {59try {60const doc = await this.workspaceService.openTextDocument(fileUri);61let content = doc.getText();62if (toolReferences && toolReferences.length > 0) {63content = await this.promptVariablesService.resolveToolReferencesInPrompt(content, toolReferences);64}6566let bodyOffset = 0;67if (content.match(/^---[\s\r\n]/)) {68// find the start of the body69const match = content.slice(3).match(/[\r\n]---[\s\r\n]*/);70if (match) {71bodyOffset = match.index! + match[0].length;72}73}74const bodyContent = content.substring(bodyOffset);7576return bodyContent;77} catch (e) {78this.logService.debug(`Prompt file not found: ${fileUri.toString()}`);79return undefined;80}81}82}838485