Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/common/chatService/chatService.ts
5251 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 { DisposableStore, IReference } from '../../../../../base/common/lifecycle.js';
12
import { autorun, autorunSelfDisposable, IObservable, IReader } from '../../../../../base/common/observable.js';
13
import { ThemeIcon } from '../../../../../base/common/themables.js';
14
import { hasKey } from '../../../../../base/common/types.js';
15
import { URI, UriComponents } from '../../../../../base/common/uri.js';
16
import { IRange, Range } from '../../../../../editor/common/core/range.js';
17
import { HookTypeValue } from '../promptSyntax/hookSchema.js';
18
import { ISelection } from '../../../../../editor/common/core/selection.js';
19
import { Command, Location, TextEdit } from '../../../../../editor/common/languages.js';
20
import { FileType } from '../../../../../platform/files/common/files.js';
21
import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js';
22
import { IAutostartResult } from '../../../mcp/common/mcpTypes.js';
23
import { ICellEditOperation } from '../../../notebook/common/notebookCommon.js';
24
import { IWorkspaceSymbol } from '../../../search/common/search.js';
25
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, UserSelectedTools } from '../participants/chatAgents.js';
26
import { IChatEditingSession } from '../editing/chatEditingService.js';
27
import { IChatModel, IChatRequestModeInfo, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData } from '../model/chatModel.js';
28
import { IParsedChatRequest } from '../requestParser/chatParserTypes.js';
29
import { IChatParserContext } from '../requestParser/chatRequestParser.js';
30
import { IChatRequestVariableEntry } from '../attachments/chatVariableEntries.js';
31
import { IChatRequestVariableValue } from '../attachments/chatVariables.js';
32
import { ChatAgentLocation } from '../constants.js';
33
import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult, IToolResultInputOutputDetails, ToolDataSource } from '../tools/languageModelToolsService.js';
34
35
export interface IChatRequest {
36
message: string;
37
variables: Record<string, IChatRequestVariableValue[]>;
38
}
39
40
export enum ChatErrorLevel {
41
Info = 0,
42
Warning = 1,
43
Error = 2
44
}
45
46
export interface IChatResponseErrorDetailsConfirmationButton {
47
// eslint-disable-next-line @typescript-eslint/no-explicit-any
48
data: any;
49
label: string;
50
isSecondary?: boolean;
51
}
52
53
export interface IChatResponseErrorDetails {
54
message: string;
55
responseIsIncomplete?: boolean;
56
responseIsFiltered?: boolean;
57
responseIsRedacted?: boolean;
58
isQuotaExceeded?: boolean;
59
isRateLimited?: boolean;
60
level?: ChatErrorLevel;
61
confirmationButtons?: IChatResponseErrorDetailsConfirmationButton[];
62
code?: string;
63
}
64
65
export interface IChatResponseProgressFileTreeData {
66
label: string;
67
uri: URI;
68
type?: FileType;
69
children?: IChatResponseProgressFileTreeData[];
70
}
71
72
export type IDocumentContext = {
73
uri: URI;
74
version: number;
75
ranges: IRange[];
76
};
77
78
export function isIDocumentContext(obj: unknown): obj is IDocumentContext {
79
return (
80
!!obj &&
81
typeof obj === 'object' &&
82
'uri' in obj && obj.uri instanceof URI &&
83
'version' in obj && typeof obj.version === 'number' &&
84
'ranges' in obj && Array.isArray(obj.ranges) && obj.ranges.every(Range.isIRange)
85
);
86
}
87
88
export interface IChatUsedContext {
89
documents: IDocumentContext[];
90
kind: 'usedContext';
91
}
92
93
export function isIUsedContext(obj: unknown): obj is IChatUsedContext {
94
return (
95
!!obj &&
96
typeof obj === 'object' &&
97
'documents' in obj &&
98
Array.isArray(obj.documents) &&
99
obj.documents.every(isIDocumentContext)
100
);
101
}
102
103
export interface IChatContentVariableReference {
104
variableName: string;
105
value?: URI | Location;
106
}
107
108
export function isChatContentVariableReference(obj: unknown): obj is IChatContentVariableReference {
109
return !!obj &&
110
typeof obj === 'object' &&
111
typeof (obj as IChatContentVariableReference).variableName === 'string';
112
}
113
114
export enum ChatResponseReferencePartStatusKind {
115
Complete = 1,
116
Partial = 2,
117
Omitted = 3
118
}
119
120
export enum ChatResponseClearToPreviousToolInvocationReason {
121
NoReason = 0,
122
FilteredContentRetry = 1,
123
CopyrightContentRetry = 2,
124
}
125
126
export interface IChatContentReference {
127
reference: URI | Location | IChatContentVariableReference | string;
128
iconPath?: ThemeIcon | { light: URI; dark?: URI };
129
options?: {
130
status?: { description: string; kind: ChatResponseReferencePartStatusKind };
131
diffMeta?: { added: number; removed: number };
132
originalUri?: URI;
133
isDeletion?: boolean;
134
};
135
kind: 'reference';
136
}
137
138
export interface IChatCodeCitation {
139
value: URI;
140
license: string;
141
snippet: string;
142
kind: 'codeCitation';
143
}
144
145
export interface IChatUsagePromptTokenDetail {
146
category: string;
147
label: string;
148
percentageOfPrompt: number;
149
}
150
151
export interface IChatUsage {
152
promptTokens: number;
153
completionTokens: number;
154
promptTokenDetails?: readonly IChatUsagePromptTokenDetail[];
155
kind: 'usage';
156
}
157
158
export interface IChatContentInlineReference {
159
resolveId?: string;
160
inlineReference: URI | Location | IWorkspaceSymbol;
161
name?: string;
162
kind: 'inlineReference';
163
}
164
165
export interface IChatMarkdownContent {
166
kind: 'markdownContent';
167
content: IMarkdownString;
168
inlineReferences?: Record<string, IChatContentInlineReference>;
169
}
170
171
export interface IChatTreeData {
172
treeData: IChatResponseProgressFileTreeData;
173
kind: 'treeData';
174
}
175
export interface IMultiDiffResource {
176
originalUri?: URI;
177
modifiedUri?: URI;
178
goToFileUri?: URI;
179
added?: number;
180
removed?: number;
181
}
182
183
export interface IChatMultiDiffInnerData {
184
title: string;
185
resources: IMultiDiffResource[];
186
}
187
188
export interface IChatMultiDiffData {
189
multiDiffData: IChatMultiDiffInnerData | IObservable<IChatMultiDiffInnerData>;
190
kind: 'multiDiffData';
191
collapsed?: boolean;
192
readOnly?: boolean;
193
toJSON(): IChatMultiDiffDataSerialized;
194
}
195
196
export interface IChatMultiDiffDataSerialized {
197
multiDiffData: IChatMultiDiffInnerData;
198
kind: 'multiDiffData';
199
collapsed?: boolean;
200
readOnly?: boolean;
201
}
202
203
export class ChatMultiDiffData implements IChatMultiDiffData {
204
public readonly kind = 'multiDiffData';
205
public readonly collapsed?: boolean | undefined;
206
public readonly readOnly?: boolean | undefined;
207
public readonly multiDiffData: IChatMultiDiffData['multiDiffData'];
208
209
constructor(opts: {
210
multiDiffData: IChatMultiDiffInnerData | IObservable<IChatMultiDiffInnerData>;
211
collapsed?: boolean;
212
readOnly?: boolean;
213
}) {
214
this.readOnly = opts.readOnly;
215
this.collapsed = opts.collapsed;
216
this.multiDiffData = opts.multiDiffData;
217
}
218
219
toJSON(): IChatMultiDiffDataSerialized {
220
return {
221
kind: this.kind,
222
multiDiffData: hasKey(this.multiDiffData, { title: true }) ? this.multiDiffData : this.multiDiffData.get(),
223
collapsed: this.collapsed,
224
readOnly: this.readOnly,
225
};
226
}
227
}
228
229
export interface IChatProgressMessage {
230
content: IMarkdownString;
231
kind: 'progressMessage';
232
}
233
234
export interface IChatTask extends IChatTaskDto {
235
deferred: DeferredPromise<string | void>;
236
progress: (IChatWarningMessage | IChatContentReference)[];
237
readonly onDidAddProgress: Event<IChatWarningMessage | IChatContentReference>;
238
add(progress: IChatWarningMessage | IChatContentReference): void;
239
240
complete: (result: string | void) => void;
241
task: () => Promise<string | void>;
242
isSettled: () => boolean;
243
toJSON(): IChatTaskSerialized;
244
}
245
246
export interface IChatUndoStop {
247
kind: 'undoStop';
248
id: string;
249
}
250
251
export interface IChatExternalEditsDto {
252
kind: 'externalEdits';
253
undoStopId: string;
254
start: boolean; /** true=start, false=stop */
255
resources: UriComponents[];
256
}
257
258
export interface IChatTaskDto {
259
content: IMarkdownString;
260
kind: 'progressTask';
261
}
262
263
export interface IChatTaskSerialized {
264
content: IMarkdownString;
265
progress: (IChatWarningMessage | IChatContentReference)[];
266
kind: 'progressTaskSerialized';
267
}
268
269
export interface IChatTaskResult {
270
content: IMarkdownString | void;
271
kind: 'progressTaskResult';
272
}
273
274
export interface IChatWarningMessage {
275
content: IMarkdownString;
276
kind: 'warning';
277
}
278
279
export interface IChatAgentVulnerabilityDetails {
280
title: string;
281
description: string;
282
}
283
284
export interface IChatResponseCodeblockUriPart {
285
kind: 'codeblockUri';
286
uri: URI;
287
isEdit?: boolean;
288
undoStopId?: string;
289
subAgentInvocationId?: string;
290
}
291
292
export interface IChatAgentMarkdownContentWithVulnerability {
293
content: IMarkdownString;
294
vulnerabilities: IChatAgentVulnerabilityDetails[];
295
kind: 'markdownVuln';
296
}
297
298
export interface IChatCommandButton {
299
command: Command;
300
kind: 'command';
301
additionalCommands?: Command[]; // rendered as secondary buttons
302
}
303
304
export interface IChatMoveMessage {
305
uri: URI;
306
range: IRange;
307
kind: 'move';
308
}
309
310
export interface IChatTextEdit {
311
uri: URI;
312
edits: TextEdit[];
313
kind: 'textEdit';
314
done?: boolean;
315
isExternalEdit?: boolean;
316
}
317
318
export interface IChatClearToPreviousToolInvocation {
319
kind: 'clearToPreviousToolInvocation';
320
reason: ChatResponseClearToPreviousToolInvocationReason;
321
}
322
323
export interface IChatNotebookEdit {
324
uri: URI;
325
edits: ICellEditOperation[];
326
kind: 'notebookEdit';
327
done?: boolean;
328
isExternalEdit?: boolean;
329
}
330
331
export interface IChatWorkspaceFileEdit {
332
oldResource?: URI;
333
newResource?: URI;
334
}
335
336
export interface IChatWorkspaceEdit {
337
kind: 'workspaceEdit';
338
edits: IChatWorkspaceFileEdit[];
339
}
340
341
export interface IChatConfirmation {
342
title: string;
343
message: string | IMarkdownString;
344
// eslint-disable-next-line @typescript-eslint/no-explicit-any
345
data: any;
346
buttons?: string[];
347
isUsed?: boolean;
348
kind: 'confirmation';
349
}
350
351
/**
352
* Represents an individual question in a question carousel.
353
*/
354
export interface IChatQuestion {
355
id: string;
356
type: 'text' | 'singleSelect' | 'multiSelect';
357
title: string;
358
message?: string | IMarkdownString;
359
options?: { id: string; label: string; value: unknown }[];
360
defaultValue?: string | string[];
361
allowFreeformInput?: boolean;
362
}
363
364
/**
365
* A carousel for presenting multiple questions inline in the chat response.
366
* Users can navigate between questions and submit their answers.
367
*/
368
export interface IChatQuestionCarousel {
369
questions: IChatQuestion[];
370
allowSkip: boolean;
371
/** Unique identifier for resolving the carousel answers back to the extension */
372
resolveId?: string;
373
/** Storage for collected answers when user submits */
374
data?: Record<string, unknown>;
375
/** Whether the carousel has been submitted/skipped */
376
isUsed?: boolean;
377
kind: 'questionCarousel';
378
}
379
380
export const enum ElicitationState {
381
Pending = 'pending',
382
Accepted = 'accepted',
383
Rejected = 'rejected',
384
}
385
386
export interface IChatElicitationRequest {
387
kind: 'elicitation2'; // '2' because initially serialized data used the same kind
388
title: string | IMarkdownString;
389
message: string | IMarkdownString;
390
acceptButtonLabel: string;
391
rejectButtonLabel: string | undefined;
392
subtitle?: string | IMarkdownString;
393
source?: ToolDataSource;
394
state: IObservable<ElicitationState>;
395
acceptedResult?: Record<string, unknown>;
396
moreActions?: IAction[];
397
accept(value: IAction | true): Promise<void>;
398
reject?: () => Promise<void>;
399
isHidden?: IObservable<boolean>;
400
hide?(): void;
401
toJSON(): IChatElicitationRequestSerialized;
402
}
403
404
export interface IChatElicitationRequestSerialized {
405
kind: 'elicitationSerialized';
406
title: string | IMarkdownString;
407
message: string | IMarkdownString;
408
subtitle: string | IMarkdownString | undefined;
409
source: ToolDataSource | undefined;
410
state: ElicitationState.Accepted | ElicitationState.Rejected;
411
isHidden: boolean;
412
acceptedResult?: Record<string, unknown>;
413
}
414
415
export interface IChatThinkingPart {
416
kind: 'thinking';
417
value?: string | string[];
418
id?: string;
419
// eslint-disable-next-line @typescript-eslint/no-explicit-any
420
metadata?: { readonly [key: string]: any };
421
generatedTitle?: string;
422
}
423
424
/**
425
* A progress part representing the execution result of a hook.
426
* Aligned with the hook output JSON structure: { stopReason, systemMessage, hookSpecificOutput }.
427
* If {@link stopReason} is set, the hook blocked/denied the operation.
428
*/
429
export interface IChatHookPart {
430
kind: 'hook';
431
/** The type of hook that was executed */
432
hookType: HookTypeValue;
433
/** If set, the hook blocked processing. This message is shown to the user. */
434
stopReason?: string;
435
/** Warning/system message from the hook, shown to the user */
436
systemMessage?: string;
437
metadata?: { readonly [key: string]: unknown };
438
}
439
440
export interface IChatTerminalToolInvocationData {
441
kind: 'terminal';
442
commandLine: {
443
original: string;
444
userEdited?: string;
445
toolEdited?: string;
446
// command to show in the chat UI (potentially different from what is actually run in the terminal)
447
forDisplay?: string;
448
};
449
/** The working directory URI for the terminal */
450
cwd?: UriComponents;
451
/**
452
* Pre-computed confirmation display data (localization must happen at source).
453
* Contains the command line to show in confirmation (potentially without cd prefix)
454
* and the formatted cwd label if a cd prefix was extracted.
455
*/
456
confirmation?: {
457
/** The command line to display in the confirmation editor */
458
commandLine: string;
459
/** The formatted cwd label to show in title (if cd was extracted) */
460
cwdLabel?: string;
461
/** The cd prefix to prepend back when user edits */
462
cdPrefix?: string;
463
};
464
/**
465
* Overrides to apply to the presentation of the tool call only, but not actually change the
466
* command that gets run. For example, python -c "print('hello')" can be presented as just
467
* the Python code with Python syntax highlighting.
468
*/
469
presentationOverrides?: {
470
/** The command line to display in the UI */
471
commandLine: string;
472
/** The language for syntax highlighting */
473
language?: string;
474
};
475
/** Message for model recommending the use of an alternative tool */
476
alternativeRecommendation?: string;
477
language: string;
478
terminalToolSessionId?: string;
479
/** The predefined command ID that will be used for this terminal command */
480
terminalCommandId?: string;
481
/** Whether the terminal command was started as a background execution */
482
isBackground?: boolean;
483
/** Serialized URI for the command that was executed in the terminal */
484
terminalCommandUri?: UriComponents;
485
/** Serialized output of the executed command */
486
terminalCommandOutput?: {
487
text: string;
488
truncated?: boolean;
489
lineCount?: number;
490
};
491
/** Stored theme colors at execution time to style detached output */
492
terminalTheme?: {
493
background?: string;
494
foreground?: string;
495
};
496
/** Stored command state to restore decorations after reload */
497
terminalCommandState?: {
498
exitCode?: number;
499
timestamp?: number;
500
duration?: number;
501
};
502
/** Whether the user chose to continue in background for this tool invocation */
503
didContinueInBackground?: boolean;
504
autoApproveInfo?: IMarkdownString;
505
}
506
507
/**
508
* @deprecated This is the old API shape, we should support this for a while before removing it so
509
* we don't break existing chats
510
*/
511
export interface ILegacyChatTerminalToolInvocationData {
512
kind: 'terminal';
513
command: string;
514
language: string;
515
}
516
517
export function isLegacyChatTerminalToolInvocationData(data: unknown): data is ILegacyChatTerminalToolInvocationData {
518
return !!data && typeof data === 'object' && 'command' in data && 'language' in data;
519
}
520
521
export interface IChatToolInputInvocationData {
522
kind: 'input';
523
// eslint-disable-next-line @typescript-eslint/no-explicit-any
524
rawInput: any;
525
/** Optional MCP App UI metadata for rendering during and after tool execution */
526
mcpAppData?: {
527
/** URI of the UI resource for rendering (e.g., "ui://weather-server/dashboard") */
528
resourceUri: string;
529
/** Reference to the server definition for reconnection */
530
serverDefinitionId: string;
531
/** Reference to the collection containing the server */
532
collectionId: string;
533
};
534
}
535
536
export const enum ToolConfirmKind {
537
Denied,
538
ConfirmationNotNeeded,
539
Setting,
540
LmServicePerTool,
541
UserAction,
542
Skipped
543
}
544
545
export type ConfirmedReason =
546
| { type: ToolConfirmKind.Denied }
547
| { type: ToolConfirmKind.ConfirmationNotNeeded; reason?: string | IMarkdownString }
548
| { type: ToolConfirmKind.Setting; id: string }
549
| { type: ToolConfirmKind.LmServicePerTool; scope: 'session' | 'workspace' | 'profile' }
550
| { type: ToolConfirmKind.UserAction; selectedButton?: string }
551
| { type: ToolConfirmKind.Skipped };
552
553
export interface IChatToolInvocation {
554
readonly presentation: IPreparedToolInvocation['presentation'];
555
readonly toolSpecificData?: IChatTerminalToolInvocationData | ILegacyChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent | IChatSubagentToolInvocationData | IChatSimpleToolInvocationData | IChatToolResourcesInvocationData;
556
readonly originMessage: string | IMarkdownString | undefined;
557
readonly invocationMessage: string | IMarkdownString;
558
readonly pastTenseMessage: string | IMarkdownString | undefined;
559
readonly source: ToolDataSource;
560
readonly toolId: string;
561
readonly toolCallId: string;
562
readonly subAgentInvocationId?: string;
563
readonly state: IObservable<IChatToolInvocation.State>;
564
generatedTitle?: string;
565
566
kind: 'toolInvocation';
567
568
toJSON(): IChatToolInvocationSerialized;
569
}
570
571
export namespace IChatToolInvocation {
572
export const enum StateKind {
573
/** Tool call is streaming partial input from the LM */
574
Streaming,
575
WaitingForConfirmation,
576
Executing,
577
WaitingForPostApproval,
578
Completed,
579
Cancelled,
580
}
581
582
interface IChatToolInvocationStateBase {
583
type: StateKind;
584
}
585
586
export interface IChatToolInvocationStreamingState extends IChatToolInvocationStateBase {
587
type: StateKind.Streaming;
588
/** Observable partial input from the LM stream */
589
readonly partialInput: IObservable<unknown>;
590
/** Custom invocation message from handleToolStream */
591
readonly streamingMessage: IObservable<string | IMarkdownString | undefined>;
592
}
593
594
/** Properties available after streaming is complete */
595
interface IChatToolInvocationPostStreamState {
596
readonly parameters: unknown;
597
readonly confirmationMessages?: IToolConfirmationMessages;
598
}
599
600
interface IChatToolInvocationWaitingForConfirmationState extends IChatToolInvocationStateBase, IChatToolInvocationPostStreamState {
601
type: StateKind.WaitingForConfirmation;
602
confirm(reason: ConfirmedReason): void;
603
}
604
605
interface IChatToolInvocationPostConfirmState extends IChatToolInvocationPostStreamState {
606
confirmed: ConfirmedReason;
607
}
608
609
interface IChatToolInvocationExecutingState extends IChatToolInvocationStateBase, IChatToolInvocationPostConfirmState {
610
type: StateKind.Executing;
611
progress: IObservable<{ message?: string | IMarkdownString; progress: number | undefined }>;
612
}
613
614
interface IChatToolInvocationPostExecuteState extends IChatToolInvocationPostConfirmState {
615
resultDetails: IToolResult['toolResultDetails'];
616
}
617
618
interface IChatToolWaitingForPostApprovalState extends IChatToolInvocationStateBase, IChatToolInvocationPostExecuteState {
619
type: StateKind.WaitingForPostApproval;
620
confirm(reason: ConfirmedReason): void;
621
contentForModel: IToolResult['content'];
622
}
623
624
interface IChatToolInvocationCompleteState extends IChatToolInvocationStateBase, IChatToolInvocationPostExecuteState {
625
type: StateKind.Completed;
626
postConfirmed: ConfirmedReason | undefined;
627
contentForModel: IToolResult['content'];
628
}
629
630
interface IChatToolInvocationCancelledState extends IChatToolInvocationStateBase, IChatToolInvocationPostStreamState {
631
type: StateKind.Cancelled;
632
reason: ToolConfirmKind.Denied | ToolConfirmKind.Skipped;
633
/** Optional message explaining why the tool was cancelled (e.g., from hook denial) */
634
reasonMessage?: string | IMarkdownString;
635
}
636
637
export type State =
638
| IChatToolInvocationStreamingState
639
| IChatToolInvocationWaitingForConfirmationState
640
| IChatToolInvocationExecutingState
641
| IChatToolWaitingForPostApprovalState
642
| IChatToolInvocationCompleteState
643
| IChatToolInvocationCancelledState;
644
645
export function executionConfirmedOrDenied(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): ConfirmedReason | undefined {
646
if (invocation.kind === 'toolInvocationSerialized') {
647
if (invocation.isConfirmed === undefined || typeof invocation.isConfirmed === 'boolean') {
648
return { type: invocation.isConfirmed ? ToolConfirmKind.UserAction : ToolConfirmKind.Denied };
649
}
650
return invocation.isConfirmed;
651
}
652
653
const state = invocation.state.read(reader);
654
if (state.type === StateKind.Streaming || state.type === StateKind.WaitingForConfirmation) {
655
return undefined; // don't know yet
656
}
657
if (state.type === StateKind.Cancelled) {
658
return { type: state.reason };
659
}
660
661
return state.confirmed;
662
}
663
664
export function awaitConfirmation(invocation: IChatToolInvocation, token?: CancellationToken): Promise<ConfirmedReason> {
665
const reason = executionConfirmedOrDenied(invocation);
666
if (reason) {
667
return Promise.resolve(reason);
668
}
669
670
const store = new DisposableStore();
671
return new Promise<ConfirmedReason>(resolve => {
672
if (token) {
673
store.add(token.onCancellationRequested(() => {
674
resolve({ type: ToolConfirmKind.Denied });
675
}));
676
}
677
678
store.add(autorun(reader => {
679
const reason = executionConfirmedOrDenied(invocation, reader);
680
if (reason) {
681
store.dispose();
682
resolve(reason);
683
}
684
}));
685
}).finally(() => {
686
store.dispose();
687
});
688
}
689
690
function postApprovalConfirmedOrDenied(invocation: IChatToolInvocation, reader?: IReader): ConfirmedReason | undefined {
691
const state = invocation.state.read(reader);
692
if (state.type === StateKind.Completed) {
693
return state.postConfirmed || { type: ToolConfirmKind.ConfirmationNotNeeded };
694
}
695
if (state.type === StateKind.Cancelled) {
696
return { type: state.reason };
697
}
698
699
return undefined;
700
}
701
702
export function confirmWith(invocation: IChatToolInvocation | undefined, reason: ConfirmedReason) {
703
const state = invocation?.state.get();
704
if (state?.type === StateKind.WaitingForConfirmation || state?.type === StateKind.WaitingForPostApproval) {
705
state.confirm(reason);
706
return true;
707
}
708
return false;
709
}
710
711
export function awaitPostConfirmation(invocation: IChatToolInvocation, token?: CancellationToken): Promise<ConfirmedReason> {
712
const reason = postApprovalConfirmedOrDenied(invocation);
713
if (reason) {
714
return Promise.resolve(reason);
715
}
716
717
const store = new DisposableStore();
718
return new Promise<ConfirmedReason>(resolve => {
719
if (token) {
720
store.add(token.onCancellationRequested(() => {
721
resolve({ type: ToolConfirmKind.Denied });
722
}));
723
}
724
725
store.add(autorun(reader => {
726
const reason = postApprovalConfirmedOrDenied(invocation, reader);
727
if (reason) {
728
store.dispose();
729
resolve(reason);
730
}
731
}));
732
}).finally(() => {
733
store.dispose();
734
});
735
}
736
737
export function resultDetails(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader) {
738
if (invocation.kind === 'toolInvocationSerialized') {
739
return invocation.resultDetails;
740
}
741
742
const state = invocation.state.read(reader);
743
if (state.type === StateKind.Completed || state.type === StateKind.WaitingForPostApproval) {
744
return state.resultDetails;
745
}
746
747
return undefined;
748
}
749
750
export function isComplete(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): boolean {
751
if (invocation.kind === 'toolInvocationSerialized') {
752
return true; // always cancelled or complete
753
}
754
755
const state = invocation.state.read(reader);
756
return state.type === StateKind.Completed || state.type === StateKind.Cancelled;
757
}
758
759
export function isStreaming(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): boolean {
760
if (invocation.kind === 'toolInvocationSerialized') {
761
return false;
762
}
763
764
const state = invocation.state.read(reader);
765
return state.type === StateKind.Streaming;
766
}
767
768
/**
769
* Get parameters from invocation. Returns undefined during streaming state.
770
*/
771
export function getParameters(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): unknown | undefined {
772
if (invocation.kind === 'toolInvocationSerialized') {
773
return undefined; // serialized invocations don't store parameters
774
}
775
776
const state = invocation.state.read(reader);
777
if (state.type === StateKind.Streaming) {
778
return undefined;
779
}
780
781
return state.parameters;
782
}
783
784
/**
785
* Get confirmation messages from invocation. Returns undefined during streaming state.
786
*/
787
export function getConfirmationMessages(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): IToolConfirmationMessages | undefined {
788
if (invocation.kind === 'toolInvocationSerialized') {
789
return undefined; // serialized invocations don't store confirmation messages
790
}
791
792
const state = invocation.state.read(reader);
793
if (state.type === StateKind.Streaming) {
794
return undefined;
795
}
796
797
return state.confirmationMessages;
798
}
799
}
800
801
802
export interface IToolResultOutputDetailsSerialized {
803
output: {
804
type: 'data';
805
mimeType: string;
806
base64Data: string;
807
};
808
}
809
810
/**
811
* This is a IChatToolInvocation that has been serialized, like after window reload, so it is no longer an active tool invocation.
812
*/
813
export interface IChatToolInvocationSerialized {
814
presentation: IPreparedToolInvocation['presentation'];
815
toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent | IChatSubagentToolInvocationData | IChatSimpleToolInvocationData | IChatToolResourcesInvocationData;
816
invocationMessage: string | IMarkdownString;
817
originMessage: string | IMarkdownString | undefined;
818
pastTenseMessage: string | IMarkdownString | undefined;
819
resultDetails?: Array<URI | Location> | IToolResultInputOutputDetails | IToolResultOutputDetailsSerialized;
820
/** boolean used by pre-1.104 versions */
821
isConfirmed: ConfirmedReason | boolean | undefined;
822
isComplete: boolean;
823
toolCallId: string;
824
toolId: string;
825
source: ToolDataSource | undefined; // undefined on pre-1.104 versions
826
readonly subAgentInvocationId?: string;
827
generatedTitle?: string;
828
kind: 'toolInvocationSerialized';
829
}
830
831
export interface IChatExtensionsContent {
832
extensions: string[];
833
kind: 'extensions';
834
}
835
836
export interface IChatPullRequestContent {
837
/**
838
* @deprecated use `command` instead
839
*/
840
uri?: URI;
841
command: Command;
842
title: string;
843
description: string;
844
author: string;
845
linkTag: string;
846
kind: 'pullRequest';
847
}
848
849
export interface IChatSubagentToolInvocationData {
850
kind: 'subagent';
851
description?: string;
852
agentName?: string;
853
prompt?: string;
854
result?: string;
855
modelName?: string;
856
}
857
858
/**
859
* Progress type for external tool invocation updates from extensions.
860
* When isComplete is false, creates or updates a tool invocation.
861
* When isComplete is true, completes an existing tool invocation.
862
*/
863
export interface IChatExternalToolInvocationUpdate {
864
kind: 'externalToolInvocationUpdate';
865
toolCallId: string;
866
toolName: string;
867
isComplete: boolean;
868
errorMessage?: string;
869
invocationMessage?: string | IMarkdownString;
870
pastTenseMessage?: string | IMarkdownString;
871
toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatTodoListContent | IChatSubagentToolInvocationData;
872
subagentInvocationId?: string;
873
}
874
875
export interface IChatTodoListContent {
876
kind: 'todoList';
877
todoList: Array<{
878
id: string;
879
title: string;
880
status: 'not-started' | 'in-progress' | 'completed';
881
}>;
882
}
883
884
export interface IChatSimpleToolInvocationData {
885
kind: 'simpleToolInvocation';
886
input: string;
887
output: string;
888
}
889
890
export interface IChatToolResourcesInvocationData {
891
readonly kind: 'resources';
892
readonly values: Array<URI | Location>;
893
}
894
895
export interface IChatMcpServersStarting {
896
readonly kind: 'mcpServersStarting';
897
readonly state?: IObservable<IAutostartResult>; // not hydrated when serialized
898
didStartServerIds?: string[];
899
toJSON(): IChatMcpServersStartingSerialized;
900
}
901
902
export interface IChatMcpServersStartingSerialized {
903
readonly kind: 'mcpServersStarting';
904
readonly state?: undefined;
905
didStartServerIds?: string[];
906
}
907
908
export class ChatMcpServersStarting implements IChatMcpServersStarting {
909
public readonly kind = 'mcpServersStarting';
910
911
public didStartServerIds?: string[] = [];
912
913
public get isEmpty() {
914
const s = this.state.get();
915
return !s.working && s.serversRequiringInteraction.length === 0;
916
}
917
918
constructor(public readonly state: IObservable<IAutostartResult>) { }
919
920
wait() {
921
return new Promise<IAutostartResult>(resolve => {
922
autorunSelfDisposable(reader => {
923
const s = this.state.read(reader);
924
if (!s.working) {
925
reader.dispose();
926
resolve(s);
927
}
928
});
929
});
930
}
931
932
toJSON(): IChatMcpServersStartingSerialized {
933
return { kind: 'mcpServersStarting', didStartServerIds: this.didStartServerIds };
934
}
935
}
936
937
export type IChatProgress =
938
| IChatMarkdownContent
939
| IChatAgentMarkdownContentWithVulnerability
940
| IChatTreeData
941
| IChatMultiDiffData
942
| IChatMultiDiffDataSerialized
943
| IChatUsedContext
944
| IChatContentReference
945
| IChatContentInlineReference
946
| IChatCodeCitation
947
| IChatProgressMessage
948
| IChatTask
949
| IChatTaskResult
950
| IChatCommandButton
951
| IChatWarningMessage
952
| IChatTextEdit
953
| IChatNotebookEdit
954
| IChatWorkspaceEdit
955
| IChatMoveMessage
956
| IChatResponseCodeblockUriPart
957
| IChatConfirmation
958
| IChatQuestionCarousel
959
| IChatClearToPreviousToolInvocation
960
| IChatToolInvocation
961
| IChatToolInvocationSerialized
962
| IChatExtensionsContent
963
| IChatPullRequestContent
964
| IChatUndoStop
965
| IChatThinkingPart
966
| IChatTaskSerialized
967
| IChatElicitationRequest
968
| IChatElicitationRequestSerialized
969
| IChatMcpServersStarting
970
| IChatMcpServersStartingSerialized
971
| IChatHookPart
972
| IChatExternalToolInvocationUpdate;
973
974
export interface IChatFollowup {
975
kind: 'reply';
976
message: string;
977
agentId: string;
978
subCommand?: string;
979
title?: string;
980
tooltip?: string;
981
}
982
983
export function isChatFollowup(obj: unknown): obj is IChatFollowup {
984
return (
985
!!obj &&
986
(obj as IChatFollowup).kind === 'reply' &&
987
typeof (obj as IChatFollowup).message === 'string' &&
988
typeof (obj as IChatFollowup).agentId === 'string'
989
);
990
}
991
992
export enum ChatAgentVoteDirection {
993
Down = 0,
994
Up = 1
995
}
996
997
export enum ChatAgentVoteDownReason {
998
IncorrectCode = 'incorrectCode',
999
DidNotFollowInstructions = 'didNotFollowInstructions',
1000
IncompleteCode = 'incompleteCode',
1001
MissingContext = 'missingContext',
1002
PoorlyWrittenOrFormatted = 'poorlyWrittenOrFormatted',
1003
RefusedAValidRequest = 'refusedAValidRequest',
1004
OffensiveOrUnsafe = 'offensiveOrUnsafe',
1005
Other = 'other',
1006
WillReportIssue = 'willReportIssue'
1007
}
1008
1009
export interface IChatVoteAction {
1010
kind: 'vote';
1011
direction: ChatAgentVoteDirection;
1012
reason: ChatAgentVoteDownReason | undefined;
1013
}
1014
1015
export enum ChatCopyKind {
1016
// Keyboard shortcut or context menu
1017
Action = 1,
1018
Toolbar = 2
1019
}
1020
1021
export interface IChatCopyAction {
1022
kind: 'copy';
1023
codeBlockIndex: number;
1024
copyKind: ChatCopyKind;
1025
copiedCharacters: number;
1026
totalCharacters: number;
1027
copiedText: string;
1028
totalLines: number;
1029
copiedLines: number;
1030
modelId: string;
1031
languageId?: string;
1032
}
1033
1034
export interface IChatInsertAction {
1035
kind: 'insert';
1036
codeBlockIndex: number;
1037
totalCharacters: number;
1038
totalLines: number;
1039
languageId?: string;
1040
modelId: string;
1041
newFile?: boolean;
1042
}
1043
1044
export interface IChatApplyAction {
1045
kind: 'apply';
1046
codeBlockIndex: number;
1047
totalCharacters: number;
1048
totalLines: number;
1049
languageId?: string;
1050
modelId: string;
1051
newFile?: boolean;
1052
codeMapper?: string;
1053
editsProposed: boolean;
1054
}
1055
1056
1057
export interface IChatTerminalAction {
1058
kind: 'runInTerminal';
1059
codeBlockIndex: number;
1060
languageId?: string;
1061
}
1062
1063
export interface IChatCommandAction {
1064
kind: 'command';
1065
commandButton: IChatCommandButton;
1066
}
1067
1068
export interface IChatFollowupAction {
1069
kind: 'followUp';
1070
followup: IChatFollowup;
1071
}
1072
1073
export interface IChatBugReportAction {
1074
kind: 'bug';
1075
}
1076
1077
export interface IChatInlineChatCodeAction {
1078
kind: 'inlineChat';
1079
action: 'accepted' | 'discarded';
1080
}
1081
1082
1083
export interface IChatEditingSessionAction {
1084
kind: 'chatEditingSessionAction';
1085
uri: URI;
1086
hasRemainingEdits: boolean;
1087
outcome: 'accepted' | 'rejected' | 'userModified';
1088
}
1089
1090
export interface IChatEditingHunkAction {
1091
kind: 'chatEditingHunkAction';
1092
uri: URI;
1093
lineCount: number;
1094
linesAdded: number;
1095
linesRemoved: number;
1096
outcome: 'accepted' | 'rejected';
1097
hasRemainingEdits: boolean;
1098
modeId?: string;
1099
modelId?: string;
1100
languageId?: string;
1101
}
1102
1103
export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction | IChatEditingSessionAction | IChatEditingHunkAction;
1104
1105
export interface IChatUserActionEvent {
1106
action: ChatUserAction;
1107
agentId: string | undefined;
1108
command: string | undefined;
1109
sessionResource: URI;
1110
requestId: string;
1111
result: IChatAgentResult | undefined;
1112
modelId?: string | undefined;
1113
modeId?: string | undefined;
1114
}
1115
1116
export interface IChatDynamicRequest {
1117
/**
1118
* The message that will be displayed in the UI
1119
*/
1120
message: string;
1121
1122
/**
1123
* Any extra metadata/context that will go to the provider.
1124
*/
1125
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1126
metadata?: any;
1127
}
1128
1129
export interface IChatCompleteResponse {
1130
message: string | ReadonlyArray<IChatProgress>;
1131
result?: IChatAgentResult;
1132
followups?: IChatFollowup[];
1133
}
1134
1135
export interface IChatSessionStats {
1136
fileCount: number;
1137
added: number;
1138
removed: number;
1139
}
1140
1141
export type IChatSessionTiming = {
1142
/**
1143
* Timestamp when the session was created in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
1144
*/
1145
created: number;
1146
1147
/**
1148
* Timestamp when the most recent request started in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
1149
*
1150
* Should be undefined if no requests have been made yet.
1151
*/
1152
lastRequestStarted: number | undefined;
1153
1154
/**
1155
* Timestamp when the most recent request completed in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
1156
*
1157
* Should be undefined if the most recent request is still in progress or if no requests have been made yet.
1158
*/
1159
lastRequestEnded: number | undefined;
1160
};
1161
1162
interface ILegacyChatSessionTiming {
1163
startTime: number;
1164
endTime?: number;
1165
}
1166
1167
export function convertLegacyChatSessionTiming(timing: IChatSessionTiming | ILegacyChatSessionTiming): IChatSessionTiming {
1168
if (hasKey(timing, { created: true })) {
1169
return timing;
1170
}
1171
return {
1172
created: timing.startTime,
1173
lastRequestStarted: timing.startTime,
1174
lastRequestEnded: timing.endTime,
1175
};
1176
}
1177
1178
export const enum ResponseModelState {
1179
Pending,
1180
Complete,
1181
Cancelled,
1182
Failed,
1183
NeedsInput,
1184
}
1185
1186
export interface IChatDetail {
1187
sessionResource: URI;
1188
title: string;
1189
lastMessageDate: number;
1190
// Also support old timing format for backwards compatibility with persisted data
1191
timing: IChatSessionTiming | ILegacyChatSessionTiming;
1192
isActive: boolean;
1193
stats?: IChatSessionStats;
1194
lastResponseState: ResponseModelState;
1195
}
1196
1197
export interface IChatProviderInfo {
1198
id: string;
1199
}
1200
1201
export interface IChatSendRequestResponseState {
1202
responseCreatedPromise: Promise<IChatResponseModel>;
1203
responseCompletePromise: Promise<void>;
1204
}
1205
1206
export interface IChatSendRequestData extends IChatSendRequestResponseState {
1207
agent: IChatAgentData;
1208
slashCommand?: IChatAgentCommand;
1209
}
1210
1211
/**
1212
* Result of a sendRequest call - a discriminated union of possible outcomes.
1213
*/
1214
export type ChatSendResult =
1215
| ChatSendResultRejected
1216
| ChatSendResultSent
1217
| ChatSendResultQueued;
1218
1219
export interface ChatSendResultRejected {
1220
readonly kind: 'rejected';
1221
readonly reason: string;
1222
}
1223
1224
export interface ChatSendResultSent {
1225
readonly kind: 'sent';
1226
readonly data: IChatSendRequestData;
1227
}
1228
1229
export interface ChatSendResultQueued {
1230
readonly kind: 'queued';
1231
/**
1232
* Promise that resolves when the queued message is actually processed.
1233
* Will resolve to a 'sent' or 'rejected' result.
1234
*/
1235
readonly deferred: Promise<ChatSendResult>;
1236
}
1237
1238
export namespace ChatSendResult {
1239
export function isSent(result: ChatSendResult): result is ChatSendResultSent {
1240
return result.kind === 'sent';
1241
}
1242
1243
export function isRejected(result: ChatSendResult): result is ChatSendResultRejected {
1244
return result.kind === 'rejected';
1245
}
1246
1247
export function isQueued(result: ChatSendResult): result is ChatSendResultQueued {
1248
return result.kind === 'queued';
1249
}
1250
1251
/** Assertion function for tests - asserts that the result is a sent result */
1252
export function assertSent(result: ChatSendResult): asserts result is ChatSendResultSent {
1253
if (result.kind !== 'sent') {
1254
throw new Error(`Expected ChatSendResult to be 'sent', but was '${result.kind}'`);
1255
}
1256
}
1257
}
1258
1259
export interface IChatEditorLocationData {
1260
type: ChatAgentLocation.EditorInline;
1261
id: string;
1262
document: URI;
1263
selection: ISelection;
1264
wholeRange: IRange;
1265
}
1266
1267
export interface IChatNotebookLocationData {
1268
type: ChatAgentLocation.Notebook;
1269
sessionInputUri: URI;
1270
}
1271
1272
export interface IChatTerminalLocationData {
1273
type: ChatAgentLocation.Terminal;
1274
// TBD
1275
}
1276
1277
export type IChatLocationData = IChatEditorLocationData | IChatNotebookLocationData | IChatTerminalLocationData;
1278
1279
/**
1280
* The kind of queue request.
1281
*/
1282
export const enum ChatRequestQueueKind {
1283
/** Request is queued to be sent after current request completes */
1284
Queued = 'queued',
1285
/** Request is queued and signals the active request to yield */
1286
Steering = 'steering'
1287
}
1288
1289
export interface IChatSendRequestOptions {
1290
modeInfo?: IChatRequestModeInfo;
1291
userSelectedModelId?: string;
1292
userSelectedTools?: IObservable<UserSelectedTools>;
1293
location?: ChatAgentLocation;
1294
locationData?: IChatLocationData;
1295
parserContext?: IChatParserContext;
1296
attempt?: number;
1297
noCommandDetection?: boolean;
1298
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1299
acceptedConfirmationData?: any[];
1300
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1301
rejectedConfirmationData?: any[];
1302
attachedContext?: IChatRequestVariableEntry[];
1303
1304
/** The target agent ID can be specified with this property instead of using @ in 'message' */
1305
agentId?: string;
1306
/** agentId, but will not add a @ name to the request */
1307
agentIdSilent?: string;
1308
slashCommand?: string;
1309
1310
/**
1311
* The label of the confirmation action that was selected.
1312
*/
1313
confirmation?: string;
1314
1315
/**
1316
* When set, queues this message to be sent after the current request completes.
1317
* If Steering, also sets yieldRequested on any active request to signal it should wrap up.
1318
*/
1319
queue?: ChatRequestQueueKind;
1320
1321
}
1322
1323
export type IChatModelReference = IReference<IChatModel>;
1324
1325
export const IChatService = createDecorator<IChatService>('IChatService');
1326
1327
export interface IChatService {
1328
_serviceBrand: undefined;
1329
transferredSessionResource: URI | undefined;
1330
1331
readonly onDidSubmitRequest: Event<{ readonly chatSessionResource: URI }>;
1332
1333
readonly onDidCreateModel: Event<IChatModel>;
1334
1335
/**
1336
* An observable containing all live chat models.
1337
*/
1338
readonly chatModels: IObservable<Iterable<IChatModel>>;
1339
1340
isEnabled(location: ChatAgentLocation): boolean;
1341
hasSessions(): boolean;
1342
startSession(location: ChatAgentLocation, options?: IChatSessionStartOptions): IChatModelReference;
1343
1344
/**
1345
* Get an active session without holding a reference to it.
1346
*/
1347
getSession(sessionResource: URI): IChatModel | undefined;
1348
1349
/**
1350
* Acquire a reference to an active session.
1351
*/
1352
getActiveSessionReference(sessionResource: URI): IChatModelReference | undefined;
1353
1354
getOrRestoreSession(sessionResource: URI): Promise<IChatModelReference | undefined>;
1355
getSessionTitle(sessionResource: URI): string | undefined;
1356
loadSessionFromContent(data: IExportableChatData | ISerializableChatData | URI): IChatModelReference | undefined;
1357
loadSessionForResource(resource: URI, location: ChatAgentLocation, token: CancellationToken): Promise<IChatModelReference | undefined>;
1358
readonly editingSessions: IChatEditingSession[];
1359
getChatSessionFromInternalUri(sessionResource: URI): IChatSessionContext | undefined;
1360
1361
/**
1362
* Sends a chat request for the given session.
1363
* @returns A result indicating whether the request was sent, queued, or rejected.
1364
*/
1365
sendRequest(sessionResource: URI, message: string, options?: IChatSendRequestOptions): Promise<ChatSendResult>;
1366
1367
/**
1368
* Sets a custom title for a chat model.
1369
*/
1370
setTitle(sessionResource: URI, title: string): void;
1371
appendProgress(request: IChatRequestModel, progress: IChatProgress): void;
1372
resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions): Promise<void>;
1373
adoptRequest(sessionResource: URI, request: IChatRequestModel): Promise<void>;
1374
removeRequest(sessionResource: URI, requestId: string): Promise<void>;
1375
cancelCurrentRequestForSession(sessionResource: URI): void;
1376
/**
1377
* Sets yieldRequested on the active request for the given session.
1378
*/
1379
setYieldRequested(sessionResource: URI): void;
1380
/**
1381
* Removes a pending request from the session's queue.
1382
*/
1383
removePendingRequest(sessionResource: URI, requestId: string): void;
1384
/**
1385
* Sets the pending requests for a session, allowing for deletions/reordering.
1386
* Adding new requests should go through sendRequest with the queue option.
1387
*/
1388
setPendingRequests(sessionResource: URI, requests: readonly { requestId: string; kind: ChatRequestQueueKind }[]): void;
1389
/**
1390
* Ensures pending requests for the session are processing. If restoring from
1391
* storage or after an error, pending requests may be present without an
1392
* active chat message 'loop' happening. THis triggers the loop to happen
1393
* as needed. Idempotent, safe to call at any time.
1394
*/
1395
processPendingRequests(sessionResource: URI): void;
1396
addCompleteRequest(sessionResource: URI, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, attempt: number | undefined, response: IChatCompleteResponse): void;
1397
setChatSessionTitle(sessionResource: URI, title: string): void;
1398
getLocalSessionHistory(): Promise<IChatDetail[]>;
1399
clearAllHistoryEntries(): Promise<void>;
1400
removeHistoryEntry(sessionResource: URI): Promise<void>;
1401
getChatStorageFolder(): URI;
1402
logChatIndex(): void;
1403
getLiveSessionItems(): Promise<IChatDetail[]>;
1404
getHistorySessionItems(): Promise<IChatDetail[]>;
1405
getMetadataForSession(sessionResource: URI): Promise<IChatDetail | undefined>;
1406
1407
readonly onDidPerformUserAction: Event<IChatUserActionEvent>;
1408
notifyUserAction(event: IChatUserActionEvent): void;
1409
1410
readonly onDidReceiveQuestionCarouselAnswer: Event<{ requestId: string; resolveId: string; answers: Record<string, unknown> | undefined }>;
1411
notifyQuestionCarouselAnswer(requestId: string, resolveId: string, answers: Record<string, unknown> | undefined): void;
1412
1413
readonly onDidDisposeSession: Event<{ readonly sessionResource: URI[]; readonly reason: 'cleared' }>;
1414
1415
transferChatSession(transferredSessionResource: URI, toWorkspace: URI): Promise<void>;
1416
1417
activateDefaultAgent(location: ChatAgentLocation): Promise<void>;
1418
1419
readonly edits2Enabled: boolean;
1420
1421
readonly requestInProgressObs: IObservable<boolean>;
1422
1423
/**
1424
* For tests only!
1425
*/
1426
setSaveModelsEnabled(enabled: boolean): void;
1427
1428
/**
1429
* For tests only!
1430
*/
1431
waitForModelDisposals(): Promise<void>;
1432
}
1433
1434
export interface IChatSessionContext {
1435
readonly chatSessionType: string;
1436
readonly chatSessionResource: URI;
1437
readonly isUntitled: boolean;
1438
}
1439
1440
export const KEYWORD_ACTIVIATION_SETTING_ID = 'accessibility.voice.keywordActivation';
1441
1442
export interface IChatSessionStartOptions {
1443
canUseTools?: boolean;
1444
disableBackgroundKeepAlive?: boolean;
1445
}
1446
1447