Path: blob/main/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.ts
4780 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { renderAsPlaintext } from '../../../../../base/browser/markdownRenderer.js';6import { Codicon } from '../../../../../base/common/codicons.js';7import { fromNow } from '../../../../../base/common/date.js';8import { DisposableStore } from '../../../../../base/common/lifecycle.js';9import { ThemeIcon } from '../../../../../base/common/themables.js';10import { localize } from '../../../../../nls.js';11import { ICommandService } from '../../../../../platform/commands/common/commands.js';12import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';13import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js';14import { openSession } from './agentSessionsOpener.js';15import { IAgentSession, isLocalAgentSessionItem } from './agentSessionsModel.js';16import { IAgentSessionsService } from './agentSessionsService.js';17import { AgentSessionsSorter, groupAgentSessions } from './agentSessionsViewer.js';18import { AGENT_SESSION_DELETE_ACTION_ID, AGENT_SESSION_RENAME_ACTION_ID } from './agentSessions.js';1920interface ISessionPickItem extends IQuickPickItem {21readonly session: IAgentSession;22}2324export const archiveButton: IQuickInputButton = {25iconClass: ThemeIcon.asClassName(Codicon.archive),26tooltip: localize('archiveSession', "Archive")27};2829export const unarchiveButton: IQuickInputButton = {30iconClass: ThemeIcon.asClassName(Codicon.inbox),31tooltip: localize('unarchiveSession', "Unarchive")32};3334export const renameButton: IQuickInputButton = {35iconClass: ThemeIcon.asClassName(Codicon.edit),36tooltip: localize('renameSession', "Rename")37};3839export const deleteButton: IQuickInputButton = {40iconClass: ThemeIcon.asClassName(Codicon.trash),41tooltip: localize('deleteSession', "Delete")42};4344export function getSessionDescription(session: IAgentSession): string {45const descriptionText = typeof session.description === 'string' ? session.description : session.description ? renderAsPlaintext(session.description) : undefined;46const timeAgo = fromNow(session.timing.endTime || session.timing.startTime);47const descriptionParts = [descriptionText, session.providerLabel, timeAgo].filter(part => !!part);4849return descriptionParts.join(' • ');50}5152export function getSessionButtons(session: IAgentSession): IQuickInputButton[] {53const buttons: IQuickInputButton[] = [];5455if (isLocalAgentSessionItem(session)) {56buttons.push(renameButton);57buttons.push(deleteButton);58}59buttons.push(session.isArchived() ? unarchiveButton : archiveButton);6061return buttons;62}6364export class AgentSessionsPicker {6566private readonly sorter = new AgentSessionsSorter();6768constructor(69@IAgentSessionsService private readonly agentSessionsService: IAgentSessionsService,70@IQuickInputService private readonly quickInputService: IQuickInputService,71@IInstantiationService private readonly instantiationService: IInstantiationService,72@ICommandService private readonly commandService: ICommandService,73) { }7475async pickAgentSession(): Promise<void> {76const disposables = new DisposableStore();77const picker = disposables.add(this.quickInputService.createQuickPick<ISessionPickItem>({ useSeparators: true }));7879picker.items = this.createPickerItems();80picker.canAcceptInBackground = true;81picker.placeholder = localize('chatAgentPickerPlaceholder', "Search agent sessions by name");8283disposables.add(picker.onDidAccept(e => {84const pick = picker.selectedItems[0];85if (pick) {86this.instantiationService.invokeFunction(openSession, pick.session, {87sideBySide: e.inBackground,88editorOptions: {89preserveFocus: e.inBackground,90pinned: e.inBackground91}92});93}9495if (!e.inBackground) {96picker.hide();97}98}));99100disposables.add(picker.onDidTriggerItemButton(async e => {101const session = e.item.session;102103let reopenResolved: boolean = false;104if (e.button === renameButton) {105reopenResolved = true;106await this.commandService.executeCommand(AGENT_SESSION_RENAME_ACTION_ID, session);107} else if (e.button === deleteButton) {108reopenResolved = true;109await this.commandService.executeCommand(AGENT_SESSION_DELETE_ACTION_ID, session);110} else {111const newArchivedState = !session.isArchived();112session.setArchived(newArchivedState);113}114115if (reopenResolved) {116await this.agentSessionsService.model.resolve(session.providerType);117this.pickAgentSession();118} else {119picker.items = this.createPickerItems();120}121}));122123disposables.add(picker.onDidHide(() => disposables.dispose()));124picker.show();125}126127private createPickerItems(): (ISessionPickItem | IQuickPickSeparator)[] {128const sessions = this.agentSessionsService.model.sessions.sort(this.sorter.compare.bind(this.sorter));129const items: (ISessionPickItem | IQuickPickSeparator)[] = [];130131const groupedSessions = groupAgentSessions(sessions);132133for (const group of groupedSessions.values()) {134if (group.sessions.length > 0) {135items.push({ type: 'separator', label: group.label });136items.push(...group.sessions.map(session => this.toPickItem(session)));137}138}139140return items;141}142143private toPickItem(session: IAgentSession): ISessionPickItem {144const description = getSessionDescription(session);145const buttons = getSessionButtons(session);146147return {148id: session.resource.toString(),149label: session.label,150tooltip: session.tooltip,151description,152iconClass: ThemeIcon.asClassName(session.icon),153buttons,154session155};156}157}158159160