mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Support variable references for non-file variables (#208510)
Fix microsoft/vscode-copilot-release#926
This commit is contained in:
parent
9b215e88df
commit
3c1fdd40ea
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Location } from 'vs/editor/common/languages';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
@ -22,7 +23,7 @@ import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extH
|
|||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatFollowup, IChatProgress, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatContentReference, IChatFollowup, IChatProgress, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import type * as vscode from 'vscode';
|
||||
|
@ -115,15 +116,48 @@ class ChatAgentResponseStream {
|
|||
},
|
||||
reference(value) {
|
||||
throwIfDone(this.reference);
|
||||
const part = new extHostTypes.ChatResponseReferencePart(value);
|
||||
const dto = typeConvert.ChatResponseReferencePart.to(part);
|
||||
_report(dto);
|
||||
|
||||
if ('variableName' in value && !value.value) {
|
||||
// The participant used this variable. Does that variable have any references to pull in?
|
||||
const matchingVarData = that._request.variables.variables.find(v => v.name === value.variableName);
|
||||
if (matchingVarData) {
|
||||
let references: Dto<IChatContentReference>[] | undefined;
|
||||
if (matchingVarData.references?.length) {
|
||||
references = matchingVarData.references.map(r => ({
|
||||
kind: 'reference',
|
||||
reference: { variableName: value.variableName, value: r.reference as URI | Location }
|
||||
} satisfies IChatContentReference));
|
||||
} else {
|
||||
// Participant sent a variableName reference but the variable produced no references. Show variable reference with no value
|
||||
const part = new extHostTypes.ChatResponseReferencePart(value);
|
||||
const dto = typeConvert.ChatResponseReferencePart.to(part);
|
||||
references = [dto];
|
||||
}
|
||||
|
||||
references.forEach(r => _report(r));
|
||||
return this;
|
||||
} else {
|
||||
// Something went wrong- that variable doesn't actually exist
|
||||
}
|
||||
} else {
|
||||
const part = new extHostTypes.ChatResponseReferencePart(value);
|
||||
const dto = typeConvert.ChatResponseReferencePart.to(part);
|
||||
_report(dto);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
push(part) {
|
||||
throwIfDone(this.push);
|
||||
const dto = typeConvert.ChatResponsePart.to(part, that._commandsConverter, that._sessionDisposables);
|
||||
_report(dto);
|
||||
|
||||
if (part instanceof extHostTypes.ChatResponseReferencePart) {
|
||||
// Ensure variable reference values get fixed up
|
||||
this.reference(part.value);
|
||||
} else {
|
||||
const dto = typeConvert.ChatResponsePart.to(part, that._commandsConverter, that._sessionDisposables);
|
||||
_report(dto);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
report(progress) {
|
||||
|
|
|
@ -2444,9 +2444,9 @@ export namespace ChatResponseReferencePart {
|
|||
kind: 'reference',
|
||||
reference: {
|
||||
variableName: part.value.variableName,
|
||||
value: URI.isUri(part.value.value) ?
|
||||
value: URI.isUri(part.value.value) || !part.value.value ?
|
||||
part.value.value :
|
||||
Location.from(<vscode.Location>part.value.value)
|
||||
Location.from(part.value.value as vscode.Location)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -574,7 +574,8 @@ class ResourceLabelWidget extends IconLabel {
|
|||
separator: this.options?.separator,
|
||||
domId: this.options?.domId,
|
||||
disabledCommand: this.options?.disabledCommand,
|
||||
labelEscapeNewLines: this.options?.labelEscapeNewLines
|
||||
labelEscapeNewLines: this.options?.labelEscapeNewLines,
|
||||
descriptionTitle: this.options?.descriptionTitle,
|
||||
};
|
||||
|
||||
const resource = toResource(this.label);
|
||||
|
|
|
@ -1237,12 +1237,19 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
|
|||
const reference = data.reference;
|
||||
templateData.label.element.style.display = 'flex';
|
||||
if ('variableName' in reference) {
|
||||
const variable = this.chatVariablesService.getVariable(reference.variableName);
|
||||
if (reference.value) {
|
||||
const uri = URI.isUri(reference.value) ? reference.value : reference.value.uri;
|
||||
const title = this.labelService.getUriLabel(dirname(uri), { relative: true });
|
||||
templateData.label.setResource({ resource: uri, name: basenameOrAuthority(uri), description: `#${reference.variableName}` }, { title });
|
||||
templateData.label.setResource(
|
||||
{
|
||||
resource: uri,
|
||||
name: basenameOrAuthority(uri),
|
||||
description: `#${reference.variableName}`,
|
||||
range: 'range' in reference.value ? reference.value.range : undefined
|
||||
},
|
||||
{ title, descriptionTitle: variable?.description });
|
||||
} else {
|
||||
const variable = this.chatVariablesService.getVariable(reference.variableName);
|
||||
templateData.label.setLabel(`#${reference.variableName}`, undefined, { title: variable?.description });
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -8,12 +8,12 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IOffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { ChatDynamicVariableModel } from 'vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables';
|
||||
import { IChatModel, IChatRequestVariableData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IParsedChatRequest, ChatRequestVariablePart, ChatRequestDynamicVariablePart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { IChatVariablesService, IChatRequestVariableValue, IChatVariableData, IChatVariableResolver, IDynamicVariable, IChatVariableResolverProgress } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { ChatRequestDynamicVariablePart, ChatRequestVariablePart, IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { IChatContentReference } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
|
||||
interface IChatData {
|
||||
data: IChatVariableData;
|
||||
|
@ -31,7 +31,7 @@ export class ChatVariablesService implements IChatVariablesService {
|
|||
}
|
||||
|
||||
async resolveVariables(prompt: IParsedChatRequest, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise<IChatRequestVariableData> {
|
||||
let resolvedVariables: { name: string; range: IOffsetRange; values: IChatRequestVariableValue[] }[] = [];
|
||||
let resolvedVariables: IChatRequestVariableEntry[] = [];
|
||||
const jobs: Promise<any>[] = [];
|
||||
|
||||
prompt.parts
|
||||
|
@ -39,8 +39,16 @@ export class ChatVariablesService implements IChatVariablesService {
|
|||
if (part instanceof ChatRequestVariablePart) {
|
||||
const data = this._resolver.get(part.variableName.toLowerCase());
|
||||
if (data) {
|
||||
jobs.push(data.resolver(prompt.text, part.variableArg, model, progress, token).then(values => {
|
||||
resolvedVariables[i] = { name: part.variableName, range: part.range, values: values ?? [] };
|
||||
const references: IChatContentReference[] = [];
|
||||
const variableProgressCallback = (item: IChatVariableResolverProgress) => {
|
||||
if (item.kind === 'reference') {
|
||||
references.push(item);
|
||||
return;
|
||||
}
|
||||
progress(item);
|
||||
};
|
||||
jobs.push(data.resolver(prompt.text, part.variableArg, model, variableProgressCallback, token).then(values => {
|
||||
resolvedVariables[i] = { name: part.variableName, range: part.range, values: values ?? [], references };
|
||||
}).catch(onUnexpectedExternalError));
|
||||
}
|
||||
} else if (part instanceof ChatRequestDynamicVariablePart) {
|
||||
|
@ -53,7 +61,7 @@ export class ChatVariablesService implements IChatVariablesService {
|
|||
resolvedVariables = coalesce(resolvedVariables);
|
||||
|
||||
// "reverse", high index first so that replacement is simple
|
||||
resolvedVariables.sort((a, b) => b.range.start - a.range.start);
|
||||
resolvedVariables.sort((a, b) => b.range!.start - a.range!.start);
|
||||
|
||||
return {
|
||||
variables: resolvedVariables,
|
||||
|
|
|
@ -31,6 +31,7 @@ export interface IChatRequestVariableEntry {
|
|||
name: string;
|
||||
range?: IOffsetRange;
|
||||
values: IChatRequestVariableValue[];
|
||||
references?: IChatContentReference[];
|
||||
}
|
||||
|
||||
export interface IChatRequestVariableData {
|
||||
|
|
Loading…
Reference in a new issue