mirror of
https://github.com/Microsoft/vscode
synced 2024-10-05 19:02:54 +00:00
Kill "interactive session provider" DEAD (#209700)
* Reduce chat provider usage * Clear out IChat props * Delete interactive session provider API * Totally remove static chat provider registration * Clean up onDidRegisterProvider events * Remove provider ID references from model * Eliminate many 'providerId' references * Simplify view registration * Clean up participant-specific actions * Delete getProviderInfos * Rename context key * Fix tests * Fix action label * Fix view title * Fix test * Fix test * Fix integration test * Remove more providerId * Add API stub to make this compatible with the existing Copilot Chat
This commit is contained in:
parent
8af2f4e3bf
commit
ed6c6d3f28
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import { commands, CancellationToken, ChatContext, ChatRequest, ChatResult, ChatVariableLevel, Disposable, Event, EventEmitter, InteractiveSession, ProviderResult, chat, interactive } from 'vscode';
|
import { ChatContext, ChatRequest, ChatResult, ChatVariableLevel, Disposable, Event, EventEmitter, chat, commands } from 'vscode';
|
||||||
import { DeferredPromise, assertNoRpc, closeAllEditors, disposeAll } from '../utils';
|
import { DeferredPromise, assertNoRpc, closeAllEditors, disposeAll } from '../utils';
|
||||||
|
|
||||||
suite('chat', () => {
|
suite('chat', () => {
|
||||||
|
@ -31,14 +31,6 @@ suite('chat', () => {
|
||||||
function setupParticipant(): Event<{ request: ChatRequest; context: ChatContext }> {
|
function setupParticipant(): Event<{ request: ChatRequest; context: ChatContext }> {
|
||||||
const emitter = new EventEmitter<{ request: ChatRequest; context: ChatContext }>();
|
const emitter = new EventEmitter<{ request: ChatRequest; context: ChatContext }>();
|
||||||
disposables.push(emitter);
|
disposables.push(emitter);
|
||||||
disposables.push(interactive.registerInteractiveSessionProvider('provider', {
|
|
||||||
prepareSession: (_token: CancellationToken): ProviderResult<InteractiveSession> => {
|
|
||||||
return {
|
|
||||||
requester: { name: 'test' },
|
|
||||||
responder: { name: 'test' },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const participant = chat.createChatParticipant('api-test.participant', (request, context, _progress, _token) => {
|
const participant = chat.createChatParticipant('api-test.participant', (request, context, _progress, _token) => {
|
||||||
emitter.fire({ request, context });
|
emitter.fire({ request, context });
|
||||||
|
@ -52,19 +44,29 @@ suite('chat', () => {
|
||||||
const onRequest = setupParticipant();
|
const onRequest = setupParticipant();
|
||||||
commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' });
|
commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' });
|
||||||
|
|
||||||
|
const deferred = new DeferredPromise<void>();
|
||||||
let i = 0;
|
let i = 0;
|
||||||
disposables.push(onRequest(request => {
|
disposables.push(onRequest(request => {
|
||||||
|
try {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
assert.deepStrictEqual(request.request.command, 'hello');
|
assert.deepStrictEqual(request.request.command, 'hello');
|
||||||
assert.strictEqual(request.request.prompt, 'friend');
|
assert.strictEqual(request.request.prompt, 'friend');
|
||||||
i++;
|
i++;
|
||||||
|
setTimeout(() => {
|
||||||
commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' });
|
commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' });
|
||||||
|
}, 0);
|
||||||
} else {
|
} else {
|
||||||
assert.strictEqual(request.context.history.length, 1);
|
assert.strictEqual(request.context.history.length, 2);
|
||||||
assert.strictEqual(request.context.history[0].participant, 'api-test.participant');
|
assert.strictEqual(request.context.history[0].participant, 'api-test.participant');
|
||||||
assert.strictEqual(request.context.history[0].command, 'hello');
|
assert.strictEqual(request.context.history[0].command, 'hello');
|
||||||
|
deferred.complete();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
deferred.error(e);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
await deferred.p;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('participant and variable', async () => {
|
test('participant and variable', async () => {
|
||||||
|
@ -82,15 +84,6 @@ suite('chat', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('result metadata is returned to the followup provider', async () => {
|
test('result metadata is returned to the followup provider', async () => {
|
||||||
disposables.push(interactive.registerInteractiveSessionProvider('provider', {
|
|
||||||
prepareSession: (_token: CancellationToken): ProviderResult<InteractiveSession> => {
|
|
||||||
return {
|
|
||||||
requester: { name: 'test' },
|
|
||||||
responder: { name: 'test' },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const deferred = new DeferredPromise<ChatResult>();
|
const deferred = new DeferredPromise<ChatResult>();
|
||||||
const participant = chat.createChatParticipant('api-test.participant', (_request, _context, _progress, _token) => {
|
const participant = chat.createChatParticipant('api-test.participant', (_request, _context, _progress, _token) => {
|
||||||
return { metadata: { key: 'value' } };
|
return { metadata: { key: 'value' } };
|
||||||
|
|
|
@ -76,7 +76,6 @@ import './mainThreadNotebookRenderers';
|
||||||
import './mainThreadNotebookSaveParticipant';
|
import './mainThreadNotebookSaveParticipant';
|
||||||
import './mainThreadInteractive';
|
import './mainThreadInteractive';
|
||||||
import './mainThreadInlineChat';
|
import './mainThreadInlineChat';
|
||||||
import './mainThreadChat';
|
|
||||||
import './mainThreadTask';
|
import './mainThreadTask';
|
||||||
import './mainThreadLabelService';
|
import './mainThreadLabelService';
|
||||||
import './mainThreadTunnelService';
|
import './mainThreadTunnelService';
|
||||||
|
|
|
@ -1,84 +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 { Emitter } from 'vs/base/common/event';
|
|
||||||
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
import { ExtHostChatShape, ExtHostContext, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadChat)
|
|
||||||
export class MainThreadChat extends Disposable implements MainThreadChatShape {
|
|
||||||
|
|
||||||
private readonly _providerRegistrations = this._register(new DisposableMap<number>());
|
|
||||||
private readonly _stateEmitters = new Map<number, Emitter<any>>();
|
|
||||||
|
|
||||||
private readonly _proxy: ExtHostChatShape;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
extHostContext: IExtHostContext,
|
|
||||||
@IChatService private readonly _chatService: IChatService,
|
|
||||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
|
|
||||||
@IChatContributionService private readonly _chatContribService: IChatContributionService,
|
|
||||||
@ILogService private readonly _logService: ILogService,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
$transferActiveChatSession(toWorkspace: UriComponents): void {
|
|
||||||
const widget = this._chatWidgetService.lastFocusedWidget;
|
|
||||||
const sessionId = widget?.viewModel?.model.sessionId;
|
|
||||||
if (!sessionId) {
|
|
||||||
this._logService.error(`MainThreadChat#$transferActiveChatSession: No active chat session found`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputValue = widget?.inputEditor.getValue() ?? '';
|
|
||||||
this._chatService.transferChatSession({ sessionId, inputValue }, URI.revive(toWorkspace));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $registerChatProvider(handle: number, id: string): Promise<void> {
|
|
||||||
const registration = this._chatContribService.registeredProviders.find(staticProvider => staticProvider.id === id);
|
|
||||||
if (!registration) {
|
|
||||||
throw new Error(`Provider ${id} must be declared in the package.json.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unreg = this._chatService.registerProvider({
|
|
||||||
id,
|
|
||||||
prepareSession: async (token) => {
|
|
||||||
const session = await this._proxy.$prepareChat(handle, token);
|
|
||||||
if (!session) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emitter = new Emitter<any>();
|
|
||||||
this._stateEmitters.set(session.id, emitter);
|
|
||||||
return {
|
|
||||||
id: session.id,
|
|
||||||
dispose: () => {
|
|
||||||
emitter.dispose();
|
|
||||||
this._stateEmitters.delete(session.id);
|
|
||||||
this._proxy.$releaseSession(session.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this._providerRegistrations.set(handle, unreg);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $acceptChatState(sessionId: number, state: any): Promise<void> {
|
|
||||||
this._stateEmitters.get(sessionId)?.fire(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $unregisterChatProvider(handle: number): Promise<void> {
|
|
||||||
this._providerRegistrations.deleteAndDispose(handle);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Disposable, DisposableMap, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableMap, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
import { revive } from 'vs/base/common/marshalling';
|
||||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||||
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { getWordAtText } from 'vs/editor/common/core/wordHelper';
|
import { getWordAtText } from 'vs/editor/common/core/wordHelper';
|
||||||
|
@ -15,6 +16,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { ExtHostChatAgentsShape2, ExtHostContext, IChatProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostChatAgentsShape2, ExtHostContext, IChatProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } 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 { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
||||||
|
@ -48,6 +50,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
||||||
@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,
|
||||||
|
@ILogService private readonly _logService: ILogService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2);
|
||||||
|
@ -75,6 +78,18 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
||||||
this._agents.deleteAndDispose(handle);
|
this._agents.deleteAndDispose(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$transferActiveChatSession(toWorkspace: UriComponents): void {
|
||||||
|
const widget = this._chatWidgetService.lastFocusedWidget;
|
||||||
|
const sessionId = widget?.viewModel?.model.sessionId;
|
||||||
|
if (!sessionId) {
|
||||||
|
this._logService.error(`MainThreadChat#$transferActiveChatSession: No active chat session found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputValue = widget?.inputEditor.getValue() ?? '';
|
||||||
|
this._chatService.transferChatSession({ sessionId, inputValue }, URI.revive(toWorkspace));
|
||||||
|
}
|
||||||
|
|
||||||
$registerAgent(handle: number, extension: ExtensionIdentifier, id: string, metadata: IExtensionChatAgentMetadata, dynamicProps: { name: string; description: string } | undefined): void {
|
$registerAgent(handle: number, extension: ExtensionIdentifier, id: string, metadata: IExtensionChatAgentMetadata, dynamicProps: { name: string; description: string } | undefined): void {
|
||||||
const staticAgentRegistration = this._chatAgentService.getAgent(id);
|
const staticAgentRegistration = this._chatAgentService.getAgent(id);
|
||||||
if (!staticAgentRegistration && !dynamicProps) {
|
if (!staticAgentRegistration && !dynamicProps) {
|
||||||
|
|
|
@ -196,7 +196,6 @@ export class MainThreadEditorTabs implements MainThreadEditorTabsShape {
|
||||||
if (editor instanceof ChatEditorInput) {
|
if (editor instanceof ChatEditorInput) {
|
||||||
return {
|
return {
|
||||||
kind: TabInputKind.ChatEditorInput,
|
kind: TabInputKind.ChatEditorInput,
|
||||||
providerId: editor.providerId ?? 'unknown',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
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 { Disposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { Schemas, matchesScheme } from 'vs/base/common/network';
|
import { Schemas, matchesScheme } 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';
|
||||||
|
@ -27,9 +27,7 @@ import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||||
import { IExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
import { IExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||||
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
|
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 { ExtHostChatAgents2 } from 'vs/workbench/api/common/extHostChatAgents2';
|
||||||
import { IExtHostLanguageModels } from 'vs/workbench/api/common/extHostLanguageModels';
|
|
||||||
import { ExtHostChatVariables } from 'vs/workbench/api/common/extHostChatVariables';
|
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 { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
|
||||||
|
@ -57,6 +55,7 @@ import { ExtHostInteractiveEditor } from 'vs/workbench/api/common/extHostInlineC
|
||||||
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
|
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
|
||||||
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
|
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 { IExtHostLanguageModels } from 'vs/workbench/api/common/extHostLanguageModels';
|
||||||
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 { IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService';
|
||||||
import { IExtHostManagedSockets } from 'vs/workbench/api/common/extHostManagedSockets';
|
import { IExtHostManagedSockets } from 'vs/workbench/api/common/extHostManagedSockets';
|
||||||
|
@ -84,6 +83,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
|
||||||
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
||||||
import { ExtHostTelemetryLogger, IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry';
|
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 { IExtHostTerminalShellIntegration } from 'vs/workbench/api/common/extHostTerminalShellIntegration';
|
||||||
import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
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 { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
|
||||||
|
@ -107,7 +107,6 @@ import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/serv
|
||||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||||
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
|
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
|
||||||
import type * as vscode from 'vscode';
|
import type * as vscode from 'vscode';
|
||||||
import { IExtHostTerminalShellIntegration } from 'vs/workbench/api/common/extHostTerminalShellIntegration';
|
|
||||||
|
|
||||||
export interface IExtensionRegistries {
|
export interface IExtensionRegistries {
|
||||||
mine: ExtensionDescriptionRegistry;
|
mine: ExtensionDescriptionRegistry;
|
||||||
|
@ -213,7 +212,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||||
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 extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands));
|
const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands));
|
||||||
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));
|
|
||||||
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 extHostStatusBar = rpcProtocol.set(ExtHostContext.ExtHostStatusBar, new ExtHostStatusBar(rpcProtocol, extHostCommands.converter));
|
const extHostStatusBar = rpcProtocol.set(ExtHostContext.ExtHostStatusBar, new ExtHostStatusBar(rpcProtocol, extHostCommands.converter));
|
||||||
|
@ -1392,12 +1390,13 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||||
return extHostInteractiveEditor.registerProvider(extension, provider, metadata);
|
return extHostInteractiveEditor.registerProvider(extension, provider, metadata);
|
||||||
},
|
},
|
||||||
registerInteractiveSessionProvider(id: string, provider: vscode.InteractiveSessionProvider) {
|
registerInteractiveSessionProvider(id: string, provider: vscode.InteractiveSessionProvider) {
|
||||||
|
// temp stub
|
||||||
checkProposedApiEnabled(extension, 'interactive');
|
checkProposedApiEnabled(extension, 'interactive');
|
||||||
return extHostChat.registerChatProvider(extension, id, provider);
|
return Disposable.None;
|
||||||
},
|
},
|
||||||
transferActiveChat(toWorkspace: vscode.Uri) {
|
transferActiveChat(toWorkspace: vscode.Uri) {
|
||||||
checkProposedApiEnabled(extension, 'interactive');
|
checkProposedApiEnabled(extension, 'interactive');
|
||||||
return extHostChat.transferActiveChat(toWorkspace);
|
return extHostChatAgents2.transferActiveChat(toWorkspace);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -769,7 +769,6 @@ export interface InteractiveEditorInputDto {
|
||||||
|
|
||||||
export interface ChatEditorInputDto {
|
export interface ChatEditorInputDto {
|
||||||
kind: TabInputKind.ChatEditorInput;
|
kind: TabInputKind.ChatEditorInput;
|
||||||
providerId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MultiDiffEditorInputDto {
|
export interface MultiDiffEditorInputDto {
|
||||||
|
@ -1219,6 +1218,8 @@ export interface MainThreadChatAgentsShape2 extends IDisposable {
|
||||||
$updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void;
|
$updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void;
|
||||||
$unregisterAgent(handle: number): void;
|
$unregisterAgent(handle: number): void;
|
||||||
$handleProgressChunk(requestId: string, chunk: IChatProgressDto): Promise<number | void>;
|
$handleProgressChunk(requestId: string, chunk: IChatProgressDto): Promise<number | void>;
|
||||||
|
|
||||||
|
$transferActiveChatSession(toWorkspace: UriComponents): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatAgentCompletionItem {
|
export interface IChatAgentCompletionItem {
|
||||||
|
@ -1287,7 +1288,6 @@ export interface MainThreadUrlsShape extends IDisposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatDto {
|
export interface IChatDto {
|
||||||
id: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatRequestDto {
|
export interface IChatRequestDto {
|
||||||
|
@ -1318,18 +1318,6 @@ export type IDocumentContextDto = {
|
||||||
export type IChatProgressDto =
|
export type IChatProgressDto =
|
||||||
| Dto<IChatProgress>;
|
| Dto<IChatProgress>;
|
||||||
|
|
||||||
export interface MainThreadChatShape extends IDisposable {
|
|
||||||
$registerChatProvider(handle: number, id: string): Promise<void>;
|
|
||||||
$acceptChatState(sessionId: number, state: any): Promise<void>;
|
|
||||||
$unregisterChatProvider(handle: number): Promise<void>;
|
|
||||||
$transferActiveChatSession(toWorkspace: UriComponents): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExtHostChatShape {
|
|
||||||
$prepareChat(handle: number, token: CancellationToken): Promise<IChatDto | undefined>;
|
|
||||||
$releaseSession(sessionId: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExtHostUrlsShape {
|
export interface ExtHostUrlsShape {
|
||||||
$handleExternalUri(handle: number, uri: UriComponents): Promise<void>;
|
$handleExternalUri(handle: number, uri: UriComponents): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -2839,7 +2827,6 @@ export const MainContext = {
|
||||||
MainThreadNotebookKernels: createProxyIdentifier<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
|
MainThreadNotebookKernels: createProxyIdentifier<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
|
||||||
MainThreadNotebookRenderers: createProxyIdentifier<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
|
MainThreadNotebookRenderers: createProxyIdentifier<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
|
||||||
MainThreadInteractive: createProxyIdentifier<MainThreadInteractiveShape>('MainThreadInteractive'),
|
MainThreadInteractive: createProxyIdentifier<MainThreadInteractiveShape>('MainThreadInteractive'),
|
||||||
MainThreadChat: createProxyIdentifier<MainThreadChatShape>('MainThreadChat'),
|
|
||||||
MainThreadInlineChat: createProxyIdentifier<MainThreadInlineChatShape>('MainThreadInlineChatShape'),
|
MainThreadInlineChat: createProxyIdentifier<MainThreadInlineChatShape>('MainThreadInlineChatShape'),
|
||||||
MainThreadTheming: createProxyIdentifier<MainThreadThemingShape>('MainThreadTheming'),
|
MainThreadTheming: createProxyIdentifier<MainThreadThemingShape>('MainThreadTheming'),
|
||||||
MainThreadTunnelService: createProxyIdentifier<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
|
MainThreadTunnelService: createProxyIdentifier<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
|
||||||
|
@ -2904,7 +2891,6 @@ export const ExtHostContext = {
|
||||||
ExtHostNotebookDocumentSaveParticipant: createProxyIdentifier<ExtHostNotebookDocumentSaveParticipantShape>('ExtHostNotebookDocumentSaveParticipant'),
|
ExtHostNotebookDocumentSaveParticipant: createProxyIdentifier<ExtHostNotebookDocumentSaveParticipantShape>('ExtHostNotebookDocumentSaveParticipant'),
|
||||||
ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
|
ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
|
||||||
ExtHostInlineChat: createProxyIdentifier<ExtHostInlineChatShape>('ExtHostInlineChatShape'),
|
ExtHostInlineChat: createProxyIdentifier<ExtHostInlineChatShape>('ExtHostInlineChatShape'),
|
||||||
ExtHostChat: createProxyIdentifier<ExtHostChatShape>('ExtHostChat'),
|
|
||||||
ExtHostChatAgents2: createProxyIdentifier<ExtHostChatAgentsShape2>('ExtHostChatAgents'),
|
ExtHostChatAgents2: createProxyIdentifier<ExtHostChatAgentsShape2>('ExtHostChatAgents'),
|
||||||
ExtHostChatVariables: createProxyIdentifier<ExtHostChatVariablesShape>('ExtHostChatVariables'),
|
ExtHostChatVariables: createProxyIdentifier<ExtHostChatVariablesShape>('ExtHostChatVariables'),
|
||||||
ExtHostChatProvider: createProxyIdentifier<ExtHostLanguageModelsShape>('ExtHostChatProvider'),
|
ExtHostChatProvider: createProxyIdentifier<ExtHostLanguageModelsShape>('ExtHostChatProvider'),
|
||||||
|
|
|
@ -1,79 +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 { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { ExtHostChatShape, IChatDto, IMainContext, MainContext, MainThreadChatShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import type * as vscode from 'vscode';
|
|
||||||
|
|
||||||
class ChatProviderWrapper<T> {
|
|
||||||
|
|
||||||
private static _pool = 0;
|
|
||||||
|
|
||||||
readonly handle: number = ChatProviderWrapper._pool++;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
readonly extension: Readonly<IRelaxedExtensionDescription>,
|
|
||||||
readonly provider: T,
|
|
||||||
) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExtHostChat implements ExtHostChatShape {
|
|
||||||
private static _nextId = 0;
|
|
||||||
|
|
||||||
private readonly _chatProvider = new Map<number, ChatProviderWrapper<vscode.InteractiveSessionProvider>>();
|
|
||||||
|
|
||||||
private readonly _chatSessions = new Map<number, vscode.InteractiveSession>();
|
|
||||||
|
|
||||||
private readonly _proxy: MainThreadChatShape;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
mainContext: IMainContext,
|
|
||||||
) {
|
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#region interactive session
|
|
||||||
|
|
||||||
registerChatProvider(extension: Readonly<IRelaxedExtensionDescription>, id: string, provider: vscode.InteractiveSessionProvider): vscode.Disposable {
|
|
||||||
const wrapper = new ChatProviderWrapper(extension, provider);
|
|
||||||
this._chatProvider.set(wrapper.handle, wrapper);
|
|
||||||
this._proxy.$registerChatProvider(wrapper.handle, id);
|
|
||||||
return toDisposable(() => {
|
|
||||||
this._proxy.$unregisterChatProvider(wrapper.handle);
|
|
||||||
this._chatProvider.delete(wrapper.handle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
transferActiveChat(newWorkspace: vscode.Uri): void {
|
|
||||||
this._proxy.$transferActiveChatSession(newWorkspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $prepareChat(handle: number, token: CancellationToken): Promise<IChatDto | undefined> {
|
|
||||||
const entry = this._chatProvider.get(handle);
|
|
||||||
if (!entry) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const session = await entry.provider.prepareSession(token);
|
|
||||||
if (!session) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = ExtHostChat._nextId++;
|
|
||||||
this._chatSessions.set(id, session);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$releaseSession(sessionId: number) {
|
|
||||||
this._chatSessions.delete(sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
}
|
|
|
@ -213,6 +213,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2);
|
this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transferActiveChat(newWorkspace: vscode.Uri): void {
|
||||||
|
this._proxy.$transferActiveChatSession(newWorkspace);
|
||||||
|
}
|
||||||
|
|
||||||
createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
|
createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
|
||||||
const handle = ExtHostChatAgents2._idPool++;
|
const handle = ExtHostChatAgents2._idPool++;
|
||||||
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
|
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
|
||||||
|
|
|
@ -99,7 +99,7 @@ class ExtHostEditorTab {
|
||||||
case TabInputKind.InteractiveEditorInput:
|
case TabInputKind.InteractiveEditorInput:
|
||||||
return new InteractiveWindowInput(URI.revive(this._dto.input.uri), URI.revive(this._dto.input.inputBoxUri));
|
return new InteractiveWindowInput(URI.revive(this._dto.input.uri), URI.revive(this._dto.input.inputBoxUri));
|
||||||
case TabInputKind.ChatEditorInput:
|
case TabInputKind.ChatEditorInput:
|
||||||
return new ChatEditorTabInput(this._dto.input.providerId);
|
return new ChatEditorTabInput();
|
||||||
case TabInputKind.MultiDiffEditorInput:
|
case TabInputKind.MultiDiffEditorInput:
|
||||||
return new TextMultiDiffTabInput(this._dto.input.diffEditors.map(diff => new TextDiffTabInput(URI.revive(diff.original), URI.revive(diff.modified))));
|
return new TextMultiDiffTabInput(this._dto.input.diffEditors.map(diff => new TextDiffTabInput(URI.revive(diff.original), URI.revive(diff.modified))));
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -4207,7 +4207,7 @@ export class InteractiveWindowInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChatEditorTabInput {
|
export class ChatEditorTabInput {
|
||||||
constructor(readonly providerId: string) { }
|
constructor() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextMultiDiffTabInput {
|
export class TextMultiDiffTabInput {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { AccessibleViewProviderId, AccessibilityVerbositySettingId } from 'vs/wo
|
||||||
import { descriptionForCommand } from 'vs/workbench/contrib/accessibility/browser/accessibleViewContributions';
|
import { descriptionForCommand } from 'vs/workbench/contrib/accessibility/browser/accessibleViewContributions';
|
||||||
import { IAccessibleViewService, IAccessibleContentProvider, IAccessibleViewOptions, AccessibleViewType } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
import { IAccessibleViewService, IAccessibleContentProvider, IAccessibleViewOptions, AccessibleViewType } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||||
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { CommentAccessibilityHelpNLS } from 'vs/workbench/contrib/comments/browser/commentsAccessibility';
|
import { CommentAccessibilityHelpNLS } from 'vs/workbench/contrib/comments/browser/commentsAccessibility';
|
||||||
import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds';
|
import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds';
|
||||||
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
|
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
|
||||||
|
@ -117,7 +117,7 @@ export function getCommentCommandInfo(keybindingService: IKeybindingService, con
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChatCommandInfo(keybindingService: IKeybindingService, contextKeyService: IContextKeyService): string | undefined {
|
export function getChatCommandInfo(keybindingService: IKeybindingService, contextKeyService: IContextKeyService): string | undefined {
|
||||||
if (CONTEXT_PROVIDER_EXISTS.getValue(contextKeyService)) {
|
if (CONTEXT_HAS_DEFAULT_AGENT.getValue(contextKeyService)) {
|
||||||
const commentCommandInfo: string[] = [];
|
const commentCommandInfo: string[] = [];
|
||||||
commentCommandInfo.push(descriptionForCommand('workbench.action.quickchat.toggle', AccessibilityHelpNLS.quickChat, AccessibilityHelpNLS.quickChatNoKb, keybindingService));
|
commentCommandInfo.push(descriptionForCommand('workbench.action.quickchat.toggle', AccessibilityHelpNLS.quickChat, AccessibilityHelpNLS.quickChatNoKb, keybindingService));
|
||||||
commentCommandInfo.push(descriptionForCommand('inlineChat.start', AccessibilityHelpNLS.startInlineChat, AccessibilityHelpNLS.startInlineChatNoKb, keybindingService));
|
commentCommandInfo.push(descriptionForCommand('inlineChat.start', AccessibilityHelpNLS.startInlineChat, AccessibilityHelpNLS.startInlineChatNoKb, keybindingService));
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
import { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
import { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||||
import { localize, localize2 } from 'vs/nls';
|
import { localize, localize2 } from 'vs/nls';
|
||||||
import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IsLinuxContext, IsWindowsContext } from 'vs/platform/contextkey/common/contextkeys';
|
import { IsLinuxContext, IsWindowsContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
|
@ -21,19 +21,26 @@ import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||||
import { runAccessibilityHelpAction } from 'vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp';
|
import { runAccessibilityHelpAction } from 'vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { CHAT_VIEW_ID, IChatWidgetService, showChatView } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
import { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
||||||
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||||
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { CONTEXT_CHAT_INPUT_CURSOR_AT_TOP, CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS, CONTEXT_REQUEST, CONTEXT_RESPONSE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_CHAT_INPUT_CURSOR_AT_TOP, CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_HAS_DEFAULT_AGENT, CONTEXT_REQUEST, CONTEXT_RESPONSE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { IChatDetail, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatDetail, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatWidgetHistoryService } from 'vs/workbench/contrib/chat/common/chatWidgetHistoryService';
|
import { IChatWidgetHistoryService } from 'vs/workbench/contrib/chat/common/chatWidgetHistoryService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
|
export interface IChatViewTitleActionContext {
|
||||||
|
chatView: ChatViewPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isChatViewTitleActionContext(obj: unknown): obj is IChatViewTitleActionContext {
|
||||||
|
return obj instanceof Object && 'chatView' in obj;
|
||||||
|
}
|
||||||
|
|
||||||
export const CHAT_CATEGORY = localize2('chat.category', 'Chat');
|
export const CHAT_CATEGORY = localize2('chat.category', 'Chat');
|
||||||
export const CHAT_OPEN_ACTION_ID = 'workbench.action.chat.open';
|
export const CHAT_OPEN_ACTION_ID = 'workbench.action.chat.open';
|
||||||
|
|
||||||
|
@ -53,7 +60,7 @@ class OpenChatGlobalAction extends Action2 {
|
||||||
super({
|
super({
|
||||||
id: CHAT_OPEN_ACTION_ID,
|
id: CHAT_OPEN_ACTION_ID,
|
||||||
title: localize2('openChat', "Open Chat"),
|
title: localize2('openChat', "Open Chat"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
icon: Codicon.commentDiscussion,
|
icon: Codicon.commentDiscussion,
|
||||||
f1: false,
|
f1: false,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
|
@ -70,13 +77,7 @@ class OpenChatGlobalAction extends Action2 {
|
||||||
override async run(accessor: ServicesAccessor, opts?: string | IChatViewOpenOptions): Promise<void> {
|
override async run(accessor: ServicesAccessor, opts?: string | IChatViewOpenOptions): Promise<void> {
|
||||||
opts = typeof opts === 'string' ? { query: opts } : opts;
|
opts = typeof opts === 'string' ? { query: opts } : opts;
|
||||||
|
|
||||||
const chatService = accessor.get(IChatService);
|
const chatWidget = await showChatView(accessor.get(IViewsService));
|
||||||
const chatWidgetService = accessor.get(IChatWidgetService);
|
|
||||||
const providers = chatService.getProviderInfos();
|
|
||||||
if (!providers.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const chatWidget = await chatWidgetService.revealViewForProvider(providers[0].id);
|
|
||||||
if (!chatWidget) {
|
if (!chatWidget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -92,15 +93,82 @@ class OpenChatGlobalAction extends Action2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ChatHistoryAction extends ViewAction<ChatViewPane> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
viewId: CHAT_VIEW_ID,
|
||||||
|
id: `workbench.action.chat.history`,
|
||||||
|
title: localize2('chat.history.label', "Show Chats..."),
|
||||||
|
menu: {
|
||||||
|
id: MenuId.ViewTitle,
|
||||||
|
when: ContextKeyExpr.equals('view', CHAT_VIEW_ID),
|
||||||
|
group: 'navigation',
|
||||||
|
order: -1
|
||||||
|
},
|
||||||
|
category: CHAT_CATEGORY,
|
||||||
|
icon: Codicon.history,
|
||||||
|
f1: true,
|
||||||
|
precondition: CONTEXT_HAS_DEFAULT_AGENT
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async runInView(accessor: ServicesAccessor, view: ChatViewPane) {
|
||||||
|
const chatService = accessor.get(IChatService);
|
||||||
|
const quickInputService = accessor.get(IQuickInputService);
|
||||||
|
const viewsService = accessor.get(IViewsService);
|
||||||
|
const items = chatService.getHistory();
|
||||||
|
const picks = items.map(i => (<IQuickPickItem & { chat: IChatDetail }>{
|
||||||
|
label: i.title,
|
||||||
|
chat: i,
|
||||||
|
buttons: [{
|
||||||
|
iconClass: ThemeIcon.asClassName(Codicon.x),
|
||||||
|
tooltip: localize('interactiveSession.history.delete', "Delete"),
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
const selection = await quickInputService.pick(picks,
|
||||||
|
{
|
||||||
|
placeHolder: localize('interactiveSession.history.pick', "Switch to chat"),
|
||||||
|
onDidTriggerItemButton: context => {
|
||||||
|
chatService.removeHistoryEntry(context.item.chat.sessionId);
|
||||||
|
context.removeItem();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (selection) {
|
||||||
|
const sessionId = selection.chat.sessionId;
|
||||||
|
const view = await viewsService.openView(CHAT_VIEW_ID) as ChatViewPane;
|
||||||
|
view.loadSession(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpenChatEditorAction extends Action2 {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: `workbench.action.openChat`,
|
||||||
|
title: localize2('interactiveSession.open', "Open Editor"),
|
||||||
|
f1: true,
|
||||||
|
category: CHAT_CATEGORY,
|
||||||
|
precondition: CONTEXT_HAS_DEFAULT_AGENT
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(accessor: ServicesAccessor) {
|
||||||
|
const editorService = accessor.get(IEditorService);
|
||||||
|
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: { pinned: true } satisfies IChatEditorOptions });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function registerChatActions() {
|
export function registerChatActions() {
|
||||||
registerAction2(OpenChatGlobalAction);
|
registerAction2(OpenChatGlobalAction);
|
||||||
|
registerAction2(ChatHistoryAction);
|
||||||
|
registerAction2(OpenChatEditorAction);
|
||||||
|
|
||||||
registerAction2(class ClearChatInputHistoryAction extends Action2 {
|
registerAction2(class ClearChatInputHistoryAction extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
id: 'workbench.action.chat.clearInputHistory',
|
id: 'workbench.action.chat.clearInputHistory',
|
||||||
title: localize2('interactiveSession.clearHistory.label', "Clear Input History"),
|
title: localize2('interactiveSession.clearHistory.label', "Clear Input History"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
f1: true,
|
f1: true,
|
||||||
});
|
});
|
||||||
|
@ -116,7 +184,7 @@ export function registerChatActions() {
|
||||||
super({
|
super({
|
||||||
id: 'workbench.action.chat.clearHistory',
|
id: 'workbench.action.chat.clearHistory',
|
||||||
title: localize2('chat.clear.label', "Clear All Workspace Chats"),
|
title: localize2('chat.clear.label', "Clear All Workspace Chats"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
f1: true,
|
f1: true,
|
||||||
});
|
});
|
||||||
|
@ -193,79 +261,3 @@ export function registerChatActions() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOpenChatEditorAction(id: string, label: string, when?: string) {
|
|
||||||
return class OpenChatEditor extends Action2 {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
id: `workbench.action.openChat.${id}`,
|
|
||||||
title: localize2('interactiveSession.open', "Open Editor ({0})", label),
|
|
||||||
f1: true,
|
|
||||||
category: CHAT_CATEGORY,
|
|
||||||
precondition: ContextKeyExpr.deserialize(when)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async run(accessor: ServicesAccessor) {
|
|
||||||
const editorService = accessor.get(IEditorService);
|
|
||||||
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ target: { providerId: id }, pinned: true } });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const getHistoryChatActionDescriptorForViewTitle = (viewId: string, providerId: string): Readonly<IAction2Options> & { viewId: string } => ({
|
|
||||||
viewId,
|
|
||||||
id: `workbench.action.chat.${providerId}.history`,
|
|
||||||
title: localize2('chat.history.label', "Show Chats"),
|
|
||||||
menu: {
|
|
||||||
id: MenuId.ViewTitle,
|
|
||||||
when: ContextKeyExpr.equals('view', viewId),
|
|
||||||
group: 'navigation',
|
|
||||||
order: -1
|
|
||||||
},
|
|
||||||
category: CHAT_CATEGORY,
|
|
||||||
icon: Codicon.history,
|
|
||||||
f1: true,
|
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getHistoryAction(viewId: string, providerId: string) {
|
|
||||||
return class HistoryAction extends ViewAction<ChatViewPane> {
|
|
||||||
constructor() {
|
|
||||||
super(getHistoryChatActionDescriptorForViewTitle(viewId, providerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
async runInView(accessor: ServicesAccessor, view: ChatViewPane) {
|
|
||||||
const chatService = accessor.get(IChatService);
|
|
||||||
const quickInputService = accessor.get(IQuickInputService);
|
|
||||||
const chatContribService = accessor.get(IChatContributionService);
|
|
||||||
const viewsService = accessor.get(IViewsService);
|
|
||||||
const items = chatService.getHistory();
|
|
||||||
const picks = items.map(i => (<IQuickPickItem & { chat: IChatDetail }>{
|
|
||||||
label: i.title,
|
|
||||||
chat: i,
|
|
||||||
buttons: [{
|
|
||||||
iconClass: ThemeIcon.asClassName(Codicon.x),
|
|
||||||
tooltip: localize('interactiveSession.history.delete', "Delete"),
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
const selection = await quickInputService.pick(picks,
|
|
||||||
{
|
|
||||||
placeHolder: localize('interactiveSession.history.pick', "Switch to chat"),
|
|
||||||
onDidTriggerItemButton: context => {
|
|
||||||
chatService.removeHistoryEntry(context.item.chat.sessionId);
|
|
||||||
context.removeItem();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (selection) {
|
|
||||||
const sessionId = selection.chat.sessionId;
|
|
||||||
const provider = chatContribService.registeredProviders[0]?.id;
|
|
||||||
if (provider) {
|
|
||||||
const viewId = chatContribService.getViewIdForProvider(provider);
|
|
||||||
const view = await viewsService.openView(viewId) as ChatViewPane;
|
|
||||||
view.loadSession(sessionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ export async function clearChatEditor(accessor: ServicesAccessor): Promise<void>
|
||||||
const editorGroupsService = accessor.get(IEditorGroupsService);
|
const editorGroupsService = accessor.get(IEditorGroupsService);
|
||||||
|
|
||||||
const chatEditorInput = editorService.activeEditor;
|
const chatEditorInput = editorService.activeEditor;
|
||||||
if (chatEditorInput instanceof ChatEditorInput && chatEditorInput.providerId) {
|
if (chatEditorInput instanceof ChatEditorInput) {
|
||||||
await editorService.replaceEditors([{
|
await editorService.replaceEditors([{
|
||||||
editor: chatEditorInput,
|
editor: chatEditorInput,
|
||||||
replacement: { resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ target: { providerId: chatEditorInput.providerId, pinned: true } } }
|
replacement: { resource: ChatEditorInput.getNewEditorUri(), options: { pinned: true } satisfies IChatEditorOptions }
|
||||||
}], editorGroupsService.activeGroup);
|
}], editorGroupsService.activeGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,20 @@ import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||||
import { localize2 } from 'vs/nls';
|
import { localize2 } from 'vs/nls';
|
||||||
import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
|
||||||
import { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';
|
import { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';
|
||||||
|
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
|
|
||||||
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_CATEGORY, isChatViewTitleActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { clearChatEditor } from 'vs/workbench/contrib/chat/browser/actions/chatClear';
|
import { clearChatEditor } from 'vs/workbench/contrib/chat/browser/actions/chatClear';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { CHAT_VIEW_ID, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
|
||||||
|
|
||||||
export const ACTION_ID_NEW_CHAT = `workbench.action.chat.newChat`;
|
export const ACTION_ID_NEW_CHAT = `workbench.action.chat.newChat`;
|
||||||
|
|
||||||
export function registerNewChatActions() {
|
export function registerNewChatActions() {
|
||||||
|
|
||||||
registerAction2(class NewChatEditorAction extends Action2 {
|
registerAction2(class NewChatEditorAction extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
|
@ -31,7 +28,7 @@ export function registerNewChatActions() {
|
||||||
title: localize2('chat.newChat.label', "New Chat"),
|
title: localize2('chat.newChat.label', "New Chat"),
|
||||||
icon: Codicon.plus,
|
icon: Codicon.plus,
|
||||||
f1: false,
|
f1: false,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
menu: [{
|
menu: [{
|
||||||
id: MenuId.EditorTitle,
|
id: MenuId.EditorTitle,
|
||||||
group: 'navigation',
|
group: 'navigation',
|
||||||
|
@ -46,7 +43,6 @@ export function registerNewChatActions() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
registerAction2(class GlobalClearChatAction extends Action2 {
|
registerAction2(class GlobalClearChatAction extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
|
@ -54,7 +50,7 @@ export function registerNewChatActions() {
|
||||||
title: localize2('chat.newChat.label', "New Chat"),
|
title: localize2('chat.newChat.label', "New Chat"),
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
icon: Codicon.plus,
|
icon: Codicon.plus,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
keybinding: {
|
keybinding: {
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
|
@ -64,58 +60,42 @@ export function registerNewChatActions() {
|
||||||
},
|
},
|
||||||
when: CONTEXT_IN_CHAT_SESSION
|
when: CONTEXT_IN_CHAT_SESSION
|
||||||
},
|
},
|
||||||
menu: {
|
menu: [{
|
||||||
id: MenuId.ChatContext,
|
id: MenuId.ChatContext,
|
||||||
group: 'z_clear'
|
group: 'z_clear'
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
id: MenuId.ViewTitle,
|
||||||
|
when: ContextKeyExpr.equals('view', CHAT_VIEW_ID),
|
||||||
|
group: 'navigation',
|
||||||
|
order: -1
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
run(accessor: ServicesAccessor, ...args: any[]) {
|
run(accessor: ServicesAccessor, ...args: any[]) {
|
||||||
|
const context = args[0];
|
||||||
|
if (isChatViewTitleActionContext(context)) {
|
||||||
|
// Is running in the Chat view title
|
||||||
|
announceChatCleared(accessor);
|
||||||
|
context.chatView.clear();
|
||||||
|
context.chatView.widget.focusInput();
|
||||||
|
} else {
|
||||||
|
// Is running from f1 or keybinding
|
||||||
const widgetService = accessor.get(IChatWidgetService);
|
const widgetService = accessor.get(IChatWidgetService);
|
||||||
|
|
||||||
const widget = widgetService.lastFocusedWidget;
|
const widget = widgetService.lastFocusedWidget;
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
announceChatCleared(accessor);
|
announceChatCleared(accessor);
|
||||||
widget.clear();
|
widget.clear();
|
||||||
widget.focusInput();
|
widget.focusInput();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNewChatActionDescriptorForViewTitle = (viewId: string, providerId: string): Readonly<IAction2Options> & { viewId: string } => ({
|
|
||||||
viewId,
|
|
||||||
id: `workbench.action.chat.${providerId}.newChat`,
|
|
||||||
title: localize2('chat.newChat.label', "New Chat"),
|
|
||||||
menu: {
|
|
||||||
id: MenuId.ViewTitle,
|
|
||||||
when: ContextKeyExpr.equals('view', viewId),
|
|
||||||
group: 'navigation',
|
|
||||||
order: -1
|
|
||||||
},
|
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
|
||||||
category: CHAT_CATEGORY,
|
|
||||||
icon: Codicon.plus,
|
|
||||||
f1: false
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getNewChatAction(viewId: string, providerId: string) {
|
|
||||||
return class NewChatAction extends ViewAction<ChatViewPane> {
|
|
||||||
constructor() {
|
|
||||||
super(getNewChatActionDescriptorForViewTitle(viewId, providerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
async runInView(accessor: ServicesAccessor, view: ChatViewPane) {
|
|
||||||
announceChatCleared(accessor);
|
|
||||||
await view.clear();
|
|
||||||
view.widget.focusInput();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function announceChatCleared(accessor: ServicesAccessor): void {
|
function announceChatCleared(accessor: ServicesAccessor): void {
|
||||||
accessor.get(IAccessibilitySignalService).playSignal(AccessibilitySignal.clear);
|
accessor.get(IAccessibilitySignalService).playSignal(AccessibilitySignal.clear);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { accessibleViewInCodeBlock } from 'vs/workbench/contrib/accessibility/br
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { IChatWidgetService, IChatCodeBlockContextProviderService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatWidgetService, IChatCodeBlockContextProviderService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ICodeBlockActionContext, ICodeCompareBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
import { ICodeBlockActionContext, ICodeCompareBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||||
import { CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { ChatCopyKind, IChatService, IDocumentContext } from 'vs/workbench/contrib/chat/common/chatService';
|
import { ChatCopyKind, IChatService, IDocumentContext } 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 { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||||
|
@ -109,7 +109,6 @@ export function registerChatCodeBlockActions() {
|
||||||
if (isResponseVM(context.element)) {
|
if (isResponseVM(context.element)) {
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
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,
|
||||||
|
@ -155,7 +154,6 @@ export function registerChatCodeBlockActions() {
|
||||||
const element = context.element as IChatResponseViewModel | undefined;
|
const element = context.element as IChatResponseViewModel | undefined;
|
||||||
if (element) {
|
if (element) {
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
providerId: element.providerId,
|
|
||||||
agentId: element.agent?.id,
|
agentId: element.agent?.id,
|
||||||
sessionId: element.sessionId,
|
sessionId: element.sessionId,
|
||||||
requestId: element.requestId,
|
requestId: element.requestId,
|
||||||
|
@ -185,7 +183,7 @@ export function registerChatCodeBlockActions() {
|
||||||
super({
|
super({
|
||||||
id: 'workbench.action.chat.insertCodeBlock',
|
id: 'workbench.action.chat.insertCodeBlock',
|
||||||
title: localize2('interactive.insertCodeBlock.label', "Insert at Cursor"),
|
title: localize2('interactive.insertCodeBlock.label', "Insert at Cursor"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
icon: Codicon.insert,
|
icon: Codicon.insert,
|
||||||
|
@ -331,7 +329,6 @@ export function registerChatCodeBlockActions() {
|
||||||
if (isResponseVM(context.element)) {
|
if (isResponseVM(context.element)) {
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
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,
|
||||||
|
@ -352,7 +349,7 @@ export function registerChatCodeBlockActions() {
|
||||||
super({
|
super({
|
||||||
id: 'workbench.action.chat.insertIntoNewFile',
|
id: 'workbench.action.chat.insertIntoNewFile',
|
||||||
title: localize2('interactive.insertIntoNewFile.label', "Insert into New File"),
|
title: localize2('interactive.insertIntoNewFile.label', "Insert into New File"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
icon: Codicon.newFile,
|
icon: Codicon.newFile,
|
||||||
|
@ -377,7 +374,6 @@ export function registerChatCodeBlockActions() {
|
||||||
|
|
||||||
if (isResponseVM(context.element)) {
|
if (isResponseVM(context.element)) {
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
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,
|
||||||
|
@ -407,7 +403,7 @@ export function registerChatCodeBlockActions() {
|
||||||
super({
|
super({
|
||||||
id: 'workbench.action.chat.runInTerminal',
|
id: 'workbench.action.chat.runInTerminal',
|
||||||
title: localize2('interactive.runInTerminal.label', "Insert into Terminal"),
|
title: localize2('interactive.runInTerminal.label', "Insert into Terminal"),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
icon: Codicon.terminal,
|
icon: Codicon.terminal,
|
||||||
|
@ -470,7 +466,6 @@ export function registerChatCodeBlockActions() {
|
||||||
|
|
||||||
if (isResponseVM(context.element)) {
|
if (isResponseVM(context.element)) {
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
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,
|
||||||
|
@ -526,7 +521,7 @@ export function registerChatCodeBlockActions() {
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
when: CONTEXT_IN_CHAT_SESSION,
|
when: CONTEXT_IN_CHAT_SESSION,
|
||||||
},
|
},
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
});
|
});
|
||||||
|
@ -548,7 +543,7 @@ export function registerChatCodeBlockActions() {
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
when: CONTEXT_IN_CHAT_SESSION,
|
when: CONTEXT_IN_CHAT_SESSION,
|
||||||
},
|
},
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
|
|
||||||
export function registerChatFileTreeActions() {
|
export function registerChatFileTreeActions() {
|
||||||
|
@ -24,7 +24,7 @@ export function registerChatFileTreeActions() {
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
when: CONTEXT_IN_CHAT_SESSION,
|
when: CONTEXT_IN_CHAT_SESSION,
|
||||||
},
|
},
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
});
|
});
|
||||||
|
@ -45,7 +45,7 @@ export function registerChatFileTreeActions() {
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
when: CONTEXT_IN_CHAT_SESSION,
|
when: CONTEXT_IN_CHAT_SESSION,
|
||||||
},
|
},
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,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 { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
import { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
||||||
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { isExportableSessionData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { isExportableSessionData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
@ -29,7 +29,7 @@ export function registerChatExportActions() {
|
||||||
id: 'workbench.action.chat.export',
|
id: 'workbench.action.chat.export',
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
title: localize2('chat.export.label', "Export Chat..."),
|
title: localize2('chat.export.label', "Export Chat..."),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ export function registerChatExportActions() {
|
||||||
id: 'workbench.action.chat.import',
|
id: 'workbench.action.chat.import',
|
||||||
title: localize2('chat.import.label', "Import Chat..."),
|
title: localize2('chat.import.label', "Import Chat..."),
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ export function registerChatExportActions() {
|
||||||
throw new Error('Invalid chat session data');
|
throw new Error('Invalid chat session data');
|
||||||
}
|
}
|
||||||
|
|
||||||
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ target: { data }, pinned: true } });
|
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: { target: { data }, pinned: true } as IChatEditorOptions });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,107 +3,68 @@
|
||||||
* 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 { localize, localize2 } from 'vs/nls';
|
import { localize2 } from 'vs/nls';
|
||||||
import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
|
|
||||||
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
import { CHAT_CATEGORY, isChatViewTitleActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_VIEW_ID, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
|
||||||
import { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
import { IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
||||||
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { ACTIVE_GROUP, AUX_WINDOW_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { ACTIVE_GROUP, AUX_WINDOW_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
enum MoveToNewLocation {
|
enum MoveToNewLocation {
|
||||||
Editor = 'Editor',
|
Editor = 'Editor',
|
||||||
Window = 'Window'
|
Window = 'Window'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMoveToChatActionDescriptorForViewTitle = (viewId: string, providerId: string, moveTo: MoveToNewLocation): Readonly<IAction2Options> & { viewId: string } => ({
|
|
||||||
id: `workbench.action.chat.${providerId}.openIn${moveTo}`,
|
|
||||||
title: {
|
|
||||||
value: moveTo === MoveToNewLocation.Editor ? localize('chat.openInEditor.label', "Open Chat in Editor") : localize('chat.openInNewWindow.label', "Open Chat in New Window"),
|
|
||||||
original: moveTo === MoveToNewLocation.Editor ? 'Open Chat in Editor' : 'Open Chat in New Window',
|
|
||||||
},
|
|
||||||
category: CHAT_CATEGORY,
|
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
|
||||||
f1: false,
|
|
||||||
viewId,
|
|
||||||
menu: {
|
|
||||||
id: MenuId.ViewTitle,
|
|
||||||
when: ContextKeyExpr.equals('view', viewId),
|
|
||||||
order: 0
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getMoveToEditorAction(viewId: string, providerId: string) {
|
|
||||||
return getMoveToAction(viewId, providerId, MoveToNewLocation.Editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMoveToNewWindowAction(viewId: string, providerId: string) {
|
|
||||||
return getMoveToAction(viewId, providerId, MoveToNewLocation.Window);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMoveToAction(viewId: string, providerId: string, moveTo: MoveToNewLocation) {
|
|
||||||
return class MoveToAction extends ViewAction<ChatViewPane> {
|
|
||||||
constructor() {
|
|
||||||
super(getMoveToChatActionDescriptorForViewTitle(viewId, providerId, moveTo));
|
|
||||||
}
|
|
||||||
|
|
||||||
async runInView(accessor: ServicesAccessor, view: ChatViewPane) {
|
|
||||||
const viewModel = view.widget.viewModel;
|
|
||||||
if (!viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const editorService = accessor.get(IEditorService);
|
|
||||||
const sessionId = viewModel.sessionId;
|
|
||||||
const viewState = view.widget.getViewState();
|
|
||||||
view.clear();
|
|
||||||
|
|
||||||
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ target: { sessionId }, pinned: true, viewState: viewState } }, moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerMoveActions() {
|
export function registerMoveActions() {
|
||||||
registerAction2(class GlobalMoveToEditorAction extends Action2 {
|
registerAction2(class GlobalMoveToEditorAction extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
id: `workbench.action.chat.openInEditor`,
|
id: `workbench.action.chat.openInEditor`,
|
||||||
title: localize2('interactiveSession.openInEditor.label', "Open Chat in Editor"),
|
title: localize2('chat.openInEditor.label', "Open Chat in Editor"),
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true
|
f1: true,
|
||||||
|
menu: {
|
||||||
|
id: MenuId.ViewTitle,
|
||||||
|
when: ContextKeyExpr.equals('view', CHAT_VIEW_ID),
|
||||||
|
order: 0
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(accessor: ServicesAccessor, ...args: any[]) {
|
async run(accessor: ServicesAccessor, ...args: any[]) {
|
||||||
executeMoveToAction(accessor, MoveToNewLocation.Editor);
|
const context = args[0];
|
||||||
|
executeMoveToAction(accessor, MoveToNewLocation.Editor, isChatViewTitleActionContext(context) ? context.chatView : undefined);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
registerAction2(class GlobalMoveToNewWindowAction extends Action2 {
|
registerAction2(class GlobalMoveToNewWindowAction extends Action2 {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
id: `workbench.action.chat.openInNewWindow`,
|
id: `workbench.action.chat.openInNewWindow`,
|
||||||
title: localize2('interactiveSession.openInNewWindow.label', "Open/move the panel chat to an undocked window."),
|
title: localize2('chat.openInNewWindow.label', "Open Chat in New Window"),
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true
|
f1: true,
|
||||||
|
menu: {
|
||||||
|
id: MenuId.ViewTitle,
|
||||||
|
when: ContextKeyExpr.equals('view', CHAT_VIEW_ID),
|
||||||
|
order: 0
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(accessor: ServicesAccessor, ...args: any[]) {
|
async run(accessor: ServicesAccessor, ...args: any[]) {
|
||||||
executeMoveToAction(accessor, MoveToNewLocation.Window);
|
const context = args[0];
|
||||||
|
executeMoveToAction(accessor, MoveToNewLocation.Window, isChatViewTitleActionContext(context) ? context.chatView : undefined);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +74,7 @@ export function registerMoveActions() {
|
||||||
id: `workbench.action.chat.openInSidebar`,
|
id: `workbench.action.chat.openInSidebar`,
|
||||||
title: localize2('interactiveSession.openInSidebar.label', "Open Chat in Side Bar"),
|
title: localize2('interactiveSession.openInSidebar.label', "Open Chat in Side Bar"),
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
f1: true,
|
f1: true,
|
||||||
menu: [{
|
menu: [{
|
||||||
id: MenuId.EditorTitle,
|
id: MenuId.EditorTitle,
|
||||||
|
@ -129,17 +90,14 @@ export function registerMoveActions() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeMoveToAction(accessor: ServicesAccessor, moveTo: MoveToNewLocation) {
|
async function executeMoveToAction(accessor: ServicesAccessor, moveTo: MoveToNewLocation, chatView?: ChatViewPane) {
|
||||||
const widgetService = accessor.get(IChatWidgetService);
|
const widgetService = accessor.get(IChatWidgetService);
|
||||||
const viewService = accessor.get(IViewsService);
|
const viewService = accessor.get(IViewsService);
|
||||||
const chatService = accessor.get(IChatService);
|
|
||||||
const editorService = accessor.get(IEditorService);
|
const editorService = accessor.get(IEditorService);
|
||||||
|
|
||||||
const widget = widgetService.lastFocusedWidget;
|
const widget = chatView?.widget ?? widgetService.lastFocusedWidget;
|
||||||
if (!widget || !('viewId' in widget.viewContext)) {
|
if (!widget || !('viewId' in widget.viewContext)) {
|
||||||
const providerId = chatService.getProviderInfos()[0].id;
|
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ pinned: true } }, moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP);
|
||||||
|
|
||||||
await editorService.openEditor({ resource: ChatEditorInput.getNewEditorUri(), options: <IChatEditorOptions>{ target: { providerId }, pinned: true } }, moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,19 +117,14 @@ async function executeMoveToAction(accessor: ServicesAccessor, moveTo: MoveToNew
|
||||||
async function moveToSidebar(accessor: ServicesAccessor): Promise<void> {
|
async function moveToSidebar(accessor: ServicesAccessor): Promise<void> {
|
||||||
const viewsService = accessor.get(IViewsService);
|
const viewsService = accessor.get(IViewsService);
|
||||||
const editorService = accessor.get(IEditorService);
|
const editorService = accessor.get(IEditorService);
|
||||||
const chatContribService = accessor.get(IChatContributionService);
|
|
||||||
const editorGroupService = accessor.get(IEditorGroupsService);
|
const editorGroupService = accessor.get(IEditorGroupsService);
|
||||||
|
|
||||||
const chatEditorInput = editorService.activeEditor;
|
const chatEditorInput = editorService.activeEditor;
|
||||||
if (chatEditorInput instanceof ChatEditorInput && chatEditorInput.sessionId && chatEditorInput.providerId) {
|
if (chatEditorInput instanceof ChatEditorInput && chatEditorInput.sessionId) {
|
||||||
await editorService.closeEditor({ editor: chatEditorInput, groupId: editorGroupService.activeGroup.id });
|
await editorService.closeEditor({ editor: chatEditorInput, groupId: editorGroupService.activeGroup.id });
|
||||||
const viewId = chatContribService.getViewIdForProvider(chatEditorInput.providerId);
|
const view = await viewsService.openView(CHAT_VIEW_ID) as ChatViewPane;
|
||||||
const view = await viewsService.openView(viewId) as ChatViewPane;
|
|
||||||
view.loadSession(chatEditorInput.sessionId);
|
view.loadSession(chatEditorInput.sessionId);
|
||||||
} else {
|
} else {
|
||||||
const chatService = accessor.get(IChatService);
|
await viewsService.openView(CHAT_VIEW_ID);
|
||||||
const providerId = chatService.getProviderInfos()[0].id;
|
|
||||||
const viewId = chatContribService.getViewIdForProvider(providerId);
|
|
||||||
await viewsService.openView(viewId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,14 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { IQuickChatService, IQuickChatOpenOptions } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IQuickChatOpenOptions, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
||||||
|
|
||||||
export const ASK_QUICK_QUESTION_ACTION_ID = 'workbench.action.quickchat.toggle';
|
export const ASK_QUICK_QUESTION_ACTION_ID = 'workbench.action.quickchat.toggle';
|
||||||
export function registerQuickChatActions() {
|
export function registerQuickChatActions() {
|
||||||
registerAction2(QuickChatGlobalAction);
|
registerAction2(QuickChatGlobalAction);
|
||||||
|
registerAction2(AskQuickChatAction);
|
||||||
|
|
||||||
registerAction2(class OpenInChatViewAction extends Action2 {
|
registerAction2(class OpenInChatViewAction extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -94,6 +95,7 @@ export function registerQuickChatActions() {
|
||||||
controller.focus();
|
controller.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class QuickChatGlobalAction extends Action2 {
|
class QuickChatGlobalAction extends Action2 {
|
||||||
|
@ -101,7 +103,7 @@ class QuickChatGlobalAction extends Action2 {
|
||||||
super({
|
super({
|
||||||
id: ASK_QUICK_QUESTION_ACTION_ID,
|
id: ASK_QUICK_QUESTION_ACTION_ID,
|
||||||
title: localize2('quickChat', 'Quick Chat'),
|
title: localize2('quickChat', 'Quick Chat'),
|
||||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
precondition: CONTEXT_HAS_DEFAULT_AGENT,
|
||||||
icon: Codicon.commentDiscussion,
|
icon: Codicon.commentDiscussion,
|
||||||
f1: false,
|
f1: false,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
|
@ -153,35 +155,25 @@ class QuickChatGlobalAction extends Action2 {
|
||||||
if (options?.query) {
|
if (options?.query) {
|
||||||
options.selection = new Selection(1, options.query.length + 1, 1, options.query.length + 1);
|
options.selection = new Selection(1, options.query.length + 1, 1, options.query.length + 1);
|
||||||
}
|
}
|
||||||
quickChatService.toggle(undefined, options);
|
quickChatService.toggle(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
class AskQuickChatAction extends Action2 {
|
||||||
* Returns a provider specific action that will open the quick chat for that provider.
|
|
||||||
* This is used to include the provider label in the action title so it shows up in
|
|
||||||
* the command palette.
|
|
||||||
* @param id The id of the provider
|
|
||||||
* @param label The label of the provider
|
|
||||||
* @returns An action that will open the quick chat for this provider
|
|
||||||
*/
|
|
||||||
export function getQuickChatActionForProvider(id: string, label: string) {
|
|
||||||
return class AskQuickChatAction extends Action2 {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
id: `workbench.action.openQuickChat.${id}`,
|
id: `workbench.action.openQuickChat`,
|
||||||
category: CHAT_CATEGORY,
|
category: CHAT_CATEGORY,
|
||||||
title: localize2('interactiveSession.open', "Open Quick Chat ({0})", label),
|
title: localize2('interactiveSession.open', "Open Quick Chat"),
|
||||||
f1: true
|
f1: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override run(accessor: ServicesAccessor, query?: string): void {
|
override run(accessor: ServicesAccessor, query?: string): void {
|
||||||
const quickChatService = accessor.get(IQuickChatService);
|
const quickChatService = accessor.get(IQuickChatService);
|
||||||
quickChatService.toggle(id, query ? {
|
quickChatService.toggle(query ? {
|
||||||
query,
|
query,
|
||||||
selection: new Selection(1, query.length + 1, 1, query.length + 1)
|
selection: new Selection(1, query.length + 1, 1, query.length + 1)
|
||||||
} : undefined);
|
} : undefined);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ export function registerChatTitleActions() {
|
||||||
|
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
providerId: item.providerId,
|
|
||||||
agentId: item.agent?.id,
|
agentId: item.agent?.id,
|
||||||
sessionId: item.sessionId,
|
sessionId: item.sessionId,
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
|
@ -90,7 +89,6 @@ export function registerChatTitleActions() {
|
||||||
|
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
providerId: item.providerId,
|
|
||||||
agentId: item.agent?.id,
|
agentId: item.agent?.id,
|
||||||
sessionId: item.sessionId,
|
sessionId: item.sessionId,
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
|
@ -129,7 +127,6 @@ export function registerChatTitleActions() {
|
||||||
|
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
chatService.notifyUserAction({
|
chatService.notifyUserAction({
|
||||||
providerId: item.providerId,
|
|
||||||
agentId: item.agent?.id,
|
agentId: item.agent?.id,
|
||||||
sessionId: item.sessionId,
|
sessionId: item.sessionId,
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
|
|
|
@ -19,9 +19,9 @@ import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
|
||||||
import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor';
|
import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor';
|
||||||
import { AccessibilityVerbositySettingId, AccessibleViewProviderId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
import { AccessibilityVerbositySettingId, AccessibleViewProviderId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||||
import { alertFocusChange } from 'vs/workbench/contrib/accessibility/browser/accessibleViewContributions';
|
|
||||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||||
import { AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
import { AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||||
|
import { alertFocusChange } from 'vs/workbench/contrib/accessibility/browser/accessibleViewContributions';
|
||||||
import { registerChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { registerChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
import { ACTION_ID_NEW_CHAT, registerNewChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
import { ACTION_ID_NEW_CHAT, registerNewChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
||||||
import { registerChatCodeBlockActions, registerChatCodeCompareBlockActions } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions';
|
import { registerChatCodeBlockActions, registerChatCodeCompareBlockActions } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions';
|
||||||
|
@ -34,17 +34,16 @@ import { registerQuickChatActions } from 'vs/workbench/contrib/chat/browser/acti
|
||||||
import { registerChatTitleActions } from 'vs/workbench/contrib/chat/browser/actions/chatTitleActions';
|
import { registerChatTitleActions } from 'vs/workbench/contrib/chat/browser/actions/chatTitleActions';
|
||||||
import { IChatAccessibilityService, IChatCodeBlockContextProviderService, IChatWidget, IChatWidgetService, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatAccessibilityService, IChatCodeBlockContextProviderService, IChatWidget, IChatWidgetService, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
|
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
|
||||||
import { ChatContributionService } from 'vs/workbench/contrib/chat/browser/chatContributionServiceImpl';
|
|
||||||
import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
||||||
import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { QuickChatService } from 'vs/workbench/contrib/chat/browser/chatQuick';
|
import { QuickChatService } from 'vs/workbench/contrib/chat/browser/chatQuick';
|
||||||
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
||||||
import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
|
import { ChatCodeBlockContextProviderService } from 'vs/workbench/contrib/chat/browser/codeBlockContextProviderService';
|
||||||
import 'vs/workbench/contrib/chat/browser/contrib/chatHistoryVariables';
|
import 'vs/workbench/contrib/chat/browser/contrib/chatHistoryVariables';
|
||||||
import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib';
|
import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib';
|
||||||
import { ChatAgentLocation, ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { ChatWelcomeMessageModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatWelcomeMessageModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
@ -58,7 +57,7 @@ import { IVoiceChatService, VoiceChatService } from 'vs/workbench/contrib/chat/c
|
||||||
import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
|
import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import '../common/chatColors';
|
import '../common/chatColors';
|
||||||
import { ChatCodeBlockContextProviderService } from 'vs/workbench/contrib/chat/browser/codeBlockContextProviderService';
|
import { ChatExtensionPointHandler } from 'vs/workbench/contrib/chat/browser/chatParticipantContributions';
|
||||||
|
|
||||||
// Register configuration
|
// Register configuration
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||||
|
@ -314,6 +313,7 @@ registerWorkbenchContribution2(ChatResolverContribution.ID, ChatResolverContribu
|
||||||
workbenchContributionsRegistry.registerWorkbenchContribution(ChatAccessibleViewContribution, LifecyclePhase.Eventually);
|
workbenchContributionsRegistry.registerWorkbenchContribution(ChatAccessibleViewContribution, LifecyclePhase.Eventually);
|
||||||
workbenchContributionsRegistry.registerWorkbenchContribution(ChatSlashStaticSlashCommandsContribution, LifecyclePhase.Eventually);
|
workbenchContributionsRegistry.registerWorkbenchContribution(ChatSlashStaticSlashCommandsContribution, LifecyclePhase.Eventually);
|
||||||
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(ChatEditorInput.TypeID, ChatEditorInputSerializer);
|
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(ChatEditorInput.TypeID, ChatEditorInputSerializer);
|
||||||
|
registerWorkbenchContribution2(ChatExtensionPointHandler.ID, ChatExtensionPointHandler, WorkbenchPhase.BlockStartup);
|
||||||
|
|
||||||
registerChatActions();
|
registerChatActions();
|
||||||
registerChatCopyActions();
|
registerChatCopyActions();
|
||||||
|
@ -328,7 +328,6 @@ registerMoveActions();
|
||||||
registerNewChatActions();
|
registerNewChatActions();
|
||||||
|
|
||||||
registerSingleton(IChatService, ChatService, InstantiationType.Delayed);
|
registerSingleton(IChatService, ChatService, InstantiationType.Delayed);
|
||||||
registerSingleton(IChatContributionService, ChatContributionService, InstantiationType.Delayed);
|
|
||||||
registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed);
|
registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed);
|
||||||
registerSingleton(IQuickChatService, QuickChatService, InstantiationType.Delayed);
|
registerSingleton(IQuickChatService, QuickChatService, InstantiationType.Delayed);
|
||||||
registerSingleton(IChatAccessibilityService, ChatAccessibilityService, InstantiationType.Delayed);
|
registerSingleton(IChatAccessibilityService, ChatAccessibilityService, InstantiationType.Delayed);
|
||||||
|
|
|
@ -11,11 +11,14 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||||
import { IChatWidgetContrib } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { IChatWidgetContrib } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||||
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
|
import { CHAT_PROVIDER_ID } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
export const IChatWidgetService = createDecorator<IChatWidgetService>('chatWidgetService');
|
export const IChatWidgetService = createDecorator<IChatWidgetService>('chatWidgetService');
|
||||||
|
|
||||||
|
@ -28,25 +31,24 @@ export interface IChatWidgetService {
|
||||||
*/
|
*/
|
||||||
readonly lastFocusedWidget: IChatWidget | undefined;
|
readonly lastFocusedWidget: IChatWidget | undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a view was successfully revealed.
|
|
||||||
*/
|
|
||||||
revealViewForProvider(providerId: string): Promise<IChatWidget | undefined>;
|
|
||||||
|
|
||||||
getWidgetByInputUri(uri: URI): IChatWidget | undefined;
|
getWidgetByInputUri(uri: URI): IChatWidget | undefined;
|
||||||
|
|
||||||
getWidgetBySessionId(sessionId: string): IChatWidget | undefined;
|
getWidgetBySessionId(sessionId: string): IChatWidget | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showChatView(viewsService: IViewsService): Promise<IChatWidget | undefined> {
|
||||||
|
return (await viewsService.openView<ChatViewPane>(CHAT_VIEW_ID))?.widget;
|
||||||
|
}
|
||||||
|
|
||||||
export const IQuickChatService = createDecorator<IQuickChatService>('quickChatService');
|
export const IQuickChatService = createDecorator<IQuickChatService>('quickChatService');
|
||||||
export interface IQuickChatService {
|
export interface IQuickChatService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
readonly onDidClose: Event<void>;
|
readonly onDidClose: Event<void>;
|
||||||
readonly enabled: boolean;
|
readonly enabled: boolean;
|
||||||
readonly focused: boolean;
|
readonly focused: boolean;
|
||||||
toggle(providerId?: string, options?: IQuickChatOpenOptions): void;
|
toggle(options?: IQuickChatOpenOptions): void;
|
||||||
focus(): void;
|
focus(): void;
|
||||||
open(providerId?: string, options?: IQuickChatOpenOptions): void;
|
open(options?: IQuickChatOpenOptions): void;
|
||||||
close(): void;
|
close(): void;
|
||||||
openInChatView(): void;
|
openInChatView(): void;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,6 @@ export interface IChatWidget {
|
||||||
readonly viewContext: IChatWidgetViewContext;
|
readonly viewContext: IChatWidgetViewContext;
|
||||||
readonly viewModel: IChatViewModel | undefined;
|
readonly viewModel: IChatViewModel | undefined;
|
||||||
readonly inputEditor: ICodeEditor;
|
readonly inputEditor: ICodeEditor;
|
||||||
readonly providerId: string;
|
|
||||||
readonly supportsFileReferences: boolean;
|
readonly supportsFileReferences: boolean;
|
||||||
readonly parsedInput: IParsedChatRequest;
|
readonly parsedInput: IParsedChatRequest;
|
||||||
lastSelectedAgent: IChatAgentData | undefined;
|
lastSelectedAgent: IChatAgentData | undefined;
|
||||||
|
@ -172,3 +173,5 @@ export interface IChatCodeBlockContextProviderService {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GeneratingPhrase = localize('generating', "Generating");
|
export const GeneratingPhrase = localize('generating', "Generating");
|
||||||
|
|
||||||
|
export const CHAT_VIEW_ID = `workbench.panel.chat.view.${CHAT_PROVIDER_ID}`;
|
||||||
|
|
|
@ -18,13 +18,14 @@ import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||||
import { Memento } from 'vs/workbench/common/memento';
|
import { Memento } from 'vs/workbench/common/memento';
|
||||||
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||||
import { IChatViewState, ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { IChatViewState, ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { IChatModel, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { IChatModel, IExportableChatData, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { clearChatEditor } from 'vs/workbench/contrib/chat/browser/actions/chatClear';
|
import { clearChatEditor } from 'vs/workbench/contrib/chat/browser/actions/chatClear';
|
||||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
|
import { CHAT_PROVIDER_ID } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
|
|
||||||
export interface IChatEditorOptions extends IEditorOptions {
|
export interface IChatEditorOptions extends IEditorOptions {
|
||||||
target: { sessionId: string } | { providerId: string } | { data: ISerializableChatData };
|
target?: { sessionId: string } | { data: IExportableChatData | ISerializableChatData };
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChatEditor extends EditorPane {
|
export class ChatEditor extends EditorPane {
|
||||||
|
@ -101,7 +102,7 @@ export class ChatEditor extends EditorPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateModel(model: IChatModel, viewState?: IChatViewState): void {
|
private updateModel(model: IChatModel, viewState?: IChatViewState): void {
|
||||||
this._memento = new Memento('interactive-session-editor-' + model.providerId, this.storageService);
|
this._memento = new Memento('interactive-session-editor-' + CHAT_PROVIDER_ID, this.storageService);
|
||||||
this._viewState = viewState ?? this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IChatViewState;
|
this._viewState = viewState ?? this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IChatViewState;
|
||||||
this.widget.setModel(model, { ...this._viewState });
|
this.widget.setModel(model, { ...this._viewState });
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ export class ChatEditorInput extends EditorInput {
|
||||||
|
|
||||||
private readonly inputCount: number;
|
private readonly inputCount: number;
|
||||||
public sessionId: string | undefined;
|
public sessionId: string | undefined;
|
||||||
public providerId: string | undefined;
|
|
||||||
|
|
||||||
private model: IChatModel | undefined;
|
private model: IChatModel | undefined;
|
||||||
|
|
||||||
|
@ -59,8 +58,9 @@ export class ChatEditorInput extends EditorInput {
|
||||||
throw new Error('Invalid chat URI');
|
throw new Error('Invalid chat URI');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sessionId = 'sessionId' in options.target ? options.target.sessionId : undefined;
|
this.sessionId = (options.target && 'sessionId' in options.target) ?
|
||||||
this.providerId = 'providerId' in options.target ? options.target.providerId : undefined;
|
options.target.sessionId :
|
||||||
|
undefined;
|
||||||
this.inputCount = ChatEditorInput.getNextCount();
|
this.inputCount = ChatEditorInput.getNextCount();
|
||||||
ChatEditorInput.countsInUse.add(this.inputCount);
|
ChatEditorInput.countsInUse.add(this.inputCount);
|
||||||
this._register(toDisposable(() => ChatEditorInput.countsInUse.delete(this.inputCount)));
|
this._register(toDisposable(() => ChatEditorInput.countsInUse.delete(this.inputCount)));
|
||||||
|
@ -93,8 +93,8 @@ export class ChatEditorInput extends EditorInput {
|
||||||
override async resolve(): Promise<ChatEditorModel | null> {
|
override async resolve(): Promise<ChatEditorModel | null> {
|
||||||
if (typeof this.sessionId === 'string') {
|
if (typeof this.sessionId === 'string') {
|
||||||
this.model = this.chatService.getOrRestoreSession(this.sessionId);
|
this.model = this.chatService.getOrRestoreSession(this.sessionId);
|
||||||
} else if (typeof this.providerId === 'string') {
|
} else if (!this.options.target) {
|
||||||
this.model = this.chatService.startSession(this.providerId, CancellationToken.None);
|
this.model = this.chatService.startSession(CancellationToken.None);
|
||||||
} else if ('data' in this.options.target) {
|
} else if ('data' in this.options.target) {
|
||||||
this.model = this.chatService.loadSessionFromContent(this.options.target.data);
|
this.model = this.chatService.loadSessionFromContent(this.options.target.data);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,6 @@ export class ChatEditorInput extends EditorInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sessionId = this.model.sessionId;
|
this.sessionId = this.model.sessionId;
|
||||||
this.providerId = this.model.providerId;
|
|
||||||
this._register(this.model.onDidChange(() => this._onDidChangeLabel.fire()));
|
this._register(this.model.onDidChange(() => this._onDidChangeLabel.fire()));
|
||||||
|
|
||||||
return this._register(new ChatEditorModel(this.model));
|
return this._register(new ChatEditorModel(this.model));
|
||||||
|
|
|
@ -125,7 +125,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||||
private inputEditorHasText: IContextKey<boolean>;
|
private inputEditorHasText: IContextKey<boolean>;
|
||||||
private chatCursorAtTop: IContextKey<boolean>;
|
private chatCursorAtTop: IContextKey<boolean>;
|
||||||
private inputEditorHasFocus: IContextKey<boolean>;
|
private inputEditorHasFocus: IContextKey<boolean>;
|
||||||
private providerId: string | undefined;
|
|
||||||
|
|
||||||
private cachedDimensions: dom.Dimension | undefined;
|
private cachedDimensions: dom.Dimension | undefined;
|
||||||
private cachedToolbarWidth: number | undefined;
|
private cachedToolbarWidth: number | undefined;
|
||||||
|
@ -174,9 +173,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||||
return localize('chatInput', "Chat Input");
|
return localize('chatInput', "Chat Input");
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(providerId: string, inputValue: string | undefined): void {
|
setState(inputValue: string | undefined): void {
|
||||||
this.providerId = providerId;
|
const history = this.historyService.getHistory();
|
||||||
const history = this.historyService.getHistory(providerId);
|
|
||||||
this.history = new HistoryNavigator(history, 50);
|
this.history = new HistoryNavigator(history, 50);
|
||||||
|
|
||||||
if (typeof inputValue === 'string') {
|
if (typeof inputValue === 'string') {
|
||||||
|
@ -495,7 +493,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||||
|
|
||||||
saveState(): void {
|
saveState(): void {
|
||||||
const inputHistory = this.history.getHistory();
|
const inputHistory = this.history.getHistory();
|
||||||
this.historyService.saveHistory(this.providerId!, inputHistory);
|
this.historyService.saveHistory(inputHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||||
import { Codicon } from 'vs/base/common/codicons';
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { DisposableMap, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { DisposableMap, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { localize, localize2 } from 'vs/nls';
|
import { localize, localize2 } from 'vs/nls';
|
||||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
|
||||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
|
@ -15,55 +14,15 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IProductService } from 'vs/platform/product/common/productService';
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
import { IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation, Extensions as ViewExtensions } from 'vs/workbench/common/views';
|
import { IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation, Extensions as ViewExtensions } from 'vs/workbench/common/views';
|
||||||
import { getHistoryAction, getOpenChatEditorAction } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
import { CHAT_VIEW_ID } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { getNewChatAction } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
import { CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||||
import { getMoveToEditorAction, getMoveToNewWindowAction } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
|
|
||||||
import { getQuickChatActionForProvider } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions';
|
|
||||||
import { CHAT_SIDEBAR_PANEL_ID, ChatViewPane, IChatViewOptions } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
|
||||||
import { ChatAgentLocation, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IChatContributionService, IChatProviderContribution, IRawChatParticipantContribution, IRawChatProviderContribution } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
import { IRawChatParticipantContribution } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||||
|
|
||||||
const chatExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawChatProviderContribution[]>({
|
|
||||||
extensionPoint: 'interactiveSession',
|
|
||||||
jsonSchema: {
|
|
||||||
description: localize('vscode.extension.contributes.interactiveSession', 'Contributes an Interactive Session provider'),
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
additionalProperties: false,
|
|
||||||
type: 'object',
|
|
||||||
defaultSnippets: [{ body: { id: '', program: '', runtime: '' } }],
|
|
||||||
required: ['id', 'label'],
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
description: localize('vscode.extension.contributes.interactiveSession.id', "Unique identifier for this Interactive Session provider."),
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
description: localize('vscode.extension.contributes.interactiveSession.label', "Display name for this Interactive Session provider."),
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
description: localize('vscode.extension.contributes.interactiveSession.icon', "An icon for this Interactive Session provider."),
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
when: {
|
|
||||||
description: localize('vscode.extension.contributes.interactiveSession.when', "A condition which must be true to enable this Interactive Session provider."),
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
activationEventsGenerator: (contributions: IRawChatProviderContribution[], result: { push(item: string): void }) => {
|
|
||||||
for (const contrib of contributions) {
|
|
||||||
result.push(`onInteractiveSession:${contrib.id}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const chatParticipantExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawChatParticipantContribution[]>({
|
const chatParticipantExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawChatParticipantContribution[]>({
|
||||||
extensionPoint: 'chatParticipants',
|
extensionPoint: 'chatParticipants',
|
||||||
jsonSchema: {
|
jsonSchema: {
|
||||||
|
@ -168,11 +127,9 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
private readonly disposables = new DisposableStore();
|
private readonly disposables = new DisposableStore();
|
||||||
private _welcomeViewDescriptor?: IViewDescriptor;
|
private _welcomeViewDescriptor?: IViewDescriptor;
|
||||||
private _viewContainer: ViewContainer;
|
private _viewContainer: ViewContainer;
|
||||||
private _registrationDisposables = new Map<string, IDisposable>();
|
|
||||||
private _participantRegistrationDisposables = new DisposableMap<string>();
|
private _participantRegistrationDisposables = new DisposableMap<string>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IChatContributionService private readonly _chatContributionService: IChatContributionService,
|
|
||||||
@IChatAgentService private readonly _chatAgentService: IChatAgentService,
|
@IChatAgentService private readonly _chatAgentService: IChatAgentService,
|
||||||
@IProductService private readonly productService: IProductService,
|
@IProductService private readonly productService: IProductService,
|
||||||
@IContextKeyService private readonly contextService: IContextKeyService,
|
@IContextKeyService private readonly contextService: IContextKeyService,
|
||||||
|
@ -196,20 +153,18 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
const contextKeyExpr = ContextKeyExpr.equals(showWelcomeViewConfigKey, true);
|
const contextKeyExpr = ContextKeyExpr.equals(showWelcomeViewConfigKey, true);
|
||||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
||||||
if (this.contextService.contextMatchesRules(contextKeyExpr)) {
|
if (this.contextService.contextMatchesRules(contextKeyExpr)) {
|
||||||
const viewId = this._chatContributionService.getViewIdForProvider(this.productService.chatWelcomeView.welcomeViewId);
|
|
||||||
|
|
||||||
this._welcomeViewDescriptor = {
|
this._welcomeViewDescriptor = {
|
||||||
id: viewId,
|
id: CHAT_VIEW_ID,
|
||||||
name: { original: this.productService.chatWelcomeView.welcomeViewTitle, value: this.productService.chatWelcomeView.welcomeViewTitle },
|
name: { original: this.productService.chatWelcomeView.welcomeViewTitle, value: this.productService.chatWelcomeView.welcomeViewTitle },
|
||||||
containerIcon: this._viewContainer.icon,
|
containerIcon: this._viewContainer.icon,
|
||||||
ctorDescriptor: new SyncDescriptor(ChatViewPane, [<IChatViewOptions>{ providerId: this.productService.chatWelcomeView.welcomeViewId }]),
|
ctorDescriptor: new SyncDescriptor(ChatViewPane),
|
||||||
canToggleVisibility: false,
|
canToggleVisibility: false,
|
||||||
canMoveView: true,
|
canMoveView: true,
|
||||||
order: 100
|
order: 100
|
||||||
};
|
};
|
||||||
viewsRegistry.registerViews([this._welcomeViewDescriptor], this._viewContainer);
|
viewsRegistry.registerViews([this._welcomeViewDescriptor], this._viewContainer);
|
||||||
|
|
||||||
viewsRegistry.registerViewWelcomeContent(viewId, {
|
viewsRegistry.registerViewWelcomeContent(CHAT_VIEW_ID, {
|
||||||
content: this.productService.chatWelcomeView.welcomeViewContent,
|
content: this.productService.chatWelcomeView.welcomeViewContent,
|
||||||
});
|
});
|
||||||
} else if (this._welcomeViewDescriptor) {
|
} else if (this._welcomeViewDescriptor) {
|
||||||
|
@ -220,29 +175,6 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleAndRegisterChatExtensions(): void {
|
private handleAndRegisterChatExtensions(): void {
|
||||||
chatExtensionPoint.setHandler((extensions, delta) => {
|
|
||||||
for (const extension of delta.added) {
|
|
||||||
const extensionDisposable = new DisposableStore();
|
|
||||||
for (const providerDescriptor of extension.value) {
|
|
||||||
this.registerChatProvider(providerDescriptor);
|
|
||||||
this._chatContributionService.registerChatProvider(providerDescriptor);
|
|
||||||
}
|
|
||||||
this._registrationDisposables.set(extension.description.identifier.value, extensionDisposable);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const extension of delta.removed) {
|
|
||||||
const registration = this._registrationDisposables.get(extension.description.identifier.value);
|
|
||||||
if (registration) {
|
|
||||||
registration.dispose();
|
|
||||||
this._registrationDisposables.delete(extension.description.identifier.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const providerDescriptor of extension.value) {
|
|
||||||
this._chatContributionService.deregisterChatProvider(providerDescriptor.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
chatParticipantExtensionPoint.setHandler((extensions, delta) => {
|
chatParticipantExtensionPoint.setHandler((extensions, delta) => {
|
||||||
for (const extension of delta.added) {
|
for (const extension of delta.added) {
|
||||||
for (const providerDescriptor of extension.value) {
|
for (const providerDescriptor of extension.value) {
|
||||||
|
@ -261,9 +193,12 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._participantRegistrationDisposables.set(
|
const store = new DisposableStore();
|
||||||
getParticipantKey(extension.description.identifier, providerDescriptor.name),
|
if (providerDescriptor.isDefault) {
|
||||||
this._chatAgentService.registerAgent(
|
store.add(this.registerDefaultParticipant(providerDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
store.add(this._chatAgentService.registerAgent(
|
||||||
providerDescriptor.id,
|
providerDescriptor.id,
|
||||||
{
|
{
|
||||||
extensionId: extension.description.identifier,
|
extensionId: extension.description.identifier,
|
||||||
|
@ -280,6 +215,11 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
[ChatAgentLocation.Panel],
|
[ChatAgentLocation.Panel],
|
||||||
slashCommands: providerDescriptor.commands ?? []
|
slashCommands: providerDescriptor.commands ?? []
|
||||||
} satisfies IChatAgentData));
|
} satisfies IChatAgentData));
|
||||||
|
|
||||||
|
this._participantRegistrationDisposables.set(
|
||||||
|
getParticipantKey(extension.description.identifier, providerDescriptor.name),
|
||||||
|
store
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,72 +249,26 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||||
return viewContainer;
|
return viewContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerChatProvider(providerDescriptor: IRawChatProviderContribution): IDisposable {
|
private registerDefaultParticipant(defaultParticipantDescriptor: IRawChatParticipantContribution): IDisposable {
|
||||||
// Register View
|
// Register View
|
||||||
const viewId = this._chatContributionService.getViewIdForProvider(providerDescriptor.id);
|
|
||||||
const viewDescriptor: IViewDescriptor[] = [{
|
const viewDescriptor: IViewDescriptor[] = [{
|
||||||
id: viewId,
|
id: CHAT_VIEW_ID,
|
||||||
containerIcon: this._viewContainer.icon,
|
containerIcon: this._viewContainer.icon,
|
||||||
containerTitle: this._viewContainer.title.value,
|
containerTitle: this._viewContainer.title.value,
|
||||||
singleViewPaneContainerTitle: this._viewContainer.title.value,
|
singleViewPaneContainerTitle: this._viewContainer.title.value,
|
||||||
name: { value: providerDescriptor.label, original: providerDescriptor.label },
|
name: { value: defaultParticipantDescriptor.name, original: defaultParticipantDescriptor.name },
|
||||||
canToggleVisibility: false,
|
canToggleVisibility: false,
|
||||||
canMoveView: true,
|
canMoveView: true,
|
||||||
ctorDescriptor: new SyncDescriptor(ChatViewPane, [<IChatViewOptions>{ providerId: providerDescriptor.id }]),
|
ctorDescriptor: new SyncDescriptor(ChatViewPane),
|
||||||
when: ContextKeyExpr.deserialize(providerDescriptor.when)
|
|
||||||
}];
|
}];
|
||||||
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews(viewDescriptor, this._viewContainer);
|
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews(viewDescriptor, this._viewContainer);
|
||||||
|
|
||||||
// Per-provider actions
|
return toDisposable(() => {
|
||||||
|
|
||||||
// Actions in view title
|
|
||||||
const disposables = new DisposableStore();
|
|
||||||
disposables.add(registerAction2(getHistoryAction(viewId, providerDescriptor.id)));
|
|
||||||
disposables.add(registerAction2(getNewChatAction(viewId, providerDescriptor.id)));
|
|
||||||
disposables.add(registerAction2(getMoveToEditorAction(viewId, providerDescriptor.id)));
|
|
||||||
disposables.add(registerAction2(getMoveToNewWindowAction(viewId, providerDescriptor.id)));
|
|
||||||
|
|
||||||
// "Open Chat" Actions
|
|
||||||
disposables.add(registerAction2(getOpenChatEditorAction(providerDescriptor.id, providerDescriptor.label, providerDescriptor.when)));
|
|
||||||
disposables.add(registerAction2(getQuickChatActionForProvider(providerDescriptor.id, providerDescriptor.label)));
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).deregisterViews(viewDescriptor, this._viewContainer);
|
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).deregisterViews(viewDescriptor, this._viewContainer);
|
||||||
Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).deregisterViewContainer(this._viewContainer);
|
});
|
||||||
disposables.dispose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerWorkbenchContribution2(ChatExtensionPointHandler.ID, ChatExtensionPointHandler, WorkbenchPhase.BlockStartup);
|
|
||||||
|
|
||||||
function getParticipantKey(extensionId: ExtensionIdentifier, participantName: string): string {
|
function getParticipantKey(extensionId: ExtensionIdentifier, participantName: string): string {
|
||||||
return `${extensionId.value}_${participantName}`;
|
return `${extensionId.value}_${participantName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChatContributionService implements IChatContributionService {
|
|
||||||
declare _serviceBrand: undefined;
|
|
||||||
|
|
||||||
private _registeredProviders = new Map<string, IChatProviderContribution>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public getViewIdForProvider(providerId: string): string {
|
|
||||||
return ChatViewPane.ID + '.' + providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public registerChatProvider(provider: IChatProviderContribution): void {
|
|
||||||
this._registeredProviders.set(provider.id, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public deregisterChatProvider(providerId: string): void {
|
|
||||||
this._registeredProviders.delete(providerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get registeredProviders(): IChatProviderContribution[] {
|
|
||||||
return Array.from(this._registeredProviders.values());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,13 +17,13 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||||
import { IQuickInputService, IQuickWidget } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService, IQuickWidget } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { editorBackground, inputBackground, quickInputBackground, quickInputForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { editorBackground, inputBackground, quickInputBackground, quickInputForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { IChatWidgetService, IQuickChatService, IQuickChatOpenOptions } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IQuickChatOpenOptions, IQuickChatService, showChatView } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { IChatViewOptions } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
|
||||||
import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation } 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 { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
export class QuickChatService extends Disposable implements IQuickChatService {
|
export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
|
@ -45,7 +45,7 @@ export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
get enabled(): boolean {
|
get enabled(): boolean {
|
||||||
return this.chatService.getProviderInfos().length > 0;
|
return !!this.chatService.isEnabled(ChatAgentLocation.Panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
get focused(): boolean {
|
get focused(): boolean {
|
||||||
|
@ -56,13 +56,13 @@ export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
return dom.isAncestorOfActiveElement(widget);
|
return dom.isAncestorOfActiveElement(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(providerId?: string, options?: IQuickChatOpenOptions): void {
|
toggle(options?: IQuickChatOpenOptions): void {
|
||||||
// If the input is already shown, hide it. This provides a toggle behavior of the quick
|
// If the input is already shown, hide it. This provides a toggle behavior of the quick
|
||||||
// pick. This should not happen when there is a query.
|
// pick. This should not happen when there is a query.
|
||||||
if (this.focused && !options?.query) {
|
if (this.focused && !options?.query) {
|
||||||
this.close();
|
this.close();
|
||||||
} else {
|
} else {
|
||||||
this.open(providerId, options);
|
this.open(options);
|
||||||
// If this is a partial query, the value should be cleared when closed as otherwise it
|
// If this is a partial query, the value should be cleared when closed as otherwise it
|
||||||
// would remain for the next time the quick chat is opened in any context.
|
// would remain for the next time the quick chat is opened in any context.
|
||||||
if (options?.isPartialQuery) {
|
if (options?.isPartialQuery) {
|
||||||
|
@ -74,7 +74,7 @@ export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open(providerId?: string, options?: IQuickChatOpenOptions): void {
|
open(options?: IQuickChatOpenOptions): void {
|
||||||
if (this._input) {
|
if (this._input) {
|
||||||
if (this._currentChat && options?.query) {
|
if (this._currentChat && options?.query) {
|
||||||
this._currentChat.focus();
|
this._currentChat.focus();
|
||||||
|
@ -87,15 +87,6 @@ export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
return this.focus();
|
return this.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any providers are available. If not, show nothing
|
|
||||||
// This shouldn't be needed because of the precondition, but just in case
|
|
||||||
const providerInfo = providerId
|
|
||||||
? this.chatService.getProviderInfos().find(info => info.id === providerId)
|
|
||||||
: this.chatService.getProviderInfos()[0];
|
|
||||||
if (!providerInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const disposableStore = new DisposableStore();
|
const disposableStore = new DisposableStore();
|
||||||
|
|
||||||
this._input = this.quickInputService.createQuickWidget();
|
this._input = this.quickInputService.createQuickWidget();
|
||||||
|
@ -108,9 +99,7 @@ export class QuickChatService extends Disposable implements IQuickChatService {
|
||||||
|
|
||||||
this._input.show();
|
this._input.show();
|
||||||
if (!this._currentChat) {
|
if (!this._currentChat) {
|
||||||
this._currentChat = this.instantiationService.createInstance(QuickChat, {
|
this._currentChat = this.instantiationService.createInstance(QuickChat);
|
||||||
providerId: providerInfo.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
// show needs to come after the quickpick is shown
|
// show needs to come after the quickpick is shown
|
||||||
this._currentChat.render(this._container);
|
this._currentChat.render(this._container);
|
||||||
|
@ -160,12 +149,11 @@ class QuickChat extends Disposable {
|
||||||
private _deferUpdatingDynamicLayout: boolean = false;
|
private _deferUpdatingDynamicLayout: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _options: IChatViewOptions,
|
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||||
@IChatService private readonly chatService: IChatService,
|
@IChatService private readonly chatService: IChatService,
|
||||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
|
@ILayoutService private readonly layoutService: ILayoutService,
|
||||||
@ILayoutService private readonly layoutService: ILayoutService
|
@IViewsService private readonly viewsService: IViewsService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -288,7 +276,7 @@ class QuickChat extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
async openChatView(): Promise<void> {
|
async openChatView(): Promise<void> {
|
||||||
const widget = await this._chatWidgetService.revealViewForProvider(this._options.providerId);
|
const widget = await showChatView(this.viewsService);
|
||||||
if (!widget?.viewModel || !this.model) {
|
if (!widget?.viewModel || !this.model) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +313,7 @@ class QuickChat extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateModel(): void {
|
private updateModel(): void {
|
||||||
this.model ??= this.chatService.startSession(this._options.providerId, CancellationToken.None);
|
this.model ??= this.chatService.startSession(CancellationToken.None);
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
throw new Error('Could not start chat session');
|
throw new Error('Could not start chat session');
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,11 @@ import { SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme';
|
||||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
import { IChatViewPane } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatViewPane } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { IChatViewState, ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { IChatViewState, ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { CHAT_PROVIDER_ID } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
|
import { ChatModelInitState, IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
import { IChatViewTitleActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
export interface IChatViewOptions {
|
|
||||||
readonly providerId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IViewPaneState extends IChatViewState {
|
interface IViewPaneState extends IChatViewState {
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
|
@ -38,8 +36,6 @@ interface IViewPaneState extends IChatViewState {
|
||||||
|
|
||||||
export const CHAT_SIDEBAR_PANEL_ID = 'workbench.panel.chatSidebar';
|
export const CHAT_SIDEBAR_PANEL_ID = 'workbench.panel.chatSidebar';
|
||||||
export class ChatViewPane extends ViewPane implements IChatViewPane {
|
export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
static ID = 'workbench.panel.chat.view';
|
|
||||||
|
|
||||||
private _widget!: ChatWidget;
|
private _widget!: ChatWidget;
|
||||||
get widget(): ChatWidget { return this._widget; }
|
get widget(): ChatWidget { return this._widget; }
|
||||||
|
|
||||||
|
@ -50,7 +46,6 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
private didUnregisterProvider = false;
|
private didUnregisterProvider = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly chatViewOptions: IChatViewOptions,
|
|
||||||
options: IViewPaneOptions,
|
options: IViewPaneOptions,
|
||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IContextMenuService contextMenuService: IContextMenuService,
|
@IContextMenuService contextMenuService: IContextMenuService,
|
||||||
|
@ -64,15 +59,17 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
@IHoverService hoverService: IHoverService,
|
@IHoverService hoverService: IHoverService,
|
||||||
@IStorageService private readonly storageService: IStorageService,
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
@IChatService private readonly chatService: IChatService,
|
@IChatService private readonly chatService: IChatService,
|
||||||
|
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
||||||
@ILogService private readonly logService: ILogService,
|
@ILogService private readonly logService: ILogService,
|
||||||
) {
|
) {
|
||||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, hoverService);
|
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, hoverService);
|
||||||
|
|
||||||
// View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento.
|
// View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento.
|
||||||
this.memento = new Memento('interactive-session-view-' + this.chatViewOptions.providerId, this.storageService);
|
this.memento = new Memento('interactive-session-view-' + CHAT_PROVIDER_ID, this.storageService);
|
||||||
this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState;
|
this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState;
|
||||||
this._register(this.chatService.onDidRegisterProvider(({ providerId }) => {
|
this._register(this.chatAgentService.onDidChangeAgents(() => {
|
||||||
if (providerId === this.chatViewOptions.providerId && !this._widget?.viewModel) {
|
if (this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel)) {
|
||||||
|
if (!this._widget?.viewModel) {
|
||||||
const sessionId = this.getSessionId();
|
const sessionId = this.getSessionId();
|
||||||
const model = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined;
|
const model = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined;
|
||||||
|
|
||||||
|
@ -89,21 +86,26 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
this.widget.setVisible(true);
|
this.widget.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
} else if (this._widget?.viewModel?.initState === ChatModelInitState.Initialized) {
|
||||||
this._register(this.chatService.onDidUnregisterProvider(({ providerId }) => {
|
// Model is initialized, and the default agent disappeared, so show welcome view
|
||||||
if (providerId === this.chatViewOptions.providerId) {
|
|
||||||
this.didUnregisterProvider = true;
|
this.didUnregisterProvider = true;
|
||||||
this._onDidChangeViewWelcomeState.fire();
|
this._onDidChangeViewWelcomeState.fire();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override getActionsContext(): IChatViewTitleActionContext {
|
||||||
|
return {
|
||||||
|
chatView: this
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private updateModel(model?: IChatModel | undefined, viewState?: IViewPaneState): void {
|
private updateModel(model?: IChatModel | undefined, viewState?: IViewPaneState): void {
|
||||||
this.modelDisposables.clear();
|
this.modelDisposables.clear();
|
||||||
|
|
||||||
model = model ?? (this.chatService.transferredSessionData?.sessionId
|
model = model ?? (this.chatService.transferredSessionData?.sessionId
|
||||||
? this.chatService.getOrRestoreSession(this.chatService.transferredSessionData.sessionId)
|
? this.chatService.getOrRestoreSession(this.chatService.transferredSessionData.sessionId)
|
||||||
: this.chatService.startSession(this.chatViewOptions.providerId, CancellationToken.None));
|
: this.chatService.startSession(CancellationToken.None));
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new Error('Could not start chat session');
|
throw new Error('Could not start chat session');
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
override shouldShowWelcome(): boolean {
|
override shouldShowWelcome(): boolean {
|
||||||
const noPersistedSessions = !this.chatService.hasSessions(this.chatViewOptions.providerId);
|
const noPersistedSessions = !this.chatService.hasSessions();
|
||||||
return this.didUnregisterProvider || !this._widget?.viewModel && (noPersistedSessions || this.didProviderRegistrationFail);
|
return this.didUnregisterProvider || !this._widget?.viewModel && (noPersistedSessions || this.didProviderRegistrationFail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +157,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
// Render the welcome view if this session gets disposed at any point,
|
// Render the welcome view if this session gets disposed at any point,
|
||||||
// including if the provider registration fails
|
// including if the provider registration fails
|
||||||
const disposeListener = sessionId ? this._register(this.chatService.onDidDisposeSession((e) => {
|
const disposeListener = sessionId ? this._register(this.chatService.onDidDisposeSession((e) => {
|
||||||
if (e.reason === 'initializationFailed' && e.providerId === this.chatViewOptions.providerId) {
|
if (e.reason === 'initializationFailed') {
|
||||||
this.didProviderRegistrationFail = true;
|
this.didProviderRegistrationFail = true;
|
||||||
disposeListener?.dispose();
|
disposeListener?.dispose();
|
||||||
this._onDidChangeViewWelcomeState.fire();
|
this._onDidChangeViewWelcomeState.fire();
|
||||||
|
@ -174,7 +176,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||||
this._widget.acceptInput(query);
|
this._widget.acceptInput(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
async clear(): Promise<void> {
|
clear(): void {
|
||||||
if (this.widget.viewModel) {
|
if (this.widget.viewModel) {
|
||||||
this.chatService.clearSession(this.widget.viewModel.sessionId);
|
this.chatService.clearSession(this.widget.viewModel.sessionId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,9 @@ import { ChatTreeItem, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileT
|
||||||
import { ChatAccessibilityProvider } from 'vs/workbench/contrib/chat/browser/chatAccessibilityProvider';
|
import { ChatAccessibilityProvider } from 'vs/workbench/contrib/chat/browser/chatAccessibilityProvider';
|
||||||
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
||||||
import { ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
|
import { ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
|
||||||
import { IChatListItemRendererOptions } from './chat';
|
|
||||||
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
||||||
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
|
||||||
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION, CONTEXT_RESPONSE_FILTERED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION, CONTEXT_RESPONSE_FILTERED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
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 { ChatRequestAgentPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, extractAgentAndCommand } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestAgentPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, extractAgentAndCommand } 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';
|
||||||
|
@ -42,7 +39,7 @@ import { IChatFollowup, IChatService } from 'vs/workbench/contrib/chat/common/ch
|
||||||
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
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';
|
||||||
import { CodeBlockModelCollection } from 'vs/workbench/contrib/chat/common/codeBlockModelCollection';
|
import { CodeBlockModelCollection } from 'vs/workbench/contrib/chat/common/codeBlockModelCollection';
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
import { IChatListItemRendererOptions } from './chat';
|
||||||
|
|
||||||
const $ = dom.$;
|
const $ = dom.$;
|
||||||
|
|
||||||
|
@ -242,10 +239,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
return !!this.viewOptions.supportsFileReferences;
|
return !!this.viewOptions.supportsFileReferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
get providerId(): string {
|
|
||||||
return this.viewModel?.providerId || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
get input(): ChatInputPart {
|
get input(): ChatInputPart {
|
||||||
return this.inputPart;
|
return this.inputPart;
|
||||||
}
|
}
|
||||||
|
@ -563,7 +556,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chatService.notifyUserAction({
|
this.chatService.notifyUserAction({
|
||||||
providerId: this.viewModel.providerId,
|
|
||||||
sessionId: this.viewModel.sessionId,
|
sessionId: this.viewModel.sessionId,
|
||||||
requestId: e.response.requestId,
|
requestId: e.response.requestId,
|
||||||
agentId: e.response.agent?.id,
|
agentId: e.response.agent?.id,
|
||||||
|
@ -641,7 +633,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||||
this.viewModel = undefined;
|
this.viewModel = undefined;
|
||||||
this.onDidChangeItems();
|
this.onDidChangeItems();
|
||||||
}));
|
}));
|
||||||
this.inputPart.setState(model.providerId, viewState.inputValue);
|
this.inputPart.setState(viewState.inputValue);
|
||||||
this.contribs.forEach(c => {
|
this.contribs.forEach(c => {
|
||||||
if (c.setInputState && viewState.inputState?.[c.id]) {
|
if (c.setInputState && viewState.inputState?.[c.id]) {
|
||||||
c.setInputState(viewState.inputState?.[c.id]);
|
c.setInputState(viewState.inputState?.[c.id]);
|
||||||
|
@ -914,10 +906,7 @@ export class ChatWidgetService implements IChatWidgetService {
|
||||||
return this._lastFocusedWidget;
|
return this._lastFocusedWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor() { }
|
||||||
@IViewsService private readonly viewsService: IViewsService,
|
|
||||||
@IChatContributionService private readonly chatContributionService: IChatContributionService,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
getWidgetByInputUri(uri: URI): ChatWidget | undefined {
|
getWidgetByInputUri(uri: URI): ChatWidget | undefined {
|
||||||
return this._widgets.find(w => isEqual(w.inputUri, uri));
|
return this._widgets.find(w => isEqual(w.inputUri, uri));
|
||||||
|
@ -927,13 +916,6 @@ export class ChatWidgetService implements IChatWidgetService {
|
||||||
return this._widgets.find(w => w.viewModel?.sessionId === sessionId);
|
return this._widgets.find(w => w.viewModel?.sessionId === sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async revealViewForProvider(providerId: string): Promise<ChatWidget | undefined> {
|
|
||||||
const viewId = this.chatContributionService.getViewIdForProvider(providerId);
|
|
||||||
const view = await this.viewsService.openView<ChatViewPane>(viewId);
|
|
||||||
|
|
||||||
return view?.widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
private setLastFocusedWidget(widget: ChatWidget | undefined): void {
|
private setLastFocusedWidget(widget: ChatWidget | undefined): void {
|
||||||
if (widget === this._lastFocusedWidget) {
|
if (widget === this._lastFocusedWidget) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,11 +11,12 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { ThemeIcon } from 'vs/base/common/themables';
|
import { ThemeIcon } from 'vs/base/common/themables';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ProviderResult } from 'vs/editor/common/languages';
|
import { ProviderResult } from 'vs/editor/common/languages';
|
||||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IRawChatCommandContribution, RawChatParticipantLocation } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
import { CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
import { IChatProgressResponseContent, IChatRequestVariableData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { IChatProgressResponseContent, IChatRequestVariableData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
|
import { IRawChatCommandContribution, RawChatParticipantLocation } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
import { IChatFollowup, IChatProgress, IChatResponseErrorDetails } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatFollowup, IChatProgress, IChatResponseErrorDetails } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
|
||||||
//#region agent service, commands etc
|
//#region agent service, commands etc
|
||||||
|
@ -139,7 +140,16 @@ export interface IChatAgentService {
|
||||||
getAgents(): IChatAgentData[];
|
getAgents(): IChatAgentData[];
|
||||||
getActivatedAgents(): Array<IChatAgent>;
|
getActivatedAgents(): Array<IChatAgent>;
|
||||||
getAgentsByName(name: string): IChatAgentData[];
|
getAgentsByName(name: string): IChatAgentData[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default agent (only if activated)
|
||||||
|
*/
|
||||||
getDefaultAgent(location: ChatAgentLocation): IChatAgent | undefined;
|
getDefaultAgent(location: ChatAgentLocation): IChatAgent | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default agent data that has been contributed (may not be activated yet)
|
||||||
|
*/
|
||||||
|
getContributedDefaultAgent(location: ChatAgentLocation): IChatAgentData | undefined;
|
||||||
getSecondaryAgent(): IChatAgentData | undefined;
|
getSecondaryAgent(): IChatAgentData | undefined;
|
||||||
updateAgent(id: string, updateMetadata: IChatAgentMetadata): void;
|
updateAgent(id: string, updateMetadata: IChatAgentMetadata): void;
|
||||||
}
|
}
|
||||||
|
@ -155,9 +165,13 @@ export class ChatAgentService implements IChatAgentService {
|
||||||
private readonly _onDidChangeAgents = new Emitter<IChatAgent | undefined>();
|
private readonly _onDidChangeAgents = new Emitter<IChatAgent | undefined>();
|
||||||
readonly onDidChangeAgents: Event<IChatAgent | undefined> = this._onDidChangeAgents.event;
|
readonly onDidChangeAgents: Event<IChatAgent | undefined> = this._onDidChangeAgents.event;
|
||||||
|
|
||||||
|
private readonly _hasDefaultAgent: IContextKey<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IContextKeyService private readonly contextKeyService: IContextKeyService
|
@IContextKeyService private readonly contextKeyService: IContextKeyService
|
||||||
) { }
|
) {
|
||||||
|
this._hasDefaultAgent = CONTEXT_HAS_DEFAULT_AGENT.bindTo(this.contextKeyService);
|
||||||
|
}
|
||||||
|
|
||||||
registerAgent(id: string, data: IChatAgentData): IDisposable {
|
registerAgent(id: string, data: IChatAgentData): IDisposable {
|
||||||
const existingAgent = this.getAgent(id);
|
const existingAgent = this.getAgent(id);
|
||||||
|
@ -191,12 +205,20 @@ export class ChatAgentService implements IChatAgentService {
|
||||||
throw new Error(`Agent already has implementation: ${JSON.stringify(id)}`);
|
throw new Error(`Agent already has implementation: ${JSON.stringify(id)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry.data.isDefault) {
|
||||||
|
this._hasDefaultAgent.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
entry.impl = agentImpl;
|
entry.impl = agentImpl;
|
||||||
this._onDidChangeAgents.fire(new MergedChatAgent(entry.data, agentImpl));
|
this._onDidChangeAgents.fire(new MergedChatAgent(entry.data, agentImpl));
|
||||||
|
|
||||||
return toDisposable(() => {
|
return toDisposable(() => {
|
||||||
entry.impl = undefined;
|
entry.impl = undefined;
|
||||||
this._onDidChangeAgents.fire(undefined);
|
this._onDidChangeAgents.fire(undefined);
|
||||||
|
|
||||||
|
if (entry.data.isDefault) {
|
||||||
|
this._hasDefaultAgent.set(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +246,10 @@ export class ChatAgentService implements IChatAgentService {
|
||||||
return this.getActivatedAgents().find(a => !!a.isDefault && a.locations.includes(location));
|
return this.getActivatedAgents().find(a => !!a.isDefault && a.locations.includes(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getContributedDefaultAgent(location: ChatAgentLocation): IChatAgentData | undefined {
|
||||||
|
return this.getAgents().find(a => !!a.isDefault && a.locations.includes(location));
|
||||||
|
}
|
||||||
|
|
||||||
getSecondaryAgent(): IChatAgentData | undefined {
|
getSecondaryAgent(): IChatAgentData | undefined {
|
||||||
// TODO also static
|
// TODO also static
|
||||||
return Iterable.find(this._agents.values(), a => !!a.data.metadata.isSecondary)?.data;
|
return Iterable.find(this._agents.values(), a => !!a.data.metadata.isSecondary)?.data;
|
||||||
|
|
|
@ -21,7 +21,8 @@ export const CONTEXT_CHAT_INPUT_HAS_FOCUS = new RawContextKey<boolean>('chatInpu
|
||||||
export const CONTEXT_IN_CHAT_INPUT = new RawContextKey<boolean>('inChatInput', false, { type: 'boolean', description: localize('inInteractiveInput', "True when focus is in the chat input, false otherwise.") });
|
export const CONTEXT_IN_CHAT_INPUT = new RawContextKey<boolean>('inChatInput', false, { type: 'boolean', description: localize('inInteractiveInput', "True when focus is in the chat input, false otherwise.") });
|
||||||
export const CONTEXT_IN_CHAT_SESSION = new RawContextKey<boolean>('inChat', false, { type: 'boolean', description: localize('inChat', "True when focus is in the chat widget, false otherwise.") });
|
export const CONTEXT_IN_CHAT_SESSION = new RawContextKey<boolean>('inChat', false, { type: 'boolean', description: localize('inChat', "True when focus is in the chat widget, false otherwise.") });
|
||||||
|
|
||||||
export const CONTEXT_PROVIDER_EXISTS = new RawContextKey<boolean>('hasChatProvider', false, { type: 'boolean', description: localize('hasChatProvider', "True when some chat provider has been registered.") });
|
// TODO call it 'has default agent'
|
||||||
|
export const CONTEXT_HAS_DEFAULT_AGENT = new RawContextKey<boolean>('hasChatProvider', false, { type: 'boolean', description: localize('hasChatProvider', "True when some chat provider has been registered.") });
|
||||||
export const CONTEXT_CHAT_INPUT_CURSOR_AT_TOP = new RawContextKey<boolean>('chatCursorAtTop', false);
|
export const CONTEXT_CHAT_INPUT_CURSOR_AT_TOP = new RawContextKey<boolean>('chatCursorAtTop', false);
|
||||||
export const CONTEXT_CHAT_INPUT_HAS_AGENT = new RawContextKey<boolean>('chatInputHasAgent', false);
|
export const CONTEXT_CHAT_INPUT_HAS_AGENT = new RawContextKey<boolean>('chatInputHasAgent', false);
|
||||||
export const CONTEXT_CHAT_LOCATION = new RawContextKey<ChatAgentLocation>('chatLocation', undefined);
|
export const CONTEXT_CHAT_LOCATION = new RawContextKey<ChatAgentLocation>('chatLocation', undefined);
|
||||||
|
|
|
@ -1,56 +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 { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
|
|
||||||
export interface IChatProviderContribution {
|
|
||||||
id: string;
|
|
||||||
when?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IChatContributionService = createDecorator<IChatContributionService>('IChatContributionService');
|
|
||||||
export interface IChatContributionService {
|
|
||||||
_serviceBrand: undefined;
|
|
||||||
|
|
||||||
registeredProviders: IChatProviderContribution[];
|
|
||||||
registerChatProvider(provider: IChatProviderContribution): void;
|
|
||||||
deregisterChatProvider(providerId: string): void;
|
|
||||||
getViewIdForProvider(providerId: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRawChatProviderContribution {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
icon?: string;
|
|
||||||
when?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRawChatCommandContribution {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
sampleRequest?: string;
|
|
||||||
isSticky?: boolean;
|
|
||||||
when?: string;
|
|
||||||
defaultImplicitVariables?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook';
|
|
||||||
|
|
||||||
export interface IRawChatParticipantContribution {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
isDefault?: boolean;
|
|
||||||
isSticky?: boolean;
|
|
||||||
commands?: IRawChatCommandContribution[];
|
|
||||||
defaultImplicitVariables?: string[];
|
|
||||||
locations?: RawChatParticipantLocation[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChatParticipantContribution extends IRawChatParticipantContribution {
|
|
||||||
// Participant id is extensionId + name
|
|
||||||
extensionId: ExtensionIdentifier;
|
|
||||||
}
|
|
|
@ -18,7 +18,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatRequestTextPart, IParsedChatRequest, getPromptText, reviveParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestTextPart, IParsedChatRequest, getPromptText, reviveParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChat, IChatAgentMarkdownContentWithVulnerability, IChatCommandButton, IChatContent, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgress, IChatProgressMessage, IChatResponseProgressFileTreeData, IChatTextEdit, IChatTreeData, IChatUsedContext, InteractiveSessionVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatAgentMarkdownContentWithVulnerability, IChatCommandButton, IChatContent, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgress, IChatProgressMessage, IChatResponseProgressFileTreeData, IChatTextEdit, IChatTreeData, IChatUsedContext, InteractiveSessionVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
|
|
||||||
export interface IChatPromptVariableData {
|
export interface IChatPromptVariableData {
|
||||||
|
@ -65,7 +65,6 @@ export interface IResponse {
|
||||||
export interface IChatResponseModel {
|
export interface IChatResponseModel {
|
||||||
readonly onDidChange: Event<void>;
|
readonly onDidChange: Event<void>;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly providerId: string;
|
|
||||||
readonly requestId: string;
|
readonly requestId: string;
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
readonly avatarIcon?: ThemeIcon | URI;
|
readonly avatarIcon?: ThemeIcon | URI;
|
||||||
|
@ -260,10 +259,6 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
|
||||||
return this._result;
|
return this._result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providerId(): string {
|
|
||||||
return this.session.providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get username(): string {
|
public get username(): string {
|
||||||
return this.session.responderUsername;
|
return this.session.responderUsername;
|
||||||
}
|
}
|
||||||
|
@ -391,7 +386,6 @@ export interface IChatModel {
|
||||||
readonly onDidDispose: Event<void>;
|
readonly onDidDispose: Event<void>;
|
||||||
readonly onDidChange: Event<IChatChangeEvent>;
|
readonly onDidChange: Event<IChatChangeEvent>;
|
||||||
readonly sessionId: string;
|
readonly sessionId: string;
|
||||||
readonly providerId: string;
|
|
||||||
readonly initState: ChatModelInitState;
|
readonly initState: ChatModelInitState;
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
readonly welcomeMessage: IChatWelcomeMessageModel | undefined;
|
readonly welcomeMessage: IChatWelcomeMessageModel | undefined;
|
||||||
|
@ -426,7 +420,6 @@ export interface ISerializableChatRequestData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExportableChatData {
|
export interface IExportableChatData {
|
||||||
providerId: string;
|
|
||||||
welcomeMessage: (string | IChatFollowup[])[] | undefined;
|
welcomeMessage: (string | IChatFollowup[])[] | undefined;
|
||||||
requests: ISerializableChatRequestData[];
|
requests: ISerializableChatRequestData[];
|
||||||
requesterUsername: string;
|
requesterUsername: string;
|
||||||
|
@ -444,7 +437,6 @@ export interface ISerializableChatData extends IExportableChatData {
|
||||||
export function isExportableSessionData(obj: unknown): obj is IExportableChatData {
|
export function isExportableSessionData(obj: unknown): obj is IExportableChatData {
|
||||||
const data = obj as IExportableChatData;
|
const data = obj as IExportableChatData;
|
||||||
return typeof data === 'object' &&
|
return typeof data === 'object' &&
|
||||||
typeof data.providerId === 'string' &&
|
|
||||||
typeof data.requesterUsername === 'string';
|
typeof data.requesterUsername === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,11 +497,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
private _initState: ChatModelInitState = ChatModelInitState.Created;
|
private _initState: ChatModelInitState = ChatModelInitState.Created;
|
||||||
private _isInitializedDeferred = new DeferredPromise<void>();
|
private _isInitializedDeferred = new DeferredPromise<void>();
|
||||||
|
|
||||||
private _session: IChat | undefined;
|
|
||||||
get session(): IChat | undefined {
|
|
||||||
return this._session;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _welcomeMessage: ChatWelcomeMessageModel | undefined;
|
private _welcomeMessage: ChatWelcomeMessageModel | undefined;
|
||||||
get welcomeMessage(): ChatWelcomeMessageModel | undefined {
|
get welcomeMessage(): ChatWelcomeMessageModel | undefined {
|
||||||
return this._welcomeMessage;
|
return this._welcomeMessage;
|
||||||
|
@ -580,7 +567,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly providerId: string,
|
|
||||||
private readonly initialData: ISerializableChatData | IExportableChatData | undefined,
|
private readonly initialData: ISerializableChatData | IExportableChatData | undefined,
|
||||||
@ILogService private readonly logService: ILogService,
|
@ILogService private readonly logService: ILogService,
|
||||||
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
||||||
|
@ -672,19 +658,17 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
deinitialize(): void {
|
deinitialize(): void {
|
||||||
this._session = undefined;
|
|
||||||
this._initState = ChatModelInitState.Created;
|
this._initState = ChatModelInitState.Created;
|
||||||
this._isInitializedDeferred = new DeferredPromise<void>();
|
this._isInitializedDeferred = new DeferredPromise<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(session: IChat, welcomeMessage: ChatWelcomeMessageModel | undefined): void {
|
initialize(welcomeMessage: ChatWelcomeMessageModel | undefined): void {
|
||||||
if (this.initState !== ChatModelInitState.Initializing) {
|
if (this.initState !== ChatModelInitState.Initializing) {
|
||||||
// Must call startInitialize before initialize, and only call it once
|
// Must call startInitialize before initialize, and only call it once
|
||||||
throw new Error(`ChatModel is in the wrong state for initialize: ${ChatModelInitState[this.initState]}`);
|
throw new Error(`ChatModel is in the wrong state for initialize: ${ChatModelInitState[this.initState]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._initState = ChatModelInitState.Initialized;
|
this._initState = ChatModelInitState.Initialized;
|
||||||
this._session = session;
|
|
||||||
if (!this._welcomeMessage) {
|
if (!this._welcomeMessage) {
|
||||||
// Could also have loaded the welcome message from persisted data
|
// Could also have loaded the welcome message from persisted data
|
||||||
this._welcomeMessage = welcomeMessage;
|
this._welcomeMessage = welcomeMessage;
|
||||||
|
@ -713,10 +697,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
addRequest(message: IParsedChatRequest, variableData: IChatRequestVariableData, chatAgent?: IChatAgentData, slashCommand?: IChatAgentCommand): ChatRequestModel {
|
addRequest(message: IParsedChatRequest, variableData: IChatRequestVariableData, chatAgent?: IChatAgentData, slashCommand?: IChatAgentCommand): ChatRequestModel {
|
||||||
if (!this._session) {
|
|
||||||
throw new Error('addRequest: No session');
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = new ChatRequestModel(this, message, variableData);
|
const request = new ChatRequestModel(this, message, variableData);
|
||||||
request.response = new ChatResponseModel([], this, chatAgent, slashCommand, request.id);
|
request.response = new ChatResponseModel([], this, chatAgent, slashCommand, request.id);
|
||||||
|
|
||||||
|
@ -726,10 +706,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptResponseProgress(request: ChatRequestModel, progress: IChatProgress, quiet?: boolean): void {
|
acceptResponseProgress(request: ChatRequestModel, progress: IChatProgress, quiet?: boolean): void {
|
||||||
if (!this._session) {
|
|
||||||
throw new Error('acceptResponseProgress: No session');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request.response) {
|
if (!request.response) {
|
||||||
request.response = new ChatResponseModel([], this, undefined, undefined, request.id);
|
request.response = new ChatResponseModel([], this, undefined, undefined, request.id);
|
||||||
}
|
}
|
||||||
|
@ -772,10 +748,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
setResponse(request: ChatRequestModel, result: IChatAgentResult): void {
|
setResponse(request: ChatRequestModel, result: IChatAgentResult): void {
|
||||||
if (!this._session) {
|
|
||||||
throw new Error('completeResponse: No session');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request.response) {
|
if (!request.response) {
|
||||||
request.response = new ChatResponseModel([], this, undefined, undefined, request.id);
|
request.response = new ChatResponseModel([], this, undefined, undefined, request.id);
|
||||||
}
|
}
|
||||||
|
@ -851,7 +823,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
contentReferences: r.response?.contentReferences
|
contentReferences: r.response?.contentReferences
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
providerId: this.providerId,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +836,6 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
override dispose() {
|
override dispose() {
|
||||||
this._session?.dispose?.();
|
|
||||||
this._requests.forEach(r => r.response?.dispose());
|
this._requests.forEach(r => r.response?.dispose());
|
||||||
this._onDidDispose.fire();
|
this._onDidDispose.fire();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
export interface IRawChatCommandContribution {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
sampleRequest?: string;
|
||||||
|
isSticky?: boolean;
|
||||||
|
when?: string;
|
||||||
|
defaultImplicitVariables?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook';
|
||||||
|
|
||||||
|
export interface IRawChatParticipantContribution {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
isDefault?: boolean;
|
||||||
|
isSticky?: boolean;
|
||||||
|
commands?: IRawChatCommandContribution[];
|
||||||
|
defaultImplicitVariables?: string[];
|
||||||
|
locations?: RawChatParticipantLocation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardcoding the previous id of the Copilot Chat provider to avoid breaking view locations, persisted data, etc.
|
||||||
|
* DON'T use this for any new data, only for old persisted data.
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
export const CHAT_PROVIDER_ID = 'copilot';
|
|
@ -6,25 +6,18 @@
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||||
import { Command, Location, ProviderResult, TextEdit } from 'vs/editor/common/languages';
|
import { Command, Location, TextEdit } from 'vs/editor/common/languages';
|
||||||
import { FileType } from 'vs/platform/files/common/files';
|
import { FileType } from 'vs/platform/files/common/files';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatModel, IChatModel, IChatRequestVariableData, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatModel, IChatModel, IChatRequestVariableData, IExportableChatData, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatParserContext } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
import { IChatParserContext } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||||
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
|
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||||
|
|
||||||
export interface IChat {
|
|
||||||
id: number; // TODO Maybe remove this and move to a subclass that only the provider knows about
|
|
||||||
dispose?(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChatRequest {
|
export interface IChatRequest {
|
||||||
session: IChat;
|
|
||||||
message: string;
|
message: string;
|
||||||
variables: Record<string, IChatRequestVariableValue[]>;
|
variables: Record<string, IChatRequestVariableValue[]>;
|
||||||
}
|
}
|
||||||
|
@ -159,11 +152,6 @@ export type IChatProgress =
|
||||||
| IChatCommandButton
|
| IChatCommandButton
|
||||||
| IChatTextEdit;
|
| IChatTextEdit;
|
||||||
|
|
||||||
export interface IChatProvider {
|
|
||||||
readonly id: string;
|
|
||||||
prepareSession(token: CancellationToken): ProviderResult<IChat | undefined>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChatFollowup {
|
export interface IChatFollowup {
|
||||||
kind: 'reply';
|
kind: 'reply';
|
||||||
message: string;
|
message: string;
|
||||||
|
@ -231,7 +219,6 @@ export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertActi
|
||||||
|
|
||||||
export interface IChatUserActionEvent {
|
export interface IChatUserActionEvent {
|
||||||
action: ChatUserAction;
|
action: ChatUserAction;
|
||||||
providerId: string;
|
|
||||||
agentId: string | undefined;
|
agentId: string | undefined;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
requestId: string;
|
requestId: string;
|
||||||
|
@ -282,16 +269,12 @@ export interface IChatService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
transferredSessionData: IChatTransferredSessionData | undefined;
|
transferredSessionData: IChatTransferredSessionData | undefined;
|
||||||
|
|
||||||
onDidRegisterProvider: Event<{ providerId: string }>;
|
isEnabled(location: ChatAgentLocation): boolean;
|
||||||
onDidUnregisterProvider: Event<{ providerId: string }>;
|
hasSessions(): boolean;
|
||||||
registerProvider(provider: IChatProvider): IDisposable;
|
startSession(token: CancellationToken): ChatModel | undefined;
|
||||||
hasSessions(providerId: string): boolean;
|
|
||||||
getProviderInfos(): IChatProviderInfo[];
|
|
||||||
startSession(providerId: string, token: CancellationToken): ChatModel | undefined;
|
|
||||||
getSession(sessionId: string): IChatModel | undefined;
|
getSession(sessionId: string): IChatModel | undefined;
|
||||||
getSessionId(sessionProviderId: number): string | undefined;
|
|
||||||
getOrRestoreSession(sessionId: string): IChatModel | undefined;
|
getOrRestoreSession(sessionId: string): IChatModel | undefined;
|
||||||
loadSessionFromContent(data: ISerializableChatData): IChatModel | undefined;
|
loadSessionFromContent(data: IExportableChatData | ISerializableChatData): IChatModel | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the request was accepted.
|
* Returns whether the request was accepted.
|
||||||
|
@ -307,7 +290,7 @@ export interface IChatService {
|
||||||
|
|
||||||
onDidPerformUserAction: Event<IChatUserActionEvent>;
|
onDidPerformUserAction: Event<IChatUserActionEvent>;
|
||||||
notifyUserAction(event: IChatUserActionEvent): void;
|
notifyUserAction(event: IChatUserActionEvent): void;
|
||||||
onDidDisposeSession: Event<{ sessionId: string; providerId: string; reason: 'initializationFailed' | 'cleared' }>;
|
onDidDisposeSession: Event<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }>;
|
||||||
|
|
||||||
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void;
|
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,12 @@ import { ErrorNoTelemetry } from 'vs/base/common/errors';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { Disposable, DisposableMap, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableMap } 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';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { Progress } from 'vs/platform/progress/common/progress';
|
import { Progress } from 'vs/platform/progress/common/progress';
|
||||||
|
@ -22,11 +21,10 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ChatAgentLocation, IChatAgent, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgent, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
import { ChatModel, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, IChatRequestVariableData, IChatRequestVariableEntry, IExportableChatData, ISerializableChatData, ISerializableChatsData, getHistoryEntriesFromModel, updateRanges } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, IChatRequestVariableData, IChatRequestVariableEntry, ISerializableChatData, ISerializableChatsData, getHistoryEntriesFromModel, updateRanges } from 'vs/workbench/contrib/chat/common/chatModel';
|
|
||||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest, getPromptText } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest, getPromptText } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { ChatRequestParser, IChatParserContext } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
import { ChatRequestParser, IChatParserContext } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||||
import { ChatCopyKind, IChat, IChatCompleteResponse, IChatDetail, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatSendRequestData, IChatService, IChatTransferredSessionData, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
import { ChatCopyKind, IChatCompleteResponse, IChatDetail, IChatFollowup, IChatProgress, IChatSendRequestData, IChatService, IChatTransferredSessionData, IChatUserActionEvent, 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 { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/languageModels';
|
import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||||
|
@ -44,7 +42,6 @@ interface IChatTransfer {
|
||||||
const SESSION_TRANSFER_EXPIRATION_IN_MILLISECONDS = 1000 * 60;
|
const SESSION_TRANSFER_EXPIRATION_IN_MILLISECONDS = 1000 * 60;
|
||||||
|
|
||||||
type ChatProviderInvokedEvent = {
|
type ChatProviderInvokedEvent = {
|
||||||
providerId: string;
|
|
||||||
timeToFirstProgress: number | undefined;
|
timeToFirstProgress: number | undefined;
|
||||||
totalTime: number | undefined;
|
totalTime: number | undefined;
|
||||||
result: 'success' | 'error' | 'errorWithOutput' | 'cancelled' | 'filtered';
|
result: 'success' | 'error' | 'errorWithOutput' | 'cancelled' | 'filtered';
|
||||||
|
@ -55,7 +52,6 @@ type ChatProviderInvokedEvent = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatProviderInvokedClassification = {
|
type ChatProviderInvokedClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that was invoked.' };
|
|
||||||
timeToFirstProgress: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time in milliseconds from invoking the provider to getting the first data.' };
|
timeToFirstProgress: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time in milliseconds from invoking the provider to getting the first data.' };
|
||||||
totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The total time it took to run the provider\'s `provideResponseWithProgress`.' };
|
totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The total time it took to run the provider\'s `provideResponseWithProgress`.' };
|
||||||
result: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether invoking the ChatProvider resulted in an error.' };
|
result: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether invoking the ChatProvider resulted in an error.' };
|
||||||
|
@ -68,60 +64,50 @@ type ChatProviderInvokedClassification = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatVoteEvent = {
|
type ChatVoteEvent = {
|
||||||
providerId: string;
|
|
||||||
direction: 'up' | 'down';
|
direction: 'up' | 'down';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatVoteClassification = {
|
type ChatVoteClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that this response came from.' };
|
|
||||||
direction: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user voted up or down.' };
|
direction: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user voted up or down.' };
|
||||||
owner: 'roblourens';
|
owner: 'roblourens';
|
||||||
comment: 'Provides insight into the performance of Chat providers.';
|
comment: 'Provides insight into the performance of Chat providers.';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatCopyEvent = {
|
type ChatCopyEvent = {
|
||||||
providerId: string;
|
|
||||||
copyKind: 'action' | 'toolbar';
|
copyKind: 'action' | 'toolbar';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatCopyClassification = {
|
type ChatCopyClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that this codeblock response came from.' };
|
|
||||||
copyKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'How the copy was initiated.' };
|
copyKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'How the copy was initiated.' };
|
||||||
owner: 'roblourens';
|
owner: 'roblourens';
|
||||||
comment: 'Provides insight into the usage of Chat features.';
|
comment: 'Provides insight into the usage of Chat features.';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatInsertEvent = {
|
type ChatInsertEvent = {
|
||||||
providerId: string;
|
|
||||||
newFile: boolean;
|
newFile: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatInsertClassification = {
|
type ChatInsertClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that this codeblock response came from.' };
|
|
||||||
newFile: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the code was inserted into a new untitled file.' };
|
newFile: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the code was inserted into a new untitled file.' };
|
||||||
owner: 'roblourens';
|
owner: 'roblourens';
|
||||||
comment: 'Provides insight into the usage of Chat features.';
|
comment: 'Provides insight into the usage of Chat features.';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatCommandEvent = {
|
type ChatCommandEvent = {
|
||||||
providerId: string;
|
|
||||||
commandId: string;
|
commandId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatCommandClassification = {
|
type ChatCommandClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that this codeblock response came from.' };
|
|
||||||
commandId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The id of the command that was executed.' };
|
commandId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The id of the command that was executed.' };
|
||||||
owner: 'roblourens';
|
owner: 'roblourens';
|
||||||
comment: 'Provides insight into the usage of Chat features.';
|
comment: 'Provides insight into the usage of Chat features.';
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatTerminalEvent = {
|
type ChatTerminalEvent = {
|
||||||
providerId: string;
|
|
||||||
languageId: string;
|
languageId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChatTerminalClassification = {
|
type ChatTerminalClassification = {
|
||||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the provider that this codeblock response came from.' };
|
|
||||||
languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The language of the code that was run in the terminal.' };
|
languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The language of the code that was run in the terminal.' };
|
||||||
owner: 'roblourens';
|
owner: 'roblourens';
|
||||||
comment: 'Provides insight into the usage of Chat features.';
|
comment: 'Provides insight into the usage of Chat features.';
|
||||||
|
@ -132,12 +118,10 @@ const maxPersistedSessions = 25;
|
||||||
export class ChatService extends Disposable implements IChatService {
|
export class ChatService extends Disposable implements IChatService {
|
||||||
declare _serviceBrand: undefined;
|
declare _serviceBrand: undefined;
|
||||||
|
|
||||||
private readonly _providers = new Map<string, IChatProvider>();
|
|
||||||
|
|
||||||
private readonly _sessionModels = this._register(new DisposableMap<string, ChatModel>());
|
private readonly _sessionModels = this._register(new DisposableMap<string, ChatModel>());
|
||||||
private readonly _pendingRequests = this._register(new DisposableMap<string, CancellationTokenSource>());
|
private readonly _pendingRequests = this._register(new DisposableMap<string, CancellationTokenSource>());
|
||||||
private _persistedSessions: ISerializableChatsData;
|
private _persistedSessions: ISerializableChatsData;
|
||||||
private readonly _hasProvider: IContextKey<boolean>;
|
|
||||||
|
|
||||||
private _transferredSessionData: IChatTransferredSessionData | undefined;
|
private _transferredSessionData: IChatTransferredSessionData | undefined;
|
||||||
public get transferredSessionData(): IChatTransferredSessionData | undefined {
|
public get transferredSessionData(): IChatTransferredSessionData | undefined {
|
||||||
|
@ -147,15 +131,9 @@ 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 _onDidDisposeSession = this._register(new Emitter<{ sessionId: string; providerId: string; reason: 'initializationFailed' | 'cleared' }>());
|
private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }>());
|
||||||
public readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
public readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
||||||
|
|
||||||
private readonly _onDidRegisterProvider = this._register(new Emitter<{ providerId: string }>());
|
|
||||||
public readonly onDidRegisterProvider = this._onDidRegisterProvider.event;
|
|
||||||
|
|
||||||
private readonly _onDidUnregisterProvider = this._register(new Emitter<{ providerId: string }>());
|
|
||||||
public readonly onDidUnregisterProvider = this._onDidUnregisterProvider.event;
|
|
||||||
|
|
||||||
private readonly _sessionFollowupCancelTokens = this._register(new DisposableMap<string, CancellationTokenSource>());
|
private readonly _sessionFollowupCancelTokens = this._register(new DisposableMap<string, CancellationTokenSource>());
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -164,7 +142,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
|
||||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||||
@IChatSlashCommandService private readonly chatSlashCommandService: IChatSlashCommandService,
|
@IChatSlashCommandService private readonly chatSlashCommandService: IChatSlashCommandService,
|
||||||
@IChatVariablesService private readonly chatVariablesService: IChatVariablesService,
|
@IChatVariablesService private readonly chatVariablesService: IChatVariablesService,
|
||||||
|
@ -172,8 +149,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._hasProvider = CONTEXT_PROVIDER_EXISTS.bindTo(this.contextKeyService);
|
|
||||||
|
|
||||||
const sessionData = storageService.get(serializedChatKey, StorageScope.WORKSPACE, '');
|
const sessionData = storageService.get(serializedChatKey, StorageScope.WORKSPACE, '');
|
||||||
if (sessionData) {
|
if (sessionData) {
|
||||||
this._persistedSessions = this.deserializeChats(sessionData);
|
this._persistedSessions = this.deserializeChats(sessionData);
|
||||||
|
@ -196,6 +171,10 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
this._register(storageService.onWillSaveState(() => this.saveState()));
|
this._register(storageService.onWillSaveState(() => this.saveState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isEnabled(location: ChatAgentLocation): boolean {
|
||||||
|
return this.chatAgentService.getContributedDefaultAgent(location) !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private saveState(): void {
|
private saveState(): void {
|
||||||
let allSessions: (ChatModel | ISerializableChatData)[] = Array.from(this._sessionModels.values())
|
let allSessions: (ChatModel | ISerializableChatData)[] = Array.from(this._sessionModels.values())
|
||||||
.filter(session => session.getRequests().length > 0);
|
.filter(session => session.getRequests().length > 0);
|
||||||
|
@ -221,29 +200,24 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
notifyUserAction(action: IChatUserActionEvent): void {
|
notifyUserAction(action: IChatUserActionEvent): void {
|
||||||
if (action.action.kind === 'vote') {
|
if (action.action.kind === 'vote') {
|
||||||
this.telemetryService.publicLog2<ChatVoteEvent, ChatVoteClassification>('interactiveSessionVote', {
|
this.telemetryService.publicLog2<ChatVoteEvent, ChatVoteClassification>('interactiveSessionVote', {
|
||||||
providerId: action.providerId,
|
|
||||||
direction: action.action.direction === InteractiveSessionVoteDirection.Up ? 'up' : 'down'
|
direction: action.action.direction === InteractiveSessionVoteDirection.Up ? 'up' : 'down'
|
||||||
});
|
});
|
||||||
} else if (action.action.kind === 'copy') {
|
} else if (action.action.kind === 'copy') {
|
||||||
this.telemetryService.publicLog2<ChatCopyEvent, ChatCopyClassification>('interactiveSessionCopy', {
|
this.telemetryService.publicLog2<ChatCopyEvent, ChatCopyClassification>('interactiveSessionCopy', {
|
||||||
providerId: action.providerId,
|
|
||||||
copyKind: action.action.copyKind === ChatCopyKind.Action ? 'action' : 'toolbar'
|
copyKind: action.action.copyKind === ChatCopyKind.Action ? 'action' : 'toolbar'
|
||||||
});
|
});
|
||||||
} else if (action.action.kind === 'insert') {
|
} else if (action.action.kind === 'insert') {
|
||||||
this.telemetryService.publicLog2<ChatInsertEvent, ChatInsertClassification>('interactiveSessionInsert', {
|
this.telemetryService.publicLog2<ChatInsertEvent, ChatInsertClassification>('interactiveSessionInsert', {
|
||||||
providerId: action.providerId,
|
|
||||||
newFile: !!action.action.newFile
|
newFile: !!action.action.newFile
|
||||||
});
|
});
|
||||||
} else if (action.action.kind === 'command') {
|
} else if (action.action.kind === 'command') {
|
||||||
const command = CommandsRegistry.getCommand(action.action.commandButton.command.id);
|
const command = CommandsRegistry.getCommand(action.action.commandButton.command.id);
|
||||||
const commandId = command ? action.action.commandButton.command.id : 'INVALID';
|
const commandId = command ? action.action.commandButton.command.id : 'INVALID';
|
||||||
this.telemetryService.publicLog2<ChatCommandEvent, ChatCommandClassification>('interactiveSessionCommand', {
|
this.telemetryService.publicLog2<ChatCommandEvent, ChatCommandClassification>('interactiveSessionCommand', {
|
||||||
providerId: action.providerId,
|
|
||||||
commandId
|
commandId
|
||||||
});
|
});
|
||||||
} else if (action.action.kind === 'runInTerminal') {
|
} else if (action.action.kind === 'runInTerminal') {
|
||||||
this.telemetryService.publicLog2<ChatTerminalEvent, ChatTerminalClassification>('interactiveSessionRunInTerminal', {
|
this.telemetryService.publicLog2<ChatTerminalEvent, ChatTerminalClassification>('interactiveSessionRunInTerminal', {
|
||||||
providerId: action.providerId,
|
|
||||||
languageId: action.action.languageId ?? ''
|
languageId: action.action.languageId ?? ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -251,8 +225,12 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
this._onDidPerformUserAction.fire(action);
|
this._onDidPerformUserAction.fire(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private trace(method: string, message: string): void {
|
private trace(method: string, message?: string): void {
|
||||||
|
if (message) {
|
||||||
this.logService.trace(`ChatService#${method}: ${message}`);
|
this.logService.trace(`ChatService#${method}: ${message}`);
|
||||||
|
} else {
|
||||||
|
this.logService.trace(`ChatService#${method}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private error(method: string, message: string): void {
|
private error(method: string, message: string): void {
|
||||||
|
@ -341,53 +319,42 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
this.saveState();
|
this.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
startSession(providerId: string, token: CancellationToken): ChatModel {
|
startSession(token: CancellationToken): ChatModel {
|
||||||
this.trace('startSession', `providerId=${providerId}`);
|
this.trace('startSession');
|
||||||
return this._startSession(providerId, undefined, token);
|
return this._startSession(undefined, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _startSession(providerId: string, someSessionHistory: ISerializableChatData | undefined, token: CancellationToken): ChatModel {
|
private _startSession(someSessionHistory: IExportableChatData | ISerializableChatData | undefined, token: CancellationToken): ChatModel {
|
||||||
this.trace('_startSession', `providerId=${providerId}`);
|
const model = this.instantiationService.createInstance(ChatModel, someSessionHistory);
|
||||||
const model = this.instantiationService.createInstance(ChatModel, providerId, someSessionHistory);
|
|
||||||
this._sessionModels.set(model.sessionId, model);
|
this._sessionModels.set(model.sessionId, model);
|
||||||
this.initializeSession(model, token);
|
this.initializeSession(model, token);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private reinitializeModel(model: ChatModel): void {
|
// TODO, when default agent shows up?
|
||||||
this.trace('reinitializeModel', `Start reinit`);
|
// private reinitializeModel(model: ChatModel): void {
|
||||||
this.initializeSession(model, CancellationToken.None);
|
// this.trace('reinitializeModel', `Start reinit`);
|
||||||
}
|
// this.initializeSession(model, CancellationToken.None);
|
||||||
|
// }
|
||||||
|
|
||||||
private async initializeSession(model: ChatModel, token: CancellationToken): Promise<void> {
|
private async initializeSession(model: ChatModel, token: CancellationToken): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.trace('initializeSession', `Initialize session ${model.sessionId}`);
|
this.trace('initializeSession', `Initialize session ${model.sessionId}`);
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
await this.extensionService.activateByEvent(`onInteractiveSession:${model.providerId}`);
|
|
||||||
|
|
||||||
const provider = this._providers.get(model.providerId);
|
await this.extensionService.whenInstalledExtensionsRegistered();
|
||||||
if (!provider) {
|
const defaultAgentData = this.chatAgentService.getContributedDefaultAgent(ChatAgentLocation.Panel);
|
||||||
throw new ErrorNoTelemetry(`Unknown provider: ${model.providerId}`);
|
if (!defaultAgentData) {
|
||||||
|
throw new ErrorNoTelemetry('No default agent contributed');
|
||||||
}
|
}
|
||||||
|
|
||||||
let session: IChat | undefined;
|
await this.extensionService.activateByEvent(`onChatParticipant:${defaultAgentData.id}`);
|
||||||
try {
|
|
||||||
session = await provider.prepareSession(token) ?? undefined;
|
|
||||||
} catch (err) {
|
|
||||||
this.trace('initializeSession', `Provider initializeSession threw: ${err}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
throw new Error('Provider returned no session');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.trace('startSession', `Provider returned session`);
|
|
||||||
|
|
||||||
const defaultAgent = this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel);
|
const defaultAgent = this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel);
|
||||||
if (!defaultAgent) {
|
if (!defaultAgent) {
|
||||||
throw new ErrorNoTelemetry('No default agent');
|
// Should have been registered during activation above!
|
||||||
|
throw new ErrorNoTelemetry('No default agent registered');
|
||||||
}
|
}
|
||||||
|
|
||||||
const welcomeMessage = model.welcomeMessage ? undefined : await defaultAgent.provideWelcomeMessage?.(token) ?? undefined;
|
const welcomeMessage = model.welcomeMessage ? undefined : await defaultAgent.provideWelcomeMessage?.(token) ?? undefined;
|
||||||
const welcomeModel = welcomeMessage && this.instantiationService.createInstance(
|
const welcomeModel = welcomeMessage && this.instantiationService.createInstance(
|
||||||
ChatWelcomeMessageModel,
|
ChatWelcomeMessageModel,
|
||||||
|
@ -395,12 +362,12 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
await defaultAgent.provideSampleQuestions?.(token) ?? []
|
await defaultAgent.provideSampleQuestions?.(token) ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
model.initialize(session, welcomeModel);
|
model.initialize(welcomeModel);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.trace('startSession', `initializeSession failed: ${err}`);
|
this.trace('startSession', `initializeSession failed: ${err}`);
|
||||||
model.setInitializationError(err);
|
model.setInitializationError(err);
|
||||||
this._sessionModels.deleteAndDispose(model.sessionId);
|
this._sessionModels.deleteAndDispose(model.sessionId);
|
||||||
this._onDidDisposeSession.fire({ sessionId: model.sessionId, providerId: model.providerId, reason: 'initializationFailed' });
|
this._onDidDisposeSession.fire({ sessionId: model.sessionId, reason: 'initializationFailed' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,10 +375,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
return this._sessionModels.get(sessionId);
|
return this._sessionModels.get(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSessionId(sessionProviderId: number): string | undefined {
|
|
||||||
return Iterable.find(this._sessionModels.values(), model => model.session?.id === sessionProviderId)?.sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOrRestoreSession(sessionId: string): ChatModel | undefined {
|
getOrRestoreSession(sessionId: string): ChatModel | undefined {
|
||||||
this.trace('getOrRestoreSession', `sessionId: ${sessionId}`);
|
this.trace('getOrRestoreSession', `sessionId: ${sessionId}`);
|
||||||
const model = this._sessionModels.get(sessionId);
|
const model = this._sessionModels.get(sessionId);
|
||||||
|
@ -428,11 +391,11 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
this._transferredSessionData = undefined;
|
this._transferredSessionData = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._startSession(sessionData.providerId, sessionData, CancellationToken.None);
|
return this._startSession(sessionData, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSessionFromContent(data: ISerializableChatData): IChatModel | undefined {
|
loadSessionFromContent(data: IExportableChatData | ISerializableChatData): IChatModel | undefined {
|
||||||
return this._startSession(data.providerId, data, CancellationToken.None);
|
return this._startSession(data, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendRequest(sessionId: string, request: string, implicitVariablesEnabled?: boolean, location: ChatAgentLocation = ChatAgentLocation.Panel, parserContext?: IChatParserContext): Promise<IChatSendRequestData | undefined> {
|
async sendRequest(sessionId: string, request: string, implicitVariablesEnabled?: boolean, location: ChatAgentLocation = ChatAgentLocation.Panel, parserContext?: IChatParserContext): Promise<IChatSendRequestData | undefined> {
|
||||||
|
@ -448,10 +411,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
await model.waitForInitialization();
|
await model.waitForInitialization();
|
||||||
const provider = this._providers.get(model.providerId);
|
|
||||||
if (!provider) {
|
|
||||||
throw new Error(`Unknown provider: ${model.providerId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._pendingRequests.has(sessionId)) {
|
if (this._pendingRequests.has(sessionId)) {
|
||||||
this.trace('sendRequest', `Session ${sessionId} already has a pending request`);
|
this.trace('sendRequest', `Session ${sessionId} already has a pending request`);
|
||||||
|
@ -466,7 +425,7 @@ 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 {
|
return {
|
||||||
responseCompletePromise: this._sendRequestAsync(model, sessionId, provider, parsedRequest, implicitVariablesEnabled ?? false, defaultAgent, location),
|
responseCompletePromise: this._sendRequestAsync(model, sessionId, parsedRequest, implicitVariablesEnabled ?? false, defaultAgent, location),
|
||||||
agent,
|
agent,
|
||||||
slashCommand: agentSlashCommandPart?.command,
|
slashCommand: agentSlashCommandPart?.command,
|
||||||
};
|
};
|
||||||
|
@ -480,7 +439,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
return newTokenSource.token;
|
return newTokenSource.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _sendRequestAsync(model: ChatModel, sessionId: string, provider: IChatProvider, parsedRequest: IParsedChatRequest, implicitVariablesEnabled: boolean, defaultAgent: IChatAgent, location: ChatAgentLocation): Promise<void> {
|
private async _sendRequestAsync(model: ChatModel, sessionId: string, parsedRequest: IParsedChatRequest, implicitVariablesEnabled: boolean, defaultAgent: IChatAgent, location: ChatAgentLocation): Promise<void> {
|
||||||
const followupsCancelToken = this.refreshFollowupsCancellationToken(sessionId);
|
const followupsCancelToken = this.refreshFollowupsCancellationToken(sessionId);
|
||||||
let request: ChatRequestModel;
|
let request: ChatRequestModel;
|
||||||
const agentPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart);
|
const agentPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart);
|
||||||
|
@ -513,7 +472,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
const listener = token.onCancellationRequested(() => {
|
const listener = token.onCancellationRequested(() => {
|
||||||
this.trace('sendRequest', `Request for session ${model.sessionId} was cancelled`);
|
this.trace('sendRequest', `Request for session ${model.sessionId} was cancelled`);
|
||||||
this.telemetryService.publicLog2<ChatProviderInvokedEvent, ChatProviderInvokedClassification>('interactiveSessionProviderInvoked', {
|
this.telemetryService.publicLog2<ChatProviderInvokedEvent, ChatProviderInvokedClassification>('interactiveSessionProviderInvoked', {
|
||||||
providerId: provider.id,
|
|
||||||
timeToFirstProgress: undefined,
|
timeToFirstProgress: undefined,
|
||||||
// Normally timings happen inside the EH around the actual provider. For cancellation we can measure how long the user waited before cancelling
|
// Normally timings happen inside the EH around the actual provider. For cancellation we can measure how long the user waited before cancelling
|
||||||
totalTime: stopWatch.elapsed(),
|
totalTime: stopWatch.elapsed(),
|
||||||
|
@ -600,7 +558,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
rawResult.errorDetails ? 'error' :
|
rawResult.errorDetails ? 'error' :
|
||||||
'success';
|
'success';
|
||||||
this.telemetryService.publicLog2<ChatProviderInvokedEvent, ChatProviderInvokedClassification>('interactiveSessionProviderInvoked', {
|
this.telemetryService.publicLog2<ChatProviderInvokedEvent, ChatProviderInvokedClassification>('interactiveSessionProviderInvoked', {
|
||||||
providerId: provider.id,
|
|
||||||
timeToFirstProgress: rawResult.timings?.firstProgress,
|
timeToFirstProgress: rawResult.timings?.firstProgress,
|
||||||
totalTime: rawResult.timings?.totalElapsed,
|
totalTime: rawResult.timings?.totalElapsed,
|
||||||
result,
|
result,
|
||||||
|
@ -638,18 +595,10 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
await model.waitForInitialization();
|
await model.waitForInitialization();
|
||||||
const provider = this._providers.get(model.providerId);
|
|
||||||
if (!provider) {
|
|
||||||
throw new Error(`Unknown provider: ${model.providerId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
model.removeRequest(requestId);
|
model.removeRequest(requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProviders(): string[] {
|
|
||||||
return Array.from(this._providers.keys());
|
|
||||||
}
|
|
||||||
|
|
||||||
async addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, response: IChatCompleteResponse): Promise<void> {
|
async addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, response: IChatCompleteResponse): Promise<void> {
|
||||||
this.trace('addCompleteRequest', `message: ${message}`);
|
this.trace('addCompleteRequest', `message: ${message}`);
|
||||||
|
|
||||||
|
@ -695,47 +644,11 @@ export class ChatService extends Disposable implements IChatService {
|
||||||
this._sessionModels.deleteAndDispose(sessionId);
|
this._sessionModels.deleteAndDispose(sessionId);
|
||||||
this._pendingRequests.get(sessionId)?.cancel();
|
this._pendingRequests.get(sessionId)?.cancel();
|
||||||
this._pendingRequests.deleteAndDispose(sessionId);
|
this._pendingRequests.deleteAndDispose(sessionId);
|
||||||
this._onDidDisposeSession.fire({ sessionId, providerId: model.providerId, reason: 'cleared' });
|
this._onDidDisposeSession.fire({ sessionId, reason: 'cleared' });
|
||||||
}
|
}
|
||||||
|
|
||||||
registerProvider(provider: IChatProvider): IDisposable {
|
public hasSessions(): boolean {
|
||||||
this.trace('registerProvider', `Adding new chat provider`);
|
return !!Object.values(this._persistedSessions);
|
||||||
|
|
||||||
if (this._providers.has(provider.id)) {
|
|
||||||
throw new Error(`Provider ${provider.id} already registered`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._providers.set(provider.id, provider);
|
|
||||||
this._hasProvider.set(true);
|
|
||||||
this._onDidRegisterProvider.fire({ providerId: provider.id });
|
|
||||||
|
|
||||||
Array.from(this._sessionModels.values())
|
|
||||||
.filter(model => model.providerId === provider.id)
|
|
||||||
// The provider may have been registered in the process of initializing this model. Only grab models that were deinitialized when the provider was unregistered
|
|
||||||
.filter(model => model.initState === ChatModelInitState.Created)
|
|
||||||
.forEach(model => this.reinitializeModel(model));
|
|
||||||
|
|
||||||
return toDisposable(() => {
|
|
||||||
this.trace('registerProvider', `Disposing chat provider`);
|
|
||||||
this._providers.delete(provider.id);
|
|
||||||
this._hasProvider.set(this._providers.size > 0);
|
|
||||||
Array.from(this._sessionModels.values())
|
|
||||||
.filter(model => model.providerId === provider.id)
|
|
||||||
.forEach(model => model.deinitialize());
|
|
||||||
this._onDidUnregisterProvider.fire({ providerId: provider.id });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasSessions(providerId: string): boolean {
|
|
||||||
return !!Object.values(this._persistedSessions).find((session) => session.providerId === providerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getProviderInfos(): IChatProviderInfo[] {
|
|
||||||
return Array.from(this._providers.values()).map(provider => {
|
|
||||||
return {
|
|
||||||
id: provider.id,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void {
|
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void {
|
||||||
|
|
|
@ -47,7 +47,6 @@ export interface IChatSessionInitEvent {
|
||||||
export interface IChatViewModel {
|
export interface IChatViewModel {
|
||||||
readonly model: IChatModel;
|
readonly model: IChatModel;
|
||||||
readonly initState: ChatModelInitState;
|
readonly initState: ChatModelInitState;
|
||||||
readonly providerId: string;
|
|
||||||
readonly sessionId: string;
|
readonly sessionId: string;
|
||||||
readonly onDidDisposeModel: Event<void>;
|
readonly onDidDisposeModel: Event<void>;
|
||||||
readonly onDidChange: Event<IChatViewModelChangeEvent>;
|
readonly onDidChange: Event<IChatViewModelChangeEvent>;
|
||||||
|
@ -110,7 +109,6 @@ export interface IChatResponseViewModel {
|
||||||
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;
|
||||||
readonly providerId: string;
|
|
||||||
/** The ID of the associated IChatRequestViewModel */
|
/** The ID of the associated IChatRequestViewModel */
|
||||||
readonly requestId: string;
|
readonly requestId: string;
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
|
@ -175,10 +173,6 @@ export class ChatViewModel extends Disposable implements IChatViewModel {
|
||||||
return this._model.requestInProgress;
|
return this._model.requestInProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
get providerId() {
|
|
||||||
return this._model.providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
get initState() {
|
get initState() {
|
||||||
return this._model.initState;
|
return this._model.initState;
|
||||||
}
|
}
|
||||||
|
@ -363,10 +357,6 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi
|
||||||
return this._model.id + `_${this._modelChangeCount}` + `_${ChatModelInitState[this._model.session.initState]}`;
|
return this._model.id + `_${this._modelChangeCount}` + `_${ChatModelInitState[this._model.session.initState]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get providerId() {
|
|
||||||
return this._model.providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
get sessionId() {
|
get sessionId() {
|
||||||
return this._model.session.sessionId;
|
return this._model.session.sessionId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
import { Memento } from 'vs/workbench/common/memento';
|
import { Memento } from 'vs/workbench/common/memento';
|
||||||
|
import { CHAT_PROVIDER_ID } from 'vs/workbench/contrib/chat/common/chatParticipantContribTypes';
|
||||||
|
|
||||||
export interface IChatHistoryEntry {
|
export interface IChatHistoryEntry {
|
||||||
text: string;
|
text: string;
|
||||||
|
@ -20,8 +21,8 @@ export interface IChatWidgetHistoryService {
|
||||||
readonly onDidClearHistory: Event<void>;
|
readonly onDidClearHistory: Event<void>;
|
||||||
|
|
||||||
clearHistory(): void;
|
clearHistory(): void;
|
||||||
getHistory(providerId: string): IChatHistoryEntry[];
|
getHistory(): IChatHistoryEntry[];
|
||||||
saveHistory(providerId: string, history: IChatHistoryEntry[]): void;
|
saveHistory(history: IChatHistoryEntry[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IChatHistory {
|
interface IChatHistory {
|
||||||
|
@ -50,15 +51,15 @@ export class ChatWidgetHistoryService implements IChatWidgetHistoryService {
|
||||||
this.viewState = loadedState;
|
this.viewState = loadedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHistory(providerId: string): IChatHistoryEntry[] {
|
getHistory(): IChatHistoryEntry[] {
|
||||||
return this.viewState.history?.[providerId] ?? [];
|
return this.viewState.history?.[CHAT_PROVIDER_ID] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
saveHistory(providerId: string, history: IChatHistoryEntry[]): void {
|
saveHistory(history: IChatHistoryEntry[]): void {
|
||||||
if (!this.viewState.history) {
|
if (!this.viewState.history) {
|
||||||
this.viewState.history = {};
|
this.viewState.history = {};
|
||||||
}
|
}
|
||||||
this.viewState.history[providerId] = history;
|
this.viewState.history[CHAT_PROVIDER_ID] = history;
|
||||||
this.memento.saveMemento();
|
this.memento.saveMemento();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,57 +3,56 @@
|
||||||
* 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 'vs/css!./media/voiceChatActions';
|
import { RunOnceScheduler, disposableTimeout } from 'vs/base/common/async';
|
||||||
import { Event } from 'vs/base/common/event';
|
|
||||||
import { firstOrDefault } from 'vs/base/common/arrays';
|
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import { Codicon } from 'vs/base/common/codicons';
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
|
import { Color } from 'vs/base/common/color';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { ThemeIcon } from 'vs/base/common/themables';
|
||||||
|
import { assertIsDefined, isNumber } from 'vs/base/common/types';
|
||||||
|
import 'vs/css!./media/voiceChatActions';
|
||||||
|
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
|
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||||
import { localize, localize2 } from 'vs/nls';
|
import { localize, localize2 } from 'vs/nls';
|
||||||
import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions';
|
import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions';
|
||||||
|
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { spinningLoading } from 'vs/platform/theme/common/iconRegistry';
|
|
||||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
|
||||||
import { IChatWidget, IChatWidgetService, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat';
|
|
||||||
import { IChatService, KEYWORD_ACTIVIATION_SETTING_ID } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
|
||||||
import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_INPUT, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
|
||||||
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
|
||||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
|
||||||
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
|
||||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
|
||||||
import { HasSpeechProvider, ISpeechService, KeywordRecognitionStatus, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService';
|
|
||||||
import { RunOnceScheduler, disposableTimeout } from 'vs/base/common/async';
|
|
||||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
|
||||||
import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme';
|
|
||||||
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
|
||||||
import { Color } from 'vs/base/common/color';
|
|
||||||
import { contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
import { assertIsDefined, isNumber } from 'vs/base/common/types';
|
|
||||||
import { AccessibilityVoiceSettingId, SpeechTimeoutDefault, accessibilityConfigurationNodeBase } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
|
||||||
import { IChatExecuteActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatExecuteActions';
|
|
||||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
|
||||||
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
|
||||||
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
|
|
||||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
|
||||||
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
||||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
|
||||||
import { IVoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { ThemeIcon } from 'vs/base/common/themables';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
|
||||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
|
||||||
import { ProgressLocation } from 'vs/platform/progress/common/progress';
|
import { ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||||
import { TerminalChatController, TerminalChatContextKeys } from 'vs/workbench/contrib/terminal/browser/terminalContribExports';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
import { spinningLoading } from 'vs/platform/theme/common/iconRegistry';
|
||||||
|
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
||||||
|
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
|
||||||
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
|
import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
|
import { AccessibilityVoiceSettingId, SpeechTimeoutDefault, accessibilityConfigurationNodeBase } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||||
|
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||||
|
import { IChatExecuteActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatExecuteActions';
|
||||||
|
import { CHAT_VIEW_ID, IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
|
import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
|
import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_INPUT, CONTEXT_HAS_DEFAULT_AGENT } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||||
|
import { IChatService, KEYWORD_ACTIVIATION_SETTING_ID } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
import { IVoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
||||||
|
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
|
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
||||||
|
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||||
import { NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
|
import { NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
|
||||||
|
import { HasSpeechProvider, ISpeechService, KeywordRecognitionStatus, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService';
|
||||||
|
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||||
|
import { TerminalChatContextKeys, TerminalChatController } from 'vs/workbench/contrib/terminal/browser/terminalContribExports';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||||
|
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||||
|
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey<boolean>('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") });
|
const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey<boolean>('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") });
|
||||||
const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") });
|
const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") });
|
||||||
|
@ -64,7 +63,7 @@ const CONTEXT_TERMINAL_VOICE_CHAT_IN_PROGRESS = new RawContextKey<boolean>('term
|
||||||
const CONTEXT_VOICE_CHAT_IN_VIEW_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInViewInProgress', false, { type: 'boolean', description: localize('voiceChatInViewInProgress', "True when voice recording from microphone is in progress in the chat view.") });
|
const CONTEXT_VOICE_CHAT_IN_VIEW_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInViewInProgress', false, { type: 'boolean', description: localize('voiceChatInViewInProgress', "True when voice recording from microphone is in progress in the chat view.") });
|
||||||
const CONTEXT_VOICE_CHAT_IN_EDITOR_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInEditorInProgress', false, { type: 'boolean', description: localize('voiceChatInEditorInProgress', "True when voice recording from microphone is in progress in the chat editor.") });
|
const CONTEXT_VOICE_CHAT_IN_EDITOR_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInEditorInProgress', false, { type: 'boolean', description: localize('voiceChatInEditorInProgress', "True when voice recording from microphone is in progress in the chat editor.") });
|
||||||
|
|
||||||
const CanVoiceChat = ContextKeyExpr.and(CONTEXT_PROVIDER_EXISTS, HasSpeechProvider);
|
const CanVoiceChat = ContextKeyExpr.and(CONTEXT_HAS_DEFAULT_AGENT, HasSpeechProvider);
|
||||||
const FocusInChatInput = assertIsDefined(ContextKeyExpr.or(CTX_INLINE_CHAT_FOCUSED, CONTEXT_IN_CHAT_INPUT));
|
const FocusInChatInput = assertIsDefined(ContextKeyExpr.or(CTX_INLINE_CHAT_FOCUSED, CONTEXT_IN_CHAT_INPUT));
|
||||||
|
|
||||||
type VoiceChatSessionContext = 'inline' | 'terminal' | 'quick' | 'view' | 'editor';
|
type VoiceChatSessionContext = 'inline' | 'terminal' | 'quick' | 'view' | 'editor';
|
||||||
|
@ -96,7 +95,6 @@ class VoiceChatSessionControllerFactory {
|
||||||
static async create(accessor: ServicesAccessor, context: 'inline' | 'terminal' | 'quick' | 'view' | 'focused'): Promise<IVoiceChatSessionController | undefined> {
|
static async create(accessor: ServicesAccessor, context: 'inline' | 'terminal' | 'quick' | 'view' | 'focused'): Promise<IVoiceChatSessionController | undefined> {
|
||||||
const chatWidgetService = accessor.get(IChatWidgetService);
|
const chatWidgetService = accessor.get(IChatWidgetService);
|
||||||
const viewsService = accessor.get(IViewsService);
|
const viewsService = accessor.get(IViewsService);
|
||||||
const chatContributionService = accessor.get(IChatContributionService);
|
|
||||||
const quickChatService = accessor.get(IQuickChatService);
|
const quickChatService = accessor.get(IQuickChatService);
|
||||||
const layoutService = accessor.get(IWorkbenchLayoutService);
|
const layoutService = accessor.get(IWorkbenchLayoutService);
|
||||||
const editorService = accessor.get(IEditorService);
|
const editorService = accessor.get(IEditorService);
|
||||||
|
@ -126,11 +124,11 @@ class VoiceChatSessionControllerFactory {
|
||||||
layoutService.hasFocus(Parts.PANEL_PART) ||
|
layoutService.hasFocus(Parts.PANEL_PART) ||
|
||||||
layoutService.hasFocus(Parts.AUXILIARYBAR_PART)
|
layoutService.hasFocus(Parts.AUXILIARYBAR_PART)
|
||||||
) {
|
) {
|
||||||
return VoiceChatSessionControllerFactory.doCreateForChatView(chatInput, viewsService, chatContributionService);
|
return VoiceChatSessionControllerFactory.doCreateForChatView(chatInput, viewsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutService.hasFocus(Parts.EDITOR_PART)) {
|
if (layoutService.hasFocus(Parts.EDITOR_PART)) {
|
||||||
return VoiceChatSessionControllerFactory.doCreateForChatEditor(chatInput, viewsService, chatContributionService);
|
return VoiceChatSessionControllerFactory.doCreateForChatEditor(chatInput, viewsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
return VoiceChatSessionControllerFactory.doCreateForQuickChat(chatInput, quickChatService);
|
return VoiceChatSessionControllerFactory.doCreateForQuickChat(chatInput, quickChatService);
|
||||||
|
@ -150,7 +148,7 @@ class VoiceChatSessionControllerFactory {
|
||||||
if (context === 'view' || context === 'focused' /* fallback in case 'focused' was not successful */) {
|
if (context === 'view' || context === 'focused' /* fallback in case 'focused' was not successful */) {
|
||||||
const chatView = await VoiceChatSessionControllerFactory.revealChatView(accessor);
|
const chatView = await VoiceChatSessionControllerFactory.revealChatView(accessor);
|
||||||
if (chatView) {
|
if (chatView) {
|
||||||
return VoiceChatSessionControllerFactory.doCreateForChatView(chatView, viewsService, chatContributionService);
|
return VoiceChatSessionControllerFactory.doCreateForChatView(chatView, viewsService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,31 +188,29 @@ class VoiceChatSessionControllerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async revealChatView(accessor: ServicesAccessor): Promise<IChatWidget | undefined> {
|
static async revealChatView(accessor: ServicesAccessor): Promise<IChatWidget | undefined> {
|
||||||
const chatWidgetService = accessor.get(IChatWidgetService);
|
|
||||||
const chatService = accessor.get(IChatService);
|
const chatService = accessor.get(IChatService);
|
||||||
|
const viewsService = accessor.get(IViewsService);
|
||||||
const provider = firstOrDefault(chatService.getProviderInfos());
|
if (chatService.isEnabled(ChatAgentLocation.Panel)) {
|
||||||
if (provider) {
|
return showChatView(viewsService);
|
||||||
return chatWidgetService.revealViewForProvider(provider.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static doCreateForChatView(chatView: IChatWidget, viewsService: IViewsService, chatContributionService: IChatContributionService): IVoiceChatSessionController {
|
private static doCreateForChatView(chatView: IChatWidget, viewsService: IViewsService): IVoiceChatSessionController {
|
||||||
return VoiceChatSessionControllerFactory.doCreateForChatViewOrEditor('view', chatView, viewsService, chatContributionService);
|
return VoiceChatSessionControllerFactory.doCreateForChatViewOrEditor('view', chatView, viewsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static doCreateForChatEditor(chatView: IChatWidget, viewsService: IViewsService, chatContributionService: IChatContributionService): IVoiceChatSessionController {
|
private static doCreateForChatEditor(chatView: IChatWidget, viewsService: IViewsService): IVoiceChatSessionController {
|
||||||
return VoiceChatSessionControllerFactory.doCreateForChatViewOrEditor('editor', chatView, viewsService, chatContributionService);
|
return VoiceChatSessionControllerFactory.doCreateForChatViewOrEditor('editor', chatView, viewsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static doCreateForChatViewOrEditor(context: 'view' | 'editor', chatView: IChatWidget, viewsService: IViewsService, chatContributionService: IChatContributionService): IVoiceChatSessionController {
|
private static doCreateForChatViewOrEditor(context: 'view' | 'editor', chatView: IChatWidget, viewsService: IViewsService): IVoiceChatSessionController {
|
||||||
return {
|
return {
|
||||||
context,
|
context,
|
||||||
onDidAcceptInput: chatView.onDidAcceptInput,
|
onDidAcceptInput: chatView.onDidAcceptInput,
|
||||||
// TODO@bpasero cancellation needs to work better for chat editors that are not view bound
|
// TODO@bpasero cancellation needs to work better for chat editors that are not view bound
|
||||||
onDidCancelInput: Event.filter(viewsService.onDidChangeViewVisibility, e => e.id === chatContributionService.getViewIdForProvider(chatView.providerId)),
|
onDidCancelInput: Event.filter(viewsService.onDidChangeViewVisibility, e => e.id === CHAT_VIEW_ID),
|
||||||
focusInput: () => chatView.focusInput(),
|
focusInput: () => chatView.focusInput(),
|
||||||
acceptInput: () => chatView.acceptInput(),
|
acceptInput: () => chatView.acceptInput(),
|
||||||
updateInput: text => chatView.setInput(text),
|
updateInput: text => chatView.setInput(text),
|
||||||
|
@ -882,7 +878,7 @@ export class KeywordActivationContribution extends Disposable implements IWorkbe
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IEditorService private readonly editorService: IEditorService,
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
@IHostService private readonly hostService: IHostService,
|
@IHostService private readonly hostService: IHostService,
|
||||||
@IChatService private readonly chatService: IChatService
|
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -897,7 +893,12 @@ export class KeywordActivationContribution extends Disposable implements IWorkbe
|
||||||
this.handleKeywordActivation();
|
this.handleKeywordActivation();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._register(this.chatService.onDidRegisterProvider(() => this.updateConfiguration()));
|
const onDidAddDefaultAgent = this._register(this.chatAgentService.onDidChangeAgents(() => {
|
||||||
|
if (this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel)) {
|
||||||
|
this.updateConfiguration();
|
||||||
|
onDidAddDefaultAgent.dispose();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
this._register(this.speechService.onDidStartSpeechToTextSession(() => this.handleKeywordActivation()));
|
this._register(this.speechService.onDidStartSpeechToTextSession(() => this.handleKeywordActivation()));
|
||||||
this._register(this.speechService.onDidEndSpeechToTextSession(() => this.handleKeywordActivation()));
|
this._register(this.speechService.onDidEndSpeechToTextSession(() => this.handleKeywordActivation()));
|
||||||
|
@ -910,7 +911,7 @@ export class KeywordActivationContribution extends Disposable implements IWorkbe
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateConfiguration(): void {
|
private updateConfiguration(): void {
|
||||||
if (!this.speechService.hasSpeechProvider || this.chatService.getProviderInfos().length === 0) {
|
if (!this.speechService.hasSpeechProvider || !this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel)) {
|
||||||
return; // these settings require a speech and chat provider
|
return; // these settings require a speech and chat provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
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 { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
|
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||||
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 { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
||||||
|
@ -33,6 +35,7 @@ suite('ChatVariables', function () {
|
||||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||||
instantiationService.stub(IChatVariablesService, service);
|
instantiationService.stub(IChatVariablesService, service);
|
||||||
instantiationService.stub(IChatService, new MockChatService());
|
instantiationService.stub(IChatService, new MockChatService());
|
||||||
|
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
||||||
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,6 @@ export class MockChatWidgetService implements IChatWidgetService {
|
||||||
*/
|
*/
|
||||||
readonly lastFocusedWidget: IChatWidget | undefined;
|
readonly lastFocusedWidget: IChatWidget | undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a view was successfully revealed.
|
|
||||||
*/
|
|
||||||
async revealViewForProvider(providerId: string): Promise<IChatWidget | undefined> {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
getWidgetByInputUri(uri: URI): IChatWidget | undefined {
|
getWidgetByInputUri(uri: URI): IChatWidget | undefined {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,5 @@
|
||||||
},
|
},
|
||||||
contentReferences: [ ]
|
contentReferences: [ ]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
}
|
|
@ -4,6 +4,5 @@
|
||||||
responderUsername: "test",
|
responderUsername: "test",
|
||||||
responderAvatarIconUri: undefined,
|
responderAvatarIconUri: undefined,
|
||||||
welcomeMessage: undefined,
|
welcomeMessage: undefined,
|
||||||
requests: [ ],
|
requests: [ ]
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
}
|
|
@ -97,6 +97,5 @@
|
||||||
},
|
},
|
||||||
contentReferences: [ ]
|
contentReferences: [ ]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
}
|
|
@ -1,92 +0,0 @@
|
||||||
{
|
|
||||||
requesterUsername: "test",
|
|
||||||
requesterAvatarIconUri: undefined,
|
|
||||||
responderUsername: "test",
|
|
||||||
responderAvatarIconUri: undefined,
|
|
||||||
welcomeMessage: undefined,
|
|
||||||
requests: [
|
|
||||||
{
|
|
||||||
message: {
|
|
||||||
text: "@ChatProviderWithUsedContext test request",
|
|
||||||
parts: [
|
|
||||||
{
|
|
||||||
kind: "agent",
|
|
||||||
range: {
|
|
||||||
start: 0,
|
|
||||||
endExclusive: 28
|
|
||||||
},
|
|
||||||
editorRange: {
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 1,
|
|
||||||
endLineNumber: 1,
|
|
||||||
endColumn: 29
|
|
||||||
},
|
|
||||||
agent: {
|
|
||||||
id: "ChatProviderWithUsedContext",
|
|
||||||
metadata: { description: undefined }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
range: {
|
|
||||||
start: 28,
|
|
||||||
endExclusive: 41
|
|
||||||
},
|
|
||||||
editorRange: {
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 29,
|
|
||||||
endLineNumber: 1,
|
|
||||||
endColumn: 42
|
|
||||||
},
|
|
||||||
text: " test request",
|
|
||||||
kind: "text"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
variableData: { variables: [ ] },
|
|
||||||
response: [ ],
|
|
||||||
result: { metadata: { metadataKey: "value" } },
|
|
||||||
followups: undefined,
|
|
||||||
isCanceled: false,
|
|
||||||
vote: undefined,
|
|
||||||
agent: {
|
|
||||||
id: "ChatProviderWithUsedContext",
|
|
||||||
extensionId: {
|
|
||||||
value: "nullExtensionDescription",
|
|
||||||
_lower: "nullextensiondescription"
|
|
||||||
},
|
|
||||||
metadata: { description: undefined },
|
|
||||||
slashCommands: [ ],
|
|
||||||
locations: [ "panel" ],
|
|
||||||
isDefault: undefined
|
|
||||||
},
|
|
||||||
slashCommand: undefined,
|
|
||||||
usedContext: {
|
|
||||||
documents: [
|
|
||||||
{
|
|
||||||
uri: {
|
|
||||||
scheme: "file",
|
|
||||||
authority: "",
|
|
||||||
path: "/test/path/to/file",
|
|
||||||
query: "",
|
|
||||||
fragment: "",
|
|
||||||
_formatted: null,
|
|
||||||
_fsPath: null
|
|
||||||
},
|
|
||||||
version: 3,
|
|
||||||
ranges: [
|
|
||||||
{
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 1,
|
|
||||||
endLineNumber: 2,
|
|
||||||
endColumn: 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
kind: "usedContext"
|
|
||||||
},
|
|
||||||
contentReferences: [ ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
requesterUsername: "test",
|
|
||||||
requesterAvatarIconUri: undefined,
|
|
||||||
responderUsername: "test",
|
|
||||||
responderAvatarIconUri: undefined,
|
|
||||||
welcomeMessage: undefined,
|
|
||||||
requests: [ ],
|
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
{
|
|
||||||
requesterUsername: "test",
|
|
||||||
requesterAvatarIconUri: undefined,
|
|
||||||
responderUsername: "test",
|
|
||||||
responderAvatarIconUri: undefined,
|
|
||||||
welcomeMessage: undefined,
|
|
||||||
requests: [
|
|
||||||
{
|
|
||||||
message: {
|
|
||||||
parts: [
|
|
||||||
{
|
|
||||||
kind: "agent",
|
|
||||||
range: {
|
|
||||||
start: 0,
|
|
||||||
endExclusive: 28
|
|
||||||
},
|
|
||||||
editorRange: {
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 1,
|
|
||||||
endLineNumber: 1,
|
|
||||||
endColumn: 29
|
|
||||||
},
|
|
||||||
agent: {
|
|
||||||
id: "ChatProviderWithUsedContext",
|
|
||||||
metadata: {
|
|
||||||
description: undefined,
|
|
||||||
requester: { name: "test" },
|
|
||||||
fullName: "test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
range: {
|
|
||||||
start: 28,
|
|
||||||
endExclusive: 41
|
|
||||||
},
|
|
||||||
editorRange: {
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 29,
|
|
||||||
endLineNumber: 1,
|
|
||||||
endColumn: 42
|
|
||||||
},
|
|
||||||
text: " test request",
|
|
||||||
kind: "text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
text: "@ChatProviderWithUsedContext test request"
|
|
||||||
},
|
|
||||||
variableData: { variables: [ ] },
|
|
||||||
response: [ ],
|
|
||||||
result: { metadata: { metadataKey: "value" } },
|
|
||||||
followups: undefined,
|
|
||||||
isCanceled: false,
|
|
||||||
vote: undefined,
|
|
||||||
agent: {
|
|
||||||
id: "ChatProviderWithUsedContext",
|
|
||||||
extensionId: {
|
|
||||||
value: "nullExtensionDescription",
|
|
||||||
_lower: "nullextensiondescription"
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
description: undefined,
|
|
||||||
requester: { name: "test" },
|
|
||||||
fullName: "test"
|
|
||||||
},
|
|
||||||
slashCommands: [ ],
|
|
||||||
locations: [ "panel" ],
|
|
||||||
isDefault: undefined
|
|
||||||
},
|
|
||||||
slashCommand: undefined,
|
|
||||||
usedContext: {
|
|
||||||
documents: [
|
|
||||||
{
|
|
||||||
uri: {
|
|
||||||
scheme: "file",
|
|
||||||
authority: "",
|
|
||||||
path: "/test/path/to/file",
|
|
||||||
query: "",
|
|
||||||
fragment: "",
|
|
||||||
_formatted: null,
|
|
||||||
_fsPath: null
|
|
||||||
},
|
|
||||||
version: 3,
|
|
||||||
ranges: [
|
|
||||||
{
|
|
||||||
startLineNumber: 1,
|
|
||||||
startColumn: 1,
|
|
||||||
endLineNumber: 2,
|
|
||||||
endColumn: 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
kind: "usedContext"
|
|
||||||
},
|
|
||||||
contentReferences: [ ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
providerId: "testProvider"
|
|
||||||
}
|
|
|
@ -11,7 +11,9 @@ import { assertSnapshot } from 'vs/base/test/common/snapshot';
|
||||||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||||
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
|
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||||
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';
|
||||||
|
@ -30,11 +32,12 @@ suite('ChatModel', () => {
|
||||||
instantiationService.stub(IStorageService, testDisposables.add(new TestStorageService()));
|
instantiationService.stub(IStorageService, testDisposables.add(new TestStorageService()));
|
||||||
instantiationService.stub(ILogService, new NullLogService());
|
instantiationService.stub(ILogService, new NullLogService());
|
||||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||||
|
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
||||||
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Waits for initialization', async () => {
|
test('Waits for initialization', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
let hasInitialized = false;
|
let hasInitialized = false;
|
||||||
model.waitForInitialization().then(() => {
|
model.waitForInitialization().then(() => {
|
||||||
|
@ -45,13 +48,13 @@ suite('ChatModel', () => {
|
||||||
assert.strictEqual(hasInitialized, false);
|
assert.strictEqual(hasInitialized, false);
|
||||||
|
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
model.initialize({} as any, undefined);
|
model.initialize(undefined);
|
||||||
await timeout(0);
|
await timeout(0);
|
||||||
assert.strictEqual(hasInitialized, true);
|
assert.strictEqual(hasInitialized, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('must call startInitialize before initialize', async () => {
|
test('must call startInitialize before initialize', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
let hasInitialized = false;
|
let hasInitialized = false;
|
||||||
model.waitForInitialization().then(() => {
|
model.waitForInitialization().then(() => {
|
||||||
|
@ -61,12 +64,12 @@ suite('ChatModel', () => {
|
||||||
await timeout(0);
|
await timeout(0);
|
||||||
assert.strictEqual(hasInitialized, false);
|
assert.strictEqual(hasInitialized, false);
|
||||||
|
|
||||||
assert.throws(() => model.initialize({} as any, undefined));
|
assert.throws(() => model.initialize(undefined));
|
||||||
assert.strictEqual(hasInitialized, false);
|
assert.strictEqual(hasInitialized, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deinitialize/reinitialize', async () => {
|
test('deinitialize/reinitialize', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
let hasInitialized = false;
|
let hasInitialized = false;
|
||||||
model.waitForInitialization().then(() => {
|
model.waitForInitialization().then(() => {
|
||||||
|
@ -74,7 +77,7 @@ suite('ChatModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
model.initialize({} as any, undefined);
|
model.initialize(undefined);
|
||||||
await timeout(0);
|
await timeout(0);
|
||||||
assert.strictEqual(hasInitialized, true);
|
assert.strictEqual(hasInitialized, true);
|
||||||
|
|
||||||
|
@ -85,31 +88,31 @@ suite('ChatModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
model.initialize({} as any, undefined);
|
model.initialize(undefined);
|
||||||
await timeout(0);
|
await timeout(0);
|
||||||
assert.strictEqual(hasInitialized2, true);
|
assert.strictEqual(hasInitialized2, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cannot initialize twice', async () => {
|
test('cannot initialize twice', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
model.initialize({} as any, undefined);
|
model.initialize(undefined);
|
||||||
assert.throws(() => model.initialize({} as any, undefined));
|
assert.throws(() => model.initialize(undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Initialization fails when model is disposed', async () => {
|
test('Initialization fails when model is disposed', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
model.dispose();
|
model.dispose();
|
||||||
|
|
||||||
assert.throws(() => model.initialize({} as any, undefined));
|
assert.throws(() => model.initialize(undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('removeRequest', async () => {
|
test('removeRequest', async () => {
|
||||||
const model = testDisposables.add(instantiationService.createInstance(ChatModel, 'provider', undefined));
|
const model = testDisposables.add(instantiationService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
model.startInitialize();
|
model.startInitialize();
|
||||||
model.initialize({} as any, undefined);
|
model.initialize(undefined);
|
||||||
const text = 'hello';
|
const text = 'hello';
|
||||||
model.addRequest({ text, parts: [new ChatRequestTextPart(new OffsetRange(0, text.length), new Range(1, text.length, 1, text.length), text)] }, { variables: [] });
|
model.addRequest({ text, parts: [new ChatRequestTextPart(new OffsetRange(0, text.length), new Range(1, text.length, 1, text.length), text)] }, { variables: [] });
|
||||||
const requests = model.getRequests();
|
const requests = model.getRequests();
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
import { MockObject, mockObject } from 'vs/base/test/common/mock';
|
import { MockObject, mockObject } from 'vs/base/test/common/mock';
|
||||||
import { assertSnapshot } from 'vs/base/test/common/snapshot';
|
import { assertSnapshot } from 'vs/base/test/common/snapshot';
|
||||||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
|
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||||
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 { ChatAgentLocation, ChatAgentService, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, ChatAgentService, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
|
@ -31,6 +33,7 @@ suite('ChatRequestParser', () => {
|
||||||
instantiationService.stub(ILogService, new NullLogService());
|
instantiationService.stub(ILogService, new NullLogService());
|
||||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||||
instantiationService.stub(IChatService, new MockChatService());
|
instantiationService.stub(IChatService, new MockChatService());
|
||||||
|
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
||||||
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
instantiationService.stub(IChatAgentService, instantiationService.createInstance(ChatAgentService));
|
||||||
|
|
||||||
varService = mockObject<IChatVariablesService>()({});
|
varService = mockObject<IChatVariablesService>()({});
|
||||||
|
|
|
@ -5,12 +5,10 @@
|
||||||
|
|
||||||
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 { 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';
|
||||||
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 { Range } from 'vs/editor/common/core/range';
|
||||||
import { ProviderResult } from 'vs/editor/common/languages';
|
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
|
@ -21,9 +19,8 @@ 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 { ChatAgentLocation, ChatAgentService, IChatAgent, IChatAgentImplementation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, ChatAgentService, IChatAgent, IChatAgentImplementation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
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, IChatFollowup, IChatProgress, IChatProvider, IChatRequest, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatFollowup, IChatService } 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';
|
||||||
|
@ -33,26 +30,6 @@ import { IExtensionService, nullExtensionDescription } from 'vs/workbench/servic
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
import { TestContextService, TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestContextService, TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
|
|
||||||
class SimpleTestProvider extends Disposable implements IChatProvider {
|
|
||||||
private static sessionId = 0;
|
|
||||||
|
|
||||||
readonly displayName = 'Test';
|
|
||||||
|
|
||||||
constructor(readonly id: string) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
async prepareSession(): Promise<IChat> {
|
|
||||||
return {
|
|
||||||
id: SimpleTestProvider.sessionId++,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void): Promise<{ session: IChat; followups: never[] }> {
|
|
||||||
return { session: request.session, followups: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const chatAgentWithUsedContextId = 'ChatProviderWithUsedContext';
|
const chatAgentWithUsedContextId = 'ChatProviderWithUsedContext';
|
||||||
const chatAgentWithUsedContext: IChatAgent = {
|
const chatAgentWithUsedContext: IChatAgent = {
|
||||||
id: chatAgentWithUsedContextId,
|
id: chatAgentWithUsedContextId,
|
||||||
|
@ -100,7 +77,6 @@ suite('ChatService', () => {
|
||||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||||
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
||||||
instantiationService.stub(IViewsService, new TestExtensionService());
|
instantiationService.stub(IViewsService, 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(IChatService, new MockChatService());
|
instantiationService.stub(IChatService, new MockChatService());
|
||||||
|
@ -121,23 +97,16 @@ suite('ChatService', () => {
|
||||||
|
|
||||||
test('retrieveSession', async () => {
|
test('retrieveSession', async () => {
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
const provider1 = testDisposables.add(new SimpleTestProvider('provider1'));
|
const session1 = testDisposables.add(testService.startSession(CancellationToken.None));
|
||||||
const provider2 = testDisposables.add(new SimpleTestProvider('provider2'));
|
|
||||||
testDisposables.add(testService.registerProvider(provider1));
|
|
||||||
testDisposables.add(testService.registerProvider(provider2));
|
|
||||||
|
|
||||||
const session1 = testDisposables.add(testService.startSession('provider1', CancellationToken.None));
|
|
||||||
await session1.waitForInitialization();
|
await session1.waitForInitialization();
|
||||||
session1.addRequest({ parts: [], text: 'request 1' }, { variables: [] });
|
session1.addRequest({ parts: [], text: 'request 1' }, { variables: [] });
|
||||||
|
|
||||||
const session2 = testDisposables.add(testService.startSession('provider2', CancellationToken.None));
|
const session2 = testDisposables.add(testService.startSession(CancellationToken.None));
|
||||||
await session2.waitForInitialization();
|
await session2.waitForInitialization();
|
||||||
session2.addRequest({ parts: [], text: 'request 2' }, { variables: [] });
|
session2.addRequest({ parts: [], text: 'request 2' }, { variables: [] });
|
||||||
|
|
||||||
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(provider2));
|
|
||||||
const retrieved1 = testDisposables.add(testService2.getOrRestoreSession(session1.sessionId)!);
|
const retrieved1 = testDisposables.add(testService2.getOrRestoreSession(session1.sessionId)!);
|
||||||
await retrieved1.waitForInitialization();
|
await retrieved1.waitForInitialization();
|
||||||
const retrieved2 = testDisposables.add(testService2.getOrRestoreSession(session2.sessionId)!);
|
const retrieved2 = testDisposables.add(testService2.getOrRestoreSession(session2.sessionId)!);
|
||||||
|
@ -146,57 +115,10 @@ suite('ChatService', () => {
|
||||||
assert.deepStrictEqual(retrieved2.getRequests()[0]?.message.text, 'request 2');
|
assert.deepStrictEqual(retrieved2.getRequests()[0]?.message.text, 'request 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Handles failed session startup', async () => {
|
|
||||||
function getFailProvider(providerId: string) {
|
|
||||||
return new class implements IChatProvider {
|
|
||||||
readonly id = providerId;
|
|
||||||
readonly displayName = 'Test';
|
|
||||||
|
|
||||||
lastInitialState = undefined;
|
|
||||||
|
|
||||||
prepareSession(initialState: any): ProviderResult<any> {
|
|
||||||
throw new Error('Failed to start session');
|
|
||||||
}
|
|
||||||
|
|
||||||
async provideReply(request: IChatRequest) {
|
|
||||||
return { session: request.session, followups: [] };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
|
||||||
const provider1 = getFailProvider('provider1');
|
|
||||||
testDisposables.add(testService.registerProvider(provider1));
|
|
||||||
|
|
||||||
const session1 = testDisposables.add(testService.startSession('provider1', CancellationToken.None));
|
|
||||||
await assert.rejects(() => session1.waitForInitialization());
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Can\'t register same provider id twice', async () => {
|
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
|
||||||
const id = 'testProvider';
|
|
||||||
testDisposables.add(testService.registerProvider({
|
|
||||||
id,
|
|
||||||
prepareSession: function (token: CancellationToken): ProviderResult<IChat | undefined> {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
testDisposables.add(testService.registerProvider({
|
|
||||||
id,
|
|
||||||
prepareSession: function (token: CancellationToken): ProviderResult<IChat | undefined> {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}, 'Expected to throw for dupe provider');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('addCompleteRequest', async () => {
|
test('addCompleteRequest', async () => {
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
|
||||||
|
|
||||||
const model = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
const model = testDisposables.add(testService.startSession(CancellationToken.None));
|
||||||
assert.strictEqual(model.getRequests().length, 0);
|
assert.strictEqual(model.getRequests().length, 0);
|
||||||
|
|
||||||
await testService.addCompleteRequest(model.sessionId, 'test request', undefined, { message: 'test response' });
|
await testService.addCompleteRequest(model.sessionId, 'test request', undefined, { message: 'test response' });
|
||||||
|
@ -209,9 +131,8 @@ suite('ChatService', () => {
|
||||||
testDisposables.add(chatAgentService.registerAgentImplementation(chatAgentWithUsedContextId, chatAgentWithUsedContext));
|
testDisposables.add(chatAgentService.registerAgentImplementation(chatAgentWithUsedContextId, chatAgentWithUsedContext));
|
||||||
chatAgentService.updateAgent(chatAgentWithUsedContextId, { requester: { name: 'test' }, fullName: 'test' });
|
chatAgentService.updateAgent(chatAgentWithUsedContextId, { requester: { name: 'test' }, fullName: 'test' });
|
||||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||||
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
|
||||||
|
|
||||||
const model = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
const model = testDisposables.add(testService.startSession(CancellationToken.None));
|
||||||
assert.strictEqual(model.getRequests().length, 0);
|
assert.strictEqual(model.getRequests().length, 0);
|
||||||
|
|
||||||
await assertSnapshot(model.toExport());
|
await assertSnapshot(model.toExport());
|
||||||
|
@ -232,9 +153,8 @@ suite('ChatService', () => {
|
||||||
// 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'))));
|
|
||||||
|
|
||||||
const chatModel1 = testDisposables.add(testService.startSession('testProvider', CancellationToken.None));
|
const chatModel1 = testDisposables.add(testService.startSession(CancellationToken.None));
|
||||||
assert.strictEqual(chatModel1.getRequests().length, 0);
|
assert.strictEqual(chatModel1.getRequests().length, 0);
|
||||||
|
|
||||||
const response = await testService.sendRequest(chatModel1.sessionId, `@${chatAgentWithUsedContextId} test request`);
|
const response = await testService.sendRequest(chatModel1.sessionId, `@${chatAgentWithUsedContextId} test request`);
|
||||||
|
@ -248,7 +168,6 @@ suite('ChatService', () => {
|
||||||
// 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'))));
|
|
||||||
|
|
||||||
const chatModel2 = testService2.loadSessionFromContent(serializedChatData);
|
const chatModel2 = testService2.loadSessionFromContent(serializedChatData);
|
||||||
assert(chatModel2);
|
assert(chatModel2);
|
||||||
|
|
|
@ -1,31 +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 { IChatContributionService, IChatParticipantContribution, IChatProviderContribution } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
|
|
||||||
export class MockChatContributionService implements IChatContributionService {
|
|
||||||
_serviceBrand: undefined;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
) { }
|
|
||||||
|
|
||||||
registeredProviders: IChatProviderContribution[] = [];
|
|
||||||
registerChatParticipant(participant: IChatParticipantContribution): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
deregisterChatParticipant(participant: IChatParticipantContribution): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
registerChatProvider(provider: IChatProviderContribution): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
deregisterChatProvider(providerId: string): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
getViewIdForProvider(providerId: string): string {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,43 +5,37 @@
|
||||||
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { ChatModel, IChatModel, IChatRequestVariableData, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatModel, IChatModel, IChatRequestVariableData, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatCompleteResponse, IChatDetail, IChatProvider, IChatProviderInfo, IChatSendRequestData, IChatService, IChatTransferredSessionData, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatCompleteResponse, IChatDetail, IChatProviderInfo, IChatSendRequestData, IChatService, IChatTransferredSessionData, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
|
||||||
export class MockChatService implements IChatService {
|
export class MockChatService implements IChatService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
transferredSessionData: IChatTransferredSessionData | undefined;
|
transferredSessionData: IChatTransferredSessionData | undefined;
|
||||||
|
|
||||||
hasSessions(providerId: string): boolean {
|
isEnabled(location: ChatAgentLocation): boolean {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
hasSessions(): boolean {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
getProviderInfos(): IChatProviderInfo[] {
|
getProviderInfos(): IChatProviderInfo[] {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
startSession(providerId: string, token: CancellationToken): ChatModel | undefined {
|
startSession(token: CancellationToken): ChatModel | undefined {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
getSession(sessionId: string): IChatModel | undefined {
|
getSession(sessionId: string): IChatModel | undefined {
|
||||||
return {} as IChatModel;
|
return {} as IChatModel;
|
||||||
}
|
}
|
||||||
getSessionId(sessionProviderId: number): string | undefined {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
getOrRestoreSession(sessionId: string): IChatModel | undefined {
|
getOrRestoreSession(sessionId: string): IChatModel | undefined {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
loadSessionFromContent(data: ISerializableChatData): IChatModel | undefined {
|
loadSessionFromContent(data: ISerializableChatData): IChatModel | undefined {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
onDidRegisterProvider: Event<{ providerId: string }> = undefined!;
|
|
||||||
onDidUnregisterProvider: Event<{ providerId: string }> = undefined!;
|
|
||||||
registerProvider(provider: IChatProvider): IDisposable {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the request was accepted.
|
* Returns whether the request was accepted.
|
||||||
*/
|
*/
|
||||||
|
@ -74,7 +68,7 @@ export class MockChatService implements IChatService {
|
||||||
notifyUserAction(event: IChatUserActionEvent): void {
|
notifyUserAction(event: IChatUserActionEvent): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
onDidDisposeSession: Event<{ sessionId: string; providerId: string; reason: 'initializationFailed' | 'cleared' }> = undefined!;
|
onDidDisposeSession: Event<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }> = undefined!;
|
||||||
|
|
||||||
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void {
|
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
|
|
|
@ -57,6 +57,7 @@ suite('VoiceChat', () => {
|
||||||
getActivatedAgents(): IChatAgent[] { return agents; }
|
getActivatedAgents(): IChatAgent[] { return agents; }
|
||||||
getAgents(): IChatAgent[] { return agents; }
|
getAgents(): IChatAgent[] { return agents; }
|
||||||
getDefaultAgent(): IChatAgent | undefined { throw new Error(); }
|
getDefaultAgent(): IChatAgent | undefined { throw new Error(); }
|
||||||
|
getContributedDefaultAgent(): IChatAgentData | undefined { throw new Error(); }
|
||||||
getSecondaryAgent(): IChatAgent | undefined { throw new Error(); }
|
getSecondaryAgent(): IChatAgent | undefined { throw new Error(); }
|
||||||
registerAgent(id: string, data: IChatAgentData): IDisposable { throw new Error('Method not implemented.'); }
|
registerAgent(id: string, data: IChatAgentData): IDisposable { throw new Error('Method not implemented.'); }
|
||||||
getAgent(id: string): IChatAgentData | undefined { throw new Error('Method not implemented.'); }
|
getAgent(id: string): IChatAgentData | undefined { throw new Error('Method not implemented.'); }
|
||||||
|
|
|
@ -50,7 +50,7 @@ export class InlineChatContentWidget implements IContentWidget {
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
this._defaultChatModel = this._store.add(instaService.createInstance(ChatModel, `inlineChatDefaultModel/editorContentWidgetPlaceholder`, undefined));
|
this._defaultChatModel = this._store.add(instaService.createInstance(ChatModel, undefined));
|
||||||
|
|
||||||
const scopedInstaService = instaService.createChild(
|
const scopedInstaService = instaService.createChild(
|
||||||
new ServiceCollection([
|
new ServiceCollection([
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { IChatWidgetService, showChatView } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { chatAgentLeader, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { chatAgentLeader, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
@ -51,6 +51,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat
|
||||||
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
||||||
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||||
import { isEqual } from 'vs/base/common/resources';
|
import { isEqual } from 'vs/base/common/resources';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
export const enum State {
|
export const enum State {
|
||||||
CREATE_SESSION = 'CREATE_SESSION',
|
CREATE_SESSION = 'CREATE_SESSION',
|
||||||
|
@ -1229,8 +1230,7 @@ async function showMessageResponse(accessor: ServicesAccessor, query: string, re
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatWidgetService = accessor.get(IChatWidgetService);
|
const widget = await showChatView(accessor.get(IViewsService));
|
||||||
const widget = await chatWidgetService.revealViewForProvider(agent.name);
|
|
||||||
if (widget && widget.viewModel) {
|
if (widget && widget.viewModel) {
|
||||||
chatService.addCompleteRequest(widget.viewModel.sessionId, query, undefined, { message: response });
|
chatService.addCompleteRequest(widget.viewModel.sessionId, query, undefined, { message: response });
|
||||||
widget.focusLastMessage();
|
widget.focusLastMessage();
|
||||||
|
@ -1238,13 +1238,12 @@ async function showMessageResponse(accessor: ServicesAccessor, query: string, re
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendRequest(accessor: ServicesAccessor, query: string) {
|
async function sendRequest(accessor: ServicesAccessor, query: string) {
|
||||||
const widgetService = accessor.get(IChatWidgetService);
|
|
||||||
const chatAgentService = accessor.get(IChatAgentService);
|
const chatAgentService = accessor.get(IChatAgentService);
|
||||||
const agent = chatAgentService.getActivatedAgents().find(agent => agent.locations.includes(ChatAgentLocation.Panel) && agent.isDefault);
|
const agent = chatAgentService.getActivatedAgents().find(agent => agent.locations.includes(ChatAgentLocation.Panel) && agent.isDefault);
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const widget = await widgetService.revealViewForProvider(agent.name);
|
const widget = await showChatView(accessor.get(IViewsService));
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,41 +2,40 @@
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* 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 { URI } from 'vs/base/common/uri';
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
|
||||||
import { EditMode, IInlineChatSession, IInlineChatService, IInlineChatSessionProvider, InlineChatResponseFeedbackKind, IInlineChatProgressItem, IInlineChatResponse, IInlineChatRequest, InlineChatResponseType, IInlineChatBulkEditResponse } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
|
||||||
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|
||||||
import { IModelService } from 'vs/editor/common/services/model';
|
|
||||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
|
||||||
import { DisposableMap, DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
|
||||||
import { raceCancellation } from 'vs/base/common/async';
|
|
||||||
import { Recording, IInlineChatSessionService, ISessionKeyComputer, IInlineChatSessionEvent, IInlineChatSessionEndEvent } from './inlineChatSessionService';
|
|
||||||
import { EmptyResponse, ErrorResponse, HunkData, ReplyResponse, Session, SessionExchange, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession';
|
|
||||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
|
||||||
import { ITextModel, IValidEditOperation } from 'vs/editor/common/model';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
|
||||||
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
|
|
||||||
import { IChatFollowup, IChatProgress, IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
|
||||||
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
|
||||||
import { Progress } from 'vs/platform/progress/common/progress';
|
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { coalesceInPlace, isNonEmptyArray } from 'vs/base/common/arrays';
|
import { coalesceInPlace, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
import { raceCancellation } from 'vs/base/common/async';
|
||||||
import { TextEdit } from 'vs/editor/common/languages';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
|
||||||
import { Codicon } from 'vs/base/common/codicons';
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { CancellationError } from 'vs/base/common/errors';
|
import { CancellationError } from 'vs/base/common/errors';
|
||||||
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
|
import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { LRUCache } from 'vs/base/common/map';
|
import { LRUCache } from 'vs/base/common/map';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
|
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
|
import { TextEdit } from 'vs/editor/common/languages';
|
||||||
|
import { ITextModel, IValidEditOperation } from 'vs/editor/common/model';
|
||||||
|
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||||
|
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||||
|
import { IModelService } from 'vs/editor/common/services/model';
|
||||||
|
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { Progress } from 'vs/platform/progress/common/progress';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
|
||||||
|
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
|
import { IChatFollowup, IChatProgress, IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
import { EditMode, IInlineChatBulkEditResponse, IInlineChatProgressItem, IInlineChatRequest, IInlineChatResponse, IInlineChatService, IInlineChatSession, InlineChatResponseFeedbackKind, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
|
import { EmptyResponse, ErrorResponse, HunkData, ReplyResponse, Session, SessionExchange, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession';
|
||||||
|
import { IInlineChatSessionEndEvent, IInlineChatSessionEvent, IInlineChatSessionService, ISessionKeyComputer, Recording } from './inlineChatSessionService';
|
||||||
|
|
||||||
class BridgeAgent implements IChatAgentImplementation {
|
class BridgeAgent implements IChatAgentImplementation {
|
||||||
|
|
||||||
|
@ -299,34 +298,6 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
|
||||||
this._store.add(this._chatAgentService.onDidChangeAgents(() => addOrRemoveBridgeAgent()));
|
this._store.add(this._chatAgentService.onDidChangeAgents(() => addOrRemoveBridgeAgent()));
|
||||||
const brigdeAgent = this._store.add(new MutableDisposable());
|
const brigdeAgent = this._store.add(new MutableDisposable());
|
||||||
addOrRemoveBridgeAgent();
|
addOrRemoveBridgeAgent();
|
||||||
|
|
||||||
// MARK: register fake chat provider
|
|
||||||
|
|
||||||
const mapping = this._store.add(new DisposableMap<IInlineChatSessionProvider>());
|
|
||||||
const registerFakeChatProvider = (provider: IInlineChatSessionProvider) => {
|
|
||||||
const d = this._chatService.registerProvider({
|
|
||||||
id: this._asChatProviderBrigdeName(provider),
|
|
||||||
prepareSession() {
|
|
||||||
return {
|
|
||||||
id: Math.random()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mapping.set(provider, d);
|
|
||||||
};
|
|
||||||
|
|
||||||
this._store.add(_inlineChatService.onDidChangeProviders(e => {
|
|
||||||
if (e.added) {
|
|
||||||
registerFakeChatProvider(e.added);
|
|
||||||
}
|
|
||||||
if (e.removed) {
|
|
||||||
mapping.deleteAndDispose(e.removed);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
for (const provider of _inlineChatService.getAllProvider()) {
|
|
||||||
registerFakeChatProvider(provider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
|
@ -335,10 +306,6 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
|
||||||
this._sessions.clear();
|
this._sessions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _asChatProviderBrigdeName(provider: IInlineChatSessionProvider) {
|
|
||||||
return `inlinechat:${provider.label}:${ExtensionIdentifier.toKey(provider.extensionId)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: Range }, token: CancellationToken): Promise<Session | undefined> {
|
async createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: Range }, token: CancellationToken): Promise<Session | undefined> {
|
||||||
|
|
||||||
const provider = Iterable.first(this._inlineChatService.getAllProvider());
|
const provider = Iterable.first(this._inlineChatService.getAllProvider());
|
||||||
|
@ -347,7 +314,7 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatModel = this._chatService.startSession(this._asChatProviderBrigdeName(provider), token);
|
const chatModel = this._chatService.startSession(token);
|
||||||
if (!chatModel) {
|
if (!chatModel) {
|
||||||
this._logService.trace('[IE] NO chatModel found');
|
this._logService.trace('[IE] NO chatModel found');
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -93,7 +93,6 @@ export interface IInlineChatWidgetConstructionOptions {
|
||||||
export interface IInlineChatMessage {
|
export interface IInlineChatMessage {
|
||||||
message: IMarkdownString;
|
message: IMarkdownString;
|
||||||
requestId: string;
|
requestId: string;
|
||||||
providerId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInlineChatMessageAppender {
|
export interface IInlineChatMessageAppender {
|
||||||
|
@ -302,9 +301,9 @@ export class InlineChatWidget {
|
||||||
|
|
||||||
// LEGACY - default chat model
|
// LEGACY - default chat model
|
||||||
// this is only here for as long as we offer updateChatMessage
|
// this is only here for as long as we offer updateChatMessage
|
||||||
this._defaultChatModel = this._store.add(this._instantiationService.createInstance(ChatModel, `inlineChatDefaultModel/${location}`, undefined));
|
this._defaultChatModel = this._store.add(this._instantiationService.createInstance(ChatModel, undefined));
|
||||||
this._defaultChatModel.startInitialize();
|
this._defaultChatModel.startInitialize();
|
||||||
this._defaultChatModel.initialize({ id: 1 }, undefined);
|
this._defaultChatModel.initialize(undefined);
|
||||||
this.setChatModel(this._defaultChatModel);
|
this.setChatModel(this._defaultChatModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ import { IInlineChatSavingService } from '../../browser/inlineChatSavingService'
|
||||||
import { IInlineChatSessionService } from '../../browser/inlineChatSessionService';
|
import { IInlineChatSessionService } from '../../browser/inlineChatSessionService';
|
||||||
import { InlineChatSessionServiceImpl } from '../../browser/inlineChatSessionServiceImpl';
|
import { InlineChatSessionServiceImpl } from '../../browser/inlineChatSessionServiceImpl';
|
||||||
import { TestWorkerService } from './testWorkerService';
|
import { TestWorkerService } from './testWorkerService';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { IExtensionService, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } 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';
|
||||||
|
@ -127,7 +126,6 @@ suite('InteractiveChatController', function () {
|
||||||
[IExtensionService, new TestExtensionService()],
|
[IExtensionService, new TestExtensionService()],
|
||||||
[IContextKeyService, new MockContextKeyService()],
|
[IContextKeyService, new MockContextKeyService()],
|
||||||
[IViewsService, new TestExtensionService()],
|
[IViewsService, new TestExtensionService()],
|
||||||
[IChatContributionService, new TestExtensionService()],
|
|
||||||
[IWorkspaceContextService, new TestContextService()],
|
[IWorkspaceContextService, new TestContextService()],
|
||||||
[IChatWidgetHistoryService, new SyncDescriptor(ChatWidgetHistoryService)],
|
[IChatWidgetHistoryService, new SyncDescriptor(ChatWidgetHistoryService)],
|
||||||
[IChatWidgetService, new SyncDescriptor(ChatWidgetService)],
|
[IChatWidgetService, new SyncDescriptor(ChatWidgetService)],
|
||||||
|
|
|
@ -46,7 +46,6 @@ 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 { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
|
||||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
import { IChatService } 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 { IChatSlashCommandService, ChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
import { IChatSlashCommandService, ChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||||
|
@ -56,7 +55,6 @@ import { MockChatVariablesService } from 'vs/workbench/contrib/chat/test/common/
|
||||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
import { TestExtensionService, TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestExtensionService, TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { IChatAgentService, ChatAgentService, ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { IChatAgentService, ChatAgentService, ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { MockChatContributionService } from 'vs/workbench/contrib/chat/test/common/mockChatContributionService';
|
|
||||||
|
|
||||||
suite('InlineChatSession', function () {
|
suite('InlineChatSession', function () {
|
||||||
|
|
||||||
|
@ -80,14 +78,12 @@ suite('InlineChatSession', function () {
|
||||||
[IExtensionService, new TestExtensionService()],
|
[IExtensionService, new TestExtensionService()],
|
||||||
[IContextKeyService, new MockContextKeyService()],
|
[IContextKeyService, new MockContextKeyService()],
|
||||||
[IViewsService, new TestExtensionService()],
|
[IViewsService, new TestExtensionService()],
|
||||||
[IChatContributionService, new TestExtensionService()],
|
|
||||||
[IWorkspaceContextService, new TestContextService()],
|
[IWorkspaceContextService, new TestContextService()],
|
||||||
[IChatWidgetHistoryService, new SyncDescriptor(ChatWidgetHistoryService)],
|
[IChatWidgetHistoryService, new SyncDescriptor(ChatWidgetHistoryService)],
|
||||||
[IChatWidgetService, new SyncDescriptor(ChatWidgetService)],
|
[IChatWidgetService, new SyncDescriptor(ChatWidgetService)],
|
||||||
[IChatSlashCommandService, new SyncDescriptor(ChatSlashCommandService)],
|
[IChatSlashCommandService, new SyncDescriptor(ChatSlashCommandService)],
|
||||||
[IChatService, new SyncDescriptor(ChatService)],
|
[IChatService, new SyncDescriptor(ChatService)],
|
||||||
[IEditorWorkerService, new SyncDescriptor(TestWorkerService)],
|
[IEditorWorkerService, new SyncDescriptor(TestWorkerService)],
|
||||||
[IChatContributionService, new MockChatContributionService()],
|
|
||||||
[IChatAgentService, new SyncDescriptor(ChatAgentService)],
|
[IChatAgentService, new SyncDescriptor(ChatAgentService)],
|
||||||
[IInlineChatService, new SyncDescriptor(InlineChatServiceImpl)],
|
[IInlineChatService, new SyncDescriptor(InlineChatServiceImpl)],
|
||||||
[IContextKeyService, contextKeyService],
|
[IContextKeyService, contextKeyService],
|
||||||
|
|
|
@ -614,7 +614,6 @@ export class NotebookChatController extends Disposable implements INotebookEdito
|
||||||
if (!progressiveChatResponse) {
|
if (!progressiveChatResponse) {
|
||||||
const message = {
|
const message = {
|
||||||
message: new MarkdownString(data.markdownFragment, { supportThemeIcons: true, supportHtml: true, isTrusted: false }),
|
message: new MarkdownString(data.markdownFragment, { supportThemeIcons: true, supportHtml: true, isTrusted: false }),
|
||||||
providerId: this._activeSession!.provider.label,
|
|
||||||
requestId: request.requestId,
|
requestId: request.requestId,
|
||||||
};
|
};
|
||||||
progressiveChatResponse = this._widget?.inlineChatWidget.updateChatMessage(message, true);
|
progressiveChatResponse = this._widget?.inlineChatWidget.updateChatMessage(message, true);
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||||
import { GeneratingPhrase, IChatAccessibilityService, IChatCodeBlockContextProviderService, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
import { GeneratingPhrase, IChatAccessibilityService, IChatCodeBlockContextProviderService, showChatView } from 'vs/workbench/contrib/chat/browser/chat';
|
||||||
import { ChatAgentLocation, IChatAgentRequest, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
import { ChatAgentLocation, IChatAgentRequest, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||||
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||||
import { ChatUserAction, IChatProgress, IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
import { ChatUserAction, IChatProgress, IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||||
|
@ -24,6 +24,7 @@ import { TerminalChatWidget } from 'vs/workbench/contrib/terminalContrib/chat/br
|
||||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { ChatModel, ChatRequestModel, IChatRequestVariableData, getHistoryEntriesFromModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
import { ChatModel, ChatRequestModel, IChatRequestVariableData, getHistoryEntriesFromModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||||
import { TerminalChatContextKeys } from 'vs/workbench/contrib/terminalContrib/chat/browser/terminalChat';
|
import { TerminalChatContextKeys } from 'vs/workbench/contrib/terminalContrib/chat/browser/terminalChat';
|
||||||
|
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||||
|
|
||||||
const enum Message {
|
const enum Message {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
|
@ -95,9 +96,9 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
@IChatAgentService private readonly _chatAgentService: IChatAgentService,
|
@IChatAgentService private readonly _chatAgentService: IChatAgentService,
|
||||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||||
@IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService,
|
@IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService,
|
||||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
|
|
||||||
@IChatService private readonly _chatService: IChatService,
|
@IChatService private readonly _chatService: IChatService,
|
||||||
@IChatCodeBlockContextProviderService private readonly _chatCodeBlockContextProviderService: IChatCodeBlockContextProviderService,
|
@IChatCodeBlockContextProviderService private readonly _chatCodeBlockContextProviderService: IChatCodeBlockContextProviderService,
|
||||||
|
@IViewsService private readonly _viewsService: IViewsService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -134,13 +135,11 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
// a default chat model (unless configured) and feedback is reported against that one. This
|
// a default chat model (unless configured) and feedback is reported against that one. This
|
||||||
// code forwards the feedback to an actual registered provider
|
// code forwards the feedback to an actual registered provider
|
||||||
this._register(this._chatService.onDidPerformUserAction(e => {
|
this._register(this._chatService.onDidPerformUserAction(e => {
|
||||||
if (e.providerId === this._chatWidget?.rawValue?.inlineChatWidget.getChatModel().providerId) {
|
|
||||||
if (e.action.kind === 'bug') {
|
if (e.action.kind === 'bug') {
|
||||||
this.acceptFeedback(undefined);
|
this.acceptFeedback(undefined);
|
||||||
} else if (e.action.kind === 'vote') {
|
} else if (e.action.kind === 'vote') {
|
||||||
this.acceptFeedback(e.action.direction === InteractiveSessionVoteDirection.Up);
|
this.acceptFeedback(e.action.direction === InteractiveSessionVoteDirection.Up);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +178,8 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptFeedback(helpful?: boolean): void {
|
acceptFeedback(helpful?: boolean): void {
|
||||||
const providerId = this._chatService.getProviderInfos()?.[0]?.id;
|
|
||||||
const model = this._model.value;
|
const model = this._model.value;
|
||||||
if (!providerId || !this._currentRequest || !model) {
|
if (!this._currentRequest || !model) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let action: ChatUserAction;
|
let action: ChatUserAction;
|
||||||
|
@ -195,7 +193,6 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
for (const request of model.getRequests()) {
|
for (const request of model.getRequests()) {
|
||||||
if (request.response?.response.value || request.response?.result) {
|
if (request.response?.response.value || request.response?.result) {
|
||||||
this._chatService.notifyUserAction({
|
this._chatService.notifyUserAction({
|
||||||
providerId,
|
|
||||||
sessionId: request.session.sessionId,
|
sessionId: request.session.sessionId,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
agentId: request.response?.agent?.id,
|
agentId: request.response?.agent?.id,
|
||||||
|
@ -253,12 +250,8 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
}
|
}
|
||||||
|
|
||||||
async acceptInput(): Promise<void> {
|
async acceptInput(): Promise<void> {
|
||||||
const providerInfo = this._chatService.getProviderInfos()?.[0];
|
|
||||||
if (!providerInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this._model.value) {
|
if (!this._model.value) {
|
||||||
this._model.value = this._chatService.startSession(providerInfo.id, CancellationToken.None);
|
this._model.value = this._chatService.startSession(CancellationToken.None);
|
||||||
if (!this._model.value) {
|
if (!this._model.value) {
|
||||||
throw new Error('Could not start chat session');
|
throw new Error('Could not start chat session');
|
||||||
}
|
}
|
||||||
|
@ -328,7 +321,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
if (this._currentRequest) {
|
if (this._currentRequest) {
|
||||||
this._chatAccessibilityService.acceptResponse(responseContent, accessibilityRequestId);
|
this._chatAccessibilityService.acceptResponse(responseContent, accessibilityRequestId);
|
||||||
const containsCode = responseContent.includes('```');
|
const containsCode = responseContent.includes('```');
|
||||||
this._chatWidget?.value.inlineChatWidget.updateChatMessage({ message: new MarkdownString(responseContent), requestId: this._currentRequest.id, providerId: 'terminal' }, false, containsCode);
|
this._chatWidget?.value.inlineChatWidget.updateChatMessage({ message: new MarkdownString(responseContent), requestId: this._currentRequest.id }, false, containsCode);
|
||||||
const firstCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(0);
|
const firstCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(0);
|
||||||
const secondCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(1);
|
const secondCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(1);
|
||||||
this._responseContainsCodeBlockContextKey.set(!!firstCodeBlock);
|
this._responseContainsCodeBlockContextKey.set(!!firstCodeBlock);
|
||||||
|
@ -377,11 +370,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr
|
||||||
}
|
}
|
||||||
|
|
||||||
async viewInChat(): Promise<void> {
|
async viewInChat(): Promise<void> {
|
||||||
const providerInfo = this._chatService.getProviderInfos()?.[0];
|
const widget = await showChatView(this._viewsService);
|
||||||
if (!providerInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const widget = await this._chatWidgetService.revealViewForProvider(providerInfo.id);
|
|
||||||
const request = this._currentRequest;
|
const request = this._currentRequest;
|
||||||
if (!widget || !request?.response) {
|
if (!widget || !request?.response) {
|
||||||
return;
|
return;
|
||||||
|
|
6
src/vscode-dts/vscode.proposed.chatTab.d.ts
vendored
6
src/vscode-dts/vscode.proposed.chatTab.d.ts
vendored
|
@ -8,11 +8,7 @@ declare module 'vscode' {
|
||||||
* The tab represents an interactive window.
|
* The tab represents an interactive window.
|
||||||
*/
|
*/
|
||||||
export class TabInputChat {
|
export class TabInputChat {
|
||||||
/**
|
constructor();
|
||||||
* The uri of the history notebook in the interactive window.
|
|
||||||
*/
|
|
||||||
readonly providerId: string;
|
|
||||||
constructor(providerId: string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Tab {
|
export interface Tab {
|
||||||
|
|
|
@ -128,6 +128,9 @@ declare module 'vscode' {
|
||||||
// current version of the proposal.
|
// current version of the proposal.
|
||||||
export const _version: 1 | number;
|
export const _version: 1 | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
export function registerInteractiveSessionProvider(id: string, provider: InteractiveSessionProvider): Disposable;
|
export function registerInteractiveSessionProvider(id: string, provider: InteractiveSessionProvider): Disposable;
|
||||||
|
|
||||||
export function registerInteractiveEditorSessionProvider(provider: InteractiveEditorSessionProvider, metadata?: InteractiveEditorSessionProviderMetadata): Disposable;
|
export function registerInteractiveEditorSessionProvider(provider: InteractiveEditorSessionProvider, metadata?: InteractiveEditorSessionProviderMetadata): Disposable;
|
||||||
|
|
Loading…
Reference in a new issue