Skip to content

Commit da9c9d6

Browse files
authored
Merge pull request #282324 from microsoft/roblou/irrelevant-anaconda
Store lastResponseState in metadata
2 parents 8c4a711 + 387376f commit da9c9d6

File tree

9 files changed

+86
-32
lines changed

9 files changed

+86
-32
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatActions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ import { ChatContextKeys } from '../../common/chatContextKeys.js';
6161
import { ModifiedFileEntryState } from '../../common/chatEditingService.js';
6262
import { IChatModel, IChatResponseModel } from '../../common/chatModel.js';
6363
import { ChatMode, IChatMode, IChatModeService } from '../../common/chatModes.js';
64-
import { IChatDetail, IChatService } from '../../common/chatService.js';
64+
import { IChatDetail, IChatService, ResponseModelState } from '../../common/chatService.js';
6565
import { IChatSessionItem, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
6666
import { ISCMHistoryItemChangeRangeVariableEntry, ISCMHistoryItemChangeVariableEntry } from '../../common/chatVariableEntries.js';
6767
import { IChatRequestViewModel, IChatResponseViewModel, isRequestVM } from '../../common/chatViewModel.js';
@@ -766,6 +766,7 @@ export function registerChatActions() {
766766
title: session.label,
767767
isActive: false,
768768
lastMessageDate: 0,
769+
lastResponseState: ResponseModelState.Complete
769770
},
770771
buttons,
771772
};

src/vs/workbench/contrib/chat/browser/agentSessions/localAgentSessionsProvider.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ResourceSet } from '../../../../../base/common/map.js';
1212
import { Schemas } from '../../../../../base/common/network.js';
1313
import { IWorkbenchContribution } from '../../../../common/contributions.js';
1414
import { IChatModel } from '../../common/chatModel.js';
15-
import { IChatDetail, IChatService } from '../../common/chatService.js';
15+
import { IChatDetail, IChatService, ResponseModelState } from '../../common/chatService.js';
1616
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemProvider, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
1717
import { ChatSessionItemWithProvider } from '../chatSessions/common.js';
1818

@@ -147,7 +147,9 @@ export class LocalAgentsSessionsProvider extends Disposable implements IChatSess
147147
provider: this,
148148
label: chat.title,
149149
description,
150-
status: model ? this.modelToStatus(model) : undefined,
150+
status: model ?
151+
this.modelToStatus(model) :
152+
chatResponseStateToSessionStatus(chat.lastResponseState),
151153
iconPath: Codicon.chatSparkle,
152154
timing: {
153155
startTime,
@@ -161,3 +163,15 @@ export class LocalAgentsSessionsProvider extends Disposable implements IChatSess
161163
};
162164
}
163165
}
166+
167+
function chatResponseStateToSessionStatus(state: ResponseModelState): ChatSessionStatus {
168+
switch (state) {
169+
case ResponseModelState.Cancelled:
170+
case ResponseModelState.Complete:
171+
return ChatSessionStatus.Completed;
172+
case ResponseModelState.Failed:
173+
return ChatSessionStatus.Failed;
174+
case ResponseModelState.Pending:
175+
return ChatSessionStatus.InProgress;
176+
}
177+
}

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { migrateLegacyTerminalToolSpecificData } from './chat.js';
3232
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, UserSelectedTools, reviveSerializedAgent } from './chatAgents.js';
3333
import { IChatEditingService, IChatEditingSession, ModifiedFileEntryState, editEntriesToMultiDiffData } from './chatEditingService.js';
3434
import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js';
35-
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatResponseClearToPreviousToolInvocationReason, ElicitationState, IChatAgentMarkdownContentWithVulnerability, IChatClearToPreviousToolInvocation, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatElicitationRequestSerialized, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMcpServersStarting, IChatModelReference, IChatMultiDiffData, IChatMultiDiffDataSerialized, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatService, IChatSessionContext, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js';
35+
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatResponseClearToPreviousToolInvocationReason, ElicitationState, IChatAgentMarkdownContentWithVulnerability, IChatClearToPreviousToolInvocation, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatElicitationRequestSerialized, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMcpServersStarting, IChatModelReference, IChatMultiDiffData, IChatMultiDiffDataSerialized, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatService, IChatSessionContext, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, ResponseModelState, isIUsedContext } from './chatService.js';
3636
import { LocalChatSessionUri } from './chatUri.js';
3737
import { ChatRequestToolReferenceEntry, IChatRequestVariableEntry } from './chatVariableEntries.js';
3838
import { ChatAgentLocation, ChatModeKind } from './constants.js';
@@ -194,6 +194,8 @@ export interface IChatResponseModel {
194194
readonly timestamp: number;
195195
/** Milliseconds timestamp when this chat response was completed or cancelled. */
196196
readonly completedAt?: number;
197+
/** The state of this response */
198+
readonly state: ResponseModelState;
197199
/**
198200
* Adjusted millisecond timestamp that excludes the duration during which
199201
* the model was pending user confirmation. `Date.now() - confirmationAdjustedTimestamp`
@@ -772,15 +774,9 @@ export interface IChatResponseModelParameters {
772774
codeBlockInfos: ICodeBlockInfo[] | undefined;
773775
}
774776

775-
const enum ResponseModelState {
776-
Pending,
777-
Complete,
778-
Cancelled,
779-
}
780-
781777
type ResponseModelStateT =
782778
| { value: ResponseModelState.Pending }
783-
| { value: ResponseModelState.Complete | ResponseModelState.Cancelled; completedAt: number };
779+
| { value: ResponseModelState.Complete | ResponseModelState.Cancelled | ResponseModelState.Failed; completedAt: number };
784780

785781
export class ChatResponseModel extends Disposable implements IChatResponseModel {
786782
private readonly _onDidChange = this._register(new Emitter<ChatResponseModelChangeReason>());
@@ -838,12 +834,22 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
838834

839835
public get completedAt(): number | undefined {
840836
const state = this._modelState.get();
841-
if (state.value === ResponseModelState.Complete || state.value === ResponseModelState.Cancelled) {
837+
if (state.value === ResponseModelState.Complete || state.value === ResponseModelState.Cancelled || state.value === ResponseModelState.Failed) {
842838
return state.completedAt;
843839
}
844840
return undefined;
845841
}
846842

843+
public get state(): ResponseModelState {
844+
const state = this._modelState.get().value;
845+
if (state === ResponseModelState.Complete && !!this._result?.errorDetails && this.result?.errorDetails?.code !== 'canceled') {
846+
// This check covers sessions created in previous vscode versions which saved a failed response as 'Complete'
847+
return ResponseModelState.Failed;
848+
}
849+
850+
return state;
851+
}
852+
847853
public get vote(): ChatAgentVoteDirection | undefined {
848854
return this._vote;
849855
}
@@ -1073,7 +1079,9 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
10731079
this._response.clear();
10741080
}
10751081

1076-
this._modelState.set({ value: ResponseModelState.Complete, completedAt: Date.now() }, undefined);
1082+
// Canceled sessions can be considered 'Complete'
1083+
const state = !!this._result?.errorDetails && this._result.errorDetails.code !== 'canceled' ? ResponseModelState.Failed : ResponseModelState.Complete;
1084+
this._modelState.set({ value: state, completedAt: Date.now() }, undefined);
10771085
this._onDidChange.fire({ reason: 'completedRequest' });
10781086
}
10791087

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,12 +916,20 @@ export interface IChatSessionStats {
916916
removed: number;
917917
}
918918

919+
export const enum ResponseModelState {
920+
Pending,
921+
Complete,
922+
Cancelled,
923+
Failed
924+
}
925+
919926
export interface IChatDetail {
920927
sessionResource: URI;
921928
title: string;
922929
lastMessageDate: number;
923930
isActive: boolean;
924931
stats?: IChatSessionStats;
932+
lastResponseState: ResponseModelState;
925933
}
926934

927935
export interface IChatProviderInfo {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, ICha
3636
import { ChatModelStore, IStartSessionProps } from './chatModelStore.js';
3737
import { chatAgentLeader, ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, chatSubcommandLeader, getPromptText, IParsedChatRequest } from './chatParserTypes.js';
3838
import { ChatRequestParser } from './chatRequestParser.js';
39-
import { ChatMcpServersStarting, IChatCompleteResponse, IChatDetail, IChatFollowup, IChatModelReference, IChatProgress, IChatSendRequestData, IChatSendRequestOptions, IChatSendRequestResponseState, IChatService, IChatSessionContext, IChatSessionStartOptions, IChatTransferredSessionData, IChatUserActionEvent } from './chatService.js';
39+
import { ChatMcpServersStarting, IChatCompleteResponse, IChatDetail, IChatFollowup, IChatModelReference, IChatProgress, IChatSendRequestData, IChatSendRequestOptions, IChatSendRequestResponseState, IChatService, IChatSessionContext, IChatSessionStartOptions, IChatTransferredSessionData, IChatUserActionEvent, ResponseModelState } from './chatService.js';
4040
import { ChatRequestTelemetry, ChatServiceTelemetry } from './chatServiceTelemetry.js';
4141
import { IChatSessionsService } from './chatSessionsService.js';
4242
import { ChatSessionStore, IChatSessionEntryMetadata, IChatTransfer2 } from './chatSessionStore.js';
@@ -401,6 +401,7 @@ export class ChatService extends Disposable implements IChatService {
401401
lastMessageDate: session.lastMessageDate,
402402
isActive: true,
403403
stats: await awaitStatsForSession(session),
404+
lastResponseState: session.lastRequest?.response?.state ?? ResponseModelState.Pending,
404405
};
405406
}));
406407
}
@@ -419,6 +420,8 @@ export class ChatService extends Disposable implements IChatService {
419420
...entry,
420421
sessionResource,
421422
isActive: this._sessionModels.has(sessionResource),
423+
// TODO@roblourens- missing for old data- normalize inside the store
424+
lastResponseState: entry.lastResponseState ?? ResponseModelState.Complete,
422425
});
423426
});
424427
}
@@ -431,6 +434,8 @@ export class ChatService extends Disposable implements IChatService {
431434
...metadata,
432435
sessionResource,
433436
isActive: this._sessionModels.has(sessionResource),
437+
// TODO@roblourens- missing for old data- normalize inside the store
438+
lastResponseState: metadata.lastResponseState ?? ResponseModelState.Complete,
434439
};
435440
}
436441

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ILifecycleService } from '../../../services/lifecycle/common/lifecycle.
2323
import { awaitStatsForSession } from './chat.js';
2424
import { ModifiedFileEntryState } from './chatEditingService.js';
2525
import { ChatModel, IChatModelInputState, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, normalizeSerializableChatData } from './chatModel.js';
26-
import { IChatSessionStats } from './chatService.js';
26+
import { IChatSessionStats, ResponseModelState } from './chatService.js';
2727
import { LocalChatSessionUri } from './chatUri.js';
2828
import { ChatAgentLocation } from './constants.js';
2929

@@ -433,6 +433,7 @@ export interface IChatSessionEntryMetadata {
433433
initialLocation?: ChatAgentLocation;
434434
hasPendingEdits?: boolean;
435435
stats?: IChatSessionStats;
436+
lastResponseState?: ResponseModelState;
436437

437438
/**
438439
* This only exists because the migrated data from the storage service had empty sessions persisted, and it's impossible to know which ones are
@@ -505,7 +506,10 @@ async function getSessionMetadata(session: ChatModel | ISerializableChatData): P
505506
hasPendingEdits: session instanceof ChatModel ? (session.editingSession?.entries.get().some(e => e.state.get() === ModifiedFileEntryState.Modified)) : false,
506507
isEmpty: session instanceof ChatModel ? session.getRequests().length === 0 : session.requests.length === 0,
507508
stats,
508-
isExternal: session instanceof ChatModel && !LocalChatSessionUri.parseLocalSessionId(session.sessionResource)
509+
isExternal: session instanceof ChatModel && !LocalChatSessionUri.parseLocalSessionId(session.sessionResource),
510+
lastResponseState: session instanceof ChatModel ?
511+
(session.lastRequest?.response?.state ?? ResponseModelState.Complete) :
512+
ResponseModelState.Complete
509513
};
510514
}
511515

src/vs/workbench/contrib/chat/test/browser/localAgentSessionsProvider.test.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { workbenchInstantiationService } from '../../../../test/browser/workbenc
1717
import { LocalAgentsSessionsProvider } from '../../browser/agentSessions/localAgentSessionsProvider.js';
1818
import { ModifiedFileEntryState } from '../../common/chatEditingService.js';
1919
import { IChatModel, IChatRequestModel, IChatResponseModel } from '../../common/chatModel.js';
20-
import { IChatDetail, IChatService, IChatSessionStartOptions } from '../../common/chatService.js';
20+
import { IChatDetail, IChatService, IChatSessionStartOptions, ResponseModelState } from '../../common/chatService.js';
2121
import { ChatSessionStatus, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
2222
import { LocalChatSessionUri } from '../../common/chatUri.js';
2323
import { ChatAgentLocation } from '../../common/constants.js';
@@ -321,7 +321,8 @@ suite('LocalAgentsSessionsProvider', () => {
321321
sessionResource,
322322
title: 'Test Session',
323323
lastMessageDate: Date.now(),
324-
isActive: true
324+
isActive: true,
325+
lastResponseState: ResponseModelState.Complete
325326
}]);
326327

327328
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -342,7 +343,8 @@ suite('LocalAgentsSessionsProvider', () => {
342343
sessionResource,
343344
title: 'History Session',
344345
lastMessageDate: Date.now() - 10000,
345-
isActive: false
346+
isActive: false,
347+
lastResponseState: ResponseModelState.Complete
346348
}]);
347349

348350
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -366,13 +368,15 @@ suite('LocalAgentsSessionsProvider', () => {
366368
sessionResource,
367369
title: 'Live Session',
368370
lastMessageDate: Date.now(),
369-
isActive: true
371+
isActive: true,
372+
lastResponseState: ResponseModelState.Complete
370373
}]);
371374
mockChatService.setHistorySessionItems([{
372375
sessionResource,
373376
title: 'History Session',
374377
lastMessageDate: Date.now() - 10000,
375-
isActive: false
378+
isActive: false,
379+
lastResponseState: ResponseModelState.Complete
376380
}]);
377381

378382
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -398,7 +402,8 @@ suite('LocalAgentsSessionsProvider', () => {
398402
sessionResource,
399403
title: 'In Progress Session',
400404
lastMessageDate: Date.now(),
401-
isActive: true
405+
isActive: true,
406+
lastResponseState: ResponseModelState.Complete
402407
}]);
403408

404409
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -426,7 +431,8 @@ suite('LocalAgentsSessionsProvider', () => {
426431
sessionResource,
427432
title: 'Completed Session',
428433
lastMessageDate: Date.now(),
429-
isActive: true
434+
isActive: true,
435+
lastResponseState: ResponseModelState.Complete
430436
}]);
431437

432438
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -453,7 +459,8 @@ suite('LocalAgentsSessionsProvider', () => {
453459
sessionResource,
454460
title: 'Canceled Session',
455461
lastMessageDate: Date.now(),
456-
isActive: true
462+
isActive: true,
463+
lastResponseState: ResponseModelState.Complete
457464
}]);
458465

459466
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -480,7 +487,8 @@ suite('LocalAgentsSessionsProvider', () => {
480487
sessionResource,
481488
title: 'Error Session',
482489
lastMessageDate: Date.now(),
483-
isActive: true
490+
isActive: true,
491+
lastResponseState: ResponseModelState.Complete
484492
}]);
485493

486494
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -523,6 +531,7 @@ suite('LocalAgentsSessionsProvider', () => {
523531
title: 'Stats Session',
524532
lastMessageDate: Date.now(),
525533
isActive: true,
534+
lastResponseState: ResponseModelState.Complete,
526535
stats: {
527536
added: 30,
528537
removed: 8,
@@ -565,7 +574,8 @@ suite('LocalAgentsSessionsProvider', () => {
565574
sessionResource,
566575
title: 'No Stats Session',
567576
lastMessageDate: Date.now(),
568-
isActive: true
577+
isActive: true,
578+
lastResponseState: ResponseModelState.Complete
569579
}]);
570580

571581
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -593,7 +603,8 @@ suite('LocalAgentsSessionsProvider', () => {
593603
sessionResource,
594604
title: 'Timing Session',
595605
lastMessageDate: Date.now(),
596-
isActive: true
606+
isActive: true,
607+
lastResponseState: ResponseModelState.Complete
597608
}]);
598609

599610
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -614,7 +625,8 @@ suite('LocalAgentsSessionsProvider', () => {
614625
sessionResource,
615626
title: 'History Timing Session',
616627
lastMessageDate,
617-
isActive: false
628+
isActive: false,
629+
lastResponseState: ResponseModelState.Complete
618630
}]);
619631

620632
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -641,7 +653,8 @@ suite('LocalAgentsSessionsProvider', () => {
641653
sessionResource,
642654
title: 'EndTime Session',
643655
lastMessageDate: Date.now(),
644-
isActive: true
656+
isActive: true,
657+
lastResponseState: ResponseModelState.Complete
645658
}]);
646659

647660
const sessions = await provider.provideChatSessionItems(CancellationToken.None);
@@ -667,7 +680,8 @@ suite('LocalAgentsSessionsProvider', () => {
667680
sessionResource,
668681
title: 'Icon Session',
669682
lastMessageDate: Date.now(),
670-
isActive: true
683+
isActive: true,
684+
lastResponseState: ResponseModelState.Complete
671685
}]);
672686

673687
const sessions = await provider.provideChatSessionItems(CancellationToken.None);

src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_deserialize_with_response.0.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
responseMarkdownInfo: undefined,
8282
followups: undefined,
8383
modelState: {
84-
value: 1,
84+
value: 3,
8585
completedAt: undefined
8686
},
8787
vote: undefined,

src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_sendRequest_fails.0.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
responseMarkdownInfo: undefined,
8484
followups: undefined,
8585
modelState: {
86-
value: 1,
86+
value: 3,
8787
completedAt: undefined
8888
},
8989
vote: undefined,

0 commit comments

Comments
 (0)