Skip to content

Commit 79ff867

Browse files
committed
ignore prompt files for implicit context
1 parent 0fd5ef7 commit 79ff867

File tree

9 files changed

+52
-197
lines changed

9 files changed

+52
-197
lines changed

src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
import * as dom from '../../../../../base/browser/dom.js';
77
import { StandardKeyboardEvent } from '../../../../../base/browser/keyboardEvent.js';
88
import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js';
9-
import { Codicon } from '../../../../../base/common/codicons.js';
109
import { KeyCode } from '../../../../../base/common/keyCodes.js';
1110
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
1211
import { Schemas } from '../../../../../base/common/network.js';
1312
import { basename, dirname } from '../../../../../base/common/resources.js';
14-
import { ThemeIcon } from '../../../../../base/common/themables.js';
1513
import { URI } from '../../../../../base/common/uri.js';
1614
import { ILanguageService } from '../../../../../editor/common/languages/language.js';
1715
import { IModelService } from '../../../../../editor/common/services/model.js';
@@ -61,9 +59,7 @@ export class ImplicitContextAttachmentWidget extends Disposable {
6159
const file = URI.isUri(this.attachment.value) ? this.attachment.value : this.attachment.value!.uri;
6260
const range = undefined;
6361

64-
const attachmentTypeName = (this.attachment.isPromptFile === false)
65-
? file.scheme === Schemas.vscodeNotebookCell ? localize('cell.lowercase', "cell") : localize('file.lowercase', "file")
66-
: localize('prompt.lowercase', "prompt");
62+
const attachmentTypeName = file.scheme === Schemas.vscodeNotebookCell ? localize('cell.lowercase', "cell") : localize('file.lowercase', "file");
6763

6864
const fileBasename = basename(file);
6965
const fileDirname = dirname(file);
@@ -74,16 +70,11 @@ export class ImplicitContextAttachmentWidget extends Disposable {
7470
const currentFile = localize('openEditor', "Suggested context (current file)");
7571
const title = `${currentFile}\n${uriLabel}`;
7672

77-
const icon = this.attachment.isPromptFile
78-
? ThemeIcon.fromId(Codicon.bookmark.id)
79-
: undefined;
80-
8173
label.setFile(file, {
8274
fileKind: FileKind.FILE,
8375
hidePath: true,
8476
range,
85-
title,
86-
icon,
77+
title
8778
});
8879
this.domNode.ariaLabel = ariaLabel;
8980
this.domNode.tabIndex = 0;

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import { createNotebookOutputVariableEntry, NOTEBOOK_CELL_OUTPUT_MIME_TYPE_LIST_
2525
import { getOutputViewModelFromId } from '../../notebook/browser/controller/cellOutputActions.js';
2626
import { getNotebookEditorFromEditorPane } from '../../notebook/browser/notebookBrowser.js';
2727
import { CHAT_ATTACHABLE_IMAGE_MIME_TYPES, getAttachableImageExtension } from '../common/chatModel.js';
28-
import { IChatRequestVariableEntry, OmittedState, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry } from '../common/chatVariableEntries.js';
28+
import { IChatRequestVariableEntry, OmittedState, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js';
29+
import { getPromptsTypeForLanguageId } from '../common/promptSyntax/promptTypes.js';
2930
import { imageToHash } from './chatPasteProviders.js';
3031
import { resizeImage } from './imageUtils.js';
3132

@@ -83,8 +84,11 @@ export async function resolveResourceAttachContext(resource: URI, isDirectory: b
8384
let omittedState = OmittedState.NotOmitted;
8485

8586
if (!isDirectory) {
87+
88+
let languageId: string | undefined;
8689
try {
8790
const createdModel = await textModelService.createModelReference(resource);
91+
languageId = createdModel.object.getLanguageId();
8892
createdModel.dispose();
8993
} catch {
9094
omittedState = OmittedState.Full;
@@ -93,6 +97,9 @@ export async function resolveResourceAttachContext(resource: URI, isDirectory: b
9397
if (/\.(svg)$/i.test(resource.path)) {
9498
omittedState = OmittedState.Full;
9599
}
100+
if (languageId && getPromptsTypeForLanguageId(languageId)) {
101+
return toPromptFileVariableEntry(resource, true);
102+
}
96103
}
97104

98105
return {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,6 @@ export class PromptFileAttachmentWidget extends AbstractChatAttachmentWidget {
482482
constructor(
483483
resource: URI,
484484
attachment: IChatRequestVariableEntry,
485-
correspondingContentReference: IChatContentReference | undefined,
486485
currentLanguageModel: ILanguageModelChatMetadataAndIdentifier | undefined,
487486
options: { shouldFocusClearButton: boolean; supportsDeletion: boolean },
488487
container: HTMLElement,
@@ -497,7 +496,7 @@ export class PromptFileAttachmentWidget extends AbstractChatAttachmentWidget {
497496
super(attachment, options, container, contextResourceLabels, hoverDelegate, currentLanguageModel, commandService, openerService);
498497

499498

500-
this.hintElement = dom.append(this.element, dom.$('span.chat-implicit-hint'));
499+
this.hintElement = dom.append(this.element, dom.$('span.prompt-type'));
501500

502501
this.updateLabel(resource);
503502

src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import { URI } from '../../../../../base/common/uri.js';
1212
import { Range } from '../../../../../editor/common/core/range.js';
1313
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
1414
import { ResourceLabels } from '../../../../browser/labels.js';
15-
import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatVariableEntries.js';
15+
import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatVariableEntries.js';
1616
import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../common/chatService.js';
17-
import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js';
17+
import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, PromptFileAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js';
1818

1919
export class ChatAttachmentsContentPart extends Disposable {
2020
private readonly attachedContextDisposables = this._register(new DisposableStore());
@@ -59,6 +59,8 @@ export class ChatAttachmentsContentPart extends Disposable {
5959
} else if (isImageVariableEntry(attachment)) {
6060
attachment.omittedState = isAttachmentPartialOrOmitted ? OmittedState.Full : attachment.omittedState;
6161
widget = this.instantiationService.createInstance(ImageAttachmentWidget, resource, attachment, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate);
62+
} else if (resource && isPromptFileVariableEntry(attachment)) {
63+
widget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate);
6264
} else if (resource && (attachment.kind === 'file' || attachment.kind === 'directory')) {
6365
widget = this.instantiationService.createInstance(FileAttachmentWidget, resource, range, attachment, correspondingContentReference, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate);
6466
} else if (isPasteVariableEntry(attachment)) {

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

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
203203
*/
204204
get hasPromptFileAttachments(): boolean {
205205
// if prompt attached explicitly as a "prompt" attachment
206-
if (this._attachmentModel.hasPromptFiles(PROMPT_LANGUAGE_ID)) {
207-
return true;
208-
}
209-
210-
if (this.implicitContext === undefined) {
211-
return false;
212-
}
213-
214-
// if prompt attached as an implicit "current file" context
215-
return (this.implicitContext.isPromptFile && this.implicitContext.enabled);
206+
return this._attachmentModel.hasPromptFiles(PROMPT_LANGUAGE_ID);
216207
}
217208

218209
private _indexOfLastAttachedContextDeletedWithKeyboard: number;
@@ -459,12 +450,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
459450

460451
this._hasFileAttachmentContextKey = ChatContextKeys.hasFileAttachments.bindTo(contextKeyService);
461452

462-
// trigger re-layout of chat input when number of instruction attachment changes
463-
// this._register(this._attachmentModel.promptInstructions.onUpdate(() => {
464-
// this._handleAttachedContextChange();
465-
// this._onDidChangeHeight.fire();
466-
// }));
467-
468453
this.initSelectedModel();
469454

470455
this._register(this.onDidChangeCurrentChatMode(() => this.accessibilityService.alert(this._currentMode.kind)));
@@ -1299,7 +1284,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12991284
} else if (resource && isNotebookOutputVariableEntry(attachment)) {
13001285
attachmentWidget = this.instantiationService.createInstance(NotebookCellOutputChatAttachmentWidget, resource, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate);
13011286
} else if (resource && isPromptFileVariableEntry(attachment)) {
1302-
attachmentWidget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate);
1287+
attachmentWidget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate);
13031288
} else if (resource && (attachment.kind === 'file' || attachment.kind === 'directory')) {
13041289
attachmentWidget = this.instantiationService.createInstance(FileAttachmentWidget, resource, range, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate);
13051290
} else if (isImageVariableEntry(attachment)) {

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

Lines changed: 14 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,17 @@ import { URI } from '../../../../../base/common/uri.js';
1313
import { getCodeEditor, ICodeEditor } from '../../../../../editor/browser/editorBrowser.js';
1414
import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js';
1515
import { Location } from '../../../../../editor/common/languages.js';
16-
import { IModelService } from '../../../../../editor/common/services/model.js';
1716
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
18-
import { ILogService } from '../../../../../platform/log/common/log.js';
1917
import { IWorkbenchContribution } from '../../../../common/contributions.js';
2018
import { EditorsOrder } from '../../../../common/editor.js';
2119
import { IEditorService } from '../../../../services/editor/common/editorService.js';
2220
import { getNotebookEditorFromEditorPane, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js';
2321
import { IChatEditingService } from '../../common/chatEditingService.js';
24-
import { IChatRequestImplicitVariableEntry, IChatRequestVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js';
22+
import { IChatRequestImplicitVariableEntry, IChatRequestVariableEntry } from '../../common/chatVariableEntries.js';
2523
import { IChatService } from '../../common/chatService.js';
2624
import { ChatAgentLocation } from '../../common/constants.js';
2725
import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js';
28-
import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js';
29-
import { IPromptsService, TSharedPrompt } from '../../common/promptSyntax/service/promptsService.js';
26+
import { getPromptsTypeForLanguageId } from '../../common/promptSyntax/promptTypes.js';
3027
import { IChatWidget, IChatWidgetService } from '../chat.js';
3128

3229
export class ChatImplicitContextContribution extends Disposable implements IWorkbenchContribution {
@@ -155,6 +152,7 @@ export class ChatImplicitContextContribution extends Disposable implements IWork
155152
let languageId: string | undefined;
156153
if (model) {
157154
newValue = model.uri;
155+
languageId = model.getLanguageId();
158156
}
159157

160158
const notebookEditor = this.findActiveNotebookEditor();
@@ -174,37 +172,27 @@ export class ChatImplicitContextContribution extends Disposable implements IWork
174172
return;
175173
}
176174

175+
const isPromptFile = languageId && getPromptsTypeForLanguageId(languageId) !== undefined;
176+
177177
const widgets = updateWidget ? [updateWidget] : [...this.chatWidgetService.getWidgetsByLocations(ChatAgentLocation.Panel), ...this.chatWidgetService.getWidgetsByLocations(ChatAgentLocation.Editor)];
178178
for (const widget of widgets) {
179179
if (!widget.input.implicitContext) {
180180
continue;
181181
}
182182
const setting = this._implicitContextEnablement[widget.location];
183183
const isFirstInteraction = widget.viewModel?.getItems().length === 0;
184-
if (setting === 'first' && !isFirstInteraction) {
185-
widget.input.implicitContext.setValue(undefined, false, undefined);
186-
} else if (setting === 'always' || setting === 'first' && isFirstInteraction) {
184+
if ((setting === 'always' || setting === 'first' && isFirstInteraction) && !isPromptFile) { // disable implicit context for prompt files
187185
widget.input.implicitContext.setValue(newValue, isSelection, languageId);
188-
} else if (setting === 'never') {
186+
} else {
189187
widget.input.implicitContext.setValue(undefined, false, undefined);
190188
}
191189
}
192190
}
193191
}
194192

195193
export class ChatImplicitContext extends Disposable implements IChatRequestImplicitVariableEntry {
196-
/**
197-
* If the implicit context references a prompt file, this field
198-
* holds a reference to an associated prompt parser instance.
199-
*/
200-
private prompt: TSharedPrompt | undefined;
201194

202195
get id() {
203-
if (this.prompt !== undefined) {
204-
const variable = toPromptFileVariableEntry(this.prompt.uri, true);
205-
return variable.id;
206-
}
207-
208196
if (URI.isUri(this.value)) {
209197
return 'vscode.implicit.file';
210198
} else if (this.value) {
@@ -219,12 +207,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli
219207
}
220208

221209
get name(): string {
222-
if (this.prompt !== undefined) {
223-
const variable = toPromptFileVariableEntry(this.prompt.uri, true);
224-
225-
return variable.name;
226-
}
227-
228210
if (URI.isUri(this.value)) {
229211
return `file:${basename(this.value)}`;
230212
} else if (this.value) {
@@ -237,12 +219,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli
237219
readonly kind = 'implicit';
238220

239221
get modelDescription(): string {
240-
if (this.prompt !== undefined) {
241-
const variable = toPromptFileVariableEntry(this.prompt.uri, true);
242-
243-
return variable.modelDescription;
244-
}
245-
246222
if (URI.isUri(this.value)) {
247223
return `User's active file`;
248224
} else if (this._isSelection) {
@@ -277,90 +253,20 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli
277253
this._onDidChangeValue.fire();
278254
}
279255

280-
constructor(
281-
@IPromptsService private readonly promptsService: IPromptsService,
282-
@IModelService private readonly modelService: IModelService,
283-
@ILogService private readonly logService: ILogService,
284-
) {
285-
super();
286-
}
287-
288256
setValue(value: Location | URI | undefined, isSelection: boolean, languageId?: string): void {
289257
this._value = value;
290258
this._isSelection = isSelection;
291-
292-
// remove and dispose existent prompt parser instance
293-
this.removePrompt();
294-
// if language ID is a 'prompt' language, create a prompt parser instance
295-
if (value && (languageId === PROMPT_LANGUAGE_ID)) {
296-
this.addPrompt(value);
297-
}
298259
this._onDidChangeValue.fire();
299260
}
300261

301262
public async toBaseEntries(): Promise<readonly IChatRequestVariableEntry[]> {
302-
// chat variable for non-prompt file attachment
303-
if (this.prompt === undefined) {
304-
return [{
305-
kind: 'file',
306-
id: this.id,
307-
name: this.name,
308-
value: this.value,
309-
modelDescription: this.modelDescription,
310-
}];
311-
312-
}
313-
314-
// prompt can have any number of nested references, hence
315-
// collect all of valid ones and return the entire list
316-
await this.prompt.allSettled();
317-
return [
318-
// add all valid child references in the prompt
319-
...this.prompt.allValidReferences.map((link) => {
320-
return toPromptFileVariableEntry(link.uri, false);
321-
}),
322-
// and then the root prompt reference itself
323-
toPromptFileVariableEntry(this.prompt.uri, true)
324-
];
325-
}
326-
327-
/**
328-
* Whether the implicit context references a prompt file.
329-
*/
330-
public get isPromptFile() {
331-
return (this.prompt !== undefined);
263+
return [{
264+
kind: 'file',
265+
id: this.id,
266+
name: this.name,
267+
value: this.value,
268+
modelDescription: this.modelDescription,
269+
}];
332270
}
333271

334-
/**
335-
* Add prompt parser instance for the provided value.
336-
*/
337-
private addPrompt(
338-
value: URI | Location,
339-
): void {
340-
const uri = URI.isUri(value)
341-
? value
342-
: value.uri;
343-
344-
const model = this.modelService.getModel(uri);
345-
const modelExists = (model !== null);
346-
if ((modelExists === false) || model.isDisposed()) {
347-
return this.logService.warn(
348-
`cannot create prompt parser instance for ${uri.path} (model exists: ${modelExists})`,
349-
);
350-
}
351-
352-
this.prompt = this.promptsService.getSyntaxParserFor(model);
353-
}
354-
355-
/**
356-
* Remove and dispose prompt parser instance.
357-
*/
358-
private removePrompt(): void {
359-
delete this.prompt;
360-
}
361-
362-
public override dispose(): void {
363-
this.removePrompt();
364-
super.dispose();
365-
}
366272
}

0 commit comments

Comments
 (0)