Skip to content

Commit d3e2d18

Browse files
authored
adopt tool names in prompt files (#1129)
1 parent b83b73d commit d3e2d18

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

src/extension/prompt/common/chatVariablesCollection.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,10 @@ export class ChatVariablesCollection {
108108
export function isPromptInstruction(variable: PromptVariable): boolean {
109109
return variable.reference.id.startsWith('vscode.prompt.instructions');
110110
}
111+
112+
/**
113+
* Check if provided variable is a "prompt file".
114+
*/
115+
export function isPromptFile(variable: PromptVariable): boolean {
116+
return variable.reference.id.startsWith('vscode.prompt.file');
117+
}

src/extension/prompts/node/panel/chatVariables.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { URI } from '../../../../util/vs/base/common/uri';
2525
import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';
2626
import { ChatReferenceBinaryData, ChatReferenceDiagnostic, LanguageModelToolResult2, Range, Uri } from '../../../../vscodeTypes';
2727
import { GenericBasePromptElementProps } from '../../../context/node/resolvers/genericPanelIntentInvocation';
28-
import { ChatVariablesCollection, isPromptInstruction } from '../../../prompt/common/chatVariablesCollection';
28+
import { ChatVariablesCollection, isPromptFile, isPromptInstruction } from '../../../prompt/common/chatVariablesCollection';
2929
import { InternalToolReference } from '../../../prompt/common/intents';
3030
import { ToolName } from '../../../tools/common/toolNames';
3131
import { normalizeToolSchema } from '../../../tools/common/toolSchemaNormalizer';
@@ -38,6 +38,7 @@ import { FilePathMode, FileVariable } from './fileVariable';
3838
import { Image } from './image';
3939
import { NotebookCellOutputVariable } from './notebookVariables';
4040
import { PanelChatBasePrompt } from './panelChatBasePrompt';
41+
import { PromptFile } from './promptFile';
4142
import { sendInvokedToolTelemetry, toolCallErrorToResult, ToolResult, ToolResultMetadata } from './toolCalling';
4243
import { IFileTreeData, workspaceVisualFileTree } from './workspace/visualFileTree';
4344

@@ -142,11 +143,20 @@ function asUserMessage(element: PromptElement, priority: number | undefined): Us
142143

143144
export async function renderChatVariables(chatVariables: ChatVariablesCollection, fileSystemService: IFileSystemService, includeFilepathInCodeBlocks = true, omitReferences?: boolean, isAgent?: boolean): Promise<PromptElement[]> {
144145
const elements = [];
146+
const filePathMode = (isAgent && includeFilepathInCodeBlocks)
147+
? FilePathMode.AsAttribute
148+
: includeFilepathInCodeBlocks
149+
? FilePathMode.AsComment
150+
: FilePathMode.None;
145151
for (const variable of chatVariables) {
146152
const { uniqueName: variableName, value: variableValue, reference } = variable;
147153
if (isPromptInstruction(variable)) { // prompt instructions are handled in the `CustomInstructions` element
148154
continue;
149155
}
156+
if (isPromptFile(variable)) {
157+
elements.push(<PromptFile variable={variable} omitReferences={omitReferences} filePathMode={filePathMode} />);
158+
continue;
159+
}
150160

151161
if (URI.isUri(variableValue) || isLocation(variableValue)) {
152162
const uri = 'uri' in variableValue ? variableValue.uri : variableValue;
@@ -161,11 +171,6 @@ export async function renderChatVariables(chatVariables: ChatVariablesCollection
161171
if (isDirectory) {
162172
elements.push(<FolderVariable variableName={variableName} folderUri={uri} omitReferences={omitReferences} description={reference.modelDescription} />);
163173
} else {
164-
const filePathMode = (isAgent && includeFilepathInCodeBlocks)
165-
? FilePathMode.AsAttribute
166-
: includeFilepathInCodeBlocks
167-
? FilePathMode.AsComment
168-
: FilePathMode.None;
169174
const file = <FileVariable
170175
alwaysIncludeSummary={true}
171176
filePathMode={filePathMode}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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 { BasePromptElementProps, PromptElement, PromptReference, PromptSizing } from '@vscode/prompt-tsx';
7+
import type { ChatLanguageModelToolReference } from 'vscode';
8+
import { IFileSystemService } from '../../../../platform/filesystem/common/fileSystemService';
9+
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
10+
import { ILogService } from '../../../../platform/log/common/logService';
11+
import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';
12+
import { URI } from '../../../../util/vs/base/common/uri';
13+
import { PromptVariable } from '../../../prompt/common/chatVariablesCollection';
14+
import { IPromptVariablesService } from '../../../prompt/node/promptVariablesService';
15+
import { EmbeddedInsideUserMessage } from '../base/promptElement';
16+
import { Tag } from '../base/tag';
17+
import { FilePathMode } from './fileVariable';
18+
19+
export interface PromptFileProps extends BasePromptElementProps, EmbeddedInsideUserMessage {
20+
readonly variable: PromptVariable;
21+
readonly omitReferences?: boolean;
22+
readonly filePathMode: FilePathMode;
23+
}
24+
25+
export class PromptFile extends PromptElement<PromptFileProps, void> {
26+
27+
constructor(
28+
props: PromptFileProps,
29+
@IFileSystemService private readonly fileSystemService: IFileSystemService,
30+
@IPromptVariablesService private readonly promptVariablesService: IPromptVariablesService,
31+
@ILogService private readonly logService: ILogService,
32+
@IPromptPathRepresentationService private readonly promptPathRepresentationService: IPromptPathRepresentationService,
33+
@IIgnoreService private readonly ignoreService: IIgnoreService
34+
) {
35+
super(props);
36+
}
37+
38+
override async render(state: void, sizing: PromptSizing) {
39+
const variable = this.props.variable.reference;
40+
const uri = variable.value;
41+
if (!URI.isUri(uri)) {
42+
this.logService.debug(`Prompt file variable does not have a URI value: ${variable.value}`);
43+
return undefined;
44+
}
45+
46+
if (await this.ignoreService.isCopilotIgnored(uri)) {
47+
return <ignoredFiles value={[uri]} />;
48+
}
49+
50+
const content = await this.getBodyContent(uri, variable.toolReferences);
51+
const attrs: Record<string, string> = {};
52+
attrs.id = variable.name;
53+
if (this.props.filePathMode === FilePathMode.AsAttribute) {
54+
attrs.filePath = this.promptPathRepresentationService.getFilePath(uri);
55+
}
56+
return <Tag name='attachment' attrs={attrs}>
57+
{!this.props.omitReferences && <references value={[new PromptReference({ variableName: variable.name, value: uri }, undefined)]} />}
58+
Prompt instructions file:<br />
59+
{content}
60+
</Tag>;
61+
}
62+
63+
private async getBodyContent(fileUri: URI, toolReferences: readonly ChatLanguageModelToolReference[] | undefined): Promise<string | undefined> {
64+
try {
65+
const fileContents = await this.fileSystemService.readFile(fileUri);
66+
let content = new TextDecoder().decode(fileContents);
67+
if (toolReferences && toolReferences.length > 0) {
68+
content = await this.promptVariablesService.resolveToolReferencesInPrompt(content, toolReferences);
69+
}
70+
71+
let bodyOffset = 0;
72+
if (content.match(/^---[\s\r\n]/)) {
73+
// find the start of the body
74+
const match = content.slice(3).match(/[\r\n]---[\s\r\n]*/);
75+
if (match) {
76+
bodyOffset = match.index! + match[0].length;
77+
}
78+
}
79+
return content.substring(bodyOffset);
80+
} catch (e) {
81+
this.logService.debug(`Prompt file not found: ${fileUri.toString()}`);
82+
return undefined;
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)