mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
Chat code cleanup (#198022)
* Clean up some obsolete chat API Start deleting the interactive session provider, use agents only * Delete old chat agents API * Remove providerRequestId * Remove unused stuff from interactive.d.ts * Get rid of chat session state saving * Fix test * I guess this type was in use
This commit is contained in:
parent
bdc113ffe1
commit
7cbff1919e
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import { CancellationToken, chat, ChatAgentRequest, ChatVariableLevel, CompletionItemKind, Disposable, interactive, InteractiveProgress, InteractiveRequest, InteractiveResponseForProgress, InteractiveSession, InteractiveSessionState, Progress, ProviderResult } from 'vscode';
|
import { CancellationToken, chat, ChatAgentRequest, ChatVariableLevel, Disposable, interactive, InteractiveSession, ProviderResult } from 'vscode';
|
||||||
import { assertNoRpc, closeAllEditors, DeferredPromise, disposeAll } from '../utils';
|
import { assertNoRpc, closeAllEditors, DeferredPromise, disposeAll } from '../utils';
|
||||||
|
|
||||||
suite('chat', () => {
|
suite('chat', () => {
|
||||||
|
@ -22,24 +22,12 @@ suite('chat', () => {
|
||||||
|
|
||||||
function getDeferredForRequest(): DeferredPromise<ChatAgentRequest> {
|
function getDeferredForRequest(): DeferredPromise<ChatAgentRequest> {
|
||||||
disposables.push(interactive.registerInteractiveSessionProvider('provider', {
|
disposables.push(interactive.registerInteractiveSessionProvider('provider', {
|
||||||
prepareSession: (_initialState: InteractiveSessionState | undefined, _token: CancellationToken): ProviderResult<InteractiveSession> => {
|
prepareSession: (_token: CancellationToken): ProviderResult<InteractiveSession> => {
|
||||||
return {
|
return {
|
||||||
requester: { name: 'test' },
|
requester: { name: 'test' },
|
||||||
responder: { name: 'test' },
|
responder: { name: 'test' },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
provideResponseWithProgress: (_request: InteractiveRequest, _progress: Progress<InteractiveProgress>, _token: CancellationToken): ProviderResult<InteractiveResponseForProgress> => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
provideSlashCommands: (_session, _token) => {
|
|
||||||
return [{ command: 'hello', title: 'Hello', kind: CompletionItemKind.Text }];
|
|
||||||
},
|
|
||||||
|
|
||||||
removeRequest: (_session: InteractiveSession, _requestId: string): void => {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const deferred = new DeferredPromise<ChatAgentRequest>();
|
const deferred = new DeferredPromise<ChatAgentRequest>();
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import 'mocha';
|
|
||||||
import { CancellationToken, CompletionItemKind, Disposable, interactive, InteractiveProgress, InteractiveRequest, InteractiveResponseForProgress, InteractiveSession, InteractiveSessionState, Progress, ProviderResult } from 'vscode';
|
|
||||||
import { assertNoRpc, closeAllEditors, DeferredPromise, disposeAll } from '../utils';
|
|
||||||
|
|
||||||
suite('InteractiveSessionProvider', () => {
|
|
||||||
let disposables: Disposable[] = [];
|
|
||||||
setup(async () => {
|
|
||||||
disposables = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
teardown(async function () {
|
|
||||||
assertNoRpc();
|
|
||||||
await closeAllEditors();
|
|
||||||
disposeAll(disposables);
|
|
||||||
});
|
|
||||||
|
|
||||||
function getDeferredForRequest(): DeferredPromise<InteractiveRequest> {
|
|
||||||
const deferred = new DeferredPromise<InteractiveRequest>();
|
|
||||||
disposables.push(interactive.registerInteractiveSessionProvider('provider', {
|
|
||||||
prepareSession: (_initialState: InteractiveSessionState | undefined, _token: CancellationToken): ProviderResult<InteractiveSession> => {
|
|
||||||
return {
|
|
||||||
requester: { name: 'test' },
|
|
||||||
responder: { name: 'test' },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
provideResponseWithProgress: (request: InteractiveRequest, _progress: Progress<InteractiveProgress>, _token: CancellationToken): ProviderResult<InteractiveResponseForProgress> => {
|
|
||||||
deferred.complete(request);
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
provideSlashCommands: (_session, _token) => {
|
|
||||||
return [{ command: 'hello', title: 'Hello', kind: CompletionItemKind.Text }];
|
|
||||||
},
|
|
||||||
|
|
||||||
removeRequest: (_session: InteractiveSession, _requestId: string): void => {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
return deferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
test('plain text query', async () => {
|
|
||||||
const deferred = getDeferredForRequest();
|
|
||||||
interactive.sendInteractiveRequestToProvider('provider', { message: 'hello' });
|
|
||||||
const lastResult = await deferred.p;
|
|
||||||
assert.strictEqual(lastResult.message, 'hello');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('slash command', async () => {
|
|
||||||
const deferred = getDeferredForRequest();
|
|
||||||
interactive.sendInteractiveRequestToProvider('provider', { message: '/hello' });
|
|
||||||
const lastResult = await deferred.p;
|
|
||||||
assert.strictEqual(lastResult.message, '/hello');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -781,6 +781,10 @@ export class DisposableMap<K, V extends IDisposable = IDisposable> implements ID
|
||||||
return this._store.keys();
|
return this._store.keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
values(): IterableIterator<V> {
|
||||||
|
return this._store.values();
|
||||||
|
}
|
||||||
|
|
||||||
[Symbol.iterator](): IterableIterator<[K, V]> {
|
[Symbol.iterator](): IterableIterator<[K, V]> {
|
||||||
return this._store[Symbol.iterator]();
|
return this._store[Symbol.iterator]();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import { StatusBarItemsExtensionPoint } from 'vs/workbench/api/browser/statusBar
|
||||||
import './mainThreadLocalization';
|
import './mainThreadLocalization';
|
||||||
import './mainThreadBulkEdits';
|
import './mainThreadBulkEdits';
|
||||||
import './mainThreadChatProvider';
|
import './mainThreadChatProvider';
|
||||||
import './mainThreadChatAgents';
|
|
||||||
import './mainThreadChatAgents2';
|
import './mainThreadChatAgents2';
|
||||||
import './mainThreadChatVariables';
|
import './mainThreadChatVariables';
|
||||||
import './mainThreadCodeInsets';
|
import './mainThreadCodeInsets';
|
||||||
|
|
|
@ -3,31 +3,23 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { DeferredPromise } from 'vs/base/common/async';
|
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
|
||||||
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { ExtHostChatShape, ExtHostContext, IChatRequestDto, IChatResponseProgressDto, ILocationDto, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostChatShape, ExtHostContext, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||||
import { isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { IChatDynamicRequest, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChat, IChatDynamicRequest, IChatProgress, IChatResponse, IChatResponseProgressFileTreeData, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadChat)
|
@extHostNamedCustomer(MainContext.MainThreadChat)
|
||||||
export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
||||||
|
|
||||||
private readonly _providerRegistrations = this._register(new DisposableMap<number>());
|
private readonly _providerRegistrations = this._register(new DisposableMap<number>());
|
||||||
private readonly _activeRequestProgressCallbacks = new Map<string, (progress: IChatProgress) => (DeferredPromise<string | IMarkdownString> | void)>();
|
|
||||||
private readonly _stateEmitters = new Map<number, Emitter<any>>();
|
private readonly _stateEmitters = new Map<number, Emitter<any>>();
|
||||||
|
|
||||||
private readonly _proxy: ExtHostChatShape;
|
private readonly _proxy: ExtHostChatShape;
|
||||||
|
|
||||||
private _responsePartHandlePool = 0;
|
|
||||||
private readonly _activeResponsePartPromises = new Map<string, DeferredPromise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }>>();
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
extHostContext: IExtHostContext,
|
||||||
@IChatService private readonly _chatService: IChatService,
|
@IChatService private readonly _chatService: IChatService,
|
||||||
|
@ -64,8 +56,8 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
||||||
const unreg = this._chatService.registerProvider({
|
const unreg = this._chatService.registerProvider({
|
||||||
id,
|
id,
|
||||||
displayName: registration.label,
|
displayName: registration.label,
|
||||||
prepareSession: async (initialState, token) => {
|
prepareSession: async (token) => {
|
||||||
const session = await this._proxy.$prepareChat(handle, initialState, token);
|
const session = await this._proxy.$prepareChat(handle, token);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -75,14 +67,13 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
||||||
|
|
||||||
const emitter = new Emitter<any>();
|
const emitter = new Emitter<any>();
|
||||||
this._stateEmitters.set(session.id, emitter);
|
this._stateEmitters.set(session.id, emitter);
|
||||||
return <IChat>{
|
return {
|
||||||
id: session.id,
|
id: session.id,
|
||||||
requesterUsername: session.requesterUsername,
|
requesterUsername: session.requesterUsername,
|
||||||
requesterAvatarIconUri: URI.revive(session.requesterAvatarIconUri),
|
requesterAvatarIconUri: URI.revive(session.requesterAvatarIconUri),
|
||||||
responderUsername: session.responderUsername,
|
responderUsername: session.responderUsername,
|
||||||
responderAvatarIconUri,
|
responderAvatarIconUri,
|
||||||
inputPlaceholder: session.inputPlaceholder,
|
inputPlaceholder: session.inputPlaceholder,
|
||||||
onDidChangeState: emitter.event,
|
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
emitter.dispose();
|
emitter.dispose();
|
||||||
this._stateEmitters.delete(session.id);
|
this._stateEmitters.delete(session.id);
|
||||||
|
@ -90,87 +81,17 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
provideReply: async (request, progress, token) => {
|
|
||||||
const id = `${handle}_${request.session.id}`;
|
|
||||||
this._activeRequestProgressCallbacks.set(id, progress);
|
|
||||||
try {
|
|
||||||
const requestDto: IChatRequestDto = {
|
|
||||||
message: request.message,
|
|
||||||
variables: request.variables
|
|
||||||
};
|
|
||||||
const dto = await this._proxy.$provideReply(handle, request.session.id, requestDto, token);
|
|
||||||
return <IChatResponse>{
|
|
||||||
session: request.session,
|
|
||||||
...dto
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
this._activeRequestProgressCallbacks.delete(id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
provideWelcomeMessage: (token) => {
|
provideWelcomeMessage: (token) => {
|
||||||
return this._proxy.$provideWelcomeMessage(handle, token);
|
return this._proxy.$provideWelcomeMessage(handle, token);
|
||||||
},
|
},
|
||||||
provideSampleQuestions: (token) => {
|
provideSampleQuestions: (token) => {
|
||||||
return this._proxy.$provideSampleQuestions(handle, token);
|
return this._proxy.$provideSampleQuestions(handle, token);
|
||||||
},
|
},
|
||||||
provideSlashCommands: (session, token) => {
|
|
||||||
return this._proxy.$provideSlashCommands(handle, session.id, token);
|
|
||||||
},
|
|
||||||
provideFollowups: (session, token) => {
|
|
||||||
return this._proxy.$provideFollowups(handle, session.id, token);
|
|
||||||
},
|
|
||||||
removeRequest: (session, requestId) => {
|
|
||||||
return this._proxy.$removeRequest(handle, session.id, requestId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._providerRegistrations.set(handle, unreg);
|
this._providerRegistrations.set(handle, unreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $acceptResponseProgress(handle: number, sessionId: number, progress: IChatResponseProgressDto, responsePartHandle?: number): Promise<number | void> {
|
|
||||||
const id = `${handle}_${sessionId}`;
|
|
||||||
|
|
||||||
if ('placeholder' in progress) {
|
|
||||||
const responsePartId = `${id}_${++this._responsePartHandlePool}`;
|
|
||||||
const deferredContentPromise = new DeferredPromise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }>();
|
|
||||||
this._activeResponsePartPromises.set(responsePartId, deferredContentPromise);
|
|
||||||
this._activeRequestProgressCallbacks.get(id)?.({ ...progress, resolvedContent: deferredContentPromise.p });
|
|
||||||
return this._responsePartHandlePool;
|
|
||||||
} else if (responsePartHandle) {
|
|
||||||
// Complete an existing deferred promise with resolved content
|
|
||||||
const responsePartId = `${id}_${responsePartHandle}`;
|
|
||||||
const deferredContentPromise = this._activeResponsePartPromises.get(responsePartId);
|
|
||||||
if (deferredContentPromise && isCompleteInteractiveProgressTreeData(progress)) {
|
|
||||||
const withRevivedUris = revive<{ treeData: IChatResponseProgressFileTreeData }>(progress);
|
|
||||||
deferredContentPromise.complete(withRevivedUris);
|
|
||||||
this._activeResponsePartPromises.delete(responsePartId);
|
|
||||||
} else if (deferredContentPromise && 'content' in progress) {
|
|
||||||
deferredContentPromise.complete(progress.content);
|
|
||||||
this._activeResponsePartPromises.delete(responsePartId);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to support standalone tree data that's not attached to a placeholder in API
|
|
||||||
if (isCompleteInteractiveProgressTreeData(progress)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TS won't let us change the type of `progress`
|
|
||||||
let revivedProgress: IChatProgress;
|
|
||||||
if ('documents' in progress) {
|
|
||||||
revivedProgress = { documents: revive(progress.documents) };
|
|
||||||
} else if ('reference' in progress) {
|
|
||||||
revivedProgress = revive<{ reference: UriComponents | ILocationDto }>(progress);
|
|
||||||
} else if ('inlineReference' in progress) {
|
|
||||||
revivedProgress = revive<{ inlineReference: UriComponents | ILocationDto; name?: string }>(progress);
|
|
||||||
} else {
|
|
||||||
revivedProgress = progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activeRequestProgressCallbacks.get(id)?.(revivedProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $acceptChatState(sessionId: number, state: any): Promise<void> {
|
async $acceptChatState(sessionId: number, state: any): Promise<void> {
|
||||||
this._stateEmitters.get(sessionId)?.fire(state);
|
this._stateEmitters.get(sessionId)?.fire(state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { DisposableMap } from 'vs/base/common/lifecycle';
|
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
|
||||||
import { IProgress } from 'vs/platform/progress/common/progress';
|
|
||||||
import { ExtHostChatAgentsShape, ExtHostContext, MainContext, MainThreadChatAgentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import { IChatAgentCommand, IChatAgentMetadata, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
|
||||||
import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
|
||||||
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
|
||||||
|
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadChatAgents)
|
|
||||||
export class MainThreadChatAgents implements MainThreadChatAgentsShape {
|
|
||||||
|
|
||||||
private readonly _agents = new DisposableMap<number>;
|
|
||||||
private readonly _pendingProgress = new Map<number, IProgress<IChatProgress>>();
|
|
||||||
private readonly _proxy: ExtHostChatAgentsShape;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
extHostContext: IExtHostContext,
|
|
||||||
@IChatAgentService private readonly _chatAgentService: IChatAgentService
|
|
||||||
) {
|
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents);
|
|
||||||
}
|
|
||||||
|
|
||||||
$unregisterAgent(handle: number): void {
|
|
||||||
this._agents.deleteAndDispose(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(): void {
|
|
||||||
this._agents.clearAndDisposeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
$registerAgent(handle: number, name: string, metadata: IChatAgentMetadata & { subCommands: IChatAgentCommand[] }): void {
|
|
||||||
const d = this._chatAgentService.registerAgent({
|
|
||||||
id: name,
|
|
||||||
metadata: revive(metadata),
|
|
||||||
invoke: async (request, progress, history, token) => {
|
|
||||||
const requestId = Math.random();
|
|
||||||
this._pendingProgress.set(requestId, { report: progress });
|
|
||||||
try {
|
|
||||||
const message = request.command ? `/${request.command} ${request.message}` : request.message;
|
|
||||||
const result = await this._proxy.$invokeAgent(handle, requestId, message, { history }, token);
|
|
||||||
return {
|
|
||||||
followUp: result?.followUp ?? [],
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
this._pendingProgress.delete(requestId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async provideSlashCommands() {
|
|
||||||
return metadata.subCommands;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this._agents.set(handle, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $handleProgressChunk(requestId: number, chunk: IChatSlashFragment): Promise<void> {
|
|
||||||
// An extra step because TS really struggles with type inference in the Revived generic parameter?
|
|
||||||
const revived = revive<IChatSlashFragment>(chunk);
|
|
||||||
if (typeof revived.content === 'string') {
|
|
||||||
this._pendingProgress.get(requestId)?.report({ content: revived.content });
|
|
||||||
} else {
|
|
||||||
this._pendingProgress.get(requestId)?.report(revived.content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$unregisterCommand(handle: number): void {
|
|
||||||
this._agents.deleteAndDispose(handle);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,110 +6,109 @@
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import * as errors from 'vs/base/common/errors';
|
import * as errors from 'vs/base/common/errors';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { combinedDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||||
import { OverviewRulerLane } from 'vs/editor/common/model';
|
|
||||||
import * as languageConfiguration from 'vs/editor/common/languages/languageConfiguration';
|
|
||||||
import { score } from 'vs/editor/common/languageSelector';
|
import { score } from 'vs/editor/common/languageSelector';
|
||||||
|
import * as languageConfiguration from 'vs/editor/common/languages/languageConfiguration';
|
||||||
|
import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||||
|
import { ExtensionIdentifierSet, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import * as files from 'vs/platform/files/common/files';
|
import * as files from 'vs/platform/files/common/files';
|
||||||
import { ExtHostContext, MainContext, CandidatePortSource, ExtHostLogLevelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
import { ILogService, ILoggerService, LogLevel } from 'vs/platform/log/common/log';
|
||||||
|
import { matchesScheme } from 'vs/platform/opener/common/opener';
|
||||||
|
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||||
|
import { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||||
|
import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions';
|
||||||
|
import { CandidatePortSource, ExtHostContext, ExtHostLogLevelServiceShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
|
import { ExtHostRelatedInformation } from 'vs/workbench/api/common/extHostAiRelatedInformation';
|
||||||
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||||
|
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||||
|
import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||||
|
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
|
||||||
|
import { ExtHostChat } from 'vs/workbench/api/common/extHostChat';
|
||||||
|
import { ExtHostChatAgents2 } from 'vs/workbench/api/common/extHostChatAgents2';
|
||||||
|
import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider';
|
||||||
|
import { ExtHostChatVariables } from 'vs/workbench/api/common/extHostChatVariables';
|
||||||
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
||||||
|
import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
|
||||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||||
import { createExtHostComments } from 'vs/workbench/api/common/extHostComments';
|
import { createExtHostComments } from 'vs/workbench/api/common/extHostComments';
|
||||||
import { ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
import { ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||||
|
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
|
||||||
|
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
|
||||||
|
import { IExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
||||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||||
import { ExtHostDialogs } from 'vs/workbench/api/common/extHostDialogs';
|
import { ExtHostDialogs } from 'vs/workbench/api/common/extHostDialogs';
|
||||||
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/common/extHostDocumentContentProviders';
|
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/common/extHostDocumentContentProviders';
|
||||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
|
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
|
||||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||||
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||||
|
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
|
||||||
|
import { ExtHostAiEmbeddingVector } from 'vs/workbench/api/common/extHostEmbeddingVector';
|
||||||
import { Extension, IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
import { Extension, IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||||
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
|
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
|
||||||
|
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
||||||
import { ExtHostFileSystemEventService, FileSystemWatcherCreateOptions } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
import { ExtHostFileSystemEventService, FileSystemWatcherCreateOptions } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
||||||
|
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
||||||
|
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||||
|
import { ExtHostInteractiveEditor } from 'vs/workbench/api/common/extHostInlineChat';
|
||||||
|
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
|
||||||
|
import { ExtHostIssueReporter } from 'vs/workbench/api/common/extHostIssueReporter';
|
||||||
|
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
|
||||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||||
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
|
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
|
||||||
|
import { IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService';
|
||||||
|
import { IExtHostManagedSockets } from 'vs/workbench/api/common/extHostManagedSockets';
|
||||||
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
|
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
|
||||||
|
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||||
|
import { ExtHostNotebookDocumentSaveParticipant } from 'vs/workbench/api/common/extHostNotebookDocumentSaveParticipant';
|
||||||
|
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
|
||||||
|
import { ExtHostNotebookEditors } from 'vs/workbench/api/common/extHostNotebookEditors';
|
||||||
|
import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels';
|
||||||
|
import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers';
|
||||||
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
||||||
|
import { ExtHostProfileContentHandlers } from 'vs/workbench/api/common/extHostProfileContentHandler';
|
||||||
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
|
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
|
||||||
|
import { ExtHostQuickDiff } from 'vs/workbench/api/common/extHostQuickDiff';
|
||||||
import { createExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
|
import { createExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
|
||||||
|
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||||
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
|
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
|
||||||
|
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
|
||||||
|
import { IExtHostSecretState } from 'vs/workbench/api/common/extHostSecretState';
|
||||||
|
import { ExtHostShare } from 'vs/workbench/api/common/extHostShare';
|
||||||
|
import { ExtHostSpeech } from 'vs/workbench/api/common/extHostSpeech';
|
||||||
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
|
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
|
||||||
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||||
|
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||||
|
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
||||||
|
import { ExtHostTelemetryLogger, IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry';
|
||||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||||
|
import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||||
|
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
|
||||||
|
import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
|
||||||
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
||||||
|
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils';
|
import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener';
|
||||||
|
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
|
||||||
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
||||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||||
|
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
|
||||||
|
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
|
||||||
import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
|
||||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
|
||||||
import type * as vscode from 'vscode';
|
|
||||||
import { ExtensionIdentifierSet, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
|
|
||||||
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
|
|
||||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
import { IExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
|
||||||
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
|
||||||
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
|
|
||||||
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
|
|
||||||
import { ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log';
|
|
||||||
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
|
|
||||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
|
||||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
|
||||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
|
||||||
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
|
|
||||||
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
|
||||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
|
||||||
import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
|
||||||
import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
|
|
||||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
|
||||||
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
|
||||||
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
|
|
||||||
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
|
|
||||||
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
|
|
||||||
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
|
|
||||||
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
|
||||||
import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
|
||||||
import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener';
|
|
||||||
import { IExtHostSecretState } from 'vs/workbench/api/common/extHostSecretState';
|
|
||||||
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
|
|
||||||
import { ExtHostTelemetryLogger, IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry';
|
|
||||||
import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels';
|
|
||||||
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
|
|
||||||
import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { matchesScheme } from 'vs/platform/opener/common/opener';
|
|
||||||
import { ExtHostNotebookEditors } from 'vs/workbench/api/common/extHostNotebookEditors';
|
|
||||||
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
|
|
||||||
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
|
|
||||||
import { combinedDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
|
||||||
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug';
|
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
import { IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService';
|
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||||
import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions';
|
import { UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||||
import { ExtHostProfileContentHandlers } from 'vs/workbench/api/common/extHostProfileContentHandler';
|
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ExtHostQuickDiff } from 'vs/workbench/api/common/extHostQuickDiff';
|
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||||
import { ExtHostChat } from 'vs/workbench/api/common/extHostChat';
|
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
|
||||||
import { ExtHostInteractiveEditor } from 'vs/workbench/api/common/extHostInlineChat';
|
import type * as vscode from 'vscode';
|
||||||
import { ExtHostNotebookDocumentSaveParticipant } from 'vs/workbench/api/common/extHostNotebookDocumentSaveParticipant';
|
|
||||||
import { ExtHostIssueReporter } from 'vs/workbench/api/common/extHostIssueReporter';
|
|
||||||
import { IExtHostManagedSockets } from 'vs/workbench/api/common/extHostManagedSockets';
|
|
||||||
import { ExtHostShare } from 'vs/workbench/api/common/extHostShare';
|
|
||||||
import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider';
|
|
||||||
import { ExtHostSpeech } from 'vs/workbench/api/common/extHostSpeech';
|
|
||||||
import { ExtHostChatVariables } from 'vs/workbench/api/common/extHostChatVariables';
|
|
||||||
import { ExtHostRelatedInformation } from 'vs/workbench/api/common/extHostAiRelatedInformation';
|
|
||||||
import { ExtHostAiEmbeddingVector } from 'vs/workbench/api/common/extHostEmbeddingVector';
|
|
||||||
import { ExtHostChatAgents } from 'vs/workbench/api/common/extHostChatAgents';
|
|
||||||
import { ExtHostChatAgents2 } from 'vs/workbench/api/common/extHostChatAgents2';
|
|
||||||
|
|
||||||
export interface IExtensionRegistries {
|
export interface IExtensionRegistries {
|
||||||
mine: ExtensionDescriptionRegistry;
|
mine: ExtensionDescriptionRegistry;
|
||||||
|
@ -210,10 +209,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||||
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService));
|
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService));
|
||||||
const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInlineChat, new ExtHostInteractiveEditor(rpcProtocol, extHostCommands, extHostDocuments, extHostLogService));
|
const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInlineChat, new ExtHostInteractiveEditor(rpcProtocol, extHostCommands, extHostDocuments, extHostLogService));
|
||||||
const extHostChatProvider = rpcProtocol.set(ExtHostContext.ExtHostChatProvider, new ExtHostChatProvider(rpcProtocol, extHostLogService));
|
const extHostChatProvider = rpcProtocol.set(ExtHostContext.ExtHostChatProvider, new ExtHostChatProvider(rpcProtocol, extHostLogService));
|
||||||
const extHostChatAgents = rpcProtocol.set(ExtHostContext.ExtHostChatAgents, new ExtHostChatAgents(rpcProtocol, extHostChatProvider, extHostLogService));
|
|
||||||
const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostChatProvider, extHostLogService));
|
const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostChatProvider, extHostLogService));
|
||||||
const extHostChatVariables = rpcProtocol.set(ExtHostContext.ExtHostChatVariables, new ExtHostChatVariables(rpcProtocol));
|
const extHostChatVariables = rpcProtocol.set(ExtHostContext.ExtHostChatVariables, new ExtHostChatVariables(rpcProtocol));
|
||||||
const extHostChat = rpcProtocol.set(ExtHostContext.ExtHostChat, new ExtHostChat(rpcProtocol, extHostLogService));
|
const extHostChat = rpcProtocol.set(ExtHostContext.ExtHostChat, new ExtHostChat(rpcProtocol));
|
||||||
const extHostAiRelatedInformation = rpcProtocol.set(ExtHostContext.ExtHostAiRelatedInformation, new ExtHostRelatedInformation(rpcProtocol));
|
const extHostAiRelatedInformation = rpcProtocol.set(ExtHostContext.ExtHostAiRelatedInformation, new ExtHostRelatedInformation(rpcProtocol));
|
||||||
const extHostAiEmbeddingVector = rpcProtocol.set(ExtHostContext.ExtHostAiEmbeddingVector, new ExtHostAiEmbeddingVector(rpcProtocol));
|
const extHostAiEmbeddingVector = rpcProtocol.set(ExtHostContext.ExtHostAiEmbeddingVector, new ExtHostAiEmbeddingVector(rpcProtocol));
|
||||||
const extHostIssueReporter = rpcProtocol.set(ExtHostContext.ExtHostIssueReporter, new ExtHostIssueReporter(rpcProtocol));
|
const extHostIssueReporter = rpcProtocol.set(ExtHostContext.ExtHostIssueReporter, new ExtHostIssueReporter(rpcProtocol));
|
||||||
|
@ -1382,10 +1380,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||||
checkProposedApiEnabled(extension, 'chatAgents2');
|
checkProposedApiEnabled(extension, 'chatAgents2');
|
||||||
return extHostChatAgents2.createChatAgent(extension, name, handler);
|
return extHostChatAgents2.createChatAgent(extension, name, handler);
|
||||||
},
|
},
|
||||||
registerAgent(name: string, agent: vscode.ChatAgent, metadata: vscode.ChatAgentMetadata) {
|
|
||||||
checkProposedApiEnabled(extension, 'chatAgents');
|
|
||||||
return extHostChatAgents.registerAgent(extension.identifier, name, agent, metadata);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// namespace: speech
|
// namespace: speech
|
||||||
|
|
|
@ -52,8 +52,7 @@ import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views
|
||||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||||
import { IChatAgentCommand, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { IChatAgentCommand, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IChatMessage, IChatResponseFragment, IChatResponseProviderMetadata } from 'vs/workbench/contrib/chat/common/chatProvider';
|
import { IChatMessage, IChatResponseFragment, IChatResponseProviderMetadata } from 'vs/workbench/contrib/chat/common/chatProvider';
|
||||||
import { IChatAgentDetection, IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatAgentDetection, IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
|
||||||
import { IChatRequestVariableValue, IChatVariableData } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatRequestVariableValue, IChatVariableData } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
import { IInlineChatBulkEditResponse, IInlineChatEditResponse, IInlineChatMessageResponse, IInlineChatProgressItem, IInlineChatRequest, IInlineChatSession, InlineChatResponseFeedbackKind } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
import { IInlineChatBulkEditResponse, IInlineChatEditResponse, IInlineChatMessageResponse, IInlineChatProgressItem, IInlineChatRequest, IInlineChatSession, InlineChatResponseFeedbackKind } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||||
|
@ -63,6 +62,7 @@ import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/
|
||||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||||
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
|
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
|
||||||
import { IWorkspaceSymbol, NotebookPriorityInfo } from 'vs/workbench/contrib/search/common/search';
|
import { IWorkspaceSymbol, NotebookPriorityInfo } from 'vs/workbench/contrib/search/common/search';
|
||||||
|
import { IRawClosedNotebookFileMatch } from 'vs/workbench/contrib/search/common/searchNotebookHelpers';
|
||||||
import { ISpeechProviderMetadata, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService';
|
import { ISpeechProviderMetadata, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService';
|
||||||
import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestResultState, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes';
|
import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestResultState, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes';
|
||||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
|
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||||
|
@ -80,7 +80,6 @@ import { CandidatePort } from 'vs/workbench/services/remote/common/tunnelModel';
|
||||||
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
|
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
|
||||||
import * as search from 'vs/workbench/services/search/common/search';
|
import * as search from 'vs/workbench/services/search/common/search';
|
||||||
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||||
import { IRawClosedNotebookFileMatch } from 'vs/workbench/contrib/search/common/searchNotebookHelpers';
|
|
||||||
|
|
||||||
export interface IWorkspaceData extends IStaticWorkspaceData {
|
export interface IWorkspaceData extends IStaticWorkspaceData {
|
||||||
folders: { uri: UriComponents; name: string; index: number }[];
|
folders: { uri: UriComponents; name: string; index: number }[];
|
||||||
|
@ -1166,12 +1165,6 @@ export interface ExtHostChatProviderShape {
|
||||||
$handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise<void>;
|
$handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadChatAgentsShape extends IDisposable {
|
|
||||||
$registerAgent(handle: number, name: string, metadata: IChatAgentMetadata & { subCommands: IChatAgentCommand[] }): void;
|
|
||||||
$unregisterAgent(handle: number): void;
|
|
||||||
$handleProgressChunk(requestId: number, chunk: IChatSlashFragment): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IExtensionChatAgentMetadata extends Dto<IChatAgentMetadata> {
|
export interface IExtensionChatAgentMetadata extends Dto<IChatAgentMetadata> {
|
||||||
hasSlashCommands?: boolean;
|
hasSlashCommands?: boolean;
|
||||||
hasFollowup?: boolean;
|
hasFollowup?: boolean;
|
||||||
|
@ -1184,10 +1177,6 @@ export interface MainThreadChatAgentsShape2 extends IDisposable {
|
||||||
$handleProgressChunk(requestId: string, chunk: IChatResponseProgressDto, responsePartHandle?: number): Promise<number | void>;
|
$handleProgressChunk(requestId: string, chunk: IChatResponseProgressDto, responsePartHandle?: number): Promise<number | void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostChatAgentsShape {
|
|
||||||
$invokeAgent(handle: number, requestId: number, prompt: string, context: { history: IChatMessage[] }, token: CancellationToken): Promise<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExtHostChatAgentsShape2 {
|
export interface ExtHostChatAgentsShape2 {
|
||||||
$invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise<IChatAgentResult | undefined>;
|
$invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise<IChatAgentResult | undefined>;
|
||||||
$provideSlashCommands(handle: number, token: CancellationToken): Promise<IChatAgentCommand[]>;
|
$provideSlashCommands(handle: number, token: CancellationToken): Promise<IChatAgentCommand[]>;
|
||||||
|
@ -1263,7 +1252,6 @@ export type IDocumentContextDto = {
|
||||||
|
|
||||||
export type IChatResponseProgressDto =
|
export type IChatResponseProgressDto =
|
||||||
| { content: string | IMarkdownString }
|
| { content: string | IMarkdownString }
|
||||||
| { requestId: string }
|
|
||||||
| { placeholder: string }
|
| { placeholder: string }
|
||||||
| { treeData: IChatResponseProgressFileTreeData }
|
| { treeData: IChatResponseProgressFileTreeData }
|
||||||
| { documents: IDocumentContextDto[] }
|
| { documents: IDocumentContextDto[] }
|
||||||
|
@ -1276,18 +1264,13 @@ export interface MainThreadChatShape extends IDisposable {
|
||||||
$acceptChatState(sessionId: number, state: any): Promise<void>;
|
$acceptChatState(sessionId: number, state: any): Promise<void>;
|
||||||
$sendRequestToProvider(providerId: string, message: IChatDynamicRequest): void;
|
$sendRequestToProvider(providerId: string, message: IChatDynamicRequest): void;
|
||||||
$unregisterChatProvider(handle: number): Promise<void>;
|
$unregisterChatProvider(handle: number): Promise<void>;
|
||||||
$acceptResponseProgress(handle: number, sessionId: number, progress: IChatResponseProgressDto, responsePartHandle?: number): Promise<number | void>;
|
|
||||||
$transferChatSession(sessionId: number, toWorkspace: UriComponents): void;
|
$transferChatSession(sessionId: number, toWorkspace: UriComponents): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostChatShape {
|
export interface ExtHostChatShape {
|
||||||
$prepareChat(handle: number, initialState: any, token: CancellationToken): Promise<IChatDto | undefined>;
|
$prepareChat(handle: number, token: CancellationToken): Promise<IChatDto | undefined>;
|
||||||
$provideWelcomeMessage(handle: number, token: CancellationToken): Promise<(string | IMarkdownString | IChatReplyFollowup[])[] | undefined>;
|
$provideWelcomeMessage(handle: number, token: CancellationToken): Promise<(string | IMarkdownString | IChatReplyFollowup[])[] | undefined>;
|
||||||
$provideSampleQuestions(handle: number, token: CancellationToken): Promise<IChatReplyFollowup[] | undefined>;
|
$provideSampleQuestions(handle: number, token: CancellationToken): Promise<IChatReplyFollowup[] | undefined>;
|
||||||
$provideFollowups(handle: number, sessionId: number, token: CancellationToken): Promise<IChatFollowup[] | undefined>;
|
|
||||||
$provideReply(handle: number, sessionId: number, request: IChatRequestDto, token: CancellationToken): Promise<IChatResponseDto | undefined>;
|
|
||||||
$removeRequest(handle: number, sessionId: number, requestId: string): void;
|
|
||||||
$provideSlashCommands(handle: number, sessionId: number, token: CancellationToken): Promise<ISlashCommand[] | undefined>;
|
|
||||||
$releaseSession(sessionId: number): void;
|
$releaseSession(sessionId: number): void;
|
||||||
$onDidPerformUserAction(event: IChatUserActionEvent): Promise<void>;
|
$onDidPerformUserAction(event: IChatUserActionEvent): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -2721,7 +2704,6 @@ export const MainContext = {
|
||||||
MainThreadAuthentication: createProxyIdentifier<MainThreadAuthenticationShape>('MainThreadAuthentication'),
|
MainThreadAuthentication: createProxyIdentifier<MainThreadAuthenticationShape>('MainThreadAuthentication'),
|
||||||
MainThreadBulkEdits: createProxyIdentifier<MainThreadBulkEditsShape>('MainThreadBulkEdits'),
|
MainThreadBulkEdits: createProxyIdentifier<MainThreadBulkEditsShape>('MainThreadBulkEdits'),
|
||||||
MainThreadChatProvider: createProxyIdentifier<MainThreadChatProviderShape>('MainThreadChatProvider'),
|
MainThreadChatProvider: createProxyIdentifier<MainThreadChatProviderShape>('MainThreadChatProvider'),
|
||||||
MainThreadChatAgents: createProxyIdentifier<MainThreadChatAgentsShape>('MainThreadChatAgents'),
|
|
||||||
MainThreadChatAgents2: createProxyIdentifier<MainThreadChatAgentsShape2>('MainThreadChatAgents2'),
|
MainThreadChatAgents2: createProxyIdentifier<MainThreadChatAgentsShape2>('MainThreadChatAgents2'),
|
||||||
MainThreadChatVariables: createProxyIdentifier<MainThreadChatVariablesShape>('MainThreadChatVariables'),
|
MainThreadChatVariables: createProxyIdentifier<MainThreadChatVariablesShape>('MainThreadChatVariables'),
|
||||||
MainThreadClipboard: createProxyIdentifier<MainThreadClipboardShape>('MainThreadClipboard'),
|
MainThreadClipboard: createProxyIdentifier<MainThreadClipboardShape>('MainThreadClipboard'),
|
||||||
|
@ -2844,7 +2826,6 @@ export const ExtHostContext = {
|
||||||
ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
|
ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
|
||||||
ExtHostInlineChat: createProxyIdentifier<ExtHostInlineChatShape>('ExtHostInlineChatShape'),
|
ExtHostInlineChat: createProxyIdentifier<ExtHostInlineChatShape>('ExtHostInlineChatShape'),
|
||||||
ExtHostChat: createProxyIdentifier<ExtHostChatShape>('ExtHostChat'),
|
ExtHostChat: createProxyIdentifier<ExtHostChatShape>('ExtHostChat'),
|
||||||
ExtHostChatAgents: createProxyIdentifier<ExtHostChatAgentsShape>('ExtHostChatAgents'),
|
|
||||||
ExtHostChatAgents2: createProxyIdentifier<ExtHostChatAgentsShape2>('ExtHostChatAgents'),
|
ExtHostChatAgents2: createProxyIdentifier<ExtHostChatAgentsShape2>('ExtHostChatAgents'),
|
||||||
ExtHostChatVariables: createProxyIdentifier<ExtHostChatVariablesShape>('ExtHostChatVariables'),
|
ExtHostChatVariables: createProxyIdentifier<ExtHostChatVariablesShape>('ExtHostChatVariables'),
|
||||||
ExtHostChatProvider: createProxyIdentifier<ExtHostChatProviderShape>('ExtHostChatProvider'),
|
ExtHostChatProvider: createProxyIdentifier<ExtHostChatProviderShape>('ExtHostChatProvider'),
|
||||||
|
|
|
@ -3,19 +3,15 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { raceCancellation } from 'vs/base/common/async';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ExtHostChatShape, IChatDto, IMainContext, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ExtHostChatShape, IChatRequestDto, IChatResponseDto, IChatDto, IMainContext, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import { IChatFollowup, IChatReplyFollowup, IChatUserActionEvent, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatReplyFollowup, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import type * as vscode from 'vscode';
|
import type * as vscode from 'vscode';
|
||||||
|
|
||||||
class ChatProviderWrapper<T> {
|
class ChatProviderWrapper<T> {
|
||||||
|
@ -36,7 +32,6 @@ export class ExtHostChat implements ExtHostChatShape {
|
||||||
private readonly _chatProvider = new Map<number, ChatProviderWrapper<vscode.InteractiveSessionProvider>>();
|
private readonly _chatProvider = new Map<number, ChatProviderWrapper<vscode.InteractiveSessionProvider>>();
|
||||||
|
|
||||||
private readonly _chatSessions = new Map<number, vscode.InteractiveSession>();
|
private readonly _chatSessions = new Map<number, vscode.InteractiveSession>();
|
||||||
// private readonly _providerResponsesByRequestId = new Map<number, { response: vscode.ProviderResult<vscode.InteractiveResponse | vscode.InteractiveResponseForProgress>; sessionId: number }>();
|
|
||||||
|
|
||||||
private readonly _onDidPerformUserAction = new Emitter<vscode.InteractiveSessionUserActionEvent>();
|
private readonly _onDidPerformUserAction = new Emitter<vscode.InteractiveSessionUserActionEvent>();
|
||||||
public readonly onDidPerformUserAction = this._onDidPerformUserAction.event;
|
public readonly onDidPerformUserAction = this._onDidPerformUserAction.event;
|
||||||
|
@ -45,7 +40,6 @@ export class ExtHostChat implements ExtHostChatShape {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
mainContext: IMainContext,
|
mainContext: IMainContext,
|
||||||
private readonly logService: ILogService
|
|
||||||
) {
|
) {
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadChat);
|
this._proxy = mainContext.getProxy(MainContext.MainThreadChat);
|
||||||
}
|
}
|
||||||
|
@ -75,13 +69,13 @@ export class ExtHostChat implements ExtHostChatShape {
|
||||||
this._proxy.$sendRequestToProvider(providerId, message);
|
this._proxy.$sendRequestToProvider(providerId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $prepareChat(handle: number, initialState: any, token: CancellationToken): Promise<IChatDto | undefined> {
|
async $prepareChat(handle: number, token: CancellationToken): Promise<IChatDto | undefined> {
|
||||||
const entry = this._chatProvider.get(handle);
|
const entry = this._chatProvider.get(handle);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await entry.provider.prepareSession(initialState, token);
|
const session = await entry.provider.prepareSession(token);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -124,25 +118,6 @@ export class ExtHostChat implements ExtHostChatShape {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async $provideFollowups(handle: number, sessionId: number, token: CancellationToken): Promise<IChatFollowup[] | undefined> {
|
|
||||||
const entry = this._chatProvider.get(handle);
|
|
||||||
if (!entry) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const realSession = this._chatSessions.get(sessionId);
|
|
||||||
if (!realSession) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.provider.provideFollowups) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawFollowups = await entry.provider.provideFollowups(realSession, token);
|
|
||||||
return rawFollowups?.map(f => typeConvert.ChatFollowup.from(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $provideSampleQuestions(handle: number, token: CancellationToken): Promise<IChatReplyFollowup[] | undefined> {
|
async $provideSampleQuestions(handle: number, token: CancellationToken): Promise<IChatReplyFollowup[] | undefined> {
|
||||||
const entry = this._chatProvider.get(handle);
|
const entry = this._chatProvider.get(handle);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
@ -161,121 +136,6 @@ export class ExtHostChat implements ExtHostChatShape {
|
||||||
return rawFollowups?.map(f => typeConvert.ChatReplyFollowup.from(f));
|
return rawFollowups?.map(f => typeConvert.ChatReplyFollowup.from(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
$removeRequest(handle: number, sessionId: number, requestId: string): void {
|
|
||||||
const entry = this._chatProvider.get(handle);
|
|
||||||
if (!entry) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const realSession = this._chatSessions.get(sessionId);
|
|
||||||
if (!realSession) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.provider.removeRequest) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.provider.removeRequest(realSession, requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $provideReply(handle: number, sessionId: number, request: IChatRequestDto, token: CancellationToken): Promise<IChatResponseDto | undefined> {
|
|
||||||
const entry = this._chatProvider.get(handle);
|
|
||||||
if (!entry) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const realSession = this._chatSessions.get(sessionId);
|
|
||||||
if (!realSession) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestObj: vscode.InteractiveRequest = {
|
|
||||||
session: realSession,
|
|
||||||
message: request.message,
|
|
||||||
variables: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (request.variables) {
|
|
||||||
for (const key of Object.keys(request.variables)) {
|
|
||||||
requestObj.variables[key] = request.variables[key].map(typeConvert.ChatVariable.to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stopWatch = StopWatch.create(false);
|
|
||||||
let firstProgress: number | undefined;
|
|
||||||
const progressObj: vscode.Progress<vscode.InteractiveProgress> = {
|
|
||||||
report: (progress: vscode.InteractiveProgress) => {
|
|
||||||
if (token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof firstProgress === 'undefined') {
|
|
||||||
firstProgress = stopWatch.elapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
const convertedProgress = typeConvert.ChatResponseProgress.from(entry.extension, progress);
|
|
||||||
if ('placeholder' in progress && 'resolvedContent' in progress) {
|
|
||||||
const resolvedContent = Promise.all([this._proxy.$acceptResponseProgress(handle, sessionId, convertedProgress), progress.resolvedContent]);
|
|
||||||
raceCancellation(resolvedContent, token).then((res) => {
|
|
||||||
if (!res) {
|
|
||||||
return; /* Cancelled */
|
|
||||||
}
|
|
||||||
const [progressHandle, progressContent] = res;
|
|
||||||
this._proxy.$acceptResponseProgress(handle, sessionId, progressContent, progressHandle ?? undefined);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._proxy.$acceptResponseProgress(handle, sessionId, convertedProgress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let result: vscode.InteractiveResponseForProgress | undefined | null;
|
|
||||||
try {
|
|
||||||
result = await entry.provider.provideResponseWithProgress(requestObj, progressObj, token);
|
|
||||||
if (!result) {
|
|
||||||
result = { errorDetails: { message: localize('emptyResponse', "Provider returned null response") } };
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
result = { errorDetails: { message: localize('errorResponse', "Error from provider: {0}", err.message), responseIsIncomplete: true } };
|
|
||||||
this.logService.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Check that the session has not been released since the request started
|
|
||||||
if (realSession.saveState && this._chatSessions.has(sessionId)) {
|
|
||||||
const newState = realSession.saveState();
|
|
||||||
this._proxy.$acceptChatState(sessionId, newState);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
this.logService.warn(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
const timings = { firstProgress: firstProgress ?? 0, totalElapsed: stopWatch.elapsed() };
|
|
||||||
return { errorDetails: result.errorDetails, timings };
|
|
||||||
}
|
|
||||||
|
|
||||||
async $provideSlashCommands(handle: number, sessionId: number, token: CancellationToken): Promise<ISlashCommand[] | undefined> {
|
|
||||||
const entry = this._chatProvider.get(handle);
|
|
||||||
if (!entry) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const realSession = this._chatSessions.get(sessionId);
|
|
||||||
if (!realSession) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.provider.provideSlashCommands) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const slashCommands = await entry.provider.provideSlashCommands(realSession, token);
|
|
||||||
return slashCommands?.map(c => (<ISlashCommand>{
|
|
||||||
...c,
|
|
||||||
kind: typeConvert.CompletionItemKind.from(c.kind)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
$releaseSession(sessionId: number) {
|
$releaseSession(sessionId: number) {
|
||||||
this._chatSessions.delete(sessionId);
|
this._chatSessions.delete(sessionId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { DeferredPromise, raceCancellation } from 'vs/base/common/async';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
import { Progress } from 'vs/platform/progress/common/progress';
|
|
||||||
import { ExtHostChatAgentsShape, IMainContext, MainContext, MainThreadChatAgentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider';
|
|
||||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
|
||||||
import { ChatMessageRole } from 'vs/workbench/api/common/extHostTypes';
|
|
||||||
import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider';
|
|
||||||
import type * as vscode from 'vscode';
|
|
||||||
|
|
||||||
export class ExtHostChatAgents implements ExtHostChatAgentsShape {
|
|
||||||
|
|
||||||
private static _idPool = 0;
|
|
||||||
|
|
||||||
private readonly _agents = new Map<number, { extension: ExtensionIdentifier; agent: vscode.ChatAgent }>();
|
|
||||||
private readonly _proxy: MainThreadChatAgentsShape;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
mainContext: IMainContext,
|
|
||||||
private readonly _extHostChatProvider: ExtHostChatProvider,
|
|
||||||
private readonly _logService: ILogService,
|
|
||||||
) {
|
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerAgent(extension: ExtensionIdentifier, name: string, agent: vscode.ChatAgent, metadata: vscode.ChatAgentMetadata): IDisposable {
|
|
||||||
const handle = ExtHostChatAgents._idPool++;
|
|
||||||
this._agents.set(handle, { extension, agent });
|
|
||||||
this._proxy.$registerAgent(handle, name, metadata);
|
|
||||||
|
|
||||||
return toDisposable(() => {
|
|
||||||
this._proxy.$unregisterAgent(handle);
|
|
||||||
this._agents.delete(handle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async $invokeAgent(handle: number, requestId: number, prompt: string, context: { history: IChatMessage[] }, token: CancellationToken): Promise<any> {
|
|
||||||
const data = this._agents.get(handle);
|
|
||||||
if (!data) {
|
|
||||||
this._logService.warn(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let done = false;
|
|
||||||
function throwIfDone() {
|
|
||||||
if (done) {
|
|
||||||
throw new Error('Only valid while executing the command');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const commandExecution = new DeferredPromise<void>();
|
|
||||||
token.onCancellationRequested(() => commandExecution.complete());
|
|
||||||
setTimeout(() => commandExecution.complete(), 10 * 1000);
|
|
||||||
this._extHostChatProvider.allowListExtensionWhile(data.extension, commandExecution.p);
|
|
||||||
|
|
||||||
const task = data.agent(
|
|
||||||
{ role: ChatMessageRole.User, content: prompt },
|
|
||||||
{ history: context.history.map(typeConvert.ChatMessage.to) },
|
|
||||||
new Progress<vscode.ChatAgentResponse>(p => {
|
|
||||||
throwIfDone();
|
|
||||||
this._proxy.$handleProgressChunk(requestId, { content: isInteractiveProgressFileTree(p.message) ? p.message : p.message.value });
|
|
||||||
}),
|
|
||||||
token
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await raceCancellation(Promise.resolve(task).then((v) => {
|
|
||||||
if (v && 'followUp' in v) {
|
|
||||||
const convertedFollowup = v?.followUp?.map(f => typeConvert.ChatFollowup.from(f));
|
|
||||||
return { followUp: convertedFollowup };
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}), token);
|
|
||||||
} finally {
|
|
||||||
done = true;
|
|
||||||
commandExecution.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isInteractiveProgressFileTree(thing: unknown): thing is vscode.InteractiveProgressFileTree {
|
|
||||||
return !!thing && typeof thing === 'object' && 'treeData' in thing;
|
|
||||||
}
|
|
|
@ -2157,20 +2157,10 @@ export namespace DataTransfer {
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ChatReplyFollowup {
|
export namespace ChatReplyFollowup {
|
||||||
export function to(followup: IChatReplyFollowup): vscode.InteractiveSessionReplyFollowup {
|
|
||||||
return {
|
|
||||||
message: followup.message,
|
|
||||||
metadata: followup.metadata,
|
|
||||||
title: followup.title,
|
|
||||||
tooltip: followup.tooltip,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function from(followup: vscode.InteractiveSessionReplyFollowup): IChatReplyFollowup {
|
export function from(followup: vscode.InteractiveSessionReplyFollowup): IChatReplyFollowup {
|
||||||
return {
|
return {
|
||||||
kind: 'reply',
|
kind: 'reply',
|
||||||
message: followup.message,
|
message: followup.message,
|
||||||
metadata: followup.metadata,
|
|
||||||
title: followup.title,
|
title: followup.title,
|
||||||
tooltip: followup.tooltip,
|
tooltip: followup.tooltip,
|
||||||
};
|
};
|
||||||
|
@ -2178,7 +2168,7 @@ export namespace ChatReplyFollowup {
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ChatFollowup {
|
export namespace ChatFollowup {
|
||||||
export function from(followup: string | vscode.InteractiveSessionFollowup): IChatFollowup {
|
export function from(followup: string | vscode.ChatAgentFollowup): IChatFollowup {
|
||||||
if (typeof followup === 'string') {
|
if (typeof followup === 'string') {
|
||||||
return <IChatReplyFollowup>{ title: followup, message: followup, kind: 'reply' };
|
return <IChatReplyFollowup>{ title: followup, message: followup, kind: 'reply' };
|
||||||
} else if ('commandId' in followup) {
|
} else if ('commandId' in followup) {
|
||||||
|
@ -2303,11 +2293,9 @@ export namespace InteractiveEditorResponseFeedbackKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ChatResponseProgress {
|
export namespace ChatResponseProgress {
|
||||||
export function from(extension: IExtensionDescription, progress: vscode.InteractiveProgress | vscode.ChatAgentExtendedProgress): extHostProtocol.IChatResponseProgressDto {
|
export function from(extension: IExtensionDescription, progress: vscode.ChatAgentExtendedProgress): extHostProtocol.IChatResponseProgressDto {
|
||||||
if ('placeholder' in progress && 'resolvedContent' in progress) {
|
if ('placeholder' in progress && 'resolvedContent' in progress) {
|
||||||
return { placeholder: progress.placeholder };
|
return { placeholder: progress.placeholder };
|
||||||
} else if ('responseId' in progress) {
|
|
||||||
return { requestId: progress.responseId };
|
|
||||||
} else if ('markdownContent' in progress) {
|
} else if ('markdownContent' in progress) {
|
||||||
checkProposedApiEnabled(extension, 'chatAgents2Additions');
|
checkProposedApiEnabled(extension, 'chatAgents2Additions');
|
||||||
return { content: MarkdownString.from(progress.markdownContent) };
|
return { content: MarkdownString.from(progress.markdownContent) };
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatAct
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||||
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatCopyAction, IChatService, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
import { CTX_INLINE_CHAT_VISIBLE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
import { CTX_INLINE_CHAT_VISIBLE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||||
import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||||
|
@ -111,9 +111,8 @@ export function registerChatCodeBlockActions() {
|
||||||
agentId: context.element.agent?.id,
|
agentId: context.element.agent?.id,
|
||||||
sessionId: context.element.sessionId,
|
sessionId: context.element.sessionId,
|
||||||
requestId: context.element.requestId,
|
requestId: context.element.requestId,
|
||||||
action: <IChatCopyAction>{
|
action: {
|
||||||
kind: 'copy',
|
kind: 'copy',
|
||||||
responseId: context.element.providerResponseId,
|
|
||||||
codeBlockIndex: context.codeBlockIndex,
|
codeBlockIndex: context.codeBlockIndex,
|
||||||
copyType: InteractiveSessionCopyKind.Toolbar,
|
copyType: InteractiveSessionCopyKind.Toolbar,
|
||||||
copiedCharacters: context.code.length,
|
copiedCharacters: context.code.length,
|
||||||
|
@ -149,24 +148,21 @@ export function registerChatCodeBlockActions() {
|
||||||
const totalCharacters = editorModel.getValueLength();
|
const totalCharacters = editorModel.getValueLength();
|
||||||
|
|
||||||
// Report copy to extensions
|
// Report copy to extensions
|
||||||
if (context.element.providerResponseId) {
|
const chatService = accessor.get(IChatService);
|
||||||
const chatService = accessor.get(IChatService);
|
chatService.notifyUserAction({
|
||||||
chatService.notifyUserAction({
|
providerId: context.element.providerId,
|
||||||
providerId: context.element.providerId,
|
agentId: context.element.agent?.id,
|
||||||
agentId: context.element.agent?.id,
|
sessionId: context.element.sessionId,
|
||||||
sessionId: context.element.sessionId,
|
requestId: context.element.requestId,
|
||||||
requestId: context.element.requestId,
|
action: {
|
||||||
action: {
|
kind: 'copy',
|
||||||
kind: 'copy',
|
codeBlockIndex: context.codeBlockIndex,
|
||||||
codeBlockIndex: context.codeBlockIndex,
|
copyType: InteractiveSessionCopyKind.Action,
|
||||||
responseId: context.element.providerResponseId,
|
copiedText,
|
||||||
copyType: InteractiveSessionCopyKind.Action,
|
copiedCharacters: copiedText.length,
|
||||||
copiedText,
|
totalCharacters,
|
||||||
copiedCharacters: copiedText.length,
|
}
|
||||||
totalCharacters,
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy full cell if no selection, otherwise fall back on normal editor implementation
|
// Copy full cell if no selection, otherwise fall back on normal editor implementation
|
||||||
if (noSelection) {
|
if (noSelection) {
|
||||||
|
@ -337,7 +333,6 @@ export function registerChatCodeBlockActions() {
|
||||||
requestId: context.element.requestId,
|
requestId: context.element.requestId,
|
||||||
action: {
|
action: {
|
||||||
kind: 'insert',
|
kind: 'insert',
|
||||||
responseId: context.element.providerResponseId!,
|
|
||||||
codeBlockIndex: context.codeBlockIndex,
|
codeBlockIndex: context.codeBlockIndex,
|
||||||
totalCharacters: context.code.length,
|
totalCharacters: context.code.length,
|
||||||
}
|
}
|
||||||
|
@ -386,7 +381,6 @@ export function registerChatCodeBlockActions() {
|
||||||
requestId: context.element.requestId,
|
requestId: context.element.requestId,
|
||||||
action: {
|
action: {
|
||||||
kind: 'insert',
|
kind: 'insert',
|
||||||
responseId: context.element.providerResponseId!,
|
|
||||||
codeBlockIndex: context.codeBlockIndex,
|
codeBlockIndex: context.codeBlockIndex,
|
||||||
totalCharacters: context.code.length,
|
totalCharacters: context.code.length,
|
||||||
newFile: true
|
newFile: true
|
||||||
|
@ -482,7 +476,6 @@ export function registerChatCodeBlockActions() {
|
||||||
requestId: context.element.requestId,
|
requestId: context.element.requestId,
|
||||||
action: {
|
action: {
|
||||||
kind: 'runInTerminal',
|
kind: 'runInTerminal',
|
||||||
responseId: context.element.providerResponseId!,
|
|
||||||
codeBlockIndex: context.codeBlockIndex,
|
codeBlockIndex: context.codeBlockIndex,
|
||||||
languageId: context.languageId,
|
languageId: context.languageId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,6 @@ export function registerChatTitleActions() {
|
||||||
action: {
|
action: {
|
||||||
kind: 'vote',
|
kind: 'vote',
|
||||||
direction: InteractiveSessionVoteDirection.Up,
|
direction: InteractiveSessionVoteDirection.Up,
|
||||||
responseId: item.providerResponseId!,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
item.setVote(InteractiveSessionVoteDirection.Up);
|
item.setVote(InteractiveSessionVoteDirection.Up);
|
||||||
|
@ -103,7 +102,6 @@ export function registerChatTitleActions() {
|
||||||
action: {
|
action: {
|
||||||
kind: 'vote',
|
kind: 'vote',
|
||||||
direction: InteractiveSessionVoteDirection.Down,
|
direction: InteractiveSessionVoteDirection.Down,
|
||||||
responseId: item.providerResponseId!,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
item.setVote(InteractiveSessionVoteDirection.Down);
|
item.setVote(InteractiveSessionVoteDirection.Down);
|
||||||
|
@ -222,12 +220,12 @@ export function registerChatTitleActions() {
|
||||||
item = widget?.getFocus();
|
item = widget?.getFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const providerRequestId = isRequestVM(item) ? item.providerRequestId :
|
const requestId = isRequestVM(item) ? item.id :
|
||||||
isResponseVM(item) ? item.providerResponseId : undefined;
|
isResponseVM(item) ? item.requestId : undefined;
|
||||||
|
|
||||||
if (providerRequestId) {
|
if (requestId) {
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.removeRequest(item.sessionId, providerRequestId);
|
chatService.removeRequest(item.sessionId, requestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,14 +3,13 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|
||||||
import { ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IChatWidgetContrib } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { IChatWidgetContrib } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
|
|
||||||
export const IChatWidgetService = createDecorator<IChatWidgetService>('chatWidgetService');
|
export const IChatWidgetService = createDecorator<IChatWidgetService>('chatWidgetService');
|
||||||
export const IQuickChatService = createDecorator<IQuickChatService>('quickChatService');
|
export const IQuickChatService = createDecorator<IQuickChatService>('quickChatService');
|
||||||
|
@ -121,7 +120,6 @@ export interface IChatWidget {
|
||||||
focusLastMessage(): void;
|
focusLastMessage(): void;
|
||||||
focusInput(): void;
|
focusInput(): void;
|
||||||
hasInputFocus(): boolean;
|
hasInputFocus(): boolean;
|
||||||
getSlashCommands(): Promise<ISlashCommand[] | undefined>;
|
|
||||||
getCodeBlockInfoForEditor(uri: URI): IChatCodeBlockInfo | undefined;
|
getCodeBlockInfoForEditor(uri: URI): IChatCodeBlockInfo | undefined;
|
||||||
getCodeBlockInfosForResponse(response: IChatResponseViewModel): IChatCodeBlockInfo[];
|
getCodeBlockInfosForResponse(response: IChatResponseViewModel): IChatCodeBlockInfo[];
|
||||||
getFileTreeInfosForResponse(response: IChatResponseViewModel): IChatFileTreeInfo[];
|
getFileTreeInfosForResponse(response: IChatResponseViewModel): IChatFileTreeInfo[];
|
||||||
|
|
|
@ -54,10 +54,10 @@ import { convertParsedRequestToMarkdown, reduceInlineContentReferences, walkTree
|
||||||
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
||||||
import { CodeBlockPart, ICodeBlockData, ICodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
import { CodeBlockPart, ICodeBlockData, ICodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||||
import { IChatAgentMetadata } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { IChatAgentMetadata } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_HAS_PROVIDER_ID, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IPlaceholderMarkdownString } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { IPlaceholderMarkdownString } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { chatAgentLeader, chatSubcommandLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { chatAgentLeader, chatSubcommandLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatContentReference, IChatReplyFollowup, IChatResponseProgressFileTreeData, IChatService, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatContentReference, IChatReplyFollowup, IChatResponseProgressFileTreeData, IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatResponseMarkdownRenderData, IChatResponseRenderData, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { IChatResponseMarkdownRenderData, IChatResponseRenderData, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter';
|
import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter';
|
||||||
import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/files/browser/views/explorerView';
|
import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/files/browser/views/explorerView';
|
||||||
|
@ -89,7 +89,6 @@ const forceVerboseLayoutTracing = false;
|
||||||
|
|
||||||
export interface IChatRendererDelegate {
|
export interface IChatRendererDelegate {
|
||||||
getListLength(): number;
|
getListLength(): number;
|
||||||
getSlashCommands(): ISlashCommand[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatListItemRendererOptions {
|
export interface IChatListItemRendererOptions {
|
||||||
|
@ -264,7 +263,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||||
|
|
||||||
CONTEXT_RESPONSE.bindTo(templateData.contextKeyService).set(isResponseVM(element));
|
CONTEXT_RESPONSE.bindTo(templateData.contextKeyService).set(isResponseVM(element));
|
||||||
CONTEXT_REQUEST.bindTo(templateData.contextKeyService).set(isRequestVM(element));
|
CONTEXT_REQUEST.bindTo(templateData.contextKeyService).set(isRequestVM(element));
|
||||||
CONTEXT_RESPONSE_HAS_PROVIDER_ID.bindTo(templateData.contextKeyService).set(isResponseVM(element) && !!element.providerResponseId);
|
|
||||||
if (isResponseVM(element)) {
|
if (isResponseVM(element)) {
|
||||||
CONTEXT_RESPONSE_VOTE.bindTo(templateData.contextKeyService).set(element.vote === InteractiveSessionVoteDirection.Up ? 'up' : element.vote === InteractiveSessionVoteDirection.Down ? 'down' : '');
|
CONTEXT_RESPONSE_VOTE.bindTo(templateData.contextKeyService).set(element.vote === InteractiveSessionVoteDirection.Up ? 'up' : element.vote === InteractiveSessionVoteDirection.Down ? 'down' : '');
|
||||||
} else {
|
} else {
|
||||||
|
@ -465,7 +463,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||||
private renderWelcomeMessage(element: IChatWelcomeMessageViewModel, templateData: IChatListItemTemplate, height?: number) {
|
private renderWelcomeMessage(element: IChatWelcomeMessageViewModel, templateData: IChatListItemTemplate, height?: number) {
|
||||||
dom.clearNode(templateData.value);
|
dom.clearNode(templateData.value);
|
||||||
dom.clearNode(templateData.referencesListContainer);
|
dom.clearNode(templateData.referencesListContainer);
|
||||||
const slashCommands = this.delegate.getSlashCommands();
|
|
||||||
|
|
||||||
for (const item of element.content) {
|
for (const item of element.content) {
|
||||||
if (Array.isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
|
@ -477,11 +474,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||||
templateData.contextKeyService));
|
templateData.contextKeyService));
|
||||||
} else {
|
} else {
|
||||||
const result = this.renderMarkdown(item as IMarkdownString, element, templateData);
|
const result = this.renderMarkdown(item as IMarkdownString, element, templateData);
|
||||||
for (const codeElement of result.element.querySelectorAll('code')) {
|
|
||||||
if (codeElement.textContent && slashCommands.find(command => codeElement.textContent === `/${command.command}`)) {
|
|
||||||
codeElement.classList.add('interactive-slash-command');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templateData.value.appendChild(result.element);
|
templateData.value.appendChild(result.element);
|
||||||
templateData.elementDisposables.add(result);
|
templateData.elementDisposables.add(result);
|
||||||
}
|
}
|
||||||
|
@ -779,11 +771,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||||
const disposables = new DisposableStore();
|
const disposables = new DisposableStore();
|
||||||
let codeBlockIndex = 0;
|
let codeBlockIndex = 0;
|
||||||
|
|
||||||
// TODO if the slash commands stay completely dynamic, this isn't quite right
|
markdown = new MarkdownString(markdown.value, {
|
||||||
const slashCommands = this.delegate.getSlashCommands();
|
|
||||||
const usedSlashCommand = slashCommands.find(s => markdown.value.startsWith(`/${s.command} `));
|
|
||||||
const toRender = usedSlashCommand ? markdown.value.slice(usedSlashCommand.command.length + 2) : markdown.value;
|
|
||||||
markdown = new MarkdownString(toRender, {
|
|
||||||
isTrusted: {
|
isTrusted: {
|
||||||
// Disable all other config options except isTrusted
|
// Disable all other config options except isTrusted
|
||||||
enabledCommands: typeof markdown.isTrusted === 'object' ? markdown.isTrusted?.enabledCommands : [] ?? []
|
enabledCommands: typeof markdown.isTrusted === 'object' ? markdown.isTrusted?.enabledCommands : [] ?? []
|
||||||
|
@ -831,15 +819,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||||
|
|
||||||
walkTreeAndAnnotateReferenceLinks(result.element);
|
walkTreeAndAnnotateReferenceLinks(result.element);
|
||||||
|
|
||||||
if (usedSlashCommand) {
|
|
||||||
const slashCommandElement = $('span.interactive-slash-command', { title: usedSlashCommand.detail }, `/${usedSlashCommand.command} `);
|
|
||||||
if (result.element.firstChild?.nodeName.toLowerCase() === 'p') {
|
|
||||||
result.element.firstChild.insertBefore(slashCommandElement, result.element.firstChild.firstChild);
|
|
||||||
} else {
|
|
||||||
result.element.insertBefore($('p', undefined, slashCommandElement), result.element.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orderedDisposablesList.reverse().forEach(d => disposables.add(d));
|
orderedDisposablesList.reverse().forEach(d => disposables.add(d));
|
||||||
return {
|
return {
|
||||||
element: result.element,
|
element: result.element,
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
|
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
|
||||||
import { disposableTimeout } from 'vs/base/common/async';
|
import { disposableTimeout } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { Disposable, DisposableStore, IDisposable, MutableDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable, MutableDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
@ -23,7 +22,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||||
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
|
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IViewsService } from 'vs/workbench/common/views';
|
import { IViewsService } from 'vs/workbench/common/views';
|
||||||
import { ChatTreeItem, IChatWidgetViewOptions, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat';
|
import { ChatTreeItem, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext, IChatWidgetViewOptions } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
||||||
import { ChatAccessibilityProvider, ChatListDelegate, ChatListItemRenderer, IChatListItemRendererOptions, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
|
import { ChatAccessibilityProvider, ChatListDelegate, ChatListItemRenderer, IChatListItemRendererOptions, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
|
||||||
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
||||||
|
@ -31,7 +30,7 @@ import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||||
import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||||
import { ChatModelInitState, IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatModelInitState, IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IChatReplyFollowup, IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatReplyFollowup, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { ChatViewModel, IChatResponseViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { ChatViewModel, IChatResponseViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
|
|
||||||
const $ = dom.$;
|
const $ = dom.$;
|
||||||
|
@ -109,15 +108,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
this.viewModelDisposables.add(viewModel);
|
this.viewModelDisposables.add(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.slashCommandsPromise = undefined;
|
|
||||||
this.lastSlashCommands = undefined;
|
|
||||||
|
|
||||||
this.getSlashCommands().then(() => {
|
|
||||||
if (!this._isDisposed) {
|
|
||||||
this.onDidChangeItems();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this._onDidChangeViewModel.fire();
|
this._onDidChangeViewModel.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,9 +115,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
return this._viewModel;
|
return this._viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private lastSlashCommands: ISlashCommand[] | undefined;
|
|
||||||
private slashCommandsPromise: Promise<ISlashCommand[] | undefined> | undefined;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly viewContext: IChatWidgetViewContext,
|
readonly viewContext: IChatWidgetViewContext,
|
||||||
private readonly viewOptions: IChatWidgetViewOptions,
|
private readonly viewOptions: IChatWidgetViewOptions,
|
||||||
|
@ -164,12 +151,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
return this.inputPart.inputUri;
|
return this.inputPart.inputUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isDisposed: boolean = false;
|
|
||||||
public override dispose(): void {
|
|
||||||
this._isDisposed = true;
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
render(parent: HTMLElement): void {
|
render(parent: HTMLElement): void {
|
||||||
const viewId = 'viewId' in this.viewContext ? this.viewContext.viewId : undefined;
|
const viewId = 'viewId' in this.viewContext ? this.viewContext.viewId : undefined;
|
||||||
this.editorOptions = this._register(this.instantiationService.createInstance(ChatEditorOptions, viewId, this.styles.listForeground, this.styles.inputEditorBackground, this.styles.resultEditorBackground));
|
this.editorOptions = this._register(this.instantiationService.createInstance(ChatEditorOptions, viewId, this.styles.listForeground, this.styles.inputEditorBackground, this.styles.resultEditorBackground));
|
||||||
|
@ -260,7 +241,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
// TODO? We can give the welcome message a proper VM or get rid of the rest of the VMs
|
// TODO? We can give the welcome message a proper VM or get rid of the rest of the VMs
|
||||||
((isWelcomeVM(element) && this.viewModel) ? `_${ChatModelInitState[this.viewModel.initState]}` : '') +
|
((isWelcomeVM(element) && this.viewModel) ? `_${ChatModelInitState[this.viewModel.initState]}` : '') +
|
||||||
// Ensure re-rendering an element once slash commands are loaded, so the colorization can be applied.
|
// Ensure re-rendering an element once slash commands are loaded, so the colorization can be applied.
|
||||||
`${(isRequestVM(element) || isWelcomeVM(element)) && !!this.lastSlashCommands ? '_scLoaded' : ''}` +
|
`${(isRequestVM(element) || isWelcomeVM(element)) /* && !!this.lastSlashCommands ? '_scLoaded' : '' */}` +
|
||||||
// If a response is in the process of progressive rendering, we need to ensure that it will
|
// If a response is in the process of progressive rendering, we need to ensure that it will
|
||||||
// be re-rendered so progressive rendering is restarted, even if the model wasn't updated.
|
// be re-rendered so progressive rendering is restarted, even if the model wasn't updated.
|
||||||
`${isResponseVM(element) && element.renderData ? `_${this.visibleChangeCount}` : ''}` +
|
`${isResponseVM(element) && element.renderData ? `_${this.visibleChangeCount}` : ''}` +
|
||||||
|
@ -309,27 +290,11 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSlashCommands(): Promise<ISlashCommand[] | undefined> {
|
|
||||||
if (!this.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.slashCommandsPromise) {
|
|
||||||
this.slashCommandsPromise = this.chatService.getSlashCommands(this.viewModel.sessionId, CancellationToken.None).then(commands => {
|
|
||||||
this.lastSlashCommands = commands ?? [];
|
|
||||||
return this.lastSlashCommands;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.slashCommandsPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
private createList(listContainer: HTMLElement, options: IChatListItemRendererOptions): void {
|
private createList(listContainer: HTMLElement, options: IChatListItemRendererOptions): void {
|
||||||
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.contextKeyService]));
|
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.contextKeyService]));
|
||||||
const delegate = scopedInstantiationService.createInstance(ChatListDelegate);
|
const delegate = scopedInstantiationService.createInstance(ChatListDelegate);
|
||||||
const rendererDelegate: IChatRendererDelegate = {
|
const rendererDelegate: IChatRendererDelegate = {
|
||||||
getListLength: () => this.tree.getNode(null).visibleChildrenCount,
|
getListLength: () => this.tree.getNode(null).visibleChildrenCount,
|
||||||
getSlashCommands: () => this.lastSlashCommands ?? [],
|
|
||||||
};
|
};
|
||||||
this.renderer = this._register(scopedInstantiationService.createInstance(
|
this.renderer = this._register(scopedInstantiationService.createInstance(
|
||||||
ChatListItemRenderer,
|
ChatListItemRenderer,
|
||||||
|
@ -462,7 +427,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
this.container.setAttribute('data-session-id', model.sessionId);
|
this.container.setAttribute('data-session-id', model.sessionId);
|
||||||
this.viewModel = this.instantiationService.createInstance(ChatViewModel, model);
|
this.viewModel = this.instantiationService.createInstance(ChatViewModel, model);
|
||||||
this.viewModelDisposables.add(this.viewModel.onDidChange(e => {
|
this.viewModelDisposables.add(this.viewModel.onDidChange(e => {
|
||||||
this.slashCommandsPromise = undefined;
|
|
||||||
this.requestInProgress.set(this.viewModel!.requestInProgress);
|
this.requestInProgress.set(this.viewModel!.requestInProgress);
|
||||||
this.onDidChangeItems();
|
this.onDidChangeItems();
|
||||||
if (e?.kind === 'addRequest') {
|
if (e?.kind === 'addRequest') {
|
||||||
|
@ -536,8 +500,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
'query' in opts ? opts.query :
|
'query' in opts ? opts.query :
|
||||||
`${opts.prefix} ${editorValue}`;
|
`${opts.prefix} ${editorValue}`;
|
||||||
const isUserQuery = !opts || 'query' in opts;
|
const isUserQuery = !opts || 'query' in opts;
|
||||||
const usedSlashCommand = this.lookupSlashCommand(input);
|
const result = await this.chatService.sendRequest(this.viewModel.sessionId, input);
|
||||||
const result = await this.chatService.sendRequest(this.viewModel.sessionId, input, usedSlashCommand);
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
this.inputPart.acceptInput(isUserQuery ? input : undefined);
|
this.inputPart.acceptInput(isUserQuery ? input : undefined);
|
||||||
|
@ -552,10 +515,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lookupSlashCommand(input: string): ISlashCommand | undefined {
|
|
||||||
return this.lastSlashCommands?.find(sc => input.startsWith(`/${sc.command}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
getCodeBlockInfosForResponse(response: IChatResponseViewModel): IChatCodeBlockInfo[] {
|
getCodeBlockInfosForResponse(response: IChatResponseViewModel): IChatCodeBlockInfo[] {
|
||||||
return this.renderer.getCodeBlockInfosForResponse(response);
|
return this.renderer.getCodeBlockInfosForResponse(response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { chatSlashCommandBackground, chatSlashCommandForeground } from 'vs/workb
|
||||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||||
import { IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
|
@ -49,7 +50,7 @@ class InputEditorDecorations extends Disposable {
|
||||||
|
|
||||||
public readonly id = 'inputEditorDecorations';
|
public readonly id = 'inputEditorDecorations';
|
||||||
|
|
||||||
private readonly previouslyUsedSlashCommands = new Set<string>();
|
private readonly previouslyUsedAgents = new Set<string>();
|
||||||
|
|
||||||
private readonly viewModelDisposables = this._register(new MutableDisposable());
|
private readonly viewModelDisposables = this._register(new MutableDisposable());
|
||||||
|
|
||||||
|
@ -71,16 +72,12 @@ class InputEditorDecorations extends Disposable {
|
||||||
this._register(this.widget.inputEditor.onDidChangeModelContent(() => this.updateInputEditorDecorations()));
|
this._register(this.widget.inputEditor.onDidChangeModelContent(() => this.updateInputEditorDecorations()));
|
||||||
this._register(this.widget.onDidChangeViewModel(() => {
|
this._register(this.widget.onDidChangeViewModel(() => {
|
||||||
this.registerViewModelListeners();
|
this.registerViewModelListeners();
|
||||||
this.previouslyUsedSlashCommands.clear();
|
this.previouslyUsedAgents.clear();
|
||||||
this.updateInputEditorDecorations();
|
this.updateInputEditorDecorations();
|
||||||
}));
|
}));
|
||||||
this._register(this.chatService.onDidSubmitSlashCommand((e) => {
|
this._register(this.chatService.onDidSubmitAgent((e) => {
|
||||||
if (e.sessionId === this.widget.viewModel?.sessionId) {
|
if (e.sessionId === this.widget.viewModel?.sessionId) {
|
||||||
if ('agent' in e) {
|
this.previouslyUsedAgents.add(agentAndCommandToKey(e.agent.id, e.slashCommand.name));
|
||||||
this.previouslyUsedSlashCommands.add(agentAndCommandToKey(e.agent.id, e.slashCommand.name));
|
|
||||||
} else {
|
|
||||||
this.previouslyUsedSlashCommands.add(e.slashCommand);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -187,7 +184,7 @@ class InputEditorDecorations extends Disposable {
|
||||||
const onlyAgentCommandAndWhitespace = agentPart && agentSubcommandPart && parsedRequest.every(p => p instanceof ChatRequestTextPart && !p.text.trim().length || p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart);
|
const onlyAgentCommandAndWhitespace = agentPart && agentSubcommandPart && parsedRequest.every(p => p instanceof ChatRequestTextPart && !p.text.trim().length || p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart);
|
||||||
if (onlyAgentCommandAndWhitespace) {
|
if (onlyAgentCommandAndWhitespace) {
|
||||||
// Agent reference and subcommand with no other text - show the placeholder
|
// Agent reference and subcommand with no other text - show the placeholder
|
||||||
const isFollowupSlashCommand = this.previouslyUsedSlashCommands.has(agentAndCommandToKey(agentPart.agent.id, agentSubcommandPart.command.name));
|
const isFollowupSlashCommand = this.previouslyUsedAgents.has(agentAndCommandToKey(agentPart.agent.id, agentSubcommandPart.command.name));
|
||||||
const shouldRenderFollowupPlaceholder = isFollowupSlashCommand && agentSubcommandPart.command.followupPlaceholder;
|
const shouldRenderFollowupPlaceholder = isFollowupSlashCommand && agentSubcommandPart.command.followupPlaceholder;
|
||||||
if (agentSubcommandPart?.command.description) {
|
if (agentSubcommandPart?.command.description) {
|
||||||
placeholderDecoration = [{
|
placeholderDecoration = [{
|
||||||
|
@ -210,7 +207,7 @@ class InputEditorDecorations extends Disposable {
|
||||||
const onlySlashCommandAndWhitespace = slashCommandPart && parsedRequest.every(p => p instanceof ChatRequestTextPart && !p.text.trim().length || p instanceof ChatRequestSlashCommandPart);
|
const onlySlashCommandAndWhitespace = slashCommandPart && parsedRequest.every(p => p instanceof ChatRequestTextPart && !p.text.trim().length || p instanceof ChatRequestSlashCommandPart);
|
||||||
if (onlySlashCommandAndWhitespace) {
|
if (onlySlashCommandAndWhitespace) {
|
||||||
// Command reference with no other text - show the placeholder
|
// Command reference with no other text - show the placeholder
|
||||||
const isFollowupSlashCommand = this.previouslyUsedSlashCommands.has(slashCommandPart.slashCommand.command);
|
const isFollowupSlashCommand = this.previouslyUsedAgents.has(slashCommandPart.slashCommand.command);
|
||||||
const shouldRenderFollowupPlaceholder = isFollowupSlashCommand && slashCommandPart.slashCommand.followupPlaceholder;
|
const shouldRenderFollowupPlaceholder = isFollowupSlashCommand && slashCommandPart.slashCommand.followupPlaceholder;
|
||||||
if (shouldRenderFollowupPlaceholder || slashCommandPart.slashCommand.detail) {
|
if (shouldRenderFollowupPlaceholder || slashCommandPart.slashCommand.detail) {
|
||||||
placeholderDecoration = [{
|
placeholderDecoration = [{
|
||||||
|
@ -264,15 +261,12 @@ class InputEditorSlashCommandMode extends Disposable {
|
||||||
@IChatService private readonly chatService: IChatService
|
@IChatService private readonly chatService: IChatService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._register(this.chatService.onDidSubmitSlashCommand(e => {
|
this._register(this.chatService.onDidSubmitAgent(e => {
|
||||||
if (this.widget.viewModel?.sessionId !== e.sessionId) {
|
if (this.widget.viewModel?.sessionId !== e.sessionId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ('agent' in e) {
|
|
||||||
this.repopulateAgentCommand(e.agent, e.slashCommand);
|
this.repopulateAgentCommand(e.agent, e.slashCommand);
|
||||||
} else {
|
|
||||||
this.repopulateSlashCommand(e.slashCommand);
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,20 +277,6 @@ class InputEditorSlashCommandMode extends Disposable {
|
||||||
this.widget.inputEditor.setPosition({ lineNumber: 1, column: value.length + 1 });
|
this.widget.inputEditor.setPosition({ lineNumber: 1, column: value.length + 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async repopulateSlashCommand(slashCommand: string) {
|
|
||||||
const slashCommands = await this.widget.getSlashCommands();
|
|
||||||
|
|
||||||
if (this.widget.inputEditor.getValue().trim().length !== 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slashCommands?.find(c => c.command === slashCommand)?.shouldRepopulate) {
|
|
||||||
const value = `/${slashCommand} `;
|
|
||||||
this.widget.inputEditor.setValue(value);
|
|
||||||
this.widget.inputEditor.setPosition({ lineNumber: 1, column: value.length + 1 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatWidget.CONTRIBS.push(InputEditorDecorations, InputEditorSlashCommandMode);
|
ChatWidget.CONTRIBS.push(InputEditorDecorations, InputEditorSlashCommandMode);
|
||||||
|
@ -306,11 +286,12 @@ class SlashCommandCompletions extends Disposable {
|
||||||
@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
|
@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
|
||||||
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
|
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
@IChatSlashCommandService private readonly chatSlashCommandService: IChatSlashCommandService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, {
|
this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, {
|
||||||
_debugDisplayName: 'chatSlashCommand',
|
_debugDisplayName: 'globalSlashCommands',
|
||||||
triggerCharacters: ['/'],
|
triggerCharacters: ['/'],
|
||||||
provideCompletionItems: async (model: ITextModel, _position: Position, _context: CompletionContext, _token: CancellationToken) => {
|
provideCompletionItems: async (model: ITextModel, _position: Position, _context: CompletionContext, _token: CancellationToken) => {
|
||||||
const widget = this.chatWidgetService.getWidgetByInputUri(model.uri);
|
const widget = this.chatWidgetService.getWidgetByInputUri(model.uri);
|
||||||
|
@ -329,7 +310,7 @@ class SlashCommandCompletions extends Disposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const slashCommands = await widget.getSlashCommands();
|
const slashCommands = this.chatSlashCommandService.getCommands();
|
||||||
if (!slashCommands) {
|
if (!slashCommands) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,10 +390,6 @@
|
||||||
color: var(--vscode-notificationsInfoIcon-foreground) !important; /* Have to override default styles which apply to all lists */
|
color: var(--vscode-notificationsInfoIcon-foreground) !important; /* Have to override default styles which apply to all lists */
|
||||||
}
|
}
|
||||||
|
|
||||||
.interactive-item-container .value .interactive-slash-command {
|
|
||||||
color: var(--vscode-textLink-foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.interactive-session .interactive-input-part {
|
.interactive-session .interactive-input-part {
|
||||||
padding: 12px 0px;
|
padding: 12px 0px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
|
||||||
export const CONTEXT_RESPONSE_HAS_PROVIDER_ID = new RawContextKey<boolean>('chatSessionResponseHasProviderId', false, { type: 'boolean', description: localize('interactiveSessionResponseHasProviderId', "True when the provider has assigned an id to this response.") });
|
|
||||||
export const CONTEXT_RESPONSE_VOTE = new RawContextKey<string>('chatSessionResponseVote', '', { type: 'string', description: localize('interactiveSessionResponseVote', "When the response has been voted up, is set to 'up'. When voted down, is set to 'down'. Otherwise an empty string.") });
|
export const CONTEXT_RESPONSE_VOTE = new RawContextKey<string>('chatSessionResponseVote', '', { type: 'string', description: localize('interactiveSessionResponseVote', "When the response has been voted up, is set to 'up'. When voted down, is set to 'down'. Otherwise an empty string.") });
|
||||||
export const CONTEXT_RESPONSE_FILTERED = new RawContextKey<boolean>('chatSessionResponseFiltered', false, { type: 'boolean', description: localize('chatResponseFiltered', "True when the chat response was filtered out by the server.") });
|
export const CONTEXT_RESPONSE_FILTERED = new RawContextKey<boolean>('chatSessionResponseFiltered', false, { type: 'boolean', description: localize('chatResponseFiltered', "True when the chat response was filtered out by the server.") });
|
||||||
export const CONTEXT_CHAT_REQUEST_IN_PROGRESS = new RawContextKey<boolean>('chatSessionRequestInProgress', false, { type: 'boolean', description: localize('interactiveSessionRequestInProgress', "True when the current request is still in progress.") });
|
export const CONTEXT_CHAT_REQUEST_IN_PROGRESS = new RawContextKey<boolean>('chatSessionRequestInProgress', false, { type: 'boolean', description: localize('interactiveSessionRequestInProgress', "True when the current request is still in progress.") });
|
||||||
|
|
|
@ -20,7 +20,6 @@ import { IChat, IChatContentInlineReference, IChatContentReference, IChatFollowu
|
||||||
|
|
||||||
export interface IChatRequestModel {
|
export interface IChatRequestModel {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly providerRequestId: string | undefined;
|
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
readonly avatarIconUri?: URI;
|
readonly avatarIconUri?: URI;
|
||||||
readonly session: IChatModel;
|
readonly session: IChatModel;
|
||||||
|
@ -53,7 +52,6 @@ export interface IChatResponseModel {
|
||||||
readonly onDidChange: Event<void>;
|
readonly onDidChange: Event<void>;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly providerId: string;
|
readonly providerId: string;
|
||||||
readonly providerResponseId: string | undefined;
|
|
||||||
readonly requestId: string;
|
readonly requestId: string;
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
readonly avatarIconUri?: URI;
|
readonly avatarIconUri?: URI;
|
||||||
|
@ -79,10 +77,6 @@ export class ChatRequestModel implements IChatRequestModel {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providerRequestId(): string | undefined {
|
|
||||||
return this._providerRequestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get username(): string {
|
public get username(): string {
|
||||||
return this.session.requesterUsername;
|
return this.session.requesterUsername;
|
||||||
}
|
}
|
||||||
|
@ -93,14 +87,9 @@ export class ChatRequestModel implements IChatRequestModel {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly session: ChatModel,
|
public readonly session: ChatModel,
|
||||||
public readonly message: IParsedChatRequest,
|
public readonly message: IParsedChatRequest) {
|
||||||
private _providerRequestId?: string) {
|
|
||||||
this._id = 'request_' + ChatRequestModel.nextId++;
|
this._id = 'request_' + ChatRequestModel.nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setProviderRequestId(providerRequestId: string) {
|
|
||||||
this._providerRequestId = providerRequestId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlaceholderMarkdownString extends IMarkdownString {
|
export interface IPlaceholderMarkdownString extends IMarkdownString {
|
||||||
|
@ -256,10 +245,6 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providerResponseId(): string | undefined {
|
|
||||||
return this._providerResponseId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get isComplete(): boolean {
|
public get isComplete(): boolean {
|
||||||
return this._isComplete;
|
return this._isComplete;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +302,6 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
|
||||||
private _isComplete: boolean = false,
|
private _isComplete: boolean = false,
|
||||||
private _isCanceled = false,
|
private _isCanceled = false,
|
||||||
private _vote?: InteractiveSessionVoteDirection,
|
private _vote?: InteractiveSessionVoteDirection,
|
||||||
private _providerResponseId?: string,
|
|
||||||
private _errorDetails?: IChatResponseErrorDetails,
|
private _errorDetails?: IChatResponseErrorDetails,
|
||||||
followups?: ReadonlyArray<IChatFollowup>
|
followups?: ReadonlyArray<IChatFollowup>
|
||||||
) {
|
) {
|
||||||
|
@ -339,10 +323,6 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
|
||||||
this._onDidChange.fire();
|
this._onDidChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
setProviderResponseId(providerResponseId: string) {
|
|
||||||
this._providerResponseId = providerResponseId;
|
|
||||||
}
|
|
||||||
|
|
||||||
setErrorDetails(errorDetails?: IChatResponseErrorDetails): void {
|
setErrorDetails(errorDetails?: IChatResponseErrorDetails): void {
|
||||||
this._errorDetails = errorDetails;
|
this._errorDetails = errorDetails;
|
||||||
this._onDidChange.fire();
|
this._onDidChange.fire();
|
||||||
|
@ -392,7 +372,6 @@ export interface ISerializableChatsData {
|
||||||
export type ISerializableChatAgentData = UriDto<IChatAgentData>;
|
export type ISerializableChatAgentData = UriDto<IChatAgentData>;
|
||||||
|
|
||||||
export interface ISerializableChatRequestData {
|
export interface ISerializableChatRequestData {
|
||||||
providerRequestId: string | undefined;
|
|
||||||
message: string | IParsedChatRequest;
|
message: string | IParsedChatRequest;
|
||||||
response: ReadonlyArray<IMarkdownString | IChatResponseProgressFileTreeData | IChatContentInlineReference> | undefined;
|
response: ReadonlyArray<IMarkdownString | IChatResponseProgressFileTreeData | IChatContentInlineReference> | undefined;
|
||||||
agent?: ISerializableChatAgentData;
|
agent?: ISerializableChatAgentData;
|
||||||
|
@ -414,7 +393,6 @@ export interface IExportableChatData {
|
||||||
responderUsername: string;
|
responderUsername: string;
|
||||||
requesterAvatarIconUri: UriComponents | undefined;
|
requesterAvatarIconUri: UriComponents | undefined;
|
||||||
responderAvatarIconUri: UriComponents | undefined;
|
responderAvatarIconUri: UriComponents | undefined;
|
||||||
providerState: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISerializableChatData extends IExportableChatData {
|
export interface ISerializableChatData extends IExportableChatData {
|
||||||
|
@ -490,11 +468,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
return this._welcomeMessage;
|
return this._welcomeMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _providerState: any;
|
|
||||||
get providerState(): any {
|
|
||||||
return this._providerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO to be clear, this is not the same as the id from the session object, which belongs to the provider.
|
// TODO to be clear, this is not the same as the id from the session object, which belongs to the provider.
|
||||||
// It's easier to be able to identify this model before its async initialization is complete
|
// It's easier to be able to identify this model before its async initialization is complete
|
||||||
private _sessionId: string;
|
private _sessionId: string;
|
||||||
|
@ -560,7 +533,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
this._isImported = (!!initialData && !isSerializableSessionData(initialData)) || (initialData?.isImported ?? false);
|
this._isImported = (!!initialData && !isSerializableSessionData(initialData)) || (initialData?.isImported ?? false);
|
||||||
this._sessionId = (isSerializableSessionData(initialData) && initialData.sessionId) || generateUuid();
|
this._sessionId = (isSerializableSessionData(initialData) && initialData.sessionId) || generateUuid();
|
||||||
this._requests = initialData ? this._deserialize(initialData) : [];
|
this._requests = initialData ? this._deserialize(initialData) : [];
|
||||||
this._providerState = initialData ? initialData.providerState : undefined;
|
|
||||||
this._creationDate = (isSerializableSessionData(initialData) && initialData.creationDate) || Date.now();
|
this._creationDate = (isSerializableSessionData(initialData) && initialData.creationDate) || Date.now();
|
||||||
|
|
||||||
this._initialRequesterAvatarIconUri = initialData?.requesterAvatarIconUri && URI.revive(initialData.requesterAvatarIconUri);
|
this._initialRequesterAvatarIconUri = initialData?.requesterAvatarIconUri && URI.revive(initialData.requesterAvatarIconUri);
|
||||||
|
@ -585,11 +557,11 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
typeof raw.message === 'string'
|
typeof raw.message === 'string'
|
||||||
? this.getParsedRequestFromString(raw.message)
|
? this.getParsedRequestFromString(raw.message)
|
||||||
: reviveParsedChatRequest(raw.message);
|
: reviveParsedChatRequest(raw.message);
|
||||||
const request = new ChatRequestModel(this, parsedRequest, raw.providerRequestId);
|
const request = new ChatRequestModel(this, parsedRequest);
|
||||||
if (raw.response || raw.responseErrorDetails) {
|
if (raw.response || raw.responseErrorDetails) {
|
||||||
const agent = (raw.agent && 'metadata' in raw.agent) ? // Check for the new format, ignore entries in the old format
|
const agent = (raw.agent && 'metadata' in raw.agent) ? // Check for the new format, ignore entries in the old format
|
||||||
revive<ISerializableChatAgentData>(raw.agent) : undefined;
|
revive<ISerializableChatAgentData>(raw.agent) : undefined;
|
||||||
request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, request.id, true, raw.isCanceled, raw.vote, raw.providerRequestId, raw.responseErrorDetails, raw.followups);
|
request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, request.id, true, raw.isCanceled, raw.vote, raw.responseErrorDetails, raw.followups);
|
||||||
if (raw.usedContext) { // @ulugbekna: if this's a new vscode sessions, doc versions are incorrect anyway?
|
if (raw.usedContext) { // @ulugbekna: if this's a new vscode sessions, doc versions are incorrect anyway?
|
||||||
request.response.updateContent(raw.usedContext);
|
request.response.updateContent(raw.usedContext);
|
||||||
}
|
}
|
||||||
|
@ -642,13 +614,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isInitializedDeferred.complete();
|
this._isInitializedDeferred.complete();
|
||||||
|
|
||||||
if (session.onDidChangeState) {
|
|
||||||
this._register(session.onDidChangeState(state => {
|
|
||||||
this._providerState = state;
|
|
||||||
this.logService.trace('ChatModel#acceptNewSessionState');
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
this._onDidChange.fire({ kind: 'initialize' });
|
this._onDidChange.fire({ kind: 'initialize' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,21 +672,15 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
if (agent) {
|
if (agent) {
|
||||||
request.response.setAgent(agent, progress.command);
|
request.response.setAgent(agent, progress.command);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
request.setProviderRequestId(progress.requestId);
|
|
||||||
request.response.setProviderResponseId(progress.requestId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRequest(requestId: string): void {
|
removeRequest(id: string): void {
|
||||||
const index = this._requests.findIndex(request => request.providerRequestId === requestId);
|
const index = this._requests.findIndex(request => request.id === id);
|
||||||
const request = this._requests[index];
|
const request = this._requests[index];
|
||||||
if (!request.providerRequestId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this._onDidChange.fire({ kind: 'removeRequest', requestId: request.providerRequestId, responseId: request.response?.providerResponseId });
|
this._onDidChange.fire({ kind: 'removeRequest', requestId: request.id, responseId: request.response?.id });
|
||||||
this._requests.splice(index, 1);
|
this._requests.splice(index, 1);
|
||||||
request.response?.dispose();
|
request.response?.dispose();
|
||||||
}
|
}
|
||||||
|
@ -782,21 +741,19 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}),
|
}),
|
||||||
requests: this._requests.map((r): ISerializableChatRequestData => {
|
requests: this._requests.map((r): ISerializableChatRequestData => {
|
||||||
return {
|
return {
|
||||||
providerRequestId: r.providerRequestId,
|
|
||||||
message: r.message,
|
message: r.message,
|
||||||
response: r.response ? r.response.response.value : undefined,
|
response: r.response ? r.response.response.value : undefined,
|
||||||
responseErrorDetails: r.response?.errorDetails,
|
responseErrorDetails: r.response?.errorDetails,
|
||||||
followups: r.response?.followups,
|
followups: r.response?.followups,
|
||||||
isCanceled: r.response?.isCanceled,
|
isCanceled: r.response?.isCanceled,
|
||||||
vote: r.response?.vote,
|
vote: r.response?.vote,
|
||||||
agent: r.response?.agent,
|
agent: r.response?.agent ? { id: r.response.agent.id, metadata: r.response.agent.metadata } : undefined, // May actually be the full IChatAgent instance, just take the data props
|
||||||
slashCommand: r.response?.slashCommand,
|
slashCommand: r.response?.slashCommand,
|
||||||
usedContext: r.response?.response.usedContext,
|
usedContext: r.response?.response.usedContext,
|
||||||
contentReferences: r.response?.response.contentReferences
|
contentReferences: r.response?.response.contentReferences
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
providerId: this.providerId,
|
providerId: this.providerId,
|
||||||
providerState: this._providerState
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicReferencePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, IParsedChatRequest, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicReferencePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, IParsedChatRequest, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
import { IChatVariablesService, IDynamicReference } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatVariablesService, IDynamicReference } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
|
|
||||||
const agentReg = /^@([\w_\-]+)(?=(\s|$|\b))/i; // An @-agent
|
const agentReg = /^@([\w_\-]+)(?=(\s|$|\b))/i; // An @-agent
|
||||||
|
@ -21,7 +21,7 @@ export class ChatRequestParser {
|
||||||
constructor(
|
constructor(
|
||||||
@IChatAgentService private readonly agentService: IChatAgentService,
|
@IChatAgentService private readonly agentService: IChatAgentService,
|
||||||
@IChatVariablesService private readonly variableService: IChatVariablesService,
|
@IChatVariablesService private readonly variableService: IChatVariablesService,
|
||||||
@IChatService private readonly chatService: IChatService,
|
@IChatSlashCommandService private readonly slashCommandService: IChatSlashCommandService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async parseChatRequest(sessionId: string, message: string): Promise<IParsedChatRequest> {
|
async parseChatRequest(sessionId: string, message: string): Promise<IParsedChatRequest> {
|
||||||
|
@ -174,7 +174,7 @@ export class ChatRequestParser {
|
||||||
return new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand);
|
return new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const slashCommands = await this.chatService.getSlashCommands(sessionId, CancellationToken.None);
|
const slashCommands = this.slashCommandService.getCommands();
|
||||||
const slashCommand = slashCommands.find(c => c.command === command);
|
const slashCommand = slashCommands.find(c => c.command === command);
|
||||||
if (slashCommand) {
|
if (slashCommand) {
|
||||||
// Valid standalone slash command
|
// Valid standalone slash command
|
||||||
|
|
|
@ -23,7 +23,6 @@ export interface IChat {
|
||||||
responderUsername: string;
|
responderUsername: string;
|
||||||
responderAvatarIconUri?: URI;
|
responderAvatarIconUri?: URI;
|
||||||
inputPlaceholder?: string;
|
inputPlaceholder?: string;
|
||||||
onDidChangeState?: Event<any>;
|
|
||||||
dispose?(): void;
|
dispose?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +99,6 @@ export interface IChatAgentDetection {
|
||||||
|
|
||||||
export type IChatProgress =
|
export type IChatProgress =
|
||||||
| { content: string | IMarkdownString }
|
| { content: string | IMarkdownString }
|
||||||
| { requestId: string }
|
|
||||||
| { treeData: IChatResponseProgressFileTreeData }
|
| { treeData: IChatResponseProgressFileTreeData }
|
||||||
| { placeholder: string; resolvedContent: Promise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }> }
|
| { placeholder: string; resolvedContent: Promise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }> }
|
||||||
| IUsedContext
|
| IUsedContext
|
||||||
|
@ -108,18 +106,13 @@ export type IChatProgress =
|
||||||
| IChatContentInlineReference
|
| IChatContentInlineReference
|
||||||
| IChatAgentDetection;
|
| IChatAgentDetection;
|
||||||
|
|
||||||
export interface IPersistedChatState { }
|
|
||||||
export interface IChatProvider {
|
export interface IChatProvider {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly displayName: string;
|
readonly displayName: string;
|
||||||
readonly iconUrl?: string;
|
readonly iconUrl?: string;
|
||||||
prepareSession(initialState: IPersistedChatState | undefined, token: CancellationToken): ProviderResult<IChat | undefined>;
|
prepareSession(token: CancellationToken): ProviderResult<IChat | undefined>;
|
||||||
provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IMarkdownString | IChatReplyFollowup[])[] | undefined>;
|
provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IMarkdownString | IChatReplyFollowup[])[] | undefined>;
|
||||||
provideSampleQuestions?(token: CancellationToken): ProviderResult<IChatReplyFollowup[] | undefined>;
|
provideSampleQuestions?(token: CancellationToken): ProviderResult<IChatReplyFollowup[] | undefined>;
|
||||||
provideFollowups?(session: IChat, token: CancellationToken): ProviderResult<IChatFollowup[] | undefined>;
|
|
||||||
provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void, token: CancellationToken): ProviderResult<IChatResponse>;
|
|
||||||
provideSlashCommands?(session: IChat, token: CancellationToken): ProviderResult<ISlashCommand[]>;
|
|
||||||
removeRequest?(session: IChat, requestId: string): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISlashCommand {
|
export interface ISlashCommand {
|
||||||
|
@ -156,7 +149,6 @@ export interface IChatReplyFollowup {
|
||||||
message: string;
|
message: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
metadata?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatResponseCommandFollowup {
|
export interface IChatResponseCommandFollowup {
|
||||||
|
@ -177,7 +169,6 @@ export enum InteractiveSessionVoteDirection {
|
||||||
|
|
||||||
export interface IChatVoteAction {
|
export interface IChatVoteAction {
|
||||||
kind: 'vote';
|
kind: 'vote';
|
||||||
responseId: string;
|
|
||||||
direction: InteractiveSessionVoteDirection;
|
direction: InteractiveSessionVoteDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +180,6 @@ export enum InteractiveSessionCopyKind {
|
||||||
|
|
||||||
export interface IChatCopyAction {
|
export interface IChatCopyAction {
|
||||||
kind: 'copy';
|
kind: 'copy';
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
copyType: InteractiveSessionCopyKind;
|
copyType: InteractiveSessionCopyKind;
|
||||||
copiedCharacters: number;
|
copiedCharacters: number;
|
||||||
|
@ -199,7 +189,6 @@ export interface IChatCopyAction {
|
||||||
|
|
||||||
export interface IChatInsertAction {
|
export interface IChatInsertAction {
|
||||||
kind: 'insert';
|
kind: 'insert';
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
totalCharacters: number;
|
totalCharacters: number;
|
||||||
newFile?: boolean;
|
newFile?: boolean;
|
||||||
|
@ -207,7 +196,6 @@ export interface IChatInsertAction {
|
||||||
|
|
||||||
export interface IChatTerminalAction {
|
export interface IChatTerminalAction {
|
||||||
kind: 'runInTerminal';
|
kind: 'runInTerminal';
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
languageId?: string;
|
languageId?: string;
|
||||||
}
|
}
|
||||||
|
@ -271,7 +259,7 @@ export interface IChatService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
transferredSessionData: IChatTransferredSessionData | undefined;
|
transferredSessionData: IChatTransferredSessionData | undefined;
|
||||||
|
|
||||||
onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string } | { agent: IChatAgentData; slashCommand: IChatAgentCommand; sessionId: string }>;
|
onDidSubmitAgent: Event<{ agent: IChatAgentData; slashCommand: IChatAgentCommand; sessionId: string }>;
|
||||||
onDidRegisterProvider: Event<{ providerId: string }>;
|
onDidRegisterProvider: Event<{ providerId: string }>;
|
||||||
registerProvider(provider: IChatProvider): IDisposable;
|
registerProvider(provider: IChatProvider): IDisposable;
|
||||||
hasSessions(providerId: string): boolean;
|
hasSessions(providerId: string): boolean;
|
||||||
|
@ -285,10 +273,9 @@ export interface IChatService {
|
||||||
/**
|
/**
|
||||||
* Returns whether the request was accepted.
|
* Returns whether the request was accepted.
|
||||||
*/
|
*/
|
||||||
sendRequest(sessionId: string, message: string, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise<void> } | undefined>;
|
sendRequest(sessionId: string, message: string): Promise<{ responseCompletePromise: Promise<void> } | undefined>;
|
||||||
removeRequest(sessionid: string, requestId: string): Promise<void>;
|
removeRequest(sessionid: string, requestId: string): Promise<void>;
|
||||||
cancelCurrentRequestForSession(sessionId: string): void;
|
cancelCurrentRequestForSession(sessionId: string): void;
|
||||||
getSlashCommands(sessionId: string, token: CancellationToken): Promise<ISlashCommand[]>;
|
|
||||||
clearSession(sessionId: string): void;
|
clearSession(sessionId: string): void;
|
||||||
addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, response: IChatCompleteResponse): void;
|
addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, response: IChatCompleteResponse): void;
|
||||||
sendRequestToProvider(sessionId: string, message: IChatDynamicRequest): void;
|
sendRequestToProvider(sessionId: string, message: IChatDynamicRequest): void;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { MarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
import { MarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableMap, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
import { revive } from 'vs/base/common/marshalling';
|
||||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
|
@ -27,7 +27,7 @@ import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageMode
|
||||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider';
|
import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider';
|
||||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||||
import { IChat, IChatCompleteResponse, IChatDetail, IChatDynamicRequest, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatRequest, IChatResponse, IChatService, IChatTransferredSessionData, IChatUserActionEvent, ISlashCommand, InteractiveSessionCopyKind, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChat, IChatCompleteResponse, IChatDetail, IChatDynamicRequest, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatResponse, IChatService, IChatTransferredSessionData, IChatUserActionEvent, InteractiveSessionCopyKind, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
@ -134,7 +134,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
|
|
||||||
private readonly _providers = new Map<string, IChatProvider>();
|
private readonly _providers = new Map<string, IChatProvider>();
|
||||||
|
|
||||||
private readonly _sessionModels = new Map<string, ChatModel>();
|
private readonly _sessionModels = this._register(new DisposableMap<string, ChatModel>());
|
||||||
private readonly _pendingRequests = new Map<string, CancelablePromise<void>>();
|
private readonly _pendingRequests = new Map<string, CancelablePromise<void>>();
|
||||||
private readonly _persistedSessions: ISerializableChatsData;
|
private readonly _persistedSessions: ISerializableChatsData;
|
||||||
private readonly _hasProvider: IContextKey<boolean>;
|
private readonly _hasProvider: IContextKey<boolean>;
|
||||||
|
@ -147,8 +147,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
private readonly _onDidPerformUserAction = this._register(new Emitter<IChatUserActionEvent>());
|
private readonly _onDidPerformUserAction = this._register(new Emitter<IChatUserActionEvent>());
|
||||||
public readonly onDidPerformUserAction: Event<IChatUserActionEvent> = this._onDidPerformUserAction.event;
|
public readonly onDidPerformUserAction: Event<IChatUserActionEvent> = this._onDidPerformUserAction.event;
|
||||||
|
|
||||||
private readonly _onDidSubmitSlashCommand = this._register(new Emitter<{ slashCommand: string; sessionId: string } | { agent: IChatAgentData; slashCommand: IChatAgentCommand; sessionId: string }>());
|
private readonly _onDidSubmitAgent = this._register(new Emitter<{ agent: IChatAgentData; slashCommand: IChatAgentCommand; sessionId: string }>());
|
||||||
public readonly onDidSubmitSlashCommand = this._onDidSubmitSlashCommand.event;
|
public readonly onDidSubmitAgent = this._onDidSubmitAgent.event;
|
||||||
|
|
||||||
private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string; providerId: string; reason: 'initializationFailed' | 'cleared' }>());
|
private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string; providerId: string; reason: 'initializationFailed' | 'cleared' }>());
|
||||||
public readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
public readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
||||||
|
@ -365,7 +365,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
|
|
||||||
let session: IChat | undefined;
|
let session: IChat | undefined;
|
||||||
try {
|
try {
|
||||||
session = await provider.prepareSession(model.providerState, token) ?? undefined;
|
session = await provider.prepareSession(token) ?? undefined;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.trace('initializeSession', `Provider initializeSession threw: ${err}`);
|
this.trace('initializeSession', `Provider initializeSession threw: ${err}`);
|
||||||
}
|
}
|
||||||
|
@ -387,8 +387,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.trace('startSession', `initializeSession failed: ${err}`);
|
this.trace('startSession', `initializeSession failed: ${err}`);
|
||||||
model.setInitializationError(err);
|
model.setInitializationError(err);
|
||||||
model.dispose();
|
this._sessionModels.deleteAndDispose(model.sessionId);
|
||||||
this._sessionModels.delete(model.sessionId);
|
|
||||||
this._onDidDisposeSession.fire({ sessionId: model.sessionId, providerId: model.providerId, reason: 'initializationFailed' });
|
this._onDidDisposeSession.fire({ sessionId: model.sessionId, providerId: model.providerId, reason: 'initializationFailed' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +423,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
return this._startSession(data.providerId, data, CancellationToken.None);
|
return this._startSession(data.providerId, data, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendRequest(sessionId: string, request: string, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise<void> } | undefined> {
|
async sendRequest(sessionId: string, request: string): Promise<{ responseCompletePromise: Promise<void> } | undefined> {
|
||||||
this.trace('sendRequest', `sessionId: ${sessionId}, message: ${request.substring(0, 20)}${request.length > 20 ? '[...]' : ''}}`);
|
this.trace('sendRequest', `sessionId: ${sessionId}, message: ${request.substring(0, 20)}${request.length > 20 ? '[...]' : ''}}`);
|
||||||
if (!request.trim()) {
|
if (!request.trim()) {
|
||||||
this.trace('sendRequest', 'Rejected empty message');
|
this.trace('sendRequest', 'Rejected empty message');
|
||||||
|
@ -448,10 +447,10 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is only returning whether the request was accepted - don't block on the actual request
|
// This method is only returning whether the request was accepted - don't block on the actual request
|
||||||
return { responseCompletePromise: this._sendRequestAsync(model, sessionId, provider, request, usedSlashCommand) };
|
return { responseCompletePromise: this._sendRequestAsync(model, sessionId, provider, request) };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _sendRequestAsync(model: ChatModel, sessionId: string, provider: IChatProvider, message: string, usedSlashCommand?: ISlashCommand): Promise<void> {
|
private async _sendRequestAsync(model: ChatModel, sessionId: string, provider: IChatProvider, message: string): Promise<void> {
|
||||||
const parsedRequest = await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message);
|
const parsedRequest = await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message);
|
||||||
|
|
||||||
let request: ChatRequestModel;
|
let request: ChatRequestModel;
|
||||||
|
@ -486,7 +485,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
} else if ('agentName' in progress) {
|
} else if ('agentName' in progress) {
|
||||||
this.trace('sendRequest', `Provider returned an agent detection for session ${model.sessionId}:\n ${JSON.stringify(progress, null, '\t')}`);
|
this.trace('sendRequest', `Provider returned an agent detection for session ${model.sessionId}:\n ${JSON.stringify(progress, null, '\t')}`);
|
||||||
} else {
|
} else {
|
||||||
this.trace('sendRequest', `Provider returned id for session ${model.sessionId}, ${progress.requestId}`);
|
this.trace('sendRequest', `Provider returned unknown progress for session ${model.sessionId}:\n ${JSON.stringify(progress, null, '\t')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
model.acceptResponseProgress(request, progress);
|
model.acceptResponseProgress(request, progress);
|
||||||
|
@ -503,7 +502,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
result: 'cancelled',
|
result: 'cancelled',
|
||||||
requestType,
|
requestType,
|
||||||
agent: agentPart?.agent.id ?? '',
|
agent: agentPart?.agent.id ?? '',
|
||||||
slashCommand: agentSlashCommandPart ? agentSlashCommandPart.command.name : usedSlashCommand?.command,
|
slashCommand: agentSlashCommandPart ? agentSlashCommandPart.command.name : commandPart?.slashCommand.command,
|
||||||
chatSessionId: model.sessionId
|
chatSessionId: model.sessionId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -511,10 +510,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (usedSlashCommand?.command) {
|
if (agentPart && agentSlashCommandPart?.command) {
|
||||||
this._onDidSubmitSlashCommand.fire({ slashCommand: usedSlashCommand.command, sessionId: model.sessionId });
|
this._onDidSubmitAgent.fire({ agent: agentPart.agent, slashCommand: agentSlashCommandPart.command, sessionId: model.sessionId });
|
||||||
} else if (agentPart && agentSlashCommandPart?.command) {
|
|
||||||
this._onDidSubmitSlashCommand.fire({ agent: agentPart.agent, slashCommand: agentSlashCommandPart.command, sessionId: model.sessionId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let rawResponse: IChatResponse | null | undefined;
|
let rawResponse: IChatResponse | null | undefined;
|
||||||
|
@ -574,19 +571,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
rawResponse = { session: model.session! };
|
rawResponse = { session: model.session! };
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
request = model.addRequest(parsedRequest);
|
throw new Error(`Can't handle request`);
|
||||||
const requestProps: IChatRequest = {
|
|
||||||
session: model.session!,
|
|
||||||
message,
|
|
||||||
variables: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ('parts' in parsedRequest) {
|
|
||||||
const varResult = await this.chatVariablesService.resolveVariables(parsedRequest, model, token);
|
|
||||||
requestProps.variables = varResult.variables;
|
|
||||||
requestProps.message = varResult.prompt;
|
|
||||||
}
|
|
||||||
rawResponse = await provider.provideReply(requestProps, progressCallback, token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.isCancellationRequested) {
|
if (token.isCancellationRequested) {
|
||||||
|
@ -608,7 +593,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
result,
|
result,
|
||||||
requestType,
|
requestType,
|
||||||
agent: agentPart?.agent.id ?? '',
|
agent: agentPart?.agent.id ?? '',
|
||||||
slashCommand: agentSlashCommandPart ? agentSlashCommandPart.command.name : usedSlashCommand?.command,
|
slashCommand: agentSlashCommandPart ? agentSlashCommandPart.command.name : commandPart?.slashCommand.command,
|
||||||
chatSessionId: model.sessionId
|
chatSessionId: model.sessionId
|
||||||
});
|
});
|
||||||
model.setResponse(request, rawResponse);
|
model.setResponse(request, rawResponse);
|
||||||
|
@ -620,11 +605,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
model.setFollowups(request, followups);
|
model.setFollowups(request, followups);
|
||||||
model.completeResponse(request);
|
model.completeResponse(request);
|
||||||
});
|
});
|
||||||
} else if (provider.provideFollowups) {
|
|
||||||
Promise.resolve(provider.provideFollowups(model.session!, CancellationToken.None)).then(providerFollowups => {
|
|
||||||
model.setFollowups(request, providerFollowups ?? undefined);
|
|
||||||
model.completeResponse(request);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
model.completeResponse(request);
|
model.completeResponse(request);
|
||||||
}
|
}
|
||||||
|
@ -653,43 +633,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
model.removeRequest(requestId);
|
model.removeRequest(requestId);
|
||||||
provider.removeRequest?.(model.session!, requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSlashCommands(sessionId: string, token: CancellationToken): Promise<ISlashCommand[]> {
|
|
||||||
const model = this._sessionModels.get(sessionId);
|
|
||||||
if (!model) {
|
|
||||||
throw new Error(`Unknown session: ${sessionId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await model.waitForInitialization();
|
|
||||||
const provider = this._providers.get(model.providerId);
|
|
||||||
if (!provider) {
|
|
||||||
throw new Error(`Unknown provider: ${model.providerId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const serviceResults = this.chatSlashCommandService.getCommands().map(data => {
|
|
||||||
return <ISlashCommand>{
|
|
||||||
command: data.command,
|
|
||||||
detail: data.detail,
|
|
||||||
sortText: data.sortText,
|
|
||||||
executeImmediately: data.executeImmediately
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const mainProviderRequest = provider.provideSlashCommands?.(model.session!, token);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const providerResults = await mainProviderRequest;
|
|
||||||
if (providerResults) {
|
|
||||||
return providerResults.concat(serviceResults);
|
|
||||||
}
|
|
||||||
return serviceResults;
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
this.logService.error(e);
|
|
||||||
return serviceResults;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendRequestToProvider(sessionId: string, message: IChatDynamicRequest): Promise<{ responseCompletePromise: Promise<void> } | undefined> {
|
async sendRequestToProvider(sessionId: string, message: IChatDynamicRequest): Promise<{ responseCompletePromise: Promise<void> } | undefined> {
|
||||||
|
@ -746,8 +689,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
|
|
||||||
this._persistedSessions[sessionId] = model.toJSON();
|
this._persistedSessions[sessionId] = model.toJSON();
|
||||||
|
|
||||||
model.dispose();
|
this._sessionModels.deleteAndDispose(sessionId);
|
||||||
this._sessionModels.delete(sessionId);
|
|
||||||
this._pendingRequests.get(sessionId)?.cancel();
|
this._pendingRequests.get(sessionId)?.cancel();
|
||||||
this._onDidDisposeSession.fire({ sessionId, providerId: model.providerId, reason: 'cleared' });
|
this._onDidDisposeSession.fire({ sessionId, providerId: model.providerId, reason: 'cleared' });
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ export interface IChatViewModel {
|
||||||
|
|
||||||
export interface IChatRequestViewModel {
|
export interface IChatRequestViewModel {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly providerRequestId: string | undefined;
|
|
||||||
readonly sessionId: string;
|
readonly sessionId: string;
|
||||||
/** This ID updates every time the underlying data changes */
|
/** This ID updates every time the underlying data changes */
|
||||||
readonly dataId: string;
|
readonly dataId: string;
|
||||||
|
@ -88,7 +87,6 @@ export interface IChatResponseViewModel {
|
||||||
/** This ID updates every time the underlying data changes */
|
/** This ID updates every time the underlying data changes */
|
||||||
readonly dataId: string;
|
readonly dataId: string;
|
||||||
readonly providerId: string;
|
readonly providerId: string;
|
||||||
readonly providerResponseId: string | undefined;
|
|
||||||
/** The ID of the associated IChatRequestViewModel */
|
/** The ID of the associated IChatRequestViewModel */
|
||||||
readonly requestId: string;
|
readonly requestId: string;
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
|
@ -173,12 +171,12 @@ export class ChatViewModel extends Disposable implements IChatViewModel {
|
||||||
} else if (e.kind === 'addResponse') {
|
} else if (e.kind === 'addResponse') {
|
||||||
this.onAddResponse(e.response);
|
this.onAddResponse(e.response);
|
||||||
} else if (e.kind === 'removeRequest') {
|
} else if (e.kind === 'removeRequest') {
|
||||||
const requestIdx = this._items.findIndex(item => isRequestVM(item) && item.providerRequestId === e.requestId);
|
const requestIdx = this._items.findIndex(item => isRequestVM(item) && item.id === e.requestId);
|
||||||
if (requestIdx >= 0) {
|
if (requestIdx >= 0) {
|
||||||
this._items.splice(requestIdx, 1);
|
this._items.splice(requestIdx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const responseIdx = e.responseId && this._items.findIndex(item => isResponseVM(item) && item.providerResponseId === e.responseId);
|
const responseIdx = e.responseId && this._items.findIndex(item => isResponseVM(item) && item.id === e.responseId);
|
||||||
if (typeof responseIdx === 'number' && responseIdx >= 0) {
|
if (typeof responseIdx === 'number' && responseIdx >= 0) {
|
||||||
const items = this._items.splice(responseIdx, 1);
|
const items = this._items.splice(responseIdx, 1);
|
||||||
const item = items[0];
|
const item = items[0];
|
||||||
|
@ -218,10 +216,6 @@ export class ChatRequestViewModel implements IChatRequestViewModel {
|
||||||
return this._model.id;
|
return this._model.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
get providerRequestId() {
|
|
||||||
return this._model.providerRequestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dataId() {
|
get dataId() {
|
||||||
return this.id + `_${ChatModelInitState[this._model.session.initState]}`;
|
return this.id + `_${ChatModelInitState[this._model.session.initState]}`;
|
||||||
}
|
}
|
||||||
|
@ -269,10 +263,6 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi
|
||||||
return this._model.providerId;
|
return this._model.providerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
get providerResponseId() {
|
|
||||||
return this._model.providerResponseId;
|
|
||||||
}
|
|
||||||
|
|
||||||
get sessionId() {
|
get sessionId() {
|
||||||
return this._model.session.sessionId;
|
return this._model.session.sessionId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,32 +6,53 @@
|
||||||
welcomeMessage: undefined,
|
welcomeMessage: undefined,
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
providerRequestId: undefined,
|
|
||||||
message: {
|
message: {
|
||||||
text: "test request",
|
text: "@ChatProviderWithUsedContext test request",
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
range: {
|
range: {
|
||||||
start: 0,
|
start: 0,
|
||||||
endExclusive: 12
|
endExclusive: 28
|
||||||
},
|
},
|
||||||
editorRange: {
|
editorRange: {
|
||||||
startLineNumber: 1,
|
startLineNumber: 1,
|
||||||
startColumn: 1,
|
startColumn: 1,
|
||||||
endLineNumber: 1,
|
endLineNumber: 1,
|
||||||
endColumn: 13
|
endColumn: 29
|
||||||
},
|
},
|
||||||
text: "test request",
|
agent: {
|
||||||
|
id: "ChatProviderWithUsedContext",
|
||||||
|
metadata: { },
|
||||||
|
provideSlashCommands: [Function provideSlashCommands],
|
||||||
|
invoke: [Function invoke]
|
||||||
|
},
|
||||||
|
kind: "agent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
range: {
|
||||||
|
start: 28,
|
||||||
|
endExclusive: 41
|
||||||
|
},
|
||||||
|
editorRange: {
|
||||||
|
startLineNumber: 1,
|
||||||
|
startColumn: 29,
|
||||||
|
endLineNumber: 1,
|
||||||
|
endColumn: 42
|
||||||
|
},
|
||||||
|
text: " test request",
|
||||||
kind: "text"
|
kind: "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
response: [ ],
|
response: [ ],
|
||||||
responseErrorDetails: undefined,
|
responseErrorDetails: undefined,
|
||||||
followups: undefined,
|
followups: [ ],
|
||||||
isCanceled: false,
|
isCanceled: false,
|
||||||
vote: undefined,
|
vote: undefined,
|
||||||
agent: undefined,
|
agent: {
|
||||||
|
id: "ChatProviderWithUsedContext",
|
||||||
|
metadata: { }
|
||||||
|
},
|
||||||
slashCommand: undefined,
|
slashCommand: undefined,
|
||||||
usedContext: { documents: [
|
usedContext: { documents: [
|
||||||
{
|
{
|
||||||
|
@ -58,6 +79,5 @@
|
||||||
contentReferences: [ ]
|
contentReferences: [ ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
providerId: "ChatProviderWithUsedContext",
|
providerId: "testProvider"
|
||||||
providerState: undefined
|
|
||||||
}
|
}
|
|
@ -5,6 +5,5 @@
|
||||||
responderAvatarIconUri: undefined,
|
responderAvatarIconUri: undefined,
|
||||||
welcomeMessage: undefined,
|
welcomeMessage: undefined,
|
||||||
requests: [ ],
|
requests: [ ],
|
||||||
providerId: "ChatProviderWithUsedContext",
|
providerId: "testProvider"
|
||||||
providerState: undefined
|
|
||||||
}
|
}
|
|
@ -6,32 +6,53 @@
|
||||||
welcomeMessage: undefined,
|
welcomeMessage: undefined,
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
providerRequestId: undefined,
|
|
||||||
message: {
|
message: {
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
range: {
|
range: {
|
||||||
start: 0,
|
start: 0,
|
||||||
endExclusive: 12
|
endExclusive: 28
|
||||||
},
|
},
|
||||||
editorRange: {
|
editorRange: {
|
||||||
startLineNumber: 1,
|
startLineNumber: 1,
|
||||||
startColumn: 1,
|
startColumn: 1,
|
||||||
endLineNumber: 1,
|
endLineNumber: 1,
|
||||||
endColumn: 13
|
endColumn: 29
|
||||||
},
|
},
|
||||||
text: "test request",
|
agent: {
|
||||||
|
id: "ChatProviderWithUsedContext",
|
||||||
|
metadata: { },
|
||||||
|
provideSlashCommands: [Function provideSlashCommands],
|
||||||
|
invoke: [Function invoke]
|
||||||
|
},
|
||||||
|
kind: "agent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
range: {
|
||||||
|
start: 28,
|
||||||
|
endExclusive: 41
|
||||||
|
},
|
||||||
|
editorRange: {
|
||||||
|
startLineNumber: 1,
|
||||||
|
startColumn: 29,
|
||||||
|
endLineNumber: 1,
|
||||||
|
endColumn: 42
|
||||||
|
},
|
||||||
|
text: " test request",
|
||||||
kind: "text"
|
kind: "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
text: "test request"
|
text: "@ChatProviderWithUsedContext test request"
|
||||||
},
|
},
|
||||||
response: [ ],
|
response: [ ],
|
||||||
responseErrorDetails: undefined,
|
responseErrorDetails: undefined,
|
||||||
followups: undefined,
|
followups: [ ],
|
||||||
isCanceled: false,
|
isCanceled: false,
|
||||||
vote: undefined,
|
vote: undefined,
|
||||||
agent: undefined,
|
agent: {
|
||||||
|
id: "ChatProviderWithUsedContext",
|
||||||
|
metadata: { }
|
||||||
|
},
|
||||||
slashCommand: undefined,
|
slashCommand: undefined,
|
||||||
usedContext: { documents: [
|
usedContext: { documents: [
|
||||||
{
|
{
|
||||||
|
@ -58,6 +79,5 @@
|
||||||
contentReferences: [ ]
|
contentReferences: [ ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
providerId: "ChatProviderWithUsedContext",
|
providerId: "testProvider"
|
||||||
providerState: undefined
|
|
||||||
}
|
}
|
|
@ -6,11 +6,14 @@
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { timeout } from 'vs/base/common/async';
|
import { timeout } from 'vs/base/common/async';
|
||||||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||||
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
|
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
|
import { ChatRequestTextPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
|
|
||||||
|
@ -98,4 +101,18 @@ suite('ChatModel', () => {
|
||||||
|
|
||||||
assert.throws(() => model.initialize({} as any, undefined));
|
assert.throws(() => model.initialize({} as any, undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('removeRequest', async () => {
|
||||||
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
||||||
|
|
||||||
|
model.startInitialize();
|
||||||
|
model.initialize({} as any, undefined);
|
||||||
|
const text = 'hello';
|
||||||
|
model.addRequest({ text, parts: [new ChatRequestTextPart(new OffsetRange(0, text.length), new Range(1, text.length, 1, text.length), text)] });
|
||||||
|
const requests = model.getRequests();
|
||||||
|
assert.strictEqual(requests.length, 1);
|
||||||
|
|
||||||
|
model.removeRequest(requests[0].id);
|
||||||
|
assert.strictEqual(model.getRequests().length, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { ChatAgentService, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentService, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
|
@ -48,9 +48,9 @@ suite('ChatRequestParser', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('slash command', async () => {
|
test('slash command', async () => {
|
||||||
const chatService = mockObject<IChatService>()({});
|
const slashCommandService = mockObject<IChatSlashCommandService>()({});
|
||||||
chatService.getSlashCommands.returns(Promise.resolve([{ command: 'fix' }]));
|
slashCommandService.getCommands.returns([{ command: 'fix' }]);
|
||||||
instantiationService.stub(IChatService, chatService as any);
|
instantiationService.stub(IChatSlashCommandService, slashCommandService as any);
|
||||||
|
|
||||||
parser = instantiationService.createInstance(ChatRequestParser);
|
parser = instantiationService.createInstance(ChatRequestParser);
|
||||||
const text = '/fix this';
|
const text = '/fix this';
|
||||||
|
@ -59,9 +59,9 @@ suite('ChatRequestParser', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid slash command', async () => {
|
test('invalid slash command', async () => {
|
||||||
const chatService = mockObject<IChatService>()({});
|
const slashCommandService = mockObject<IChatSlashCommandService>()({});
|
||||||
chatService.getSlashCommands.returns(Promise.resolve([{ command: 'fix' }]));
|
slashCommandService.getCommands.returns([{ command: 'fix' }]);
|
||||||
instantiationService.stub(IChatService, chatService as any);
|
instantiationService.stub(IChatSlashCommandService, slashCommandService as any);
|
||||||
|
|
||||||
parser = instantiationService.createInstance(ChatRequestParser);
|
parser = instantiationService.createInstance(ChatRequestParser);
|
||||||
const text = '/explain this';
|
const text = '/explain this';
|
||||||
|
@ -70,9 +70,9 @@ suite('ChatRequestParser', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multiple slash commands', async () => {
|
test('multiple slash commands', async () => {
|
||||||
const chatService = mockObject<IChatService>()({});
|
const slashCommandService = mockObject<IChatSlashCommandService>()({});
|
||||||
chatService.getSlashCommands.returns(Promise.resolve([{ command: 'fix' }]));
|
slashCommandService.getCommands.returns([{ command: 'fix' }]);
|
||||||
instantiationService.stub(IChatService, chatService as any);
|
instantiationService.stub(IChatSlashCommandService, slashCommandService as any);
|
||||||
|
|
||||||
parser = instantiationService.createInstance(ChatRequestParser);
|
parser = instantiationService.createInstance(ChatRequestParser);
|
||||||
const text = '/fix /fix';
|
const text = '/fix /fix';
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { assertSnapshot } from 'vs/base/test/common/snapshot';
|
import { assertSnapshot } from 'vs/base/test/common/snapshot';
|
||||||
|
@ -22,10 +21,10 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
import { IViewsService } from 'vs/workbench/common/views';
|
import { IViewsService } from 'vs/workbench/common/views';
|
||||||
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentService, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||||
import { ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IChat, IChatProgress, IChatProvider, IChatRequest, IChatResponse, IPersistedChatState, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChat, IChatProgress, IChatProvider, IChatRequest } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { ChatService } from 'vs/workbench/contrib/chat/common/chatServiceImpl';
|
import { ChatService } from 'vs/workbench/contrib/chat/common/chatServiceImpl';
|
||||||
import { ChatSlashCommandService, IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
import { ChatSlashCommandService, IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
|
@ -36,29 +35,18 @@ import { TestContextService, TestExtensionService, TestStorageService } from 'vs
|
||||||
class SimpleTestProvider extends Disposable implements IChatProvider {
|
class SimpleTestProvider extends Disposable implements IChatProvider {
|
||||||
private static sessionId = 0;
|
private static sessionId = 0;
|
||||||
|
|
||||||
lastInitialState = undefined;
|
|
||||||
|
|
||||||
readonly displayName = 'Test';
|
readonly displayName = 'Test';
|
||||||
|
|
||||||
private _onDidChangeState = this._register(new Emitter());
|
|
||||||
|
|
||||||
constructor(readonly id: string) {
|
constructor(readonly id: string) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareSession(initialState: any) {
|
async prepareSession(): Promise<IChat> {
|
||||||
this.lastInitialState = initialState;
|
return {
|
||||||
return Promise.resolve(<IChat>{
|
|
||||||
id: SimpleTestProvider.sessionId++,
|
id: SimpleTestProvider.sessionId++,
|
||||||
username: 'test',
|
|
||||||
responderUsername: 'test',
|
responderUsername: 'test',
|
||||||
requesterUsername: 'test',
|
requesterUsername: 'test',
|
||||||
onDidChangeState: this._onDidChangeState.event
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
changeState(state: any) {
|
|
||||||
this._onDidChangeState.fire(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void): Promise<{ session: IChat; followups: never[] }> {
|
async provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void): Promise<{ session: IChat; followups: never[] }> {
|
||||||
|
@ -66,10 +54,14 @@ class SimpleTestProvider extends Disposable implements IChatProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Chat provider for testing that returns used context */
|
const chatAgentWithUsedContextId = 'ChatProviderWithUsedContext';
|
||||||
class ChatProviderWithUsedContext extends SimpleTestProvider implements IChatProvider {
|
const chatAgentWithUsedContext: IChatAgent = {
|
||||||
override provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void): Promise<{ session: IChat; followups: never[] }> {
|
id: chatAgentWithUsedContextId,
|
||||||
|
metadata: {},
|
||||||
|
async provideSlashCommands(token) {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
async invoke(request, progress, history, token) {
|
||||||
progress({
|
progress({
|
||||||
documents: [
|
documents: [
|
||||||
{
|
{
|
||||||
|
@ -82,9 +74,9 @@ class ChatProviderWithUsedContext extends SimpleTestProvider implements IChatPro
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
return super.provideReply(request, progress);
|
return {};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
suite('Chat', () => {
|
suite('Chat', () => {
|
||||||
const testDisposables = ensureNoDisposablesAreLeakedInTestSuite();
|
const testDisposables = ensureNoDisposablesAreLeakedInTestSuite();
|
||||||
|
@ -92,6 +84,8 @@ suite('Chat', () => {
|
||||||
let storageService: IStorageService;
|
let storageService: IStorageService;
|
||||||
let instantiationService: TestInstantiationService;
|
let instantiationService: TestInstantiationService;
|
||||||
|
|
||||||
|
let chatAgentService: IChatAgentService;
|
||||||
|
|
||||||
setup(async () => {
|
setup(async () => {
|
||||||
instantiationService = testDisposables.add(new TestInstantiationService(new ServiceCollection(
|
instantiationService = testDisposables.add(new TestInstantiationService(new ServiceCollection(
|
||||||
[IChatVariablesService, new MockChatVariablesService()],
|
[IChatVariablesService, new MockChatVariablesService()],
|
||||||
|
@ -105,7 +99,18 @@ suite('Chat', () => {
|
||||||
instantiationService.stub(IChatContributionService, new TestExtensionService());
|
instantiationService.stub(IChatContributionService, new TestExtensionService());
|
||||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||||
instantiationService.stub(IChatSlashCommandService, testDisposables.add(instantiationService.createInstance(ChatSlashCommandService)));
|
instantiationService.stub(IChatSlashCommandService, testDisposables.add(instantiationService.createInstance(ChatSlashCommandService)));
|
||||||
instantiationService.stub(IChatAgentService, testDisposables.add(instantiationService.createInstance(ChatAgentService)));
|
|
||||||
|
chatAgentService = testDisposables.add(instantiationService.createInstance(ChatAgentService));
|
||||||
|
instantiationService.stub(IChatAgentService, chatAgentService);
|
||||||
|
|
||||||
|
const agent = {
|
||||||
|
id: 'testAgent',
|
||||||
|
metadata: { isDefault: true },
|
||||||
|
async invoke(request, progress, history, token) {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
} as IChatAgent;
|
||||||
|
testDisposables.add(chatAgentService.registerAgent(agent));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('retrieveSession', async () => {
|
test('retrieveSession', async () => {
|
||||||
|
@ -123,12 +128,7 @@ suite('Chat', () => {
|
||||||
await session2.waitForInitialization();
|
await session2.waitForInitialization();
|
||||||
session2!.addRequest({ parts: [], text: 'request 2' });
|
session2!.addRequest({ parts: [], text: 'request 2' });
|
||||||
|
|
||||||
assert.strictEqual(provider1.lastInitialState, undefined);
|
|
||||||
assert.strictEqual(provider2.lastInitialState, undefined);
|
|
||||||
provider1.changeState({ state: 'provider1_state' });
|
|
||||||
provider2.changeState({ state: 'provider2_state' });
|
|
||||||
storageService.flush();
|
storageService.flush();
|
||||||
|
|
||||||
const testService2 = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService2 = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
testDisposables.add(testService2.registerProvider(provider1));
|
testDisposables.add(testService2.registerProvider(provider1));
|
||||||
testDisposables.add(testService2.registerProvider(provider2));
|
testDisposables.add(testService2.registerProvider(provider2));
|
||||||
|
@ -136,8 +136,8 @@ suite('Chat', () => {
|
||||||
await retrieved1!.waitForInitialization();
|
await retrieved1!.waitForInitialization();
|
||||||
const retrieved2 = testDisposables.add(testService2.getOrRestoreSession(session2.sessionId)!);
|
const retrieved2 = testDisposables.add(testService2.getOrRestoreSession(session2.sessionId)!);
|
||||||
await retrieved2!.waitForInitialization();
|
await retrieved2!.waitForInitialization();
|
||||||
assert.deepStrictEqual(provider1.lastInitialState, { state: 'provider1_state' });
|
assert.deepStrictEqual(retrieved1.getRequests()[0]?.message.text, 'request 1');
|
||||||
assert.deepStrictEqual(provider2.lastInitialState, { state: 'provider2_state' });
|
assert.deepStrictEqual(retrieved2.getRequests()[0]?.message.text, 'request 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Handles failed session startup', async () => {
|
test('Handles failed session startup', async () => {
|
||||||
|
@ -172,10 +172,7 @@ suite('Chat', () => {
|
||||||
testDisposables.add(testService.registerProvider({
|
testDisposables.add(testService.registerProvider({
|
||||||
id,
|
id,
|
||||||
displayName: 'Test',
|
displayName: 'Test',
|
||||||
prepareSession: function (initialState: IPersistedChatState | undefined, token: CancellationToken): ProviderResult<IChat | undefined> {
|
prepareSession: function (token: CancellationToken): ProviderResult<IChat | undefined> {
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
},
|
|
||||||
provideReply: function (request: IChatRequest, progress: (progress: IChatProgress) => void, token: CancellationToken): ProviderResult<IChatResponse> {
|
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -184,45 +181,13 @@ suite('Chat', () => {
|
||||||
testDisposables.add(testService.registerProvider({
|
testDisposables.add(testService.registerProvider({
|
||||||
id,
|
id,
|
||||||
displayName: 'Test',
|
displayName: 'Test',
|
||||||
prepareSession: function (initialState: IPersistedChatState | undefined, token: CancellationToken): ProviderResult<IChat | undefined> {
|
prepareSession: function (token: CancellationToken): ProviderResult<IChat | undefined> {
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
},
|
|
||||||
provideReply: function (request: IChatRequest, progress: (progress: IChatProgress) => void, token: CancellationToken): ProviderResult<IChatResponse> {
|
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}, 'Expected to throw for dupe provider');
|
}, 'Expected to throw for dupe provider');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getSlashCommands', async () => {
|
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
|
||||||
const provider = testDisposables.add(new class extends SimpleTestProvider {
|
|
||||||
constructor() {
|
|
||||||
super('testProvider');
|
|
||||||
}
|
|
||||||
|
|
||||||
provideSlashCommands(): ProviderResult<ISlashCommand[]> {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
command: 'command',
|
|
||||||
detail: 'detail',
|
|
||||||
sortText: 'sortText',
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
testDisposables.add(testService.registerProvider(provider));
|
|
||||||
|
|
||||||
const model = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
|
||||||
const commands = await testService.getSlashCommands(model.sessionId, CancellationToken.None);
|
|
||||||
|
|
||||||
assert.strictEqual(commands?.length, 1);
|
|
||||||
assert.strictEqual(commands?.[0].command, 'command');
|
|
||||||
assert.strictEqual(commands?.[0].detail, 'detail');
|
|
||||||
assert.strictEqual(commands?.[0].sortText, 'sortText');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('sendRequestToProvider', async () => {
|
test('sendRequestToProvider', async () => {
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
||||||
|
@ -249,18 +214,16 @@ suite('Chat', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can serialize', async () => {
|
test('can serialize', async () => {
|
||||||
|
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext));
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
const providerId = 'ChatProviderWithUsedContext';
|
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
||||||
|
|
||||||
testDisposables.add(testService.registerProvider(testDisposables.add(new ChatProviderWithUsedContext(providerId))));
|
const model = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
||||||
|
|
||||||
const model = testDisposables.add(testService.startSession(providerId, CancellationToken.None));
|
|
||||||
assert.strictEqual(model.getRequests().length, 0);
|
assert.strictEqual(model.getRequests().length, 0);
|
||||||
|
|
||||||
await assertSnapshot(model.toExport());
|
await assertSnapshot(model.toExport());
|
||||||
|
|
||||||
const response = await testService.sendRequest(model.sessionId, 'test request');
|
const response = await testService.sendRequest(model.sessionId, `@${chatAgentWithUsedContextId} test request`);
|
||||||
assert(response);
|
assert(response);
|
||||||
|
|
||||||
await response.responseCompletePromise;
|
await response.responseCompletePromise;
|
||||||
|
@ -271,21 +234,18 @@ suite('Chat', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can deserialize', async () => {
|
test('can deserialize', async () => {
|
||||||
|
|
||||||
let serializedChatData: ISerializableChatData;
|
let serializedChatData: ISerializableChatData;
|
||||||
|
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext));
|
||||||
const providerId = 'ChatProviderWithUsedContext';
|
|
||||||
|
|
||||||
// create the first service, send request, get response, and serialize the state
|
// create the first service, send request, get response, and serialize the state
|
||||||
{ // serapate block to not leak variables in outer scope
|
{ // serapate block to not leak variables in outer scope
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
|
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
||||||
|
|
||||||
testDisposables.add(testService.registerProvider(testDisposables.add(new ChatProviderWithUsedContext(providerId))));
|
const chatModel1 = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
||||||
|
|
||||||
const chatModel1 = testDisposables.add(testService.startSession(providerId, CancellationToken.None));
|
|
||||||
assert.strictEqual(chatModel1.getRequests().length, 0);
|
assert.strictEqual(chatModel1.getRequests().length, 0);
|
||||||
|
|
||||||
const response = await testService.sendRequest(chatModel1.sessionId, 'test request');
|
const response = await testService.sendRequest(chatModel1.sessionId, `@${chatAgentWithUsedContextId} test request`);
|
||||||
assert(response);
|
assert(response);
|
||||||
|
|
||||||
await response.responseCompletePromise;
|
await response.responseCompletePromise;
|
||||||
|
@ -296,17 +256,11 @@ suite('Chat', () => {
|
||||||
// try deserializing the state into a new service
|
// try deserializing the state into a new service
|
||||||
|
|
||||||
const testService2 = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService2 = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
|
testDisposables.add(testService2.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
||||||
testDisposables.add(testService2.registerProvider(testDisposables.add(new ChatProviderWithUsedContext(providerId))));
|
|
||||||
|
|
||||||
const chatModel2 = testService2.loadSessionFromContent(serializedChatData);
|
const chatModel2 = testService2.loadSessionFromContent(serializedChatData);
|
||||||
assert(chatModel2);
|
assert(chatModel2);
|
||||||
|
|
||||||
// should `loadSessionFromContent` return `ChatModel` that's disposable instead of `IChatModel`?
|
|
||||||
testDisposables.add({
|
|
||||||
dispose: () => testService2.clearSession(serializedChatData.sessionId)
|
|
||||||
});
|
|
||||||
|
|
||||||
await assertSnapshot(chatModel2.toExport());
|
await assertSnapshot(chatModel2.toExport());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const allApiProposals = Object.freeze({
|
||||||
authSession: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts',
|
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',
|
canonicalUriProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.canonicalUriProvider.d.ts',
|
||||||
chat: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chat.d.ts',
|
chat: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chat.d.ts',
|
||||||
chatAgents: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents.d.ts',
|
|
||||||
chatAgents2: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2.d.ts',
|
chatAgents2: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2.d.ts',
|
||||||
chatAgents2Additions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts',
|
chatAgents2Additions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts',
|
||||||
chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts',
|
chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts',
|
||||||
|
|
39
src/vscode-dts/vscode.proposed.chatAgents.d.ts
vendored
39
src/vscode-dts/vscode.proposed.chatAgents.d.ts
vendored
|
@ -1,39 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* 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' {
|
|
||||||
|
|
||||||
export interface ChatAgentContext {
|
|
||||||
history: ChatMessage[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatAgentResponse {
|
|
||||||
message: MarkdownString | InteractiveProgressFileTree;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatAgentResult {
|
|
||||||
followUp?: InteractiveSessionFollowup[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatAgentCommand {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatAgentMetadata {
|
|
||||||
description: string;
|
|
||||||
fullName?: string;
|
|
||||||
icon?: Uri;
|
|
||||||
subCommands: ChatAgentCommand[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatAgent {
|
|
||||||
(prompt: ChatMessage, context: ChatAgentContext, progress: Progress<ChatAgentResponse>, token: CancellationToken): Thenable<ChatAgentResult | void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace chat {
|
|
||||||
export function registerAgent(id: string, agent: ChatAgent, metadata: ChatAgentMetadata): Disposable;
|
|
||||||
}
|
|
||||||
}
|
|
106
src/vscode-dts/vscode.proposed.interactive.d.ts
vendored
106
src/vscode-dts/vscode.proposed.interactive.d.ts
vendored
|
@ -85,9 +85,6 @@ declare module 'vscode' {
|
||||||
handleInteractiveEditorResponseFeedback?(session: S, response: R, kind: InteractiveEditorResponseFeedbackKind): void;
|
handleInteractiveEditorResponseFeedback?(session: S, response: R, kind: InteractiveEditorResponseFeedbackKind): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface InteractiveSessionState { }
|
|
||||||
|
|
||||||
export interface InteractiveSessionParticipantInformation {
|
export interface InteractiveSessionParticipantInformation {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
@ -101,81 +98,8 @@ declare module 'vscode' {
|
||||||
requester: InteractiveSessionParticipantInformation;
|
requester: InteractiveSessionParticipantInformation;
|
||||||
responder: InteractiveSessionParticipantInformation;
|
responder: InteractiveSessionParticipantInformation;
|
||||||
inputPlaceholder?: string;
|
inputPlaceholder?: string;
|
||||||
|
|
||||||
saveState?(): InteractiveSessionState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InteractiveSessionRequestArgs {
|
|
||||||
command: string;
|
|
||||||
args: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveRequest {
|
|
||||||
session: InteractiveSession;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveResponseErrorDetails {
|
|
||||||
message: string;
|
|
||||||
responseIsIncomplete?: boolean;
|
|
||||||
responseIsFiltered?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveResponseForProgress {
|
|
||||||
errorDetails?: InteractiveResponseErrorDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveContentReference {
|
|
||||||
reference: Uri | Location;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveInlineContentReference {
|
|
||||||
inlineReference: Uri | Location;
|
|
||||||
title?: string; // eg symbol name
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveProgressContent {
|
|
||||||
content: string | MarkdownString;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveProgressId {
|
|
||||||
responseId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveProgressTask {
|
|
||||||
placeholder: string;
|
|
||||||
resolvedContent: Thenable<InteractiveProgressContent | InteractiveProgressFileTree>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileTreeData {
|
|
||||||
label: string;
|
|
||||||
uri: Uri;
|
|
||||||
children?: FileTreeData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveProgressFileTree {
|
|
||||||
treeData: FileTreeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DocumentContext {
|
|
||||||
uri: Uri;
|
|
||||||
version: number;
|
|
||||||
ranges: Range[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveProgressUsedContext {
|
|
||||||
documents: DocumentContext[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InteractiveProgress =
|
|
||||||
| InteractiveProgressContent
|
|
||||||
| InteractiveProgressId
|
|
||||||
| InteractiveProgressTask
|
|
||||||
| InteractiveProgressFileTree
|
|
||||||
| InteractiveProgressUsedContext
|
|
||||||
| InteractiveContentReference
|
|
||||||
| InteractiveInlineContentReference;
|
|
||||||
|
|
||||||
export interface InteractiveResponseCommand {
|
export interface InteractiveResponseCommand {
|
||||||
commandId: string;
|
commandId: string;
|
||||||
args?: any[];
|
args?: any[];
|
||||||
|
@ -183,40 +107,18 @@ declare module 'vscode' {
|
||||||
when?: string;
|
when?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InteractiveSessionSlashCommand {
|
|
||||||
command: string;
|
|
||||||
kind: CompletionItemKind;
|
|
||||||
detail?: string;
|
|
||||||
shouldRepopulate?: boolean;
|
|
||||||
followupPlaceholder?: string;
|
|
||||||
executeImmediately?: boolean;
|
|
||||||
yieldTo?: ReadonlyArray<{ readonly command: string }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InteractiveSessionReplyFollowup {
|
export interface InteractiveSessionReplyFollowup {
|
||||||
message: string;
|
message: string;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
||||||
// Extensions can put any serializable data here, such as an ID/version
|
|
||||||
metadata?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InteractiveSessionFollowup = InteractiveSessionReplyFollowup | InteractiveResponseCommand;
|
|
||||||
|
|
||||||
export type InteractiveWelcomeMessageContent = string | MarkdownString | InteractiveSessionReplyFollowup[];
|
export type InteractiveWelcomeMessageContent = string | MarkdownString | InteractiveSessionReplyFollowup[];
|
||||||
|
|
||||||
export interface InteractiveSessionProvider<S extends InteractiveSession = InteractiveSession> {
|
export interface InteractiveSessionProvider<S extends InteractiveSession = InteractiveSession> {
|
||||||
provideWelcomeMessage?(token: CancellationToken): ProviderResult<InteractiveWelcomeMessageContent[]>;
|
provideWelcomeMessage?(token: CancellationToken): ProviderResult<InteractiveWelcomeMessageContent[]>;
|
||||||
provideSampleQuestions?(token: CancellationToken): ProviderResult<InteractiveSessionReplyFollowup[]>;
|
provideSampleQuestions?(token: CancellationToken): ProviderResult<InteractiveSessionReplyFollowup[]>;
|
||||||
provideFollowups?(session: S, token: CancellationToken): ProviderResult<(string | InteractiveSessionFollowup)[]>;
|
prepareSession(token: CancellationToken): ProviderResult<S>;
|
||||||
provideSlashCommands?(session: S, token: CancellationToken): ProviderResult<InteractiveSessionSlashCommand[]>;
|
|
||||||
|
|
||||||
prepareSession(initialState: InteractiveSessionState | undefined, token: CancellationToken): ProviderResult<S>;
|
|
||||||
provideResponseWithProgress(request: InteractiveRequest, progress: Progress<InteractiveProgress>, token: CancellationToken): ProviderResult<InteractiveResponseForProgress>;
|
|
||||||
|
|
||||||
// eslint-disable-next-line local/vscode-dts-provider-naming
|
|
||||||
removeRequest(session: S, requestId: string): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InteractiveSessionDynamicRequest {
|
export interface InteractiveSessionDynamicRequest {
|
||||||
|
@ -224,12 +126,6 @@ declare module 'vscode' {
|
||||||
* The message that will be displayed in the UI
|
* The message that will be displayed in the UI
|
||||||
*/
|
*/
|
||||||
message: string;
|
message: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* Any extra metadata/context that will go to the provider.
|
|
||||||
* NOTE not actually used yet.
|
|
||||||
*/
|
|
||||||
metadata?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace interactive {
|
export namespace interactive {
|
||||||
|
|
|
@ -13,8 +13,6 @@ declare module 'vscode' {
|
||||||
export interface InteractiveSessionVoteAction {
|
export interface InteractiveSessionVoteAction {
|
||||||
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
||||||
kind: 'vote';
|
kind: 'vote';
|
||||||
// sessionId: string;
|
|
||||||
responseId: string;
|
|
||||||
direction: InteractiveSessionVoteDirection;
|
direction: InteractiveSessionVoteDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +25,6 @@ declare module 'vscode' {
|
||||||
export interface InteractiveSessionCopyAction {
|
export interface InteractiveSessionCopyAction {
|
||||||
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
||||||
kind: 'copy';
|
kind: 'copy';
|
||||||
// sessionId: string;
|
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
copyType: InteractiveSessionCopyKind;
|
copyType: InteractiveSessionCopyKind;
|
||||||
copiedCharacters: number;
|
copiedCharacters: number;
|
||||||
|
@ -39,8 +35,6 @@ declare module 'vscode' {
|
||||||
export interface InteractiveSessionInsertAction {
|
export interface InteractiveSessionInsertAction {
|
||||||
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
||||||
kind: 'insert';
|
kind: 'insert';
|
||||||
// sessionId: string;
|
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
totalCharacters: number;
|
totalCharacters: number;
|
||||||
newFile?: boolean;
|
newFile?: boolean;
|
||||||
|
@ -49,8 +43,6 @@ declare module 'vscode' {
|
||||||
export interface InteractiveSessionTerminalAction {
|
export interface InteractiveSessionTerminalAction {
|
||||||
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
||||||
kind: 'runInTerminal';
|
kind: 'runInTerminal';
|
||||||
// sessionId: string;
|
|
||||||
responseId: string;
|
|
||||||
codeBlockIndex: number;
|
codeBlockIndex: number;
|
||||||
languageId?: string;
|
languageId?: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue