Skip to content

Commit 6721201

Browse files
roblourensjwangxx
andauthored
Add the ability to clear a ChatResponseStream, passing in a reason which results in a warning being displayed (microsoft#257271) (microsoft#259370)
* Add the ability to clear a ChatResponseStream, passing in a reason which results in a warning being displayed * Changing ChatResponseStream.clear to ChatResponseStream.clearToPreviousToolInvocation and only clearing up to the last tool invocation * Remove unnecessary code block Co-authored-by: James Wang <[email protected]>
1 parent e151f76 commit 6721201

File tree

7 files changed

+77
-5
lines changed

7 files changed

+77
-5
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
18591859
ChatPrepareToolInvocationPart: extHostTypes.ChatPrepareToolInvocationPart,
18601860
ChatResponseMultiDiffPart: extHostTypes.ChatResponseMultiDiffPart,
18611861
ChatResponseReferencePartStatusKind: extHostTypes.ChatResponseReferencePartStatusKind,
1862+
ChatResponseClearToPreviousToolInvocationReason: extHostTypes.ChatResponseClearToPreviousToolInvocationReason,
18621863
ChatRequestTurn: extHostTypes.ChatRequestTurn,
18631864
ChatRequestTurn2: extHostTypes.ChatRequestTurn,
18641865
ChatResponseTurn: extHostTypes.ChatResponseTurn,

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import { IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from '../../c
5757
import { ICodeMapperRequest, ICodeMapperResult } from '../../contrib/chat/common/chatCodeMapperService.js';
5858
import { IChatRelatedFile, IChatRelatedFileProviderMetadata as IChatRelatedFilesProviderMetadata, IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js';
5959
import { IChatProgressHistoryResponseContent } from '../../contrib/chat/common/chatModel.js';
60-
import { IChatContentInlineReference, IChatFollowup, IChatNotebookEdit, IChatProgress, IChatTask, IChatTaskDto, IChatUserActionEvent, IChatVoteAction } from '../../contrib/chat/common/chatService.js';
60+
import { IChatContentInlineReference, IChatFollowup, IChatNotebookEdit, IChatProgress, IChatTask, IChatTaskDto, IChatUserActionEvent, IChatVoteAction, ChatResponseClearToPreviousToolInvocationReason } from '../../contrib/chat/common/chatService.js';
6161
import { IChatSessionItem } from '../../contrib/chat/common/chatSessionsService.js';
6262
import { IChatRequestVariableValue } from '../../contrib/chat/common/chatVariables.js';
6363
import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
@@ -1438,7 +1438,8 @@ export type IDocumentContextDto = {
14381438
export type IChatProgressDto =
14391439
| Dto<Exclude<IChatProgress, IChatTask | IChatNotebookEdit>>
14401440
| IChatTaskDto
1441-
| IChatNotebookEditDto;
1441+
| IChatNotebookEditDto
1442+
| IChatResponseClearToPreviousToolInvocationDto;
14421443

14431444
export interface ExtHostUrlsShape {
14441445
$handleExternalUri(handle: number, uri: UriComponents): Promise<void>;
@@ -2193,6 +2194,11 @@ export interface IChatNotebookEditDto {
21932194
done?: boolean;
21942195
}
21952196

2197+
export interface IChatResponseClearToPreviousToolInvocationDto {
2198+
kind: 'clearToPreviousToolInvocation';
2199+
reason: ChatResponseClearToPreviousToolInvocationReason;
2200+
}
2201+
21962202
export type ICellEditOperationDto =
21972203
notebookCommon.ICellMetadataEdit
21982204
| notebookCommon.IDocumentMetadataEdit

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ export class ChatAgentResponseStream {
135135
};
136136

137137
this._apiObject = Object.freeze<vscode.ChatResponseStream>({
138+
clearToPreviousToolInvocation(reason) {
139+
throwIfDone(this.markdown);
140+
send({ kind: 'clearToPreviousToolInvocation', reason: reason });
141+
return this;
142+
},
138143
markdown(value) {
139144
throwIfDone(this.markdown);
140145
const part = new extHostTypes.ChatResponseMarkdownPart(value);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,6 +4848,12 @@ export enum ChatResponseReferencePartStatusKind {
48484848
Omitted = 3
48494849
}
48504850

4851+
export enum ChatResponseClearToPreviousToolInvocationReason {
4852+
NoReason = 0,
4853+
FilteredContentRetry = 1,
4854+
CopyrightContentRetry = 2,
4855+
}
4856+
48514857
export class ChatRequestEditorData implements vscode.ChatRequestEditorData {
48524858
constructor(
48534859
readonly document: vscode.TextDocument,

src/vs/workbench/contrib/chat/common/chatModel.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommo
2626
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, reviveSerializedAgent } from './chatAgents.js';
2727
import { IChatEditingService, IChatEditingSession } from './chatEditingService.js';
2828
import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js';
29-
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMultiDiffData, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js';
29+
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatClearToPreviousToolInvocation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMultiDiffData, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext, ChatResponseClearToPreviousToolInvocationReason } from './chatService.js';
3030
import { IChatRequestVariableEntry } from './chatVariableEntries.js';
3131
import { ChatAgentLocation, ChatModeKind } from './constants.js';
3232

@@ -129,7 +129,8 @@ export type IChatProgressResponseContent =
129129
| IChatToolInvocationSerialized
130130
| IChatUndoStop
131131
| IChatPrepareToolInvocationPart
132-
| IChatElicitationRequest;
132+
| IChatElicitationRequest
133+
| IChatClearToPreviousToolInvocation;
133134

134135
const nonHistoryKinds = new Set(['toolInvocation', 'toolInvocationSerialized', 'undoStop', 'prepareToolInvocation']);
135136
function isChatProgressHistoryResponseContent(content: IChatProgressResponseContent): content is IChatProgressHistoryResponseContent {
@@ -350,6 +351,10 @@ class AbstractResponse implements IResponse {
350351
for (const part of parts) {
351352
let segment: { text: string; isBlock?: boolean } | undefined;
352353
switch (part.kind) {
354+
case 'clearToPreviousToolInvocation':
355+
currentBlockSegments = [];
356+
blocks.length = 0;
357+
continue;
353358
case 'treeData':
354359
case 'progressMessage':
355360
case 'codeblockUri':
@@ -465,8 +470,38 @@ export class Response extends AbstractResponse implements IDisposable {
465470
this._updateRepr(true);
466471
}
467472

473+
clearToPreviousToolInvocation(message?: string): void {
474+
// look through the response parts and find the last tool invocation, then slice the response parts to that point
475+
let lastToolInvocationIndex = -1;
476+
for (let i = this._responseParts.length - 1; i >= 0; i--) {
477+
const part = this._responseParts[i];
478+
if (part.kind === 'toolInvocation' || part.kind === 'toolInvocationSerialized') {
479+
lastToolInvocationIndex = i;
480+
break;
481+
}
482+
}
483+
if (lastToolInvocationIndex !== -1) {
484+
this._responseParts = this._responseParts.slice(0, lastToolInvocationIndex + 1);
485+
} else {
486+
this._responseParts = [];
487+
}
488+
if (message) {
489+
this._responseParts.push({ kind: 'warning', content: new MarkdownString(message) });
490+
}
491+
this._updateRepr(true);
492+
}
493+
468494
updateContent(progress: IChatProgressResponseContent | IChatTextEdit | IChatNotebookEdit | IChatTask, quiet?: boolean): void {
469-
if (progress.kind === 'markdownContent') {
495+
if (progress.kind === 'clearToPreviousToolInvocation') {
496+
if (progress.reason === ChatResponseClearToPreviousToolInvocationReason.CopyrightContentRetry) {
497+
this.clearToPreviousToolInvocation(localize('copyrightContentRetry', "Response cleared due to possible match to public code, retrying with modified prompt."));
498+
} else if (progress.reason === ChatResponseClearToPreviousToolInvocationReason.FilteredContentRetry) {
499+
this.clearToPreviousToolInvocation(localize('filteredContentRetry', "Response cleared due to content safety filters, retrying with modified prompt."));
500+
} else {
501+
this.clearToPreviousToolInvocation();
502+
}
503+
return;
504+
} else if (progress.kind === 'markdownContent') {
470505

471506
// last response which is NOT a text edit group because we do want to support heterogenous streaming but not have
472507
// the MD be chopped up by text edit groups (and likely other non-renderable parts)

src/vs/workbench/contrib/chat/common/chatService.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ export enum ChatResponseReferencePartStatusKind {
102102
Omitted = 3
103103
}
104104

105+
export enum ChatResponseClearToPreviousToolInvocationReason {
106+
NoReason = 0,
107+
FilteredContentRetry = 1,
108+
CopyrightContentRetry = 2,
109+
}
110+
105111
export interface IChatContentReference {
106112
reference: URI | Location | IChatContentVariableReference | string;
107113
iconPath?: ThemeIcon | { light: URI; dark?: URI };
@@ -229,6 +235,11 @@ export interface IChatTextEdit {
229235
done?: boolean;
230236
}
231237

238+
export interface IChatClearToPreviousToolInvocation {
239+
kind: 'clearToPreviousToolInvocation';
240+
reason: ChatResponseClearToPreviousToolInvocationReason;
241+
}
242+
232243
export interface IChatNotebookEdit {
233244
uri: URI;
234245
edits: ICellEditOperation[];
@@ -370,6 +381,7 @@ export type IChatProgress =
370381
| IChatMoveMessage
371382
| IChatResponseCodeblockUriPart
372383
| IChatConfirmation
384+
| IChatClearToPreviousToolInvocation
373385
| IChatToolInvocation
374386
| IChatToolInvocationSerialized
375387
| IChatExtensionsContent

src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ declare module 'vscode' {
298298
prepareToolInvocation(toolName: string): void;
299299

300300
push(part: ExtendedChatResponsePart): void;
301+
302+
clearToPreviousToolInvocation(reason: ChatResponseClearToPreviousToolInvocationReason): void;
301303
}
302304

303305
export enum ChatResponseReferencePartStatusKind {
@@ -306,6 +308,11 @@ declare module 'vscode' {
306308
Omitted = 3
307309
}
308310

311+
export enum ChatResponseClearToPreviousToolInvocationReason {
312+
NoReason = 0,
313+
FilteredContentRetry = 1,
314+
CopyrightContentRetry = 2,
315+
}
309316

310317
/**
311318
* Does this piggy-back on the existing ChatRequest, or is it a different type of request entirely?

0 commit comments

Comments
 (0)