mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-11 02:08:52 -06:00
178 lines
5.9 KiB
TypeScript
178 lines
5.9 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { coalesce } from '../../../../../base/common/arrays.js';
|
|
import { CancellationToken } from '../../../../../base/common/cancellation.js';
|
|
import { Codicon } from '../../../../../base/common/codicons.js';
|
|
import { Emitter } from '../../../../../base/common/event.js';
|
|
import { Disposable } from '../../../../../base/common/lifecycle.js';
|
|
import { ResourceSet } from '../../../../../base/common/map.js';
|
|
import { Schemas } from '../../../../../base/common/network.js';
|
|
import { IWorkbenchContribution } from '../../../../common/contributions.js';
|
|
import { IChatModel } from '../../common/chatModel.js';
|
|
import { IChatDetail, IChatService, ResponseModelState } from '../../common/chatService.js';
|
|
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemProvider, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
|
|
import { ChatSessionItemWithProvider } from '../chatSessions/common.js';
|
|
|
|
export class LocalAgentsSessionsProvider extends Disposable implements IChatSessionItemProvider, IWorkbenchContribution {
|
|
|
|
static readonly ID = 'workbench.contrib.localAgentsSessionsProvider';
|
|
|
|
readonly chatSessionType = localChatSessionType;
|
|
|
|
private readonly _onDidChange = this._register(new Emitter<void>());
|
|
readonly onDidChange = this._onDidChange.event;
|
|
|
|
readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
|
|
readonly onDidChangeChatSessionItems = this._onDidChangeChatSessionItems.event;
|
|
|
|
constructor(
|
|
@IChatService private readonly chatService: IChatService,
|
|
@IChatSessionsService private readonly chatSessionsService: IChatSessionsService,
|
|
) {
|
|
super();
|
|
|
|
this._register(this.chatSessionsService.registerChatSessionItemProvider(this));
|
|
|
|
this.registerListeners();
|
|
}
|
|
|
|
private registerListeners(): void {
|
|
|
|
this._register(this.chatSessionsService.registerChatModelChangeListeners(
|
|
this.chatService,
|
|
Schemas.vscodeLocalChatSession,
|
|
() => this._onDidChangeChatSessionItems.fire()
|
|
));
|
|
|
|
// Listen for global session items changes for our session type
|
|
this._register(this.chatSessionsService.onDidChangeSessionItems(sessionType => {
|
|
if (sessionType === this.chatSessionType) {
|
|
this._onDidChange.fire();
|
|
}
|
|
}));
|
|
}
|
|
|
|
|
|
private modelToStatus(model: IChatModel): ChatSessionStatus | undefined {
|
|
if (model.requestInProgress.get()) {
|
|
return ChatSessionStatus.InProgress;
|
|
}
|
|
|
|
const requests = model.getRequests();
|
|
if (requests.length > 0) {
|
|
|
|
// Check if the last request was completed successfully or failed
|
|
const lastRequest = requests[requests.length - 1];
|
|
if (lastRequest?.response) {
|
|
if (lastRequest.response.isCanceled || lastRequest.response.result?.errorDetails?.code === 'canceled') {
|
|
return ChatSessionStatus.Completed;
|
|
} else if (lastRequest.response.result?.errorDetails) {
|
|
return ChatSessionStatus.Failed;
|
|
} else if (lastRequest.response.isComplete) {
|
|
return ChatSessionStatus.Completed;
|
|
} else {
|
|
return ChatSessionStatus.InProgress;
|
|
}
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
async provideChatSessionItems(token: CancellationToken): Promise<IChatSessionItem[]> {
|
|
const sessions: ChatSessionItemWithProvider[] = [];
|
|
const sessionsByResource = new ResourceSet();
|
|
|
|
for (const sessionDetail of await this.chatService.getLiveSessionItems()) {
|
|
const editorSession = this.toChatSessionItem(sessionDetail);
|
|
if (!editorSession) {
|
|
continue;
|
|
}
|
|
|
|
sessionsByResource.add(sessionDetail.sessionResource);
|
|
sessions.push(editorSession);
|
|
}
|
|
|
|
if (!token.isCancellationRequested) {
|
|
const history = await this.getHistoryItems();
|
|
sessions.push(...history.filter(historyItem => !sessionsByResource.has(historyItem.resource)));
|
|
}
|
|
|
|
return sessions;
|
|
}
|
|
|
|
private async getHistoryItems(): Promise<ChatSessionItemWithProvider[]> {
|
|
try {
|
|
const historyItems = await this.chatService.getHistorySessionItems();
|
|
return coalesce(historyItems.map(history => {
|
|
const sessionItem = this.toChatSessionItem(history);
|
|
return sessionItem ? {
|
|
...sessionItem,
|
|
//todo@bpasero remove this property once classic view is gone
|
|
history: true
|
|
} : undefined;
|
|
}));
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private toChatSessionItem(chat: IChatDetail): ChatSessionItemWithProvider | undefined {
|
|
const model = this.chatService.getSession(chat.sessionResource);
|
|
|
|
let description: string | undefined;
|
|
let startTime: number;
|
|
let endTime: number | undefined;
|
|
if (model) {
|
|
if (!model.hasRequests) {
|
|
return undefined; // ignore sessions without requests
|
|
}
|
|
|
|
const lastResponse = model.getRequests().at(-1)?.response;
|
|
description = this.chatSessionsService.getInProgressSessionDescription(model);
|
|
|
|
startTime = model.timestamp;
|
|
if (lastResponse) {
|
|
endTime = lastResponse.completedAt ?? lastResponse.timestamp;
|
|
}
|
|
} else {
|
|
startTime = chat.lastMessageDate;
|
|
}
|
|
|
|
return {
|
|
resource: chat.sessionResource,
|
|
provider: this,
|
|
label: chat.title,
|
|
description,
|
|
status: model ?
|
|
this.modelToStatus(model) :
|
|
chatResponseStateToSessionStatus(chat.lastResponseState),
|
|
iconPath: Codicon.chatSparkle,
|
|
timing: {
|
|
startTime,
|
|
endTime
|
|
},
|
|
changes: chat.stats ? {
|
|
insertions: chat.stats.added,
|
|
deletions: chat.stats.removed,
|
|
files: chat.stats.fileCount,
|
|
} : undefined
|
|
};
|
|
}
|
|
}
|
|
|
|
function chatResponseStateToSessionStatus(state: ResponseModelState): ChatSessionStatus {
|
|
switch (state) {
|
|
case ResponseModelState.Cancelled:
|
|
case ResponseModelState.Complete:
|
|
return ChatSessionStatus.Completed;
|
|
case ResponseModelState.Failed:
|
|
return ChatSessionStatus.Failed;
|
|
case ResponseModelState.Pending:
|
|
return ChatSessionStatus.InProgress;
|
|
}
|
|
}
|