45
};
46
}
48
>
getActivators(sessionType: string): readonly IAsyncChatSessionActivationContribution[] {
49
return Array.from(this._contributions).filter(contribution => contribution.matchSessionType(sessionType));
50
}
52
>
53
>
Registry.add(ChatSessionsExtensions.AsyncActivation, new AsyncChatSessionActivationRegistry());
54
>
55
>
export const enum ChatSessionStatus {
56
>
Failed = 0,
57
>
Completed = 1,
58
>
InProgress = 2,
59
>
NeedsInput = 3
60
>
}
61
>
62
>
export interface IChatSessionCommandContribution {
63
>
readonly name: string;
64
>
readonly description: string;
65
>
readonly when?: string;
66
>
}
67
>
68
>
export interface IChatSessionProviderOptionModelMetadata {
69
>
readonly name: string;
70
>
readonly id: string;
71
>
readonly vendor?: string;
72
>
readonly version?: string;
73
>
readonly family?: string;
74
>
readonly tooltip?: string;
75
>
readonly pricing?: string;
76
>
readonly multiplierNumeric?: number;
77
>
readonly inputCost?: number;
78
>
readonly outputCost?: number;
79
>
readonly cacheCost?: number;
80
>
readonly cacheWriteCost?: number;
81
>
readonly longContextInputCost?: number;
82
>
readonly longContextOutputCost?: number;
83
>
readonly longContextCacheCost?: number;
84
>
readonly longContextCacheWriteCost?: number;
85
>
readonly priceCategory?: string;
86
>
readonly promo?: {
87
>
readonly id: string;
88
>
readonly discountPercent: number;
89
>
readonly endsAt: string;
90
>
readonly message: string;
91
>
};
92
>
readonly maxInputTokens?: number;
93
>
readonly maxOutputTokens?: number;
94
>
readonly capabilities?: {
95
>
readonly vision?: boolean;
96
>
readonly toolCalling?: boolean;
97
>
};
98
>
}
99
>
100
>
export interface IChatSessionProviderOptionItem {
101
>
readonly id: string;
102
>
readonly name: string;
103
>
readonly description?: string;
104
>
readonly detail?: string;
105
>
readonly locked?: boolean;
106
>
readonly icon?: ThemeIcon;
107
>
readonly default?: boolean;
108
>
readonly slashCommand?: string;
109
>
readonly tooltip?: string;
110
>
readonly modelMetadata?: IChatSessionProviderOptionModelMetadata;
111
>
// [key: string]: any;
112
>
}
113
>
114
>
export interface IChatSessionProviderOptionGroupCommand {
115
>
readonly command: string;
116
>
readonly title: string;
117
>
readonly tooltip?: string;
118
>
readonly arguments?: readonly unknown[];
119
>
}
120
>
121
>
export interface IChatSessionProviderOptionGroup {
122
>
readonly id: string;
123
>
readonly name: string;
124
>
readonly description?: string;
125
>
readonly detail?: string;
126
>
readonly selected?: IChatSessionProviderOptionItem;
127
>
readonly items: readonly IChatSessionProviderOptionItem[];
128
>
/**
129
>
* A context key expression that controls visibility of this option group picker.
130
>
* When specified, the picker is only visible when the expression evaluates to true.
131
>
* The expression can reference other option group values via `chatSessionOption.<groupId>`.
132
>
* Example: `"chatSessionOption.models == 'gpt-4'"`
133
>
*/
134
>
readonly when?: string;
135
>
readonly icon?: ThemeIcon;
136
>
/**
137
>
* Custom commands to show in the option group's picker UI.
138
>
* These will be shown in a separate section at the end of the picker.
139
>
*/
140
>
readonly commands?: readonly IChatSessionProviderOptionGroupCommand[];
141
>
/**
142
>
* Optional kind hint that controls how the group is presented.
143
>
* - `'permissions'`: the group's items are surfaced inside the chat permission picker
144
>
* instead of being rendered as a standalone picker. At most one group per provider
145
>
* may use this kind; if multiple are declared, the first one (in declaration order)
146
>
* wins. The group has no UI of its own — it is invisible when the permission
147
>
* picker is hidden by its own `when` clauses.
148
>
*/
149
>
readonly kind?: 'permissions';
150
>
}
151
>
152
>
export interface IChatSessionsExtensionPoint {
153
>
readonly type: string;
154
>
readonly name: string;
155
>
readonly displayName: string;
156
>
readonly description: string;
157
>
readonly when?: string;
158
>
readonly icon?: string | { light: string; dark: string };
159
>
readonly order?: number;
160
>
readonly alternativeIds?: string[];
161
>
readonly welcomeTitle?: string;
162
>
readonly welcomeMessage?: string;
163
>
readonly welcomeTips?: string;
164
>
readonly inputPlaceholder?: string;
165
>
readonly capabilities?: IChatAgentAttachmentCapabilities;
166
>
readonly commands?: IChatSessionCommandContribution[];
167
>
readonly canDelegate?: boolean;
168
>
readonly isReadOnly?: boolean;
169
>
/**
170
>
* When set, the chat session will show a filtered mode picker with custom agents
171
>
* that have a matching `target` property. This enables contributed chat sessions
172
>
* to reuse the standard agent/mode dropdown with filtered custom agents.
173
>
* Custom agents without a `target` property are also shown in all filtered lists
174
>
*/
175
>
readonly customAgentTarget?: Target;
176
>
readonly requiresCustomModels?: boolean;
177
>
/**
178
>
* Whether this session type supports the synthetic "Auto" model fallback.
179
>
* Defaults to true. When false and no models are available, the picker
180
>
* shows a "No models available" state instead of "Auto".
181
>
*
182
>
* This is distinct from {@link requiresCustomModels}, which only controls
183
>
* whether the picker is filtered to the session's own model pool — a
184
>
* session can own a custom pool yet still support Auto (e.g. the Copilot
185
>
* CLI agent host).
186
>
*/
187
>
readonly supportsAutoModel?: boolean;
188
>
/**
189
>
* Logical Agent Host provider ID for Agent Host-backed chat sessions.
190
>
* For example, both local `agent-host-copilotcli` and remote
191
>
* `remote-{authority}-copilotcli` sessions use `copilotcli`.
192
>
*/
193
>
readonly agentHostProviderId?: string;
194
>
/**
195
>
* Whether this type needs a GitHub Copilot account and so is unusable until the user signs in. Set by
196
>
* Copilot-backed types (Copilot CLI / agent host, cloud agent) where BYOK isn't supported. Defaults to false, so
197
>
* third-party types that don't depend on Copilot stay usable while signed out.
198
>
*/
199
>
readonly requiresCopilotSignIn?: boolean;
200
>
/**
201
>
* When false, the delegation picker is hidden for this session type.
202
>
* Defaults to true.
203
>
*/
204
>
readonly supportsDelegation?: boolean;
205
>
/**
206
>
* Decides whether to automatically attach instruction files to chat requests
207
>
* for this session type. Defaults to false when not specified.
208
>
*/
209
>
readonly autoAttachReferences?: boolean;
210
>
}
211
>
212
>
export interface IChatSessionItem {
213
>
readonly resource: URI;
214
>
readonly label: string;
215
>
readonly iconPath?: ThemeIcon;
216
>
readonly badge?: string | IMarkdownString;
217
>
readonly description?: string | IMarkdownString;
218
>
readonly status?: ChatSessionStatus;
219
>
readonly tooltip?: string | IMarkdownString;
220
>
readonly timing: IChatSessionTiming;
221
>
readonly changes?: {
222
>
readonly files: number;
223
>
readonly insertions: number;
224
>
readonly deletions: number;
225
>
} | readonly IChatSessionFileChange[] | readonly IChatSessionFileChange2[];
226
>
readonly archived?: boolean;
227
>
readonly metadata?: IChatSessionItemMetadata;
228
>
/**
229
>
* Resource identifier the item was previously known by. When set, host-stored
230
>
* per-resource state (archive, pin, read) recorded under that URI is adopted
231
>
* forward onto {@link resource} on first state read, and the legacy entry is
232
>
* removed. Scheme must match {@link resource}'s scheme; otherwise ignored.
233
>
*/
234
>
readonly legacyResource?: URI;
235
>
}
236
>
237
>
export interface IChatSessionItemMetadata {
238
>
//#region Changes metadata (for sessions window)
239
>
readonly repositoryPath?: string;
240
>
readonly workingDirectoryPath?: string;
241
>
readonly firstCheckpointRef?: string;
242
>
readonly lastCheckpointRef?: string;
243
>
readonly worktreePath?: string;
244
>
readonly uncommittedChanges?: number;
245
>
readonly baseRefOid?: string;
246
>
readonly headRefOid?: string;
247
>
readonly branchName?: string;
248
>
readonly branch?: string;
249
>
readonly baseBranchName?: string;
250
>
readonly baseBranch?: string;
251
>
readonly baseBranchProtected?: boolean;
252
>
readonly hasGitHubRemote?: boolean;
253
>
readonly upstreamBranchName?: string;
254
>
readonly incomingChanges?: number;
255
>
readonly outgoingChanges?: number;
256
>
//#endregion
257
>
258
>
readonly [key: string]: unknown;
259
>
}
260
>
261
>
export interface IChatSessionFileChange {
262
>
readonly modifiedUri: URI;
263
>
readonly originalUri?: URI;
264
>
readonly insertions: number;
265
>
readonly deletions: number;
266
>
readonly reviewed?: boolean;
267
>
}
268
>
269
>
export interface IChatSessionFileChange2 {
270
>
readonly uri: URI;
271
>
readonly originalUri?: URI;
272
>
readonly modifiedUri?: URI;
273
>
readonly insertions: number;
274
>
readonly deletions: number;
275
>
readonly reviewed?: boolean;
276
>
}
277
>
278
>
export type IChatSessionHistoryItem = {
279
>
id?: string;
280
>
type: 'request';
281
>
prompt: string;
282
>
participant: string;
283
>
command?: string;
284
>
variableData?: IChatRequestVariableData;
285
>
modelId?: string;
286
>
timestamp?: number;
287
>
modeInstructions?: IChatRequestModeInstructions;
288
>
isSystemInitiated?: boolean;
289
>
systemInitiatedLabel?: string;
290
>
isTerminalRequest?: boolean;
291
>
} | {
292
>
type: 'response';
293
>
parts: IChatProgress[];
294
>
participant: string;
295
>
details?: string;
296
>
elapsedMs?: number;
297
>
completedAt?: number;
298
>
/**
299
>
* Error details for a failed response. Rendered as a proper chat error
300
>
* (including the quota-exceeded upgrade affordance), mirroring the live
301
>
* agent result's `errorDetails`.
302
>
*/
303
>
errorDetails?: IChatResponseErrorDetails;
304
>
};
305
>
306
>
export type IChatSessionRequestHistoryItem = Extract<IChatSessionHistoryItem, { type: 'request' }>;
307
>
308
>
export interface IChatSessionServerRequest {
309
>
readonly prompt: string;
310
>
readonly variableData?: IChatRequestVariableData;
311
>
readonly timestamp?: number;
312
>
readonly isSystemInitiated?: boolean;
313
>
readonly systemInitiatedLabel?: string;
314
>
readonly isTerminalRequest?: boolean;
315
>
}
316
>
317
>
/**
318
>
* Whether `text` runs as a terminal command for the given command `prefix`
319
>
* (e.g. `!`) — it starts with the prefix and has a non-empty command after it.
320
>
* Mirrors the agent host's bang parser, where a lone `!` (or `!` followed only
321
>
* by whitespace) is forwarded to the agent rather than executed.
322
>
*/
323
>
export function isTerminalCommandPrompt(text: string, prefix: string | undefined): boolean {
324
return !!prefix && text.startsWith(prefix) && text.slice(prefix.length).trim().length > 0;
325
}
327
>
/**
328
>
* A set of well-known session types
329
>
*/
330
>
export namespace SessionType {
331
>
export const CopilotCLI = 'copilotcli';
332
>
export const CopilotCloud = 'copilot-cloud-agent';
333
>
export const Local = 'local';
334
>
export const ClaudeCode = 'claude-code';
335
>
export const Codex = 'openai-codex';
336
>
export const Growth = 'copilot-growth';
337
>
export const AgentHostCopilot = 'agent-host-copilotcli';
338
>
export const AgentHostClaude = 'agent-host-claude';
339
>
export const AgentHostCodex = 'agent-host-codex';
340
>
}
341
>
342
>
/**
343
>
* Returns whether the given session type is a local agent host target.
344
>
*/
345
>
export function isLocalAgentHostTarget(target: string): boolean {
346
return target === SessionType.AgentHostCopilot ||
347
target.startsWith(LOCAL_AGENT_HOST_SCHEME_PREFIX);
348
}
350
>
/**
351
>
* Returns whether the given session type is a remote agent host target.
352
>
*
353
>
* Note: The `remote-` prefix convention is established by
354
>
* `RemoteAgentHostContribution` which generates session types as
355
>
* `remote-{sanitizedAddress}-{provider}`. If future remote providers that
356
>
* are NOT agent hosts need a different prefix, this function must be updated.
357
>
*/
358
>
export function isRemoteAgentHostTarget(target: string): boolean {
359
return isRemoteAgentHostSessionType(target);
360
}
362
>
/**
363
>
* Returns whether the given session type is an agent host target.
364
>
* Matches the local agent host (`agent-host-*`) and remote agent hosts (`remote-*`).
365
>
*/
366
>
export function isAgentHostTarget(target: string): boolean {
367
return isLocalAgentHostTarget(target) || isRemoteAgentHostTarget(target);
368
}
370
>
/**
371
>
* The session type used for local agent chat sessions.
372
>
*/
373
>
export const localChatSessionType = SessionType.Local;
374
>
375
>
export interface IChatSession extends IDisposable {
376
>
readonly onWillDispose: Event<void>;
377
>
378
>
readonly sessionResource: URI;
379
>
380
>
readonly title?: string;
381
>
382
>
readonly history: readonly IChatSessionHistoryItem[];
383
>
384
>
385
>
readonly options?: ReadonlyChatSessionOptionsMap;
386
>
387
>
readonly progressObs?: IObservable<IChatProgress[]>;
388
>
readonly isCompleteObs?: IObservable<boolean>;
389
>
readonly isReadOnly?: IObservable<boolean>;
390
>
readonly interruptActiveResponseCallback?: () => Promise<boolean>;
391
>
392
>
/**
393
>
* Event fired when the server initiates a new request (e.g. from a consumed
394
>
* queued message). The consumer should create a new request+response pair in
395
>
* the model and prepare to receive progress via {@link progressObs}.
396
>
*/
397
>
readonly onDidStartServerRequest?: Event<IChatSessionServerRequest>;
398
>
399
>
/**
400
>
* Editing session transferred from a previously-untitled chat session in `onDidCommitChatSessionItem`.
401
>
*/
402
>
transferredState?: {
403
>
readonly editingSession: IChatEditingSession | undefined;
404
>
readonly inputState: ISerializableChatModelInputState | undefined;
405
>
};
406
>
407
>
requestHandler?: (
408
>
request: IChatAgentRequest,
409
>
progress: (progress: IChatProgress[]) => void,
410
>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
411
>
history: any[], // TODO: Nail down types
412
>
token: CancellationToken
413
>
) => Promise<void>;
414
>
415
>
/**
416
>
* Forks the session from the given request point.
417
>
* @param request The request history item to fork from, or undefined to fork from the end.
418
>
* @param token Cancellation token.
419
>
* @returns The forked session item. The promise is rejected if forking fails.
420
>
*/
421
>
forkSession?: (request: IChatSessionRequestHistoryItem | undefined, token: CancellationToken) => Promise<IChatSessionItem>;
422
>
423
>
/**
424
>
* Renames the session.
425
>
* @param title The new title for the session.
426
>
* @param token Cancellation token.
427
>
* @returns A promise that resolves once the rename has been dispatched. The promise is rejected if renaming fails.
428
>
*/
429
>
renameSession?: (title: string, token: CancellationToken) => Promise<void>;
430
>
}
431
>
432
>
export interface IChatSessionContentProvider {
433
>
provideChatSessionContent(sessionResource: URI, token: CancellationToken): Promise<IChatSession>;
434
>
435
>
/** Resolves a parsed response Markdown URI before it is sanitized and rendered. */
436
>
resolveChatResponseUri?(sessionResource: URI, href: string, kind: 'link' | 'image'): string;
437
>
438
>
/**
439
>
* Optional. Compute completion items for an input being composed in this
440
>
* session. Returning `undefined` lets the workbench fall back to its
441
>
* default in-process completion providers.
442
>
*/
443
>
provideChatInputCompletions?(sessionResource: URI, params: IChatInputCompletionsParams, token: CancellationToken): Promise<IChatInputCompletionsResult | undefined>;
444
>
445
>
/**
446
>
* Optional. Trigger characters that, when typed in the chat input,
447
>
* SHOULD cause the workbench to issue a `provideChatInputCompletions`
448
>
* request. Used to register a Monaco completion provider scoped to
449
>
* sessions handled by this content provider.
450
>
*/
451
>
provideChatInputCompletionTriggerCharacters?(): Promise<readonly string[]>;
452
>
}
453
>
454
>
/**
455
>
* Inputs for {@link IChatSessionContentProvider.provideChatInputCompletions}
456
>
* and {@link IChatSessionsService.provideChatInputCompletions}.
457
>
*/
458
>
export interface IChatInputCompletionsParams {
459
>
/**
460
>
* The complete text of the input being completed (e.g. the user message
461
>
* the user is currently composing).
462
>
*/
463
>
readonly text: string;
464
>
/**
465
>
* The character offset within {@link text} at which the completion is
466
>
* requested, measured in UTF-16 code units. MUST satisfy
467
>
* `0 <= offset <= text.length`.
468
>
*/
469
>
readonly offset: number;
470
>
}
471
>
472
>
/**
473
>
* A neutral completion-item shape returned by
474
>
* {@link IChatSessionContentProvider.provideChatInputCompletions}. The
475
>
* workbench-side completion glue maps these into Monaco completion items
476
>
* and the corresponding chat-input attachment.
477
>
*/
478
>
export interface IChatInputCompletionItem {
479
>
/** Text inserted into the input when this item is accepted. */
480
>
readonly insertText: string;
481
>
/**
482
>
* Optional display label shown in the completion picker. When omitted, the
483
>
* workbench displays {@link insertText}. Set this when the inserted text
484
>
* differs from the label — e.g. an action item that inserts nothing
485
>
* (`insertText: ''`) but should still be shown to the user.
486
>
*/
487
>
readonly label?: string;
488
>
/**
489
>
* Half-open range `[start, end)` in the *current* input text that
490
>
* {@link insertText} replaces. Positions use 1-based `lineNumber` and
491
>
* `column` to match Monaco. When omitted, the workbench replaces the
492
>
* word at the cursor.
493
>
*/
494
>
readonly start?: IPosition;
495
>
readonly end?: IPosition;
496
>
/** Attachment associated with the item. */
497
>
readonly attachment: IChatInputCompletionResourceAttachment | IChatInputCompletionCommandAttachment | IChatInputCompletionSkillAttachment;
498
>
}
499
>
500
>
/**
501
>
* Resource attachment associated with a completion item. The workbench
502
>
* adds it to the input's variable model when the item is accepted.
503
>
*/
504
>
export interface IChatInputCompletionResourceAttachment {
505
>
readonly kind: 'resource';
506
>
readonly uri: URI;
507
>
readonly displayName?: string;
508
>
readonly isDirectory?: boolean;
509
>
/**
510
>
* Implementation-defined metadata that MUST be preserved by the
511
>
* workbench when the accepted completion is sent back as part of a
512
>
* user message attachment.
513
>
*/
514
>
readonly _meta?: Record<string, unknown>;
515
>
}
516
>
517
>
/**
518
>
* Command attachment associated with a completion item.
519
>
*/
520
>
export interface IChatInputCompletionCommandAttachment {
521
>
readonly kind: 'command';
522
>
readonly command: string;
523
>
readonly description: string;
524
>
/**
525
>
* Implementation-defined metadata that MUST be preserved by the
526
>
* workbench when the accepted completion is sent back as part of a
527
>
* user message attachment.
528
>
*/
529
>
readonly _meta?: Record<string, unknown>;
530
>
}
531
>
532
>
/**
533
>
* Skill attachment associated with a completion item. The workbench
534
>
* adds it to the input's variable model when the item is accepted.
535
>
*/
536
>
export interface IChatInputCompletionSkillAttachment {
537
>
readonly kind: 'skill';
538
>
readonly uri: URI;
539
>
readonly displayName?: string;
540
>
readonly description?: string;
541
>
/**
542
>
* Implementation-defined metadata that MUST be preserved by the
543
>
* workbench when the accepted completion is sent back as part of a
544
>
* user message attachment.
545
>
*/
546
>
readonly _meta?: Record<string, unknown>;
547
>
}
548
>
549
>
/**
550
>
* Result of {@link IChatSessionContentProvider.provideChatInputCompletions}.
551
>
*/
552
>
export interface IChatInputCompletionsResult {
553
>
readonly items: readonly IChatInputCompletionItem[];
554
>
}
555
>
556
>
export interface IChatNewSessionRequest {
557
>
readonly prompt: string;
558
>
readonly command?: string;
559
>
560
>
readonly initialSessionOptions?: ReadonlyChatSessionOptionsMap;
561
>
562
>
/**
563
>
* The chat-input session resource the user was typing into when this
564
>
* request was issued. Set when the chat infrastructure is rewriting an
565
>
* untitled session URI to a real one on first send. Controllers can use
566
>
* this to bridge any pre-creation state they tracked under the old URI
567
>
* (e.g. provisional agent-host sessions) to the new resource that the
568
>
* controller returns.
569
>
*/
570
>
readonly untitledResource?: URI;
571
>
}
572
>
573
>
export interface IChatSessionItemsDelta {
574
>
readonly addedOrUpdated?: readonly IChatSessionItem[];
575
>
readonly removed?: readonly URI[];
576
>
}
577
>
578
>
export interface IChatSessionItemController {
579
>
580
>
readonly onDidChangeChatSessionItems: Event<IChatSessionItemsDelta>;
581
>
582
>
get items(): readonly IChatSessionItem[];
583
>
584
>
refresh(token: CancellationToken): Promise<void>;
585
>
586
>
newChatSessionItem?(request: IChatNewSessionRequest, token: CancellationToken): Promise<IChatSessionItem | undefined>;
587
>
588
>
getNewChatSessionInputState?(sessionResource: URI, token: CancellationToken): Promise<readonly IChatSessionProviderOptionGroup[] | undefined>;
589
>
590
>
resolveChatSessionItem?(resource: URI, token: CancellationToken): Promise<IChatSessionItem | undefined>;
591
>
592
>
/**
593
>
* Permanently delete the session identified by `resource`. Implementations should tear down any backend state for
594
>
* the session. The controller is expected to fire an `onDidChangeChatSessionItems` event with the removed resource
595
>
* as a result of the deletion.
596
>
*/
597
>
deleteChatSessionItem?(resource: URI, token: CancellationToken): Promise<void>;
598
>
599
>
/**
600
>
* Set the authoritative archived state for the session identified by `resource`.
601
>
*/
602
>
setChatSessionItemArchived?(resource: URI, archived: boolean): void;
603
>
}
604
>
605
>
export interface IChatSessionOptionsChangeEvent {
606
>
readonly sessionResource: URI;
607
>
readonly updates: ReadonlyMap<string, string | IChatSessionProviderOptionItem | undefined>;
608
>
}
609
>
610
>
export type ResolvedChatSessionsExtensionPoint = Omit<IChatSessionsExtensionPoint, 'icon'> & {
611
>
readonly icon: ThemeIcon | URI | undefined;
612
>
};
613
>
614
>
/**
615
>
* Session options as key-value pairs.
616
>
*
617
>
* Keys correspond to option group IDs (e.g., 'models', 'subagents') and values are either the selected option item IDs (string) or full option items (for locked state).
618
>
*/
619
>
export type ChatSessionOptionsMap = Map<string, string | IChatSessionProviderOptionItem>;
620
>
621
>
export namespace ChatSessionOptionsMap {
622
>
export function fromRecord(obj: { [key: string]: string | IChatSessionProviderOptionItem }): ChatSessionOptionsMap {
623
return new Map(Object.entries(obj));
624
}
626
>
export function toRecord(map: ReadonlyChatSessionOptionsMap): Record<string, string | IChatSessionProviderOptionItem> {
627
const record: Record<string, string | IChatSessionProviderOptionItem> = Object.create(null);
628
const entries = ensureIterable(map);