Skip to content

Commit 50a6f4f

Browse files
authored
Delete deprecated chat API (microsoft#210199)
* Add Chat content 'vulnerabilities' to chat response stream * Remove 'report' chat progress API and more cleanup * Remove ChatProgress entirely * Get participant detection into the new stream as well
1 parent 2cb7ce5 commit 50a6f4f

File tree

14 files changed

+142
-247
lines changed

14 files changed

+142
-247
lines changed

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
16941694
ChatResponseProgressPart: extHostTypes.ChatResponseProgressPart,
16951695
ChatResponseReferencePart: extHostTypes.ChatResponseReferencePart,
16961696
ChatResponseTextEditPart: extHostTypes.ChatResponseTextEditPart,
1697+
ChatResponseMarkdownWithVulnerabilitiesPart: extHostTypes.ChatResponseMarkdownWithVulnerabilitiesPart,
16971698
ChatResponseCommandButtonPart: extHostTypes.ChatResponseCommandButtonPart,
1699+
ChatResponseDetectedParticipantPart: extHostTypes.ChatResponseDetectedParticipantPart,
16981700
ChatRequestTurn: extHostTypes.ChatRequestTurn,
16991701
ChatResponseTurn: extHostTypes.ChatResponseTurn,
17001702
ChatLocation: extHostTypes.ChatLocation,

src/vs/workbench/api/common/extHostChatAgents2.ts

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Location } from 'vs/editor/common/languages';
76
import { coalesce } from 'vs/base/common/arrays';
87
import { raceCancellation } from 'vs/base/common/async';
98
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -15,6 +14,7 @@ import { DisposableMap, DisposableStore } from 'vs/base/common/lifecycle';
1514
import { StopWatch } from 'vs/base/common/stopwatch';
1615
import { assertType } from 'vs/base/common/types';
1716
import { URI } from 'vs/base/common/uri';
17+
import { Location } from 'vs/editor/common/languages';
1818
import { localize } from 'vs/nls';
1919
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
2020
import { ILogService } from 'vs/platform/log/common/log';
@@ -33,13 +33,12 @@ class ChatAgentResponseStream {
3333
private _stopWatch = StopWatch.create(false);
3434
private _isClosed: boolean = false;
3535
private _firstProgress: number | undefined;
36-
private _apiObject: vscode.ChatExtendedResponseStream | undefined;
36+
private _apiObject: vscode.ChatResponseStream | undefined;
3737

3838
constructor(
3939
private readonly _extension: IExtensionDescription,
4040
private readonly _request: IChatAgentRequest,
4141
private readonly _proxy: MainThreadChatAgentsShape2,
42-
private readonly _logService: ILogService,
4342
private readonly _commandsConverter: CommandsConverter,
4443
private readonly _sessionDisposables: DisposableStore
4544
) { }
@@ -86,6 +85,17 @@ class ChatAgentResponseStream {
8685
_report(dto);
8786
return this;
8887
},
88+
markdownWithVulnerabilities(value, vulnerabilities) {
89+
throwIfDone(this.markdown);
90+
if (vulnerabilities) {
91+
checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
92+
}
93+
94+
const part = new extHostTypes.ChatResponseMarkdownWithVulnerabilitiesPart(value, vulnerabilities);
95+
const dto = typeConvert.ChatResponseMarkdownWithVulnerabilitiesPart.from(part);
96+
_report(dto);
97+
return this;
98+
},
8999
filetree(value, baseUri) {
90100
throwIfDone(this.filetree);
91101
const part = new extHostTypes.ChatResponseFileTreePart(value, baseUri);
@@ -156,10 +166,19 @@ class ChatAgentResponseStream {
156166
_report(dto);
157167
return this;
158168
},
169+
detectedParticipant(participant, command) {
170+
throwIfDone(this.detectedParticipant);
171+
checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
172+
173+
const part = new extHostTypes.ChatResponseDetectedParticipantPart(participant, command);
174+
const dto = typeConvert.ChatResponseDetectedParticipantPart.from(part);
175+
_report(dto);
176+
return this;
177+
},
159178
push(part) {
160179
throwIfDone(this.push);
161180

162-
if (part instanceof extHostTypes.ChatResponseTextEditPart) {
181+
if (part instanceof extHostTypes.ChatResponseTextEditPart || part instanceof extHostTypes.ChatResponseMarkdownWithVulnerabilitiesPart || part instanceof extHostTypes.ChatResponseDetectedParticipantPart) {
163182
checkProposedApiEnabled(that._extension, 'chatParticipantAdditions');
164183
}
165184

@@ -173,22 +192,6 @@ class ChatAgentResponseStream {
173192

174193
return this;
175194
},
176-
report(progress) {
177-
throwIfDone(this.report);
178-
if ('placeholder' in progress && 'resolvedContent' in progress) {
179-
// Ignore for now, this is the deleted Task type
180-
return;
181-
}
182-
183-
const value = typeConvert.ChatResponseProgress.from(that._extension, progress);
184-
if (!value) {
185-
that._logService.error('Unknown progress type: ' + JSON.stringify(progress));
186-
return;
187-
}
188-
189-
_report(value);
190-
return this;
191-
}
192195
};
193196
}
194197

@@ -248,7 +251,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
248251
this._sessionDisposables.set(request.sessionId, sessionDisposables);
249252
}
250253

251-
const stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this._logService, this.commands.converter, sessionDisposables);
254+
const stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this.commands.converter, sessionDisposables);
252255
try {
253256
const convertedHistory = await this.prepareHistoryTurns(request.agentId, context);
254257
const task = agent.invoke(
@@ -662,7 +665,7 @@ class ExtHostChatAgent {
662665
} satisfies vscode.ChatParticipant;
663666
}
664667

665-
invoke(request: vscode.ChatRequest, context: vscode.ChatContext, response: vscode.ChatExtendedResponseStream, token: CancellationToken): vscode.ProviderResult<vscode.ChatResult | void> {
668+
invoke(request: vscode.ChatRequest, context: vscode.ChatContext, response: vscode.ChatResponseStream, token: CancellationToken): vscode.ProviderResult<vscode.ChatResult | void> {
666669
return this._requestHandler(request, context, response, token);
667670
}
668671
}

src/vs/workbench/api/common/extHostTypeConverters.ts

Lines changed: 40 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from 'vs/workbench/common/edit
3939
import { IViewBadge } from 'vs/workbench/common/views';
4040
import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
4141
import { IChatRequestVariableEntry } from 'vs/workbench/contrib/chat/common/chatModel';
42-
import { IChatCommandButton, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgressMessage, IChatTextEdit, IChatTreeData, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
42+
import { IChatAgentDetection, IChatAgentMarkdownContentWithVulnerability, IChatCommandButton, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgressMessage, IChatTextEdit, IChatTreeData, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
4343
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
4444
import * as chatProvider from 'vs/workbench/contrib/chat/common/languageModels';
4545
import { DebugTreeItemCollapsibleState, IDebugVisualizationTreeItem } from 'vs/workbench/contrib/debug/common/debug';
@@ -51,7 +51,6 @@ import { TestId } from 'vs/workbench/contrib/testing/common/testId';
5151
import { CoverageDetails, DetailType, ICoverageCount, IFileCoverage, ISerializedTestResults, ITestErrorMessage, ITestItem, ITestTag, TestMessageType, TestResultItem, denamespaceTestTag, namespaceTestTag } from 'vs/workbench/contrib/testing/common/testTypes';
5252
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
5353
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
54-
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
5554
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
5655
import type * as vscode from 'vscode';
5756
import * as types from './extHostTypes';
@@ -2361,6 +2360,32 @@ export namespace ChatResponseMarkdownPart {
23612360
}
23622361
}
23632362

2363+
export namespace ChatResponseMarkdownWithVulnerabilitiesPart {
2364+
export function from(part: vscode.ChatResponseMarkdownWithVulnerabilitiesPart): Dto<IChatAgentMarkdownContentWithVulnerability> {
2365+
return {
2366+
kind: 'markdownVuln',
2367+
content: MarkdownString.from(part.value),
2368+
vulnerabilities: part.vulnerabilities,
2369+
};
2370+
}
2371+
export function to(part: Dto<IChatAgentMarkdownContentWithVulnerability>): vscode.ChatResponseMarkdownWithVulnerabilitiesPart {
2372+
return new types.ChatResponseMarkdownWithVulnerabilitiesPart(MarkdownString.to(part.content), part.vulnerabilities);
2373+
}
2374+
}
2375+
2376+
export namespace ChatResponseDetectedParticipantPart {
2377+
export function from(part: vscode.ChatResponseDetectedParticipantPart): Dto<IChatAgentDetection> {
2378+
return {
2379+
kind: 'agentDetection',
2380+
agentId: part.participant,
2381+
command: part.command,
2382+
};
2383+
}
2384+
export function to(part: Dto<IChatAgentDetection>): vscode.ChatResponseDetectedParticipantPart {
2385+
return new types.ChatResponseDetectedParticipantPart(part.agentId, part.command);
2386+
}
2387+
}
2388+
23642389
export namespace ChatResponseFilesPart {
23652390
export function from(part: vscode.ChatResponseFileTreePart): IChatTreeData {
23662391
const { value, baseUri } = part;
@@ -2499,7 +2524,7 @@ export namespace ChatResponseReferencePart {
24992524

25002525
export namespace ChatResponsePart {
25012526

2502-
export function from(part: vscode.ChatResponsePart | vscode.ChatResponseTextEditPart, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): extHostProtocol.IChatProgressDto {
2527+
export function from(part: vscode.ChatResponsePart | vscode.ChatResponseTextEditPart | vscode.ChatResponseMarkdownWithVulnerabilitiesPart | vscode.ChatResponseDetectedParticipantPart, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): extHostProtocol.IChatProgressDto {
25032528
if (part instanceof types.ChatResponseMarkdownPart) {
25042529
return ChatResponseMarkdownPart.from(part);
25052530
} else if (part instanceof types.ChatResponseAnchorPart) {
@@ -2514,12 +2539,16 @@ export namespace ChatResponsePart {
25142539
return ChatResponseCommandButtonPart.from(part, commandsConverter, commandDisposables);
25152540
} else if (part instanceof types.ChatResponseTextEditPart) {
25162541
return ChatResponseTextEditPart.from(part);
2542+
} else if (part instanceof types.ChatResponseMarkdownWithVulnerabilitiesPart) {
2543+
return ChatResponseMarkdownWithVulnerabilitiesPart.from(part);
2544+
} else if (part instanceof types.ChatResponseDetectedParticipantPart) {
2545+
return ChatResponseDetectedParticipantPart.from(part);
25172546
}
2547+
25182548
return {
2519-
kind: 'content',
2520-
content: ''
2549+
kind: 'markdownContent',
2550+
content: MarkdownString.from('')
25212551
};
2522-
25232552
}
25242553

25252554
export function to(part: extHostProtocol.IChatProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponsePart | undefined {
@@ -2548,86 +2577,6 @@ export namespace ChatResponsePart {
25482577
}
25492578
}
25502579

2551-
export namespace ChatResponseProgress {
2552-
export function from(extension: IExtensionDescription, progress: vscode.ChatExtendedProgress): extHostProtocol.IChatProgressDto | undefined {
2553-
if ('markdownContent' in progress) {
2554-
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
2555-
return { content: MarkdownString.from(progress.markdownContent), kind: 'markdownContent' };
2556-
} else if ('content' in progress) {
2557-
if ('vulnerabilities' in progress && progress.vulnerabilities) {
2558-
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
2559-
return { content: progress.content, vulnerabilities: progress.vulnerabilities, kind: 'vulnerability' };
2560-
}
2561-
2562-
if (typeof progress.content === 'string') {
2563-
return { content: progress.content, kind: 'content' };
2564-
}
2565-
2566-
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
2567-
return { content: MarkdownString.from(progress.content), kind: 'markdownContent' };
2568-
} else if ('documents' in progress) {
2569-
return {
2570-
documents: progress.documents.map(d => ({
2571-
uri: d.uri,
2572-
version: d.version,
2573-
ranges: d.ranges.map(r => Range.from(r))
2574-
})),
2575-
kind: 'usedContext'
2576-
};
2577-
} else if ('reference' in progress) {
2578-
return {
2579-
reference: 'uri' in progress.reference ?
2580-
{
2581-
uri: progress.reference.uri,
2582-
range: Range.from(progress.reference.range)
2583-
} : progress.reference,
2584-
kind: 'reference'
2585-
};
2586-
} else if ('inlineReference' in progress) {
2587-
return {
2588-
inlineReference: 'uri' in progress.inlineReference ?
2589-
{
2590-
uri: progress.inlineReference.uri,
2591-
range: Range.from(progress.inlineReference.range)
2592-
} : progress.inlineReference,
2593-
name: progress.title,
2594-
kind: 'inlineReference'
2595-
};
2596-
} else if ('participant' in progress) {
2597-
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
2598-
return { agentId: progress.participant, command: progress.command, kind: 'agentDetection' };
2599-
} else if ('message' in progress) {
2600-
return { content: MarkdownString.from(progress.message), kind: 'progressMessage' };
2601-
} else {
2602-
return undefined;
2603-
}
2604-
}
2605-
2606-
export function toProgressContent(progress: extHostProtocol.IChatContentProgressDto, commandsConverter: Command.ICommandsConverter): vscode.ChatContentProgress | undefined {
2607-
switch (progress.kind) {
2608-
case 'markdownContent':
2609-
// For simplicity, don't sent back the 'extended' types, so downgrade markdown to just some text
2610-
return { content: progress.content.value };
2611-
case 'inlineReference':
2612-
return {
2613-
inlineReference:
2614-
isUriComponents(progress.inlineReference) ?
2615-
URI.revive(progress.inlineReference) :
2616-
Location.to(progress.inlineReference),
2617-
title: progress.name
2618-
};
2619-
case 'command':
2620-
// If the command isn't in the converter, then this session may have been restored, and the command args don't exist anymore
2621-
return {
2622-
command: commandsConverter.fromInternal(progress.command) ?? { command: progress.command.id, title: progress.command.title },
2623-
};
2624-
default:
2625-
// Unknown type, eg something in history that was removed? Ignore
2626-
return undefined;
2627-
}
2628-
}
2629-
}
2630-
26312580
export namespace ChatAgentRequest {
26322581
export function to(request: IChatAgentRequest): vscode.ChatRequest {
26332582
return {
@@ -2692,7 +2641,11 @@ export namespace ChatAgentUserActionEvent {
26922641

26932642
const ehResult = ChatAgentResult.to(result);
26942643
if (event.action.kind === 'command') {
2695-
const commandAction: vscode.ChatCommandAction = { kind: 'command', commandButton: ChatResponseProgress.toProgressContent(event.action.commandButton, commandsConverter) as vscode.ChatCommandButton };
2644+
const command = event.action.commandButton.command;
2645+
const commandButton = {
2646+
command: commandsConverter.fromInternal(command) ?? { command: command.id, title: command.title },
2647+
};
2648+
const commandAction: vscode.ChatCommandAction = { kind: 'command', commandButton };
26962649
return { action: commandAction, result: ehResult };
26972650
} else if (event.action.kind === 'followUp') {
26982651
const followupAction: vscode.ChatFollowupAction = { kind: 'followUp', followup: ChatFollowup.to(event.action.followup) };

src/vs/workbench/api/common/extHostTypes.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4276,6 +4276,29 @@ export class ChatResponseMarkdownPart {
42764276
}
42774277
}
42784278

4279+
/**
4280+
* TODO if 'vulnerabilities' is finalized, this should be merged with the base ChatResponseMarkdownPart. I just don't see how to do that while keeping
4281+
* vulnerabilities in a seperate API proposal in a clean way.
4282+
*/
4283+
export class ChatResponseMarkdownWithVulnerabilitiesPart {
4284+
value: vscode.MarkdownString;
4285+
vulnerabilities: vscode.ChatVulnerability[];
4286+
constructor(value: string | vscode.MarkdownString, vulnerabilities: vscode.ChatVulnerability[]) {
4287+
this.value = typeof value === 'string' ? new MarkdownString(value) : value;
4288+
this.vulnerabilities = vulnerabilities;
4289+
}
4290+
}
4291+
4292+
export class ChatResponseDetectedParticipantPart {
4293+
participant: string;
4294+
// TODO@API validate this against statically-declared slash commands?
4295+
command?: vscode.ChatCommand;
4296+
constructor(participant: string, command?: vscode.ChatCommand) {
4297+
this.participant = participant;
4298+
this.command = command;
4299+
}
4300+
}
4301+
42794302
export class ChatResponseFileTreePart {
42804303
value: vscode.ChatResponseFileTree[];
42814304
baseUri: vscode.Uri;

src/vs/workbench/contrib/chat/browser/chat.contribution.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
257257
if (isMarkdownString(defaultAgent.metadata.helpTextPrefix)) {
258258
progress.report({ content: defaultAgent.metadata.helpTextPrefix, kind: 'markdownContent' });
259259
} else {
260-
progress.report({ content: defaultAgent.metadata.helpTextPrefix, kind: 'content' });
260+
progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextPrefix), kind: 'markdownContent' });
261261
}
262-
progress.report({ content: '\n\n', kind: 'content' });
262+
progress.report({ content: new MarkdownString('\n\n'), kind: 'markdownContent' });
263263
}
264264

265265
// Report agent list
@@ -282,11 +282,11 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
282282

283283
// Report variables
284284
if (defaultAgent?.metadata.helpTextVariablesPrefix) {
285-
progress.report({ content: '\n\n', kind: 'content' });
285+
progress.report({ content: new MarkdownString('\n\n'), kind: 'markdownContent' });
286286
if (isMarkdownString(defaultAgent.metadata.helpTextVariablesPrefix)) {
287287
progress.report({ content: defaultAgent.metadata.helpTextVariablesPrefix, kind: 'markdownContent' });
288288
} else {
289-
progress.report({ content: defaultAgent.metadata.helpTextVariablesPrefix, kind: 'content' });
289+
progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextVariablesPrefix), kind: 'markdownContent' });
290290
}
291291

292292
const variables = [
@@ -296,16 +296,16 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
296296
const variableText = variables
297297
.map(v => `* \`${chatVariableLeader}${v.name}\` - ${v.description}`)
298298
.join('\n');
299-
progress.report({ content: '\n' + variableText, kind: 'content' });
299+
progress.report({ content: new MarkdownString('\n' + variableText), kind: 'markdownContent' });
300300
}
301301

302302
// Report help text ending
303303
if (defaultAgent?.metadata.helpTextPostfix) {
304-
progress.report({ content: '\n\n', kind: 'content' });
304+
progress.report({ content: new MarkdownString('\n\n'), kind: 'markdownContent' });
305305
if (isMarkdownString(defaultAgent.metadata.helpTextPostfix)) {
306306
progress.report({ content: defaultAgent.metadata.helpTextPostfix, kind: 'markdownContent' });
307307
} else {
308-
progress.report({ content: defaultAgent.metadata.helpTextPostfix, kind: 'content' });
308+
progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextPostfix), kind: 'markdownContent' });
309309
}
310310
}
311311
}));

src/vs/workbench/contrib/chat/browser/chatListRenderer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
957957
isTrusted: {
958958
// Disable all other config options except isTrusted
959959
enabledCommands: typeof markdown.isTrusted === 'object' ? markdown.isTrusted?.enabledCommands : [] ?? []
960-
}
960+
},
961+
supportHtml: true
961962
});
962963

963964
// We release editors in order so that it's more likely that the same editor will be assigned if this element is re-rendered right away, like it often is during progressive rendering

0 commit comments

Comments
 (0)