Don't register chat participants in stable (#213244)

* Don't register chat participants in stable
And fork some Additions APIs into chatParticipantPrivate

* Remove stale proposals

* Move more API out of Additions
This commit is contained in:
Rob Lourens 2024-05-22 12:07:40 -07:00 committed by GitHub
parent 4ebc77f80a
commit b9d35d9145
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 175 additions and 140 deletions

View file

@ -7,8 +7,6 @@
"enabledApiProposals": [
"activeComment",
"authSession",
"chatParticipant",
"languageModels",
"defaultChatParticipant",
"chatVariableResolver",
"contribViewsRemote",

View file

@ -209,7 +209,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol));
const extHostProfileContentHandlers = rpcProtocol.set(ExtHostContext.ExtHostProfileContentHandlers, new ExtHostProfileContentHandlers(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService));
const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands));
const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands, initData.quality));
const extHostChatVariables = rpcProtocol.set(ExtHostContext.ExtHostChatVariables, new ExtHostChatVariables(rpcProtocol));
const extHostAiRelatedInformation = rpcProtocol.set(ExtHostContext.ExtHostAiRelatedInformation, new ExtHostRelatedInformation(rpcProtocol));
const extHostAiEmbeddingVector = rpcProtocol.set(ExtHostContext.ExtHostAiEmbeddingVector, new ExtHostAiEmbeddingVector(rpcProtocol));
@ -1427,7 +1427,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostChatAgents2.createChatAgent(extension, id, handler);
},
createDynamicChatParticipant(id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
checkProposedApiEnabled(extension, 'chatParticipantPrivate');
return extHostChatAgents2.createDynamicChatAgent(extension, id, dynamicProps, handler);
},
attachContext(name: string, value: string | vscode.Uri | vscode.Location | unknown, location: vscode.ChatLocation.Panel) {

View file

@ -263,6 +263,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
mainContext: IMainContext,
private readonly _logService: ILogService,
private readonly commands: ExtHostCommands,
private readonly quality: string | undefined
) {
super();
this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2);
@ -274,16 +275,19 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
const handle = ExtHostChatAgents2._idPool++;
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
const agent = new ExtHostChatAgent(extension, this.quality, id, this._proxy, handle, handler);
this._agents.set(handle, agent);
this._proxy.$registerAgent(handle, extension.identifier, id, {}, undefined);
if (agent.isAgentEnabled()) {
this._proxy.$registerAgent(handle, extension.identifier, id, {}, undefined);
}
return agent.apiAgent;
}
createDynamicChatAgent(extension: IExtensionDescription, id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
const handle = ExtHostChatAgents2._idPool++;
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
const agent = new ExtHostChatAgent(extension, this.quality, id, this._proxy, handle, handler);
this._agents.set(handle, agent);
this._proxy.$registerAgent(handle, extension.identifier, id, { isSticky: true } satisfies IExtensionChatAgentMetadata, dynamicProps);
@ -330,6 +334,10 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
responseIsIncomplete: true
};
}
if (errorDetails?.responseIsRedacted) {
checkProposedApiEnabled(agent.extension, 'chatParticipantPrivate');
}
return { errorDetails, timings: stream.timings, metadata: result?.metadata } satisfies IChatAgentResult;
}), token);
} catch (e) {
@ -485,6 +493,7 @@ class ExtHostChatAgent {
constructor(
public readonly extension: IExtensionDescription,
private readonly quality: string | undefined,
public readonly id: string,
private readonly _proxy: MainThreadChatAgentsShape2,
private readonly _handle: number,
@ -507,6 +516,11 @@ class ExtHostChatAgent {
return await this._agentVariableProvider.provider.provideCompletionItems(query, token) ?? [];
}
public isAgentEnabled() {
// If in stable and this extension doesn't have the right proposed API, then don't register the agent
return !(this.quality === 'stable' && !isProposedApiEnabled(this.extension, 'chatParticipantPrivate'));
}
async provideFollowups(result: vscode.ChatResult, context: vscode.ChatContext, token: CancellationToken): Promise<vscode.ChatFollowup[]> {
if (!this._followupProvider) {
return [];
@ -564,6 +578,10 @@ class ExtHostChatAgent {
}
updateScheduled = true;
queueMicrotask(() => {
if (!that.isAgentEnabled()) {
return;
}
this._proxy.$updateAgent(this._handle, {
icon: !this._iconPath ? undefined :
this._iconPath instanceof URI ? this._iconPath :
@ -658,11 +676,11 @@ class ExtHostChatAgent {
updateMetadataSoon();
},
get supportIssueReporting() {
checkProposedApiEnabled(that.extension, 'chatParticipantAdditions');
checkProposedApiEnabled(that.extension, 'chatParticipantPrivate');
return that._supportIssueReporting;
},
set supportIssueReporting(v) {
checkProposedApiEnabled(that.extension, 'chatParticipantAdditions');
checkProposedApiEnabled(that.extension, 'chatParticipantPrivate');
that._supportIssueReporting = v;
updateMetadataSoon();
},
@ -707,10 +725,12 @@ class ExtHostChatAgent {
return that._requester;
},
set supportsSlowReferences(v) {
checkProposedApiEnabled(that.extension, 'chatParticipantPrivate');
that._supportsSlowReferences = v;
updateMetadataSoon();
},
get supportsSlowReferences() {
checkProposedApiEnabled(that.extension, 'chatParticipantPrivate');
return that._supportsSlowReferences;
},
dispose() {

View file

@ -159,6 +159,11 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
private handleAndRegisterChatExtensions(): void {
chatParticipantExtensionPoint.setHandler((extensions, delta) => {
for (const extension of delta.added) {
if (this.productService.quality === 'stable' && !isProposedApiEnabled(extension.description, 'chatParticipantPrivate')) {
this.logService.warn(`Chat participants are not yet enabled in VS Code Stable (${extension.description.identifier.value})`);
continue;
}
for (const providerDescriptor of extension.value) {
if (!providerDescriptor.name.match(/^[\w0-9_-]+$/)) {
this.logService.error(`Extension '${extension.description.identifier.value}' CANNOT register participant with invalid name: ${providerDescriptor.name}. Name must match /^[\\w0-9_-]+$/.`);

View file

@ -15,6 +15,7 @@ export const allApiProposals = Object.freeze({
authSession: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts',
canonicalUriProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.canonicalUriProvider.d.ts',
chatParticipantAdditions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts',
chatParticipantPrivate: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts',
chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts',
chatTab: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTab.d.ts',
chatVariableResolver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatVariableResolver.d.ts',

View file

@ -5,60 +5,8 @@
declare module 'vscode' {
/**
* The location at which the chat is happening.
*/
export enum ChatLocation {
/**
* The chat panel
*/
Panel = 1,
/**
* Terminal inline chat
*/
Terminal = 2,
/**
* Notebook inline chat
*/
Notebook = 3,
/**
* Code editor inline chat
*/
Editor = 4
}
export interface ChatRequest {
/**
* The attempt number of the request. The first request has attempt number 0.
*/
readonly attempt: number;
/**
* If automatic command detection is enabled.
*/
readonly enableCommandDetection: boolean;
/**
* The location at which the chat is happening. This will always be one of the supported values
*/
readonly location: ChatLocation;
}
export interface ChatParticipant {
onDidPerformAction: Event<ChatUserActionEvent>;
supportIssueReporting?: boolean;
/**
* Temp, support references that are slow to resolve and should be tools rather than references.
*/
supportsSlowReferences?: boolean;
}
export interface ChatErrorDetails {
/**
* If set to true, the message content is completely hidden. Only ChatErrorDetails#message will be shown.
*/
responseIsRedacted?: boolean;
}
/**
@ -224,8 +172,6 @@ declare module 'vscode' {
*/
export function createChatParticipant(id: string, handler: ChatExtendedRequestHandler): ChatParticipant;
export function createDynamicChatParticipant(id: string, dynamicProps: DynamicChatParticipantProps, handler: ChatExtendedRequestHandler): ChatParticipant;
/**
* Current version of the proposal. Changes whenever backwards-incompatible changes are made.
* If a new feature is added that doesn't break existing code, the version is not incremented. When the extension uses this new feature, it should set its engines.vscode version appropriately.
@ -235,16 +181,6 @@ declare module 'vscode' {
export const _version: 1 | number;
}
/**
* These don't get set on the ChatParticipant after creation, like other props, because they are typically defined in package.json and we want them at the time of creation.
*/
export interface DynamicChatParticipantProps {
name: string;
publisherName: string;
description?: string;
fullName?: string;
}
/*
* User action events
*/
@ -313,71 +249,4 @@ declare module 'vscode' {
*/
readonly name: string;
}
/**
* The detail level of this chat variable value.
*/
export enum ChatVariableLevel {
Short = 1,
Medium = 2,
Full = 3
}
export interface ChatVariableValue {
/**
* The detail level of this chat variable value. If possible, variable resolvers should try to offer shorter values that will consume fewer tokens in an LLM prompt.
*/
level: ChatVariableLevel;
/**
* The variable's value, which can be included in an LLM prompt as-is, or the chat participant may decide to read the value and do something else with it.
*/
value: string | Uri;
/**
* A description of this value, which could be provided to the LLM as a hint.
*/
description?: string;
}
export interface ChatVariableResolverResponseStream {
/**
* Push a progress part to this stream. Short-hand for
* `push(new ChatResponseProgressPart(value))`.
*
* @param value
* @returns This stream.
*/
progress(value: string): ChatVariableResolverResponseStream;
/**
* Push a reference to this stream. Short-hand for
* `push(new ChatResponseReferencePart(value))`.
*
* *Note* that the reference is not rendered inline with the response.
*
* @param value A uri or location
* @returns This stream.
*/
reference(value: Uri | Location): ChatVariableResolverResponseStream;
/**
* Pushes a part to this stream.
*
* @param part A response part, rendered or metadata
*/
push(part: ChatVariableResolverResponsePart): ChatVariableResolverResponseStream;
}
export type ChatVariableResolverResponsePart = ChatResponseProgressPart | ChatResponseReferencePart;
export interface ChatVariableResolver {
/**
* A callback to resolve the value of a chat variable.
* @param name The name of the variable.
* @param context Contextual information about this chat request.
* @param token A cancellation token.
*/
resolve2?(name: string, context: ChatVariableContext, stream: ChatVariableResolverResponseStream, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
}
}

View file

@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'vscode' {
/**
* The location at which the chat is happening.
*/
export enum ChatLocation {
/**
* The chat panel
*/
Panel = 1,
/**
* Terminal inline chat
*/
Terminal = 2,
/**
* Notebook inline chat
*/
Notebook = 3,
/**
* Code editor inline chat
*/
Editor = 4
}
export interface ChatRequest {
/**
* The attempt number of the request. The first request has attempt number 0.
*/
readonly attempt: number;
/**
* If automatic command detection is enabled.
*/
readonly enableCommandDetection: boolean;
/**
* The location at which the chat is happening. This will always be one of the supported values
*/
readonly location: ChatLocation;
}
export interface ChatParticipant {
supportIssueReporting?: boolean;
/**
* Temp, support references that are slow to resolve and should be tools rather than references.
*/
supportsSlowReferences?: boolean;
}
export interface ChatErrorDetails {
/**
* If set to true, the message content is completely hidden. Only ChatErrorDetails#message will be shown.
*/
responseIsRedacted?: boolean;
}
export namespace chat {
export function createDynamicChatParticipant(id: string, dynamicProps: DynamicChatParticipantProps, handler: ChatExtendedRequestHandler): ChatParticipant;
}
/**
* These don't get set on the ChatParticipant after creation, like other props, because they are typically defined in package.json and we want them at the time of creation.
*/
export interface DynamicChatParticipantProps {
name: string;
publisherName: string;
description?: string;
fullName?: string;
}
}

View file

@ -66,5 +66,71 @@ declare module 'vscode' {
* @param token A cancellation token.
*/
resolve(name: string, context: ChatVariableContext, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
/**
* A callback to resolve the value of a chat variable.
* @param name The name of the variable.
* @param context Contextual information about this chat request.
* @param token A cancellation token.
*/
resolve2?(name: string, context: ChatVariableContext, stream: ChatVariableResolverResponseStream, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
}
/**
* The detail level of this chat variable value.
*/
export enum ChatVariableLevel {
Short = 1,
Medium = 2,
Full = 3
}
export interface ChatVariableValue {
/**
* The detail level of this chat variable value. If possible, variable resolvers should try to offer shorter values that will consume fewer tokens in an LLM prompt.
*/
level: ChatVariableLevel;
/**
* The variable's value, which can be included in an LLM prompt as-is, or the chat participant may decide to read the value and do something else with it.
*/
value: string | Uri;
/**
* A description of this value, which could be provided to the LLM as a hint.
*/
description?: string;
}
export interface ChatVariableResolverResponseStream {
/**
* Push a progress part to this stream. Short-hand for
* `push(new ChatResponseProgressPart(value))`.
*
* @param value
* @returns This stream.
*/
progress(value: string): ChatVariableResolverResponseStream;
/**
* Push a reference to this stream. Short-hand for
* `push(new ChatResponseReferencePart(value))`.
*
* *Note* that the reference is not rendered inline with the response.
*
* @param value A uri or location
* @returns This stream.
*/
reference(value: Uri | Location): ChatVariableResolverResponseStream;
/**
* Pushes a part to this stream.
*
* @param part A response part, rendered or metadata
*/
push(part: ChatVariableResolverResponsePart): ChatVariableResolverResponseStream;
}
export type ChatVariableResolverResponsePart = ChatResponseProgressPart | ChatResponseReferencePart;
}