diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 9a7ee3f639f..9a303f6681c 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2439,15 +2439,38 @@ export namespace ChatResponseCommandButtonPart { export namespace ChatResponseReferencePart { export function to(part: vscode.ChatResponseReferencePart): Dto { + if ('variableName' in part.value) { + return { + kind: 'reference', + reference: { + variableName: part.value.variableName, + value: URI.isUri(part.value.value) ? + part.value.value : + Location.from(part.value.value) + } + }; + } + return { kind: 'reference', - reference: !URI.isUri(part.value) ? Location.from(part.value) : part.value + reference: URI.isUri(part.value) ? + part.value : + Location.from(part.value) }; } export function from(part: Dto): vscode.ChatResponseReferencePart { const value = revive(part); + + const mapValue = (value: URI | languages.Location): vscode.Uri | vscode.Location => URI.isUri(value) ? + value : + Location.to(value); + return new types.ChatResponseReferencePart( - URI.isUri(value.reference) ? value.reference : Location.to(value.reference) + 'variableName' in value.reference ? { + variableName: value.reference.variableName, + value: value.reference.value && mapValue(value.reference.value) + } : + mapValue(value.reference) ); } } @@ -2556,36 +2579,6 @@ export namespace ChatResponseProgress { } } - export function to(progress: extHostProtocol.IChatProgressDto): vscode.ChatProgress | undefined { - switch (progress.kind) { - case 'markdownContent': - case 'inlineReference': - case 'treeData': - return ChatResponseProgress.to(progress); - case 'content': - return { content: progress.content }; - case 'usedContext': - return { documents: progress.documents.map(d => ({ uri: URI.revive(d.uri), version: d.version, ranges: d.ranges.map(r => Range.to(r)) })) }; - case 'reference': - return { - reference: - isUriComponents(progress.reference) ? - URI.revive(progress.reference) : - Location.to(progress.reference) - }; - case 'agentDetection': - // For simplicity, don't sent back the 'extended' types - return undefined; - case 'progressMessage': - return { message: progress.content.value }; - case 'vulnerability': - return { content: progress.content, vulnerabilities: progress.vulnerabilities }; - default: - // Unknown type, eg something in history that was removed? Ignore - return undefined; - } - } - export function toProgressContent(progress: extHostProtocol.IChatContentProgressDto, commandsConverter: Command.ICommandsConverter): vscode.ChatContentProgress | undefined { switch (progress.kind) { case 'markdownContent': diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 4bbfe4c7787..4f65a5c418d 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4298,8 +4298,8 @@ export class ChatResponseCommandButtonPart { } export class ChatResponseReferencePart { - value: vscode.Uri | vscode.Location; - constructor(value: vscode.Uri | vscode.Location) { + value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location }; + constructor(value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location }) { this.value = value; } } diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 0e3816eafed..84a5660285c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -25,6 +25,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { FileAccess, Schemas, matchesSomeScheme } from 'vs/base/common/network'; import { clamp } from 'vs/base/common/numbers'; import { basename } from 'vs/base/common/path'; +import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { ThemeIcon } from 'vs/base/common/themables'; import { URI } from 'vs/base/common/uri'; @@ -41,6 +42,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { FileKind, FileType } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ILabelService } from 'vs/platform/label/common/label'; import { WorkbenchCompressibleAsyncDataTree, WorkbenchList } from 'vs/platform/list/browser/listService'; import { ILogService } from 'vs/platform/log/common/log'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -58,6 +60,7 @@ import { CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_REQUEST, CONTEXT import { IChatProgressRenderableResponseContent } from 'vs/workbench/contrib/chat/common/chatModel'; import { chatAgentLeader, chatSubcommandLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatCommandButton, IChatContentReference, IChatFollowup, IChatProgressMessage, IChatResponseProgressFileTreeData, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables'; import { IChatProgressMessageRenderData, IChatRenderData, IChatResponseMarkdownRenderData, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter'; import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/files/browser/views/explorerView'; @@ -800,17 +803,22 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { if (e.element) { - this.openerService.open( - 'uri' in e.element.reference ? e.element.reference.uri : e.element.reference, - { - fromUserGesture: true, - editorOptions: { - ...e.editorOptions, - ...{ - selection: 'range' in e.element.reference ? e.element.reference.range : undefined + const uriOrLocation = 'variableName' in e.element.reference ? e.element.reference.value : e.element.reference; + const uri = URI.isUri(uriOrLocation) ? uriOrLocation : + uriOrLocation?.uri; + if (uri) { + this.openerService.open( + uri, + { + fromUserGesture: true, + editorOptions: { + ...e.editorOptions, + ...{ + selection: 'range' in e.element.reference ? e.element.reference.range : undefined + } } - } - }); + }); + } } })); listDisposables.add(list.onContextMenu((e) => { @@ -1163,10 +1171,13 @@ class ContentReferencesListPool extends Disposable { alwaysConsumeMouseWheel: false, accessibilityProvider: { getAriaLabel: (element: IChatContentReference) => { - if (URI.isUri(element.reference)) { - return basename(element.reference.path); + const reference = element.reference; + if ('variableName' in reference) { + return reference.variableName; + } else if (URI.isUri(reference)) { + return basename(reference.path); } else { - return basename(element.reference.uri.path); + return basename(reference.uri.path); } }, @@ -1212,6 +1223,8 @@ class ContentReferencesListRenderer implements IListRenderer> { const all = Iterable.map(this._resolver.values(), data => data.data); return Iterable.filter(all, data => !data.hidden); diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 42c94d58248..819c41f3045 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -74,8 +74,13 @@ export function isIUsedContext(obj: unknown): obj is IChatUsedContext { ); } +export interface IChatContentVariableReference { + variableName: string; + value?: URI | Location; +} + export interface IChatContentReference { - reference: URI | Location; + reference: URI | Location | IChatContentVariableReference; kind: 'reference'; } diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index fb6eb71a858..dc999f8081f 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -41,6 +41,7 @@ export interface IChatVariablesService { _serviceBrand: undefined; registerVariable(data: IChatVariableData, resolver: IChatVariableResolver): IDisposable; hasVariable(name: string): boolean; + getVariable(name: string): IChatVariableData | undefined; getVariables(): Iterable>; getDynamicVariables(sessionId: string): ReadonlyArray; // should be its own service? diff --git a/src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts b/src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts index 45a9d686c57..08146ac2511 100644 --- a/src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts +++ b/src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts @@ -108,15 +108,22 @@ export class CodeBlockModelCollection extends Disposable { return { references: chat.contentReferences.map(ref => { - if (URI.isUri(ref.reference)) { + const uriOrLocation = 'variableName' in ref.reference ? + ref.reference.value : + ref.reference; + if (!uriOrLocation) { + return; + } + + if (URI.isUri(uriOrLocation)) { return { - uri: ref.reference.toJSON() + uri: uriOrLocation.toJSON() }; } return { - uri: ref.reference.uri.toJSON(), - range: ref.reference.range, + uri: uriOrLocation.uri.toJSON(), + range: uriOrLocation.range, }; }) }; diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index 38c63ebeee0..0df8e2b57e7 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -15,6 +15,10 @@ export class MockChatVariablesService implements IChatVariablesService { throw new Error('Method not implemented.'); } + getVariable(name: string): IChatVariableData | undefined { + throw new Error('Method not implemented.'); + } + hasVariable(name: string): boolean { throw new Error('Method not implemented.'); } diff --git a/src/vscode-dts/vscode.proposed.chatParticipant.d.ts b/src/vscode-dts/vscode.proposed.chatParticipant.d.ts index e852daece58..c71c5b6408b 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipant.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipant.d.ts @@ -392,7 +392,7 @@ declare module 'vscode' { * @param value A uri or location * @returns This stream. */ - reference(value: Uri | Location): ChatResponseStream; + reference(value: Uri | Location | { variableName: string; value?: Uri | Location }): ChatResponseStream; /** * Pushes a part to this stream. @@ -430,8 +430,8 @@ declare module 'vscode' { } export class ChatResponseReferencePart { - value: Uri | Location; - constructor(value: Uri | Location); + value: Uri | Location | { variableName: string; value?: Uri | Location }; + constructor(value: Uri | Location | { variableName: string; value?: Uri | Location }); } export class ChatResponseCommandButtonPart {