extHostChatAgents2.ts ×98

Frontier kind: Joint frontier

unlabeled · c_5097c8cf5c0c

1 test · 75584 LOC · 249 files · introduces 1 test · 451 LOC · 6 files

Introduces — evidence that enters the hierarchy at this concept

Code
105 ranges451 lines · 6 files
Tests
1 test

Contains — complete concept membership

All code (extent)
4874 ranges75584 lines · 249 files · Browse complete extent
All tests (intent)
1 testBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

1 test introduced at this concept.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

6 files ranked by introduced lines: 451 introduced LOC across 105 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/api/common/extHostChatAgents2.ts 416 introduced LOC · 98 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostChatAgents2.ts
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 type * as vscode from 'vscode';
7 > import { coalesce } from '../../../base/common/arrays.js';
8 > import { DeferredPromise, raceCancellation, raceCancellationError, timeout } from '../../../base/common/async.js';
9 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
10 > import { toErrorMessage } from '../../../base/common/errorMessage.js';
11 > import { Emitter } from '../../../base/common/event.js';
12 > import { Iterable } from '../../../base/common/iterator.js';
13 > import { Disposable, DisposableMap, DisposableResourceMap, DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
14 > import { revive } from '../../../base/common/marshalling.js';
15 > import { StopWatch } from '../../../base/common/stopwatch.js';
16 > import { assertType } from '../../../base/common/types.js';
17 > import { URI, UriComponents } from '../../../base/common/uri.js';
18 > import { generateUuid } from '../../../base/common/uuid.js';
19 > import { Location } from '../../../editor/common/languages.js';
20 > import { ExtensionIdentifier, IExtensionDescription, IRelaxedExtensionDescription } from '../../../platform/extensions/common/extensions.js';
21 > import { ILogService } from '../../../platform/log/common/log.js';
22 > import { packErrorForTelemetry } from '../../../platform/telemetry/common/errorTelemetry.js';
23 > import { isChatViewTitleActionContext } from '../../contrib/chat/common/actions/chatActions.js';
24 > import { IChatAgentRequest, IChatAgentResult, IChatAgentResultTimings, UserSelectedTools } from '../../contrib/chat/common/participants/chatAgents.js';
25 > import { ChatAgentVoteDirection, IChatContentReference, IChatFollowup, IChatResponseErrorDetails, IChatUserActionEvent, IChatVoteAction } from '../../contrib/chat/common/chatService/chatService.js';
26 > import { ChatRequestHooks } from '../../contrib/chat/common/promptSyntax/hookSchema.js';
27 > import { LocalChatSessionUri } from '../../contrib/chat/common/model/chatUri.js';
28 > import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
29 > import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
30 > import { Dto } from '../../services/extensions/common/proxyIdentifier.js';
31 > import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEntryDto, IChatAgentInvokeResult, IChatAgentProgressShape, IChatSessionCustomizationItemDto, IChatSessionCustomizationProviderMetadataDto, IChatSessionCustomizationSourceFolderDto, IChatProgressDto, IChatSessionContextDto, ICustomAgentDto, IExtensionChatAgentMetadata, IHookDto, IInstructionDto, IMainContext, IPluginDto, ISkillDto, ISlashCommandDto, MainContext, MainThreadChatAgentsShape2 } from './extHost.protocol.js';
32 > import { CommandsConverter, ExtHostCommands } from './extHostCommands.js';
33 > import { ExtHostDiagnostics } from './extHostDiagnostics.js';
34 > import { ExtHostDocuments } from './extHostDocuments.js';
35 > import { ExtHostLanguageModels } from './extHostLanguageModels.js';
36 > import { ExtHostLanguageModelTools } from './extHostLanguageModelTools.js';
37 > import * as typeConvert from './extHostTypeConverters.js';
38 > import * as extHostTypes from './extHostTypes.js';
39 > import { IPromptFileContext, IPromptFileResource } from '../../contrib/chat/common/promptSyntax/service/promptsService.js';
40 > import { PromptsType } from '../../contrib/chat/common/promptSyntax/promptTypes.js';
41 > import { ExtHostChatSessions } from './extHostChatSessions.js';
42 > import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors.js';
43 >
44 > export class ChatAgentResponseStream {
45 >
46 > private _stopWatch = StopWatch.create(false);
47 > private _isClosed: boolean = false;
48 > private _firstProgress: number | undefined;
49 > private _apiObject: vscode.ChatResponseStream | undefined;
50 >
51 > constructor(
52 > private readonly _extension: IExtensionDescription,
53 > private readonly _request: IChatAgentRequest,
54 > private readonly _proxy: IChatAgentProgressShape,
55 > private readonly _commandsConverter: CommandsConverter,
56 > private readonly _sessionDisposables: DisposableStore,
57 > private readonly _pendingCarouselResolvers: Map</* requestId */string, Map</* resolveId */ string, DeferredPromise<Record<string, unknown> | undefined>>>,
58 > private readonly _token: CancellationToken
59 > ) { }
60 >
61 > close() {
62 this._isClosed = true;
63 }
65 > get timings(): IChatAgentResultTimings {
66 return {
67 firstProgress: this._firstProgress,
69 };
70 }
72 > get apiObject() {
73 >
74 > if (!this._apiObject) {
75 >
76 > const that = this;
77 > this._stopWatch.reset();
78 >
79 >
80 > let taskHandlePool = 0;
81 >
82 >
83 > function throwIfDone(source: Function | undefined) {
84 > if (that._isClosed) {
85 const err = new Error('Response stream has been closed');
86 Error.captureStackTrace(err, source);
87 throw err;
88 }
90 >
91 >
92 > const sendQueue: (IChatProgressDto | [IChatProgressDto, number])[] = [];
93 > let notify: Function[] = [];
94 >
95 > function send(chunk: IChatProgressDto): void;
96 > function send(chunk: IChatProgressDto, handle: number): Promise<void>;
97 > function send(chunk: IChatProgressDto, handle?: number) {
98 > // push data into send queue. the first entry schedules the micro task which
99 > // does the actual send to the main thread
100 > const newLen = sendQueue.push(handle !== undefined ? [chunk, handle] : chunk);
101 > if (newLen === 1) {
102 > queueMicrotask(() => {
103 > const toNotify = notify;
104 > notify = [];
105 > that._proxy.$handleProgressChunk(that._request.requestId, sendQueue).finally(() => {
106 > toNotify.forEach(f => f());
107 > });
108 > sendQueue.length = 0;
109 > });
110 > }
111 > if (handle !== undefined) {
112 return new Promise<void>(resolve => { notify.push(resolve); });
113 }
114 > return; extHostChatAgents2.ts
115 > }
116 >
117 > const _report = (progress: IChatProgressDto, task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart | vscode.ChatResponseReferencePart>) => Thenable<string | void>) => {
118 > // Measure the time to the first progress update with real markdown content
119 > if (typeof this._firstProgress === 'undefined' && (progress.kind === 'markdownContent' || progress.kind === 'markdownVuln' || progress.kind === 'beginToolInvocation')) {
120 this._firstProgress = this._stopWatch.elapsed();
121 }
123 > if (task) {
124 const myHandle = taskHandlePool++;
125 const progressReporterPromise = send(progress, myHandle);
139 send(typeConvert.ChatTaskResult.from(res), myHandle);
140 });
141 > } else { extHostChatAgents2.ts
142 > send(progress);
143 > }
144 > };
145 >
146 > this._apiObject = Object.freeze<vscode.ChatResponseStream>({
147 > clearToPreviousToolInvocation(reason) {
148 throwIfDone(this.markdown);
149 send({ kind: 'clearToPreviousToolInvocation', reason: reason });
150 return this;
151 },
152 > markdown(value) { extHostChatAgents2.ts
153 throwIfDone(this.markdown);
154 const part = new extHostTypes.ChatResponseMarkdownPart(value);
157 return this;
158 },
159 > markdownWithVulnerabilities(value, vulnerabilities) { extHostChatAgents2.ts
160 throwIfDone(this.markdown);
161 if (vulnerabilities) {
168 return this;
169 },
170 > codeblockUri(value, isEdit) { extHostChatAgents2.ts
171 throwIfDone(this.codeblockUri);
172 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
176 return this;
177 },
178 > filetree(value, baseUri) { extHostChatAgents2.ts
179 throwIfDone(this.filetree);
180 const part = new extHostTypes.ChatResponseFileTreePart(value, baseUri);
183 return this;
184 },
185 > anchor(value, title?: string) { extHostChatAgents2.ts
186 const part = new extHostTypes.ChatResponseAnchorPart(value, title);
187 return this.push(part);
188 },
189 > button(value) { extHostChatAgents2.ts
190 throwIfDone(this.anchor);
191 const part = new extHostTypes.ChatResponseCommandButtonPart(value);
194 return this;
195 },
196 > progress(value, task?: ((progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>)) { extHostChatAgents2.ts
197 throwIfDone(this.progress);
198 const part = new extHostTypes.ChatResponseProgressPart2(value, task);
201 return this;
202 },
203 > thinkingProgress(thinkingDelta: vscode.ThinkingDelta) { extHostChatAgents2.ts
204 throwIfDone(this.thinkingProgress);
205 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
209 return this;
210 },
211 > hookProgress(hookType: vscode.ChatHookType, stopReason?: string, systemMessage?: string) { extHostChatAgents2.ts
212 throwIfDone(this.hookProgress);
213 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
217 return this;
218 },
219 > warning(value) { extHostChatAgents2.ts
220 throwIfDone(this.progress);
221 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
225 return this;
226 },
227 > info(value) { extHostChatAgents2.ts
228 throwIfDone(this.progress);
229 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
233 return this;
234 },
235 > reference(value, iconPath) { extHostChatAgents2.ts
236 return this.reference2(value, iconPath);
237 },
238 > reference2(value, iconPath, options) { extHostChatAgents2.ts
239 throwIfDone(this.reference);
240
273 return this;
274 },
275 > codeCitation(value: vscode.Uri, license: string, snippet: string): void { extHostChatAgents2.ts
276 throwIfDone(this.codeCitation);
277 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
281 _report(dto);
282 },
283 > textEdit(target, edits) { extHostChatAgents2.ts
284 throwIfDone(this.textEdit);
285 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
291 return this;
292 },
293 > notebookEdit(target, edits) { extHostChatAgents2.ts
294 throwIfDone(this.notebookEdit);
295 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
300 return this;
301 },
302 > workspaceEdit(edits) { extHostChatAgents2.ts
303 throwIfDone(this.workspaceEdit);
304 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
309 return this;
310 },
311 > async externalEdit(target, callback) { extHostChatAgents2.ts
312 throwIfDone(this.externalEdit);
313 const resources = Array.isArray(target) ? target : [target];
322 }
323 },
324 > confirmation(title, message, data, buttons) { extHostChatAgents2.ts
325 throwIfDone(this.confirmation);
326 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
331 return this;
332 },
333 > async questionCarousel(questions: vscode.ChatQuestion[], allowSkip = true): Promise<Record<string, unknown> | undefined> { extHostChatAgents2.ts
334 throwIfDone(this.questionCarousel);
335 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
354 return raceCancellation(deferred.p, that._token);
355 },
356 > beginToolInvocation(toolCallId, toolName, streamData) { extHostChatAgents2.ts
357 throwIfDone(this.beginToolInvocation);
358 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
370 return this;
371 },
372 > updateToolInvocation(toolCallId, streamData) { extHostChatAgents2.ts
373 throwIfDone(this.updateToolInvocation);
374 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
384 return this;
385 },
386 > push(part) { extHostChatAgents2.ts
387 > throwIfDone(this.push);
388 >
389 > if (
390 > part instanceof extHostTypes.ChatResponseTextEditPart ||
391 > part instanceof extHostTypes.ChatResponseNotebookEditPart ||
392 > part instanceof extHostTypes.ChatResponseMarkdownWithVulnerabilitiesPart ||
393 > part instanceof extHostTypes.ChatResponseWarningPart ||
394 > part instanceof extHostTypes.ChatResponseConfirmationPart ||
395 > part instanceof extHostTypes.ChatResponseQuestionCarouselPart ||
396 > part instanceof extHostTypes.ChatResponseCodeCitationPart ||
397 > part instanceof extHostTypes.ChatResponseMovePart ||
398 > part instanceof extHostTypes.ChatResponseExtensionsPart ||
399 > part instanceof extHostTypes.ChatResponseExternalEditPart ||
400 > part instanceof extHostTypes.ChatResponseThinkingProgressPart ||
401 > part instanceof extHostTypes.ChatResponsePullRequestPart ||
402 > part instanceof extHostTypes.ChatResponseAutoModeResolutionPart ||
403 > part instanceof extHostTypes.ChatResponseProgressPart2
404 > ) {
405 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
406 }
408 > if (part instanceof extHostTypes.ChatResponseReferencePart) {
409 // Ensure variable reference values get fixed up
410 this.reference2(part.value, part.iconPath, part.options);
411 > } else if (part instanceof extHostTypes.ChatResponseProgressPart2) { extHostChatAgents2.ts
412 const dto = part.task ? typeConvert.ChatTask.from(part) : typeConvert.ChatResponseProgressPart.from(part);
413 _report(dto, part.task);
414 > } else if (part instanceof extHostTypes.ChatResponseThinkingProgressPart) { extHostChatAgents2.ts
415 const dto = typeConvert.ChatResponseThinkingProgressPart.from(part);
416 _report(dto);
417 > } else if (part instanceof extHostTypes.ChatResponseAutoModeResolutionPart) { extHostChatAgents2.ts
418 const dto = typeConvert.ChatResponseAutoModeResolutionPart.from(part);
419 _report(dto);
420 > } else if (part instanceof extHostTypes.ChatResponseAnchorPart) { extHostChatAgents2.ts
421 > const dto = typeConvert.ChatResponseAnchorPart.from(part);
422 >
423 > if (part.resolve) {
424 > checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
425 >
426 > dto.resolveId = generateUuid();
427 > }
428 > _report(dto);
429 >
430 > if (part.resolve) {
431 > const cts = new CancellationTokenSource();
432 > part.resolve(cts.token)
433 > .then(() => {
434 > const resolvedDto = typeConvert.ChatResponseAnchorPart.from(part);
435 > that._proxy.$handleAnchorResolve(that._request.requestId, dto.resolveId!, resolvedDto);
436 > })
437 > .then(() => cts.dispose(), () => cts.dispose());
438 > that._sessionDisposables.add(toDisposable(() => cts.dispose(true)));
439 > }
440 > } else if (part instanceof extHostTypes.ChatResponseExternalEditPart) {
441 const p = this.externalEdit(part.uris, part.callback);
442 p.then((value) => part.didGetApplied(value));
446 _report(dto);
447 }
449 > return this;
450 > },
451 > usage(usage) {
452 throwIfDone(this.usage);
453 checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
464 return this;
465 },
467 > }
468 >
469 > return this._apiObject;
470 > }
471 > }
472 >
473 > interface InFlightChatRequest {
474 > requestId: string;
475 > extRequest: vscode.ChatRequest;
476 > extension: IRelaxedExtensionDescription;
477 > hooks?: ChatRequestHooks;
478 > yieldRequested: boolean;
479 > }
480 >
481 > export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsShape2 {
482 >
483 > private static _idPool = 0;
484 >
485 > private readonly _agents = new Map<number, ExtHostChatAgent>();
486 > private readonly _proxy: MainThreadChatAgentsShape2;
487 >
488 > private static _participantDetectionProviderIdPool = 0;
489 > private readonly _participantDetectionProviders = new Map<number, ExtHostParticipantDetector>();
490 >
491 > private static _contributionsProviderIdPool = 0;
492 > private readonly _promptFileProviders = new Map<number, { extension: IExtensionDescription; provider: vscode.ChatCustomAgentProvider | vscode.ChatInstructionsProvider | vscode.ChatPromptFileProvider | vscode.ChatSkillProvider | vscode.ChatHookProvider }>();
493 >
494 > private static _customizationProviderIdPool = 0;
495 > private readonly _customizationProviders = new Map<number, { extension: IExtensionDescription; provider: vscode.ChatSessionCustomizationProvider }>();
496 >
497 > private readonly _sessionDisposables: DisposableResourceMap<DisposableStore> = this._register(new DisposableResourceMap());
498 > private readonly _completionDisposables: DisposableMap<number, DisposableStore> = this._register(new DisposableMap());
499 >
500 > private readonly _inFlightRequests = new Set<InFlightChatRequest>();
501 >
502 > // Map of requestId -> resolveId -> deferred promise for question carousel answers
503 > private readonly _pendingCarouselResolvers = new Map<string, Map<string, DeferredPromise<Record<string, unknown> | undefined>>>();
504 >
505 > private readonly _onDidChangeChatRequestTools = this._register(new Emitter<vscode.ChatRequest>());
506 > readonly onDidChangeChatRequestTools = this._onDidChangeChatRequestTools.event;
507 >
508 > private readonly _onDidDisposeChatSession = this._register(new Emitter<string>());
509 > readonly onDidDisposeChatSession = this._onDidDisposeChatSession.event;
510 >
511 > private readonly _onDidChangeCustomAgents = this._register(new Emitter<void>());
512 > readonly onDidChangeCustomAgents = this._onDidChangeCustomAgents.event;
513 > private readonly _onDidChangeInstructions = this._register(new Emitter<void>());
514 > readonly onDidChangeInstructions = this._onDidChangeInstructions.event;
515 > private readonly _onDidChangeSkills = this._register(new Emitter<void>());
516 > readonly onDidChangeSkills = this._onDidChangeSkills.event;
517 > private readonly _onDidChangeSlashCommands = this._register(new Emitter<void>());
518 > readonly onDidChangeSlashCommands = this._onDidChangeSlashCommands.event;
519 > private readonly _onDidChangeHooks = this._register(new Emitter<void>());
520 > readonly onDidChangeHooks = this._onDidChangeHooks.event;
521 > private readonly _onDidChangePlugins = this._register(new Emitter<void>());
522 > readonly onDidChangePlugins = this._onDidChangePlugins.event;
523 >
524 > private readonly _customAgents = new CachedPromise(() => this._proxy.$provideCustomAgents(CancellationToken.None).then(agents => agents.map(agent => this.toCustomAgent(agent))));
525 > private readonly _instructions = new CachedPromise(() => this._proxy.$provideInstructions(CancellationToken.None).then(instructions => instructions.map(instruction => this.toInstruction(instruction))));
526 > private readonly _skills = new CachedPromise(() => this._proxy.$provideSkills(CancellationToken.None).then(skills => skills.map(skill => this.toSkill(skill))));
527 > private readonly _slashCommands = new CachedPromise(() => this._proxy.$provideSlashCommands(CancellationToken.None).then(slashCommands => slashCommands.map(slashCommand => this.toSlashCommand(slashCommand))));
528 > private readonly _hooks = new CachedPromise(() => this._proxy.$provideHooks(CancellationToken.None).then(hooks => hooks.map(hook => this.toHook(hook))));
529 > private readonly _plugins = new CachedPromise(() => this._proxy.$providePlugins(CancellationToken.None).then(plugins => plugins.map(plugin => this.toPlugin(plugin))));
530 >
531 > private _activeChatPanelSessionResource: URI | undefined;
532 >
533 > private readonly _onDidChangeActiveChatPanelSessionResource = this._register(new Emitter<URI | undefined>());
534 > readonly onDidChangeActiveChatPanelSessionResource = this._onDidChangeActiveChatPanelSessionResource.event;
535 >
536 > get activeChatPanelSessionResource(): URI | undefined {
537 return this._activeChatPanelSessionResource;
538 }
540 >
541 > private toCustomAgent(dto: ICustomAgentDto): vscode.ChatCustomAgent {
542 return Object.freeze<vscode.ChatCustomAgent>({
543 uri: URI.revive(dto.uri),
556 });
557 }
559 > private toInstruction(dto: IInstructionDto): vscode.ChatInstruction {
560 return Object.freeze<vscode.ChatInstruction>({
561 uri: URI.revive(dto.uri),
569 });
570 }
572 > private toSkill(dto: ISkillDto): vscode.ChatSkill {
573 return Object.freeze<vscode.ChatSkill>({
574 uri: URI.revive(dto.uri),
583 });
584 }
586 > private toSlashCommand(dto: ISlashCommandDto): vscode.ChatSlashCommand {
587 return Object.freeze<vscode.ChatSlashCommand>({
588 uri: URI.revive(dto.uri),
597 });
598 }
600 > private toHook(dto: IHookDto): vscode.ChatHook {
601 return Object.freeze({
602 uri: URI.revive(dto.uri),
607 });
608 }
610 > private toPlugin(dto: IPluginDto): vscode.ChatPlugin {
611 return Object.freeze({ uri: URI.revive(dto.uri) });
612 }
614 > provideCustomAgents(token: vscode.CancellationToken): Thenable<readonly vscode.ChatCustomAgent[]> {
615 return this._customAgents.get(token);
616 }
618 > provideInstructions(token: vscode.CancellationToken): Thenable<readonly vscode.ChatInstruction[]> {
619 return this._instructions.get(token);
620 }
622 > provideSkills(token: vscode.CancellationToken): Thenable<readonly vscode.ChatSkill[]> {
623 return this._skills.get(token);
624 }
626 > provideSlashCommands(token: vscode.CancellationToken): Thenable<readonly vscode.ChatSlashCommand[]> {
627 return this._slashCommands.get(token);
628 }
630 > provideHooks(token: vscode.CancellationToken): Thenable<readonly vscode.ChatHook[]> {
631 return this._hooks.get(token);
632 }
634 > providePlugins(token: vscode.CancellationToken): Thenable<readonly vscode.ChatPlugin[]> {
635 return this._plugins.get(token);
636 }
638 > $onDidChangeCustomAgents(): void {
639 this._customAgents.clear();
640 this._onDidChangeCustomAgents.fire();
641 }
643 > $onDidChangeInstructions(): void {
644 this._instructions.clear();
645 this._onDidChangeInstructions.fire();
646 }
648 > $onDidChangeSkills(): void {
649 this._skills.clear();
650 this._onDidChangeSkills.fire();
651 }
653 > $onDidChangeSlashCommands(): void {
654 this._slashCommands.clear();
655 this._onDidChangeSlashCommands.fire();
656 }
658 > $onDidChangeHooks(): void {
659 this._hooks.clear();
660 this._onDidChangeHooks.fire();
661 }
663 > $onDidChangePlugins(): void {
664 this._plugins.clear();
665 this._onDidChangePlugins.fire();
666 }
668 > constructor(
669 mainContext: IMainContext,
670 private readonly _logService: ILogService,
691 });
692 }
694 > async transferActiveChat(newWorkspace: vscode.Uri): Promise<void> {
695 await this._proxy.$transferActiveChatSession(newWorkspace);
696 }
698 > createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
699 const handle = ExtHostChatAgents2._idPool++;
700 const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
704 return agent.apiAgent;
705 }
707 > createDynamicChatAgent(extension: IExtensionDescription, id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
708 const handle = ExtHostChatAgents2._idPool++;
709 const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
713 return agent.apiAgent;
714 }
716 > registerChatParticipantDetectionProvider(extension: IExtensionDescription, provider: vscode.ChatParticipantDetectionProvider): vscode.Disposable {
717 const handle = ExtHostChatAgents2._participantDetectionProviderIdPool++;
718 this._participantDetectionProviders.set(handle, new ExtHostParticipantDetector(extension, provider));
723 });
724 }
726 > /**
727 > * Internal method that handles all prompt file provider types.
728 > * Routes custom agents, instructions, prompt files, and skills to the unified internal implementation.
729 > */
730 > registerPromptFileProvider(extension: IExtensionDescription, type: PromptsType, provider: vscode.ChatCustomAgentProvider | vscode.ChatInstructionsProvider | vscode.ChatPromptFileProvider | vscode.ChatSkillProvider | vscode.ChatHookProvider): vscode.Disposable {
731 const handle = ExtHostChatAgents2._contributionsProviderIdPool++;
732 this._promptFileProviders.set(handle, { extension, provider });
769 return disposables;
770 }
772 > async $providePromptFiles(handle: number, type: PromptsType, context: IPromptFileContext, token: CancellationToken): Promise<IPromptFileResource[] | undefined> {
773 const providerData = this._promptFileProviders.get(handle);
774 if (!providerData) {
798 return resources;
799 }
801 > registerChatSessionCustomizationProvider(extension: IExtensionDescription, chatSessionType: string, metadata: vscode.ChatSessionCustomizationProviderMetadata, provider: vscode.ChatSessionCustomizationProvider): vscode.Disposable {
802 const handle = ExtHostChatAgents2._customizationProviderIdPool++;
803 this._customizationProviders.set(handle, { extension, provider });
826 return disposables;
827 }
829 > async $provideChatSessionCustomizations(handle: number, sessionResource: UriComponents | undefined, token: CancellationToken): Promise<IChatSessionCustomizationItemDto[] | undefined> {
830 const providerData = this._customizationProviders.get(handle);
831 if (!providerData) {
864 }
865 }
867 > async $provideSourceFolders(handle: number, sessionResource: UriComponents, type: string, token: CancellationToken): Promise<IChatSessionCustomizationSourceFolderDto[] | undefined> {
868 const providerData = this._customizationProviders.get(handle);
869 if (!providerData?.provider.provideSourceFolders) {
886 }
887 }
889 > async $detectChatParticipant(handle: number, requestDto: Dto<IChatAgentRequest>, context: { history: IChatAgentHistoryEntryDto[] }, options: { location: ChatAgentLocation; participants?: vscode.ChatParticipantMetadata[] }, token: CancellationToken): Promise<vscode.ChatParticipantDetectionResult | null | undefined> {
890 const detector = this._participantDetectionProviders.get(handle);
891 if (!detector) {
914 );
915 }
917 > private async _createRequest(requestDto: Dto<IChatAgentRequest>, context: { history: IChatAgentHistoryEntryDto[] }, extension: IExtensionDescription) {
918 const request = revive<IChatAgentRequest>(requestDto);
919 const convertedHistory = await this.prepareHistoryTurns(extension, request.agentId, context);
938 return { request, location, history: convertedHistory };
939 }
941 > private async getModelForRequest(request: IChatAgentRequest, extension: IExtensionDescription): Promise<vscode.LanguageModelChat> {
942 let model: vscode.LanguageModelChat | undefined;
943 if (request.userSelectedModelId) {
953 return model;
954 }
956 >
957 > async $setRequestTools(requestId: string, tools: UserSelectedTools) {
958 const request = [...this._inFlightRequests].find(r => r.requestId === requestId);
959 if (!request) {
968 this._onDidChangeChatRequestTools.fire(request.extRequest);
969 }
971 > $setYieldRequested(requestId: string, value: boolean): void {
972 const request = [...this._inFlightRequests].find(r => r.requestId === requestId);
973 if (request) {
975 }
976 }
978 > async $invokeAgent(handle: number, requestDto: Dto<IChatAgentRequest>, context: { history: IChatAgentHistoryEntryDto[]; chatSessionContext?: IChatSessionContextDto }, token: CancellationToken): Promise<IChatAgentInvokeResult | undefined> {
979 const agent = this._agents.get(handle);
980 if (!agent) {
1097 }
1098 }
1100 > private getDiagnosticsWhenEnabled(extension: Readonly<IRelaxedExtensionDescription>) {
1101 if (!isProposedApiEnabled(extension, 'chatReferenceDiagnostic')) {
1102 return [];
1104 return this._diagnostics.getDiagnostics();
1105 }
1107 > private async getToolsForRequest(extension: IExtensionDescription, tools: UserSelectedTools | undefined, modelId: string, token: CancellationToken): Promise<Map<vscode.LanguageModelToolInformation, boolean>> {
1108 if (!tools) {
1109 return new Map();
1117 return result;
1118 }
1120 > private async prepareHistoryTurns(extension: Readonly<IRelaxedExtensionDescription>, agentId: string, context: { history: IChatAgentHistoryEntryDto[] }): Promise<(vscode.ChatRequestTurn | vscode.ChatResponseTurn)[]> {
1121 const res: (vscode.ChatRequestTurn | vscode.ChatResponseTurn)[] = [];
1122
1155 return res;
1156 }
1158 > $releaseSession(sessionResourceDto: UriComponents): void {
1159 const sessionResource = URI.revive(sessionResourceDto);
1160 this._sessionDisposables.deleteAndDispose(sessionResource);
1164 }
1165 }
1167 > $acceptActiveChatSession(sessionResourceDto: UriComponents | undefined): void {
1168 const sessionResource = sessionResourceDto ? URI.revive(sessionResourceDto) : undefined;
1169 if (this._activeChatPanelSessionResource?.toString() === sessionResource?.toString()) {
1174 this._onDidChangeActiveChatPanelSessionResource.fire(sessionResource);
1175 }
1177 > async $provideFollowups(requestDto: Dto<IChatAgentRequest>, handle: number, result: IChatAgentResult, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatFollowup[]> {
1178 const agent = this._agents.get(handle);
1179 if (!agent) {
1198 .map(f => typeConvert.ChatFollowup.from(f, request));
1199 }
1201 > $acceptFeedback(handle: number, result: IChatAgentResult, voteAction: IChatVoteAction): void {
1202 const agent = this._agents.get(handle);
1203 if (!agent) {
1222 agent.acceptFeedback(Object.freeze(feedback));
1223 }
1225 > $handleQuestionCarouselAnswer(requestId: string, resolveId: string, answers: Record<string, unknown> | undefined): void {
1226 const requestResolvers = this._pendingCarouselResolvers.get(requestId);
1227 if (!requestResolvers) {
1240 }
1241 }
1243 > $acceptAction(handle: number, result: IChatAgentResult, event: IChatUserActionEvent): void {
1244 const agent = this._agents.get(handle);
1245 if (!agent) {
1256 }
1257 }
1259 > async $invokeCompletionProvider(handle: number, query: string, token: CancellationToken): Promise<IChatAgentCompletionItem[]> {
1260 const agent = this._agents.get(handle);
1261 if (!agent) {
1276 return items.map((i) => typeConvert.ChatAgentCompletionItem.from(i, this._commands.converter, disposables));
1277 }
1279 > async $provideChatTitle(handle: number, context: IChatAgentHistoryEntryDto[], token: CancellationToken): Promise<string | undefined> {
1280 const agent = this._agents.get(handle);
1281 if (!agent) {
1287 return await agent.provideTitle({ history, sessionResource, yieldRequested: false }, token);
1288 }
1290 > async $provideChatSummary(handle: number, context: IChatAgentHistoryEntryDto[], token: CancellationToken): Promise<string | undefined> {
1291 const agent = this._agents.get(handle);
1292 if (!agent) {
1298 return await agent.provideSummary({ history, sessionResource, yieldRequested: false }, token);
1299 }
1301 >
1302 > class ExtHostParticipantDetector {
1303 > constructor(
1304 public readonly extension: IExtensionDescription,
1305 public readonly provider: vscode.ChatParticipantDetectionProvider,
1306 ) { }
1308 >
1309 > class ExtHostChatAgent {
1310 >
1311 > private _followupProvider: vscode.ChatFollowupProvider | undefined;
1312 > private _iconPath: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon | undefined;
1313 > private _helpTextPrefix: string | vscode.MarkdownString | undefined;
1314 > private _helpTextPostfix: string | vscode.MarkdownString | undefined;
1315 > private _onDidReceiveFeedback = new Emitter<vscode.ChatResultFeedback>();
1316 > private _onDidPerformAction = new Emitter<vscode.ChatUserActionEvent>();
1317 > private _supportIssueReporting: boolean | undefined;
1318 > private _agentVariableProvider?: { provider: vscode.ChatParticipantCompletionItemProvider; triggerCharacters: string[] };
1319 > private _additionalWelcomeMessage?: string | vscode.MarkdownString | undefined;
1320 > private _titleProvider?: vscode.ChatTitleProvider | undefined;
1321 > private _summarizer?: vscode.ChatSummarizer | undefined;
1322 > private _pauseStateEmitter = new Emitter<vscode.ChatParticipantPauseStateEvent>();
1323 >
1324 > constructor(
1325 public readonly extension: IExtensionDescription,
1326 public readonly id: string,
1329 private _requestHandler: vscode.ChatExtendedRequestHandler,
1330 ) { }
1332 > acceptFeedback(feedback: vscode.ChatResultFeedback) {
1333 this._onDidReceiveFeedback.fire(feedback);
1334 }
1336 > acceptAction(event: vscode.ChatUserActionEvent) {
1337 this._onDidPerformAction.fire(event);
1338 }
1340 > setChatRequestPauseState(pauseState: vscode.ChatParticipantPauseStateEvent) {
1341 this._pauseStateEmitter.fire(pauseState);
1342 }
1344 > async invokeCompletionProvider(query: string, token: CancellationToken): Promise<vscode.ChatCompletionItem[]> {
1345 if (!this._agentVariableProvider) {
1346 return [];
1349 return await this._agentVariableProvider.provider.provideCompletionItems(query, token) ?? [];
1350 }
1352 > async provideFollowups(result: vscode.ChatResult, context: vscode.ChatContext, token: CancellationToken): Promise<vscode.ChatFollowup[]> {
1353 if (!this._followupProvider) {
1354 return [];
1365 .filter(f => !(f && 'message' in f));
1366 }
1368 > async provideTitle(context: vscode.ChatContext, token: CancellationToken): Promise<string | undefined> {
1369 if (!this._titleProvider) {
1370 return;
1373 return await this._titleProvider.provideChatTitle(context, token) ?? undefined;
1374 }
1376 > async provideSummary(context: vscode.ChatContext, token: CancellationToken): Promise<string | undefined> {
1377 if (!this._summarizer) {
1378 return;
1381 return await this._summarizer.provideChatSummary(context, token) ?? undefined;
1382 }
1384 > get apiAgent(): vscode.ChatParticipant {
1385 let disposed = false;
1386 let updateScheduled = false;
1530 } satisfies vscode.ChatParticipant;
1531 }
1533 > invoke(request: vscode.ChatRequest, context: vscode.ChatContext, response: vscode.ChatResponseStream, token: CancellationToken): vscode.ProviderResult<vscode.ChatResult | void> {
1534 return this._requestHandler(request, context, response, token);
1535 }
1537 >
1538 > /**
1539 > * raceCancellation, but give the promise a little time to complete to see if we can get a real result quickly.
1540 > */
1541 function raceCancellationWithTimeout<T>(cancelWait: number, promise: Promise<T>, token: CancellationToken): Promise<T | undefined> {
1542 return new Promise((resolve, reject) => {
1549 });
1550 }
1552 > /**
1553 > * Lazily computes and caches a promise result until explicitly cleared.
1554 > * Failed computations are not retained so later callers can retry.
1555 > */
1556 > class CachedPromise<T> {
1557 >
1558 > private cachedPromise: Promise<readonly T[]> | undefined;
1559 >
1560 > constructor(private readonly computeFn: () => Promise<readonly T[]>) { }
1561 >
1562 > get(token: CancellationToken): Promise<readonly T[]> {
1563 if (!this.cachedPromise) {
1564 const promise = this.computeFn().catch(err => {
1575 return raceCancellationError(this.cachedPromise, token);
1576 }
1578 > clear(): void {
1579 this.cachedPromise = undefined;
1580 }
1582 >
1583 function isBuiltinParticipant(agentId: string): boolean {
1584 return agentId.startsWith('github.copilot');
src/vs/workbench/contrib/chat/common/actions/chatActions.ts 14 introduced LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatActions.ts
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 { MarshalledId } from '../../../../../base/common/marshallingIds.js';
7 > import { URI } from '../../../../../base/common/uri.js';
8 >
9 > export interface IChatViewTitleActionContext {
10 > readonly $mid: MarshalledId.ChatViewContext;
11 > readonly sessionResource: URI;
12 > }
13 >
14 > export function isChatViewTitleActionContext(obj: unknown): obj is IChatViewTitleActionContext {
15 return !!obj &&
16 URI.isUri((obj as IChatViewTitleActionContext).sessionResource)
src/vs/workbench/api/common/extHostTypeConverters.ts 11 introduced LOC · 2 ranges

Open complete file

2786 export namespace ChatResponseAnchorPart {
2787 export function from(part: vscode.ChatResponseAnchorPart): Dto<IChatContentInlineReference> {
2788 > // Work around type-narrowing confusion between vscode.Uri and URI extHostTypeConverters.ts
2789 > const isUri = (thing: unknown): thing is vscode.Uri => URI.isUri(thing);
2790 > const isSymbolInformation = (thing: object): thing is vscode.SymbolInformation => 'name' in thing;
2791 >
2792 > return {
2793 > kind: 'inlineReference',
2794 > name: part.title,
2795 > inlineReference: isUri(part.value)
2796 > ? part.value
2797 : isSymbolInformation(part.value)
2798 ? WorkspaceSymbol.from(part.value)
2799 : Location.from(part.value)
2801 > }
2802
2803 export function to(part: Dto<IChatContentInlineReference>): vscode.ChatResponseAnchorPart {
src/vs/workbench/api/common/extHostTypes.ts 5 introduced LOC · 1 range

Open complete file

3225
3226 constructor(value: vscode.Uri | vscode.Location | vscode.SymbolInformation, title?: string) {
3227 > // eslint-disable-next-line local/code-no-any-casts extHostTypes.ts
3228 > this.value = value as any;
3229 > this.value2 = value;
3230 > this.title = title;
3231 > }
3232 }
3233
src/vs/base/common/stopwatch.ts 3 introduced LOC · 1 range

Open complete file

29
30 public reset(): void {
31 > this._startTime = this._now(); stopwatch.ts
32 > this._stopTime = -1;
33 > }
34
35 public elapsed(): number {
src/vs/workbench/services/extensions/common/extensions.ts 2 introduced LOC · 2 ranges

Open complete file

465
466 export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {
467 > if (!isProposedApiEnabled(extension, proposal)) { extensions.ts
468 throw new Error(`Extension '${extension.identifier.value}' CANNOT use API proposal: ${proposal}.\nIts package.json#enabledApiProposals-property declares: ${extension.enabledApiProposals?.join(', ') ?? '[]'} but NOT ${proposal}.\n The missing proposal MUST be added and you must start in extension development mode or use the following command line switch: --enable-proposed-api ${extension.identifier.value}`);
469 }
470 > } extensions.ts
471
472