Skip to content

Commit e2f9cc4

Browse files
authored
Revert "Only use the main prompt file to decide about the mode and tools (#24…"
This reverts commit f83bd3c.
1 parent 278c883 commit e2f9cc4

File tree

4 files changed

+70
-81
lines changed

4 files changed

+70
-81
lines changed

src/vs/workbench/contrib/chat/browser/chatWidget.ts

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ import { IChatInputState } from '../common/chatWidgetHistoryService.js';
5454
import { CodeBlockModelCollection } from '../common/codeBlockModelCollection.js';
5555
import { ChatAgentLocation, ChatMode } from '../common/constants.js';
5656
import { ILanguageModelToolsService } from '../common/languageModelToolsService.js';
57-
import { IPromptMetadata } from '../common/promptSyntax/parsers/types.js';
58-
import { IMetadata, IPromptsService } from '../common/promptSyntax/service/types.js';
57+
import { IPromptsService } from '../common/promptSyntax/service/types.js';
5958
import { handleModeSwitch } from './actions/chatActions.js';
6059
import { ChatTreeItem, IChatAcceptInputOptions, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatListItemRendererOptions, IChatWidget, IChatWidgetService, IChatWidgetViewContext, IChatWidgetViewOptions } from './chat.js';
6160
import { ChatAccessibilityProvider } from './chatAccessibilityProvider.js';
@@ -1185,52 +1184,27 @@ export class ChatWidget extends Disposable implements IChatWidget {
11851184
return inputState;
11861185
}
11871186

1188-
private _findPromptFileInContext(attachedContext: IChatRequestVariableEntry[]): URI | undefined {
1189-
for (const item of attachedContext) {
1190-
if (isPromptFileChatVariable(item) && item.isRoot) {
1191-
return toUri(item);
1192-
}
1193-
}
1194-
return undefined;
1195-
}
1187+
private async _handlePromptSlashCommand(input: string, attachedContext: IChatRequestVariableEntry[]): Promise<string> {
11961188

1197-
private async _applyPromptFileIfSet(requestInput: { input: string; attachedContext: IChatRequestVariableEntry[] }): Promise<IMetadata | undefined> {
1198-
1199-
let metadata: IMetadata | undefined;
1200-
1201-
// frst check if the input has a prompt slash command
12021189
const agentSlashPromptPart = this.parsedInput.parts.find((r): r is ChatRequestSlashPromptPart => r instanceof ChatRequestSlashPromptPart);
1203-
if (agentSlashPromptPart) {
1204-
metadata = await this.promptsService.resolvePromptSlashCommand(agentSlashPromptPart.slashPromptCommand);
1205-
if (metadata) {
1206-
const uri = metadata.uri;
1207-
if (!requestInput.attachedContext.some(variable => isPromptFileChatVariable(variable) && isEqual(toUri(variable), uri))) {
1208-
// not yet attached, so attach it
1209-
const variable = toChatVariable({ uri: metadata.uri, isPromptFile: true }, true);
1210-
requestInput.attachedContext.push(variable);
1211-
}
1212-
// remove the slash command from the input
1213-
requestInput.input = this.parsedInput.parts.filter(part => !(part instanceof ChatRequestSlashPromptPart)).map(part => part.text).join('').trim();
1214-
}
1215-
} else {
1216-
// if not, check if the context contains a prompt file: This is the old workflow that we still support for legacy reasons
1217-
const uri = this._findPromptFileInContext(requestInput.attachedContext);
1218-
if (uri) {
1219-
metadata = await this.promptsService.getMetadata(uri);
1220-
}
1190+
if (!agentSlashPromptPart) {
1191+
return input;
12211192
}
1193+
// remove the slash command from the input
1194+
input = this.parsedInput.parts.filter(part => !(part instanceof ChatRequestSlashPromptPart)).map(part => part.text).join('').trim();
12221195

1223-
if (!metadata) {
1224-
return undefined;
1196+
const promptPath = await this.promptsService.resolvePromptSlashCommand(agentSlashPromptPart.slashPromptCommand);
1197+
if (!promptPath) {
1198+
return input;
12251199
}
12261200

1227-
if (!requestInput.input.trim()) {
1228-
requestInput.input = localize('input.1', "Follow instructions from {0}.", basename(metadata.uri));
1201+
if (!attachedContext.some(variable => isPromptFileChatVariable(variable) && isEqual(toUri(variable), promptPath.uri))) {
1202+
// not yet attached, so attach it
1203+
const variable = toChatVariable({ uri: promptPath.uri, isPromptFile: true }, true);
1204+
attachedContext.push(variable);
12291205
}
12301206

1231-
await this._applyPromptMetadata(metadata.metadata);
1232-
1233-
return metadata;
1207+
return input;
12341208
}
12351209

12361210
private async _acceptInput(query: { query: string } | undefined, options?: IChatAcceptInputOptions): Promise<IChatResponseModel | undefined> {
@@ -1244,23 +1218,26 @@ export class ChatWidget extends Disposable implements IChatWidget {
12441218

12451219
const editorValue = this.getInput();
12461220
const requestId = this.chatAccessibilityService.acceptRequest();
1247-
const requestInputs = {
1248-
input: !query ? editorValue : query.query,
1249-
attachedContext: await this.inputPart.getAttachedAndImplicitContext(this.viewModel.sessionId),
1250-
};
1251-
1221+
let input = !query ? editorValue : query.query;
12521222
const isUserQuery = !query;
12531223

1224+
let attachedContext = await this.inputPart.getAttachedAndImplicitContext(this.viewModel.sessionId);
1225+
12541226
const { promptInstructions } = this.inputPart.attachmentModel;
12551227
const instructionsEnabled = promptInstructions.featureEnabled;
12561228
if (instructionsEnabled) {
1257-
await this._applyPromptFileIfSet(requestInputs);
1258-
await this.autoAttachInstructions(requestInputs.attachedContext);
1229+
input = await this._handlePromptSlashCommand(input, attachedContext);
1230+
await this.autoAttachInstructions(attachedContext);
1231+
const newInput = await this.setupChatModeAndTools(input, attachedContext);
1232+
if (newInput === undefined) {
1233+
return;
1234+
}
1235+
input = newInput;
12591236
}
12601237

12611238
if (this.viewOptions.enableWorkingSet !== undefined && this.input.currentMode === ChatMode.Edit && !this.chatService.edits2Enabled) {
12621239
const uniqueWorkingSetEntries = new ResourceSet(); // NOTE: this is used for bookkeeping so the UI can avoid rendering references in the UI that are already shown in the working set
1263-
const editingSessionAttachedContext: IChatRequestVariableEntry[] = requestInputs.attachedContext;
1240+
const editingSessionAttachedContext: IChatRequestVariableEntry[] = attachedContext;
12641241

12651242
// Collect file variables from previous requests before sending the request
12661243
const previousRequests = this.viewModel.model.getRequests();
@@ -1275,7 +1252,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
12751252
}
12761253
}
12771254
}
1278-
requestInputs.attachedContext = editingSessionAttachedContext;
1255+
attachedContext = editingSessionAttachedContext;
12791256

12801257
type ChatEditingWorkingSetClassification = {
12811258
owner: 'joyceerhl';
@@ -1305,13 +1282,13 @@ export class ChatWidget extends Disposable implements IChatWidget {
13051282
}
13061283
}
13071284

1308-
const result = await this.chatService.sendRequest(this.viewModel.sessionId, requestInputs.input, {
1285+
const result = await this.chatService.sendRequest(this.viewModel.sessionId, input, {
13091286
mode: this.inputPart.currentMode,
13101287
userSelectedModelId: this.inputPart.currentLanguageModel,
13111288
location: this.location,
13121289
locationData: this._location.resolveData?.(),
13131290
parserContext: { selectedAgent: this._lastSelectedAgent, mode: this.inputPart.currentMode },
1314-
attachedContext: requestInputs.attachedContext,
1291+
attachedContext,
13151292
noCommandDetection: options?.noCommandDetection,
13161293
userSelectedTools,
13171294
userSelectedTools2,
@@ -1528,7 +1505,39 @@ export class ChatWidget extends Disposable implements IChatWidget {
15281505
this.agentInInput.set(!!currentAgent);
15291506
}
15301507

1531-
private async _applyPromptMetadata(metadata: IPromptMetadata): Promise<void> {
1508+
/**
1509+
* Set's up the `chat mode` and selects required `tools` based on
1510+
* the metadata defined in headers of attached prompt files.
1511+
*/
1512+
private async setupChatModeAndTools(
1513+
input: string,
1514+
attachedContext: readonly IChatRequestVariableEntry[],
1515+
): Promise<string | undefined> {
1516+
// process prompt files starting from the 'root' ones
1517+
const promptFileVariables = attachedContext
1518+
.filter(isPromptFileChatVariable)
1519+
.filter(pick('isRoot'));
1520+
const promptUris = promptFileVariables.map(toUri);
1521+
1522+
if (promptFileVariables.length === 0) {
1523+
return input;
1524+
}
1525+
1526+
if (!input.trim()) {
1527+
const promptNames = (promptUris.length === 1)
1528+
? `'${basename(promptUris[0])}'`
1529+
: `the prompt files`;
1530+
1531+
input = `Follow instructions from ${promptNames}.`;
1532+
}
1533+
1534+
1535+
const metadata = await this.promptsService
1536+
.getCombinedToolsMetadata(promptUris);
1537+
1538+
if (metadata === null) {
1539+
return input;
1540+
}
15321541

15331542
const { mode, tools } = metadata;
15341543

@@ -1546,7 +1555,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
15461555

15471556
// if not tools to enable are present, we are done
15481557
if (tools === undefined) {
1549-
return;
1558+
return input;
15501559
}
15511560

15521561
// sanity check on the logic of the `getPromptFilesMetadata` method
@@ -1577,6 +1586,8 @@ export class ChatWidget extends Disposable implements IChatWidget {
15771586
this.inputPart
15781587
.selectedToolsModel
15791588
.selectOnly(toolIds);
1589+
1590+
return input;
15801591
}
15811592

15821593
/**

src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -150,28 +150,19 @@ export class PromptsService extends Disposable implements IPromptsService {
150150
return undefined;
151151
}
152152

153-
public async resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise<IMetadata | undefined> {
154-
const promptUri = await this.getPromptPath(data);
155-
if (!promptUri) {
156-
return undefined;
157-
}
158-
return await this.getMetadata(promptUri);
159-
}
160-
161-
private async getPromptPath(data: IChatPromptSlashCommand): Promise<URI | undefined> {
153+
public async resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise<IPromptPath | undefined> {
162154
if (data.promptPath) {
163-
return data.promptPath.uri;
155+
return data.promptPath;
164156
}
165-
166157
const files = await this.listPromptFiles('prompt');
167158
const command = data.command;
168159
const result = files.find(file => getPromptCommandName(file.uri.path) === command);
169160
if (result) {
170-
return result.uri;
161+
return result;
171162
}
172163
const textModel = this.modelService.getModels().find(model => model.getLanguageId() === PROMPT_LANGUAGE_ID && getPromptCommandName(model.uri.path) === command);
173164
if (textModel) {
174-
return textModel.uri;
165+
return { uri: textModel.uri, storage: 'local', type: 'prompt' };
175166
}
176167
return undefined;
177168
}
@@ -230,11 +221,6 @@ export class PromptsService extends Disposable implements IPromptsService {
230221
return [...foundFiles];
231222
}
232223

233-
public async getMetadata(promptFileUri: URI): Promise<IMetadata> {
234-
const metaDatas = await this.getAllMetadata([promptFileUri]);
235-
return metaDatas[0];
236-
}
237-
238224
@logTime()
239225
public async getAllMetadata(
240226
promptUris: readonly URI[],

src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export interface IPromptsService extends IDisposable {
149149
/**
150150
* Gets the prompt file for a slash command.
151151
*/
152-
resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise<IMetadata | undefined>;
152+
resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise<IPromptPath | undefined>;
153153

154154
/**
155155
* Returns a prompt command if the command name is valid.
@@ -164,11 +164,6 @@ export interface IPromptsService extends IDisposable {
164164
fileUris: readonly URI[],
165165
): Promise<readonly URI[]>;
166166

167-
/**
168-
* Gets the metadata for the given prompt file uri.
169-
*/
170-
getMetadata(promptFileUri: URI): Promise<IMetadata>;
171-
172167
/**
173168
* Get all metadata for entire prompt references tree
174169
* that spans out of each of the provided files.

src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ export class MockPromptsService implements IPromptsService {
1717
getAllMetadata(_files: readonly URI[]): Promise<readonly IMetadata[]> {
1818
throw new Error('Method not implemented.');
1919
}
20-
getMetadata(_file: URI): Promise<IMetadata> {
21-
throw new Error('Method not implemented.');
22-
}
2320
getSyntaxParserFor(_model: ITextModel): TextModelPromptParser & { isDisposed: false } {
2421
throw new Error('Method not implemented.');
2522
}
@@ -32,7 +29,7 @@ export class MockPromptsService implements IPromptsService {
3229
public asPromptSlashCommand(command: string): IChatPromptSlashCommand | undefined {
3330
return undefined;
3431
}
35-
resolvePromptSlashCommand(_data: IChatPromptSlashCommand): Promise<IMetadata | undefined> {
32+
resolvePromptSlashCommand(_data: IChatPromptSlashCommand): Promise<IPromptPath | undefined> {
3633
throw new Error('Method not implemented.');
3734
}
3835
findPromptSlashCommands(): Promise<IChatPromptSlashCommand[]> {

0 commit comments

Comments
 (0)