Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/common/chatService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IAction } from '../../../../base/common/actions.js';
7
import { DeferredPromise } from '../../../../base/common/async.js';
8
import { CancellationToken } from '../../../../base/common/cancellation.js';
9
import { Event } from '../../../../base/common/event.js';
10
import { IMarkdownString } from '../../../../base/common/htmlContent.js';
11
import { IObservable } from '../../../../base/common/observable.js';
12
import { ThemeIcon } from '../../../../base/common/themables.js';
13
import { URI } from '../../../../base/common/uri.js';
14
import { IRange, Range } from '../../../../editor/common/core/range.js';
15
import { ISelection } from '../../../../editor/common/core/selection.js';
16
import { Command, Location, TextEdit } from '../../../../editor/common/languages.js';
17
import { FileType } from '../../../../platform/files/common/files.js';
18
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
19
import { ICellEditOperation } from '../../notebook/common/notebookCommon.js';
20
import { IWorkspaceSymbol } from '../../search/common/search.js';
21
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, UserSelectedTools } from './chatAgents.js';
22
import { ChatModel, IChatModel, IChatRequestModeInfo, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData } from './chatModel.js';
23
import { IParsedChatRequest } from './chatParserTypes.js';
24
import { IChatParserContext } from './chatRequestParser.js';
25
import { IChatRequestVariableEntry } from './chatVariableEntries.js';
26
import { IChatRequestVariableValue } from './chatVariables.js';
27
import { ChatAgentLocation, ChatModeKind } from './constants.js';
28
import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult, IToolResultInputOutputDetails, ToolDataSource } from './languageModelToolsService.js';
29
30
export interface IChatRequest {
31
message: string;
32
variables: Record<string, IChatRequestVariableValue[]>;
33
}
34
35
export enum ChatErrorLevel {
36
Info = 0,
37
Warning = 1,
38
Error = 2
39
}
40
41
export interface IChatResponseErrorDetailsConfirmationButton {
42
data: any;
43
label: string;
44
isSecondary?: boolean;
45
}
46
47
export interface IChatResponseErrorDetails {
48
message: string;
49
responseIsIncomplete?: boolean;
50
responseIsFiltered?: boolean;
51
responseIsRedacted?: boolean;
52
isQuotaExceeded?: boolean;
53
level?: ChatErrorLevel;
54
confirmationButtons?: IChatResponseErrorDetailsConfirmationButton[];
55
code?: string;
56
}
57
58
export interface IChatResponseProgressFileTreeData {
59
label: string;
60
uri: URI;
61
type?: FileType;
62
children?: IChatResponseProgressFileTreeData[];
63
}
64
65
export type IDocumentContext = {
66
uri: URI;
67
version: number;
68
ranges: IRange[];
69
};
70
71
export function isIDocumentContext(obj: unknown): obj is IDocumentContext {
72
return (
73
!!obj &&
74
typeof obj === 'object' &&
75
'uri' in obj && obj.uri instanceof URI &&
76
'version' in obj && typeof obj.version === 'number' &&
77
'ranges' in obj && Array.isArray(obj.ranges) && obj.ranges.every(Range.isIRange)
78
);
79
}
80
81
export interface IChatUsedContext {
82
documents: IDocumentContext[];
83
kind: 'usedContext';
84
}
85
86
export function isIUsedContext(obj: unknown): obj is IChatUsedContext {
87
return (
88
!!obj &&
89
typeof obj === 'object' &&
90
'documents' in obj &&
91
Array.isArray(obj.documents) &&
92
obj.documents.every(isIDocumentContext)
93
);
94
}
95
96
export interface IChatContentVariableReference {
97
variableName: string;
98
value?: URI | Location;
99
}
100
101
export enum ChatResponseReferencePartStatusKind {
102
Complete = 1,
103
Partial = 2,
104
Omitted = 3
105
}
106
107
export enum ChatResponseClearToPreviousToolInvocationReason {
108
NoReason = 0,
109
FilteredContentRetry = 1,
110
CopyrightContentRetry = 2,
111
}
112
113
export interface IChatContentReference {
114
reference: URI | Location | IChatContentVariableReference | string;
115
iconPath?: ThemeIcon | { light: URI; dark?: URI };
116
options?: {
117
status?: { description: string; kind: ChatResponseReferencePartStatusKind };
118
diffMeta?: { added: number; removed: number };
119
};
120
kind: 'reference';
121
}
122
123
export interface IChatChangesSummary {
124
readonly reference: URI;
125
readonly sessionId: string;
126
readonly requestId: string;
127
readonly kind: 'changesSummary';
128
}
129
130
export interface IChatCodeCitation {
131
value: URI;
132
license: string;
133
snippet: string;
134
kind: 'codeCitation';
135
}
136
137
export interface IChatContentInlineReference {
138
resolveId?: string;
139
inlineReference: URI | Location | IWorkspaceSymbol;
140
name?: string;
141
kind: 'inlineReference';
142
}
143
144
export interface IChatMarkdownContent {
145
content: IMarkdownString;
146
inlineReferences?: Record<string, IChatContentInlineReference>;
147
kind: 'markdownContent';
148
}
149
150
export interface IChatTreeData {
151
treeData: IChatResponseProgressFileTreeData;
152
kind: 'treeData';
153
}
154
export interface IChatMultiDiffData {
155
multiDiffData: {
156
title: string;
157
resources: Array<{
158
originalUri?: URI;
159
modifiedUri?: URI;
160
goToFileUri?: URI;
161
added?: number;
162
removed?: number;
163
}>;
164
};
165
kind: 'multiDiffData';
166
}
167
168
export interface IChatProgressMessage {
169
content: IMarkdownString;
170
kind: 'progressMessage';
171
}
172
173
export interface IChatTask extends IChatTaskDto {
174
deferred: DeferredPromise<string | void>;
175
progress: (IChatWarningMessage | IChatContentReference)[];
176
onDidAddProgress: Event<IChatWarningMessage | IChatContentReference>;
177
add(progress: IChatWarningMessage | IChatContentReference): void;
178
179
complete: (result: string | void) => void;
180
task: () => Promise<string | void>;
181
isSettled: () => boolean;
182
}
183
184
export interface IChatUndoStop {
185
kind: 'undoStop';
186
id: string;
187
}
188
189
export interface IChatTaskDto {
190
content: IMarkdownString;
191
kind: 'progressTask';
192
}
193
194
export interface IChatTaskSerialized {
195
content: IMarkdownString;
196
progress: (IChatWarningMessage | IChatContentReference)[];
197
kind: 'progressTaskSerialized';
198
}
199
200
export interface IChatTaskResult {
201
content: IMarkdownString | void;
202
kind: 'progressTaskResult';
203
}
204
205
export interface IChatWarningMessage {
206
content: IMarkdownString;
207
kind: 'warning';
208
}
209
210
export interface IChatAgentVulnerabilityDetails {
211
title: string;
212
description: string;
213
}
214
215
export interface IChatResponseCodeblockUriPart {
216
kind: 'codeblockUri';
217
uri: URI;
218
isEdit?: boolean;
219
}
220
221
export interface IChatAgentMarkdownContentWithVulnerability {
222
content: IMarkdownString;
223
vulnerabilities: IChatAgentVulnerabilityDetails[];
224
kind: 'markdownVuln';
225
}
226
227
export interface IChatCommandButton {
228
command: Command;
229
kind: 'command';
230
}
231
232
export interface IChatMoveMessage {
233
uri: URI;
234
range: IRange;
235
kind: 'move';
236
}
237
238
export interface IChatTextEdit {
239
uri: URI;
240
edits: TextEdit[];
241
kind: 'textEdit';
242
done?: boolean;
243
}
244
245
export interface IChatClearToPreviousToolInvocation {
246
kind: 'clearToPreviousToolInvocation';
247
reason: ChatResponseClearToPreviousToolInvocationReason;
248
}
249
250
export interface IChatNotebookEdit {
251
uri: URI;
252
edits: ICellEditOperation[];
253
kind: 'notebookEdit';
254
done?: boolean;
255
}
256
257
export interface IChatConfirmation {
258
title: string;
259
message: string | IMarkdownString;
260
data: any;
261
buttons?: string[];
262
isUsed?: boolean;
263
kind: 'confirmation';
264
}
265
266
export interface IChatElicitationRequest {
267
kind: 'elicitation';
268
title: string | IMarkdownString;
269
message: string | IMarkdownString;
270
acceptButtonLabel: string;
271
rejectButtonLabel: string;
272
subtitle?: string | IMarkdownString;
273
source?: ToolDataSource;
274
state: 'pending' | 'accepted' | 'rejected';
275
acceptedResult?: Record<string, unknown>;
276
moreActions?: IAction[];
277
accept(value: IAction | true): Promise<void>;
278
reject(): Promise<void>;
279
onDidRequestHide?: Event<void>;
280
}
281
282
export interface IChatThinkingPart {
283
kind: 'thinking';
284
value?: string | string[];
285
id?: string;
286
metadata?: { readonly [key: string]: any };
287
}
288
289
export interface IChatTerminalToolInvocationData {
290
kind: 'terminal';
291
commandLine: {
292
original: string;
293
userEdited?: string;
294
toolEdited?: string;
295
};
296
/** Message for model recommending the use of an alternative tool */
297
alternativeRecommendation?: string;
298
language: string;
299
terminalToolSessionId?: string;
300
autoApproveInfo?: IMarkdownString;
301
}
302
303
/**
304
* @deprecated This is the old API shape, we should support this for a while before removing it so
305
* we don't break existing chats
306
*/
307
export interface ILegacyChatTerminalToolInvocationData {
308
kind: 'terminal';
309
command: string;
310
language: string;
311
}
312
313
export interface IChatToolInputInvocationData {
314
kind: 'input';
315
rawInput: any;
316
}
317
318
export const enum ToolConfirmKind {
319
Denied,
320
ConfirmationNotNeeded,
321
Setting,
322
LmServicePerTool,
323
UserAction,
324
Skipped
325
}
326
327
export type ConfirmedReason =
328
| { type: ToolConfirmKind.Denied }
329
| { type: ToolConfirmKind.ConfirmationNotNeeded }
330
| { type: ToolConfirmKind.Setting; id: string }
331
| { type: ToolConfirmKind.LmServicePerTool; scope: 'session' | 'workspace' | 'profile' }
332
| { type: ToolConfirmKind.UserAction }
333
| { type: ToolConfirmKind.Skipped };
334
335
export interface IChatToolInvocation {
336
presentation: IPreparedToolInvocation['presentation'];
337
toolSpecificData?: IChatTerminalToolInvocationData | ILegacyChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent;
338
/** Presence of this property says that confirmation is required */
339
confirmationMessages?: IToolConfirmationMessages;
340
confirmed: DeferredPromise<ConfirmedReason>;
341
/** undefined=don't know yet. */
342
isConfirmed: ConfirmedReason | undefined;
343
originMessage: string | IMarkdownString | undefined;
344
invocationMessage: string | IMarkdownString;
345
pastTenseMessage: string | IMarkdownString | undefined;
346
resultDetails: IToolResult['toolResultDetails'];
347
source: ToolDataSource;
348
progress: IObservable<{ message?: string | IMarkdownString; progress: number }>;
349
readonly toolId: string;
350
readonly toolCallId: string;
351
352
isCompletePromise: Promise<void>;
353
isComplete: boolean;
354
complete(result: IToolResult): void;
355
kind: 'toolInvocation';
356
}
357
358
export interface IToolResultOutputDetailsSerialized {
359
output: {
360
type: 'data';
361
mimeType: string;
362
base64Data: string;
363
};
364
}
365
366
/**
367
* This is a IChatToolInvocation that has been serialized, like after window reload, so it is no longer an active tool invocation.
368
*/
369
export interface IChatToolInvocationSerialized {
370
presentation: IPreparedToolInvocation['presentation'];
371
toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent;
372
invocationMessage: string | IMarkdownString;
373
originMessage: string | IMarkdownString | undefined;
374
pastTenseMessage: string | IMarkdownString | undefined;
375
resultDetails?: Array<URI | Location> | IToolResultInputOutputDetails | IToolResultOutputDetailsSerialized;
376
/** boolean used by pre-1.104 versions */
377
isConfirmed: ConfirmedReason | boolean | undefined;
378
isComplete: boolean;
379
toolCallId: string;
380
toolId: string;
381
source: ToolDataSource;
382
kind: 'toolInvocationSerialized';
383
}
384
385
export interface IChatExtensionsContent {
386
extensions: string[];
387
kind: 'extensions';
388
}
389
390
export interface IChatPullRequestContent {
391
uri: URI;
392
title: string;
393
description: string;
394
author: string;
395
linkTag: string;
396
kind: 'pullRequest';
397
}
398
399
export interface IChatTodoListContent {
400
kind: 'todoList';
401
sessionId: string;
402
todoList: Array<{
403
id: string;
404
title: string;
405
description: string;
406
status: 'not-started' | 'in-progress' | 'completed';
407
}>;
408
}
409
410
export interface IChatPrepareToolInvocationPart {
411
readonly kind: 'prepareToolInvocation';
412
readonly toolName: string;
413
}
414
415
export type IChatProgress =
416
| IChatMarkdownContent
417
| IChatAgentMarkdownContentWithVulnerability
418
| IChatTreeData
419
| IChatMultiDiffData
420
| IChatUsedContext
421
| IChatContentReference
422
| IChatContentInlineReference
423
| IChatCodeCitation
424
| IChatProgressMessage
425
| IChatTask
426
| IChatTaskResult
427
| IChatCommandButton
428
| IChatWarningMessage
429
| IChatTextEdit
430
| IChatNotebookEdit
431
| IChatMoveMessage
432
| IChatResponseCodeblockUriPart
433
| IChatConfirmation
434
| IChatClearToPreviousToolInvocation
435
| IChatToolInvocation
436
| IChatToolInvocationSerialized
437
| IChatExtensionsContent
438
| IChatPullRequestContent
439
| IChatUndoStop
440
| IChatPrepareToolInvocationPart
441
| IChatThinkingPart
442
| IChatTaskSerialized
443
| IChatElicitationRequest;
444
445
export interface IChatFollowup {
446
kind: 'reply';
447
message: string;
448
agentId: string;
449
subCommand?: string;
450
title?: string;
451
tooltip?: string;
452
}
453
454
export enum ChatAgentVoteDirection {
455
Down = 0,
456
Up = 1
457
}
458
459
export enum ChatAgentVoteDownReason {
460
IncorrectCode = 'incorrectCode',
461
DidNotFollowInstructions = 'didNotFollowInstructions',
462
IncompleteCode = 'incompleteCode',
463
MissingContext = 'missingContext',
464
PoorlyWrittenOrFormatted = 'poorlyWrittenOrFormatted',
465
RefusedAValidRequest = 'refusedAValidRequest',
466
OffensiveOrUnsafe = 'offensiveOrUnsafe',
467
Other = 'other',
468
WillReportIssue = 'willReportIssue'
469
}
470
471
export interface IChatVoteAction {
472
kind: 'vote';
473
direction: ChatAgentVoteDirection;
474
reason: ChatAgentVoteDownReason | undefined;
475
}
476
477
export enum ChatCopyKind {
478
// Keyboard shortcut or context menu
479
Action = 1,
480
Toolbar = 2
481
}
482
483
export interface IChatCopyAction {
484
kind: 'copy';
485
codeBlockIndex: number;
486
copyKind: ChatCopyKind;
487
copiedCharacters: number;
488
totalCharacters: number;
489
copiedText: string;
490
totalLines: number;
491
copiedLines: number;
492
modelId: string;
493
languageId?: string;
494
}
495
496
export interface IChatInsertAction {
497
kind: 'insert';
498
codeBlockIndex: number;
499
totalCharacters: number;
500
totalLines: number;
501
languageId?: string;
502
modelId: string;
503
newFile?: boolean;
504
}
505
506
export interface IChatApplyAction {
507
kind: 'apply';
508
codeBlockIndex: number;
509
totalCharacters: number;
510
totalLines: number;
511
languageId?: string;
512
modelId: string;
513
newFile?: boolean;
514
codeMapper?: string;
515
editsProposed: boolean;
516
}
517
518
519
export interface IChatTerminalAction {
520
kind: 'runInTerminal';
521
codeBlockIndex: number;
522
languageId?: string;
523
}
524
525
export interface IChatCommandAction {
526
kind: 'command';
527
commandButton: IChatCommandButton;
528
}
529
530
export interface IChatFollowupAction {
531
kind: 'followUp';
532
followup: IChatFollowup;
533
}
534
535
export interface IChatBugReportAction {
536
kind: 'bug';
537
}
538
539
export interface IChatInlineChatCodeAction {
540
kind: 'inlineChat';
541
action: 'accepted' | 'discarded';
542
}
543
544
545
export interface IChatEditingSessionAction {
546
kind: 'chatEditingSessionAction';
547
uri: URI;
548
hasRemainingEdits: boolean;
549
outcome: 'accepted' | 'rejected' | 'userModified';
550
}
551
552
export interface IChatEditingHunkAction {
553
kind: 'chatEditingHunkAction';
554
uri: URI;
555
lineCount: number;
556
linesAdded: number;
557
linesRemoved: number;
558
outcome: 'accepted' | 'rejected';
559
hasRemainingEdits: boolean;
560
modeId?: string;
561
modelId?: string;
562
languageId?: string;
563
}
564
565
export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction | IChatEditingSessionAction | IChatEditingHunkAction;
566
567
export interface IChatUserActionEvent {
568
action: ChatUserAction;
569
agentId: string | undefined;
570
command: string | undefined;
571
sessionId: string;
572
requestId: string;
573
result: IChatAgentResult | undefined;
574
modelId?: string | undefined;
575
modeId?: string | undefined;
576
}
577
578
export interface IChatDynamicRequest {
579
/**
580
* The message that will be displayed in the UI
581
*/
582
message: string;
583
584
/**
585
* Any extra metadata/context that will go to the provider.
586
*/
587
metadata?: any;
588
}
589
590
export interface IChatCompleteResponse {
591
message: string | ReadonlyArray<IChatProgress>;
592
result?: IChatAgentResult;
593
followups?: IChatFollowup[];
594
}
595
596
export interface IChatDetail {
597
sessionId: string;
598
title: string;
599
lastMessageDate: number;
600
isActive: boolean;
601
}
602
603
export interface IChatProviderInfo {
604
id: string;
605
}
606
607
export interface IChatTransferredSessionData {
608
sessionId: string;
609
inputValue: string;
610
location: ChatAgentLocation;
611
mode: ChatModeKind;
612
}
613
614
export interface IChatSendRequestResponseState {
615
responseCreatedPromise: Promise<IChatResponseModel>;
616
responseCompletePromise: Promise<void>;
617
}
618
619
export interface IChatSendRequestData extends IChatSendRequestResponseState {
620
agent: IChatAgentData;
621
slashCommand?: IChatAgentCommand;
622
}
623
624
export interface IChatEditorLocationData {
625
type: ChatAgentLocation.Editor;
626
document: URI;
627
selection: ISelection;
628
wholeRange: IRange;
629
}
630
631
export interface IChatNotebookLocationData {
632
type: ChatAgentLocation.Notebook;
633
sessionInputUri: URI;
634
}
635
636
export interface IChatTerminalLocationData {
637
type: ChatAgentLocation.Terminal;
638
// TBD
639
}
640
641
export type IChatLocationData = IChatEditorLocationData | IChatNotebookLocationData | IChatTerminalLocationData;
642
643
export interface IChatSendRequestOptions {
644
modeInfo?: IChatRequestModeInfo;
645
userSelectedModelId?: string;
646
userSelectedTools?: IObservable<UserSelectedTools>;
647
location?: ChatAgentLocation;
648
locationData?: IChatLocationData;
649
parserContext?: IChatParserContext;
650
attempt?: number;
651
noCommandDetection?: boolean;
652
acceptedConfirmationData?: any[];
653
rejectedConfirmationData?: any[];
654
attachedContext?: IChatRequestVariableEntry[];
655
656
/** The target agent ID can be specified with this property instead of using @ in 'message' */
657
agentId?: string;
658
/** agentId, but will not add a @ name to the request */
659
agentIdSilent?: string;
660
slashCommand?: string;
661
662
/**
663
* The label of the confirmation action that was selected.
664
*/
665
confirmation?: string;
666
}
667
668
export const IChatService = createDecorator<IChatService>('IChatService');
669
670
export interface IChatService {
671
_serviceBrand: undefined;
672
transferredSessionData: IChatTransferredSessionData | undefined;
673
674
onDidSubmitRequest: Event<{ chatSessionId: string }>;
675
676
isEnabled(location: ChatAgentLocation): boolean;
677
hasSessions(): boolean;
678
startSession(location: ChatAgentLocation, token: CancellationToken, isGlobalEditingSession?: boolean): ChatModel;
679
getSession(sessionId: string): IChatModel | undefined;
680
getOrRestoreSession(sessionId: string): Promise<IChatModel | undefined>;
681
getPersistedSessionTitle(sessionId: string): string | undefined;
682
isPersistedSessionEmpty(sessionId: string): boolean;
683
loadSessionFromContent(data: IExportableChatData | ISerializableChatData | URI): IChatModel | undefined;
684
loadSessionForResource(resource: URI, location: ChatAgentLocation, token: CancellationToken): Promise<IChatModel | undefined>;
685
686
/**
687
* Returns whether the request was accepted.
688
*/
689
sendRequest(sessionId: string, message: string, options?: IChatSendRequestOptions): Promise<IChatSendRequestData | undefined>;
690
691
resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions): Promise<void>;
692
adoptRequest(sessionId: string, request: IChatRequestModel): Promise<void>;
693
removeRequest(sessionid: string, requestId: string): Promise<void>;
694
cancelCurrentRequestForSession(sessionId: string): void;
695
clearSession(sessionId: string): Promise<void>;
696
addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, attempt: number | undefined, response: IChatCompleteResponse): void;
697
getHistory(): Promise<IChatDetail[]>;
698
setChatSessionTitle(sessionId: string, title: string): void;
699
clearAllHistoryEntries(): Promise<void>;
700
removeHistoryEntry(sessionId: string): Promise<void>;
701
getChatStorageFolder(): URI;
702
logChatIndex(): void;
703
704
onDidPerformUserAction: Event<IChatUserActionEvent>;
705
notifyUserAction(event: IChatUserActionEvent): void;
706
onDidDisposeSession: Event<{ sessionId: string; reason: 'cleared' }>;
707
708
transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void;
709
710
activateDefaultAgent(location: ChatAgentLocation): Promise<void>;
711
712
readonly edits2Enabled: boolean;
713
714
readonly requestInProgressObs: IObservable<boolean>;
715
}
716
717
export const KEYWORD_ACTIVIATION_SETTING_ID = 'accessibility.voice.keywordActivation';
718
719