From 668c24118245be42c1d2d523afce50a70762acce Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 24 Apr 2026 08:56:14 -0700 Subject: [PATCH] Fix sessions pickers/quick access Meant to filter archived, not done --- .../agentHostSessionListController.ts | 3 +- .../agentSessions/agentSessionsPicker.ts | 10 +++- .../agentSessions/agentSessionsQuickAccess.ts | 4 +- .../agentHostChatContribution.test.ts | 17 ++++++ .../agentSessionsDataSource.test.ts | 57 +++++++++++++++++++ 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts index 8970d3be651dd..cb8e2d5fad5f1 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts @@ -161,7 +161,7 @@ export class AgentHostSessionListController extends Disposable implements IChatS }); return this._makeItem(rawId, { title: s.summary, - status: s.status, + status, workingDirectory: s.workingDirectory, createdAt: s.startTime, modifiedAt: s.modifiedTime, @@ -201,6 +201,7 @@ export class AgentHostSessionListController extends Disposable implements IChatS description: this._description, iconPath: getAgentHostIcon(this._productService), status: mapSessionStatus(opts.status), + archived: opts.status !== undefined && (opts.status & SessionStatus.IsArchived) === SessionStatus.IsArchived, metadata: this._buildMetadata(opts.workingDirectory), timing: { created: opts.createdAt, diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.ts index d9d3931bdb489..5803f37fb5999 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.ts @@ -12,9 +12,9 @@ import { ICommandService } from '../../../../../platform/commands/common/command import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js'; import { ISessionOpenOptions, openSession } from './agentSessionsOpener.js'; -import { AgentSessionStatus, IAgentSession, isLocalAgentSessionItem } from './agentSessionsModel.js'; +import { IAgentSession, isLocalAgentSessionItem } from './agentSessionsModel.js'; import { IAgentSessionsService } from './agentSessionsService.js'; -import { AgentSessionsSorter, groupAgentSessionsByDate, sessionDateFromNow } from './agentSessionsViewer.js'; +import { AgentSessionsSorter, groupAgentSessionsByDate, type IAgentSessionsFilter, sessionDateFromNow } from './agentSessionsViewer.js'; import { AGENT_SESSION_DELETE_ACTION_ID, AGENT_SESSION_RENAME_ACTION_ID } from './agentSessions.js'; import { AgentSessionsFilter } from './agentSessionsFilter.js'; @@ -62,6 +62,10 @@ export function getSessionButtons(session: IAgentSession): IQuickInputButton[] { return buttons; } +export function shouldShowSessionInPicker(session: IAgentSession, filter: IAgentSessionsFilter): boolean { + return !session.isArchived() && !filter.exclude(session); +} + export interface IAgentSessionsPickerOptions { overrideSessionOpen?(session: IAgentSession, openOptions?: ISessionOpenOptions): Promise; } @@ -141,7 +145,7 @@ export class AgentSessionsPicker { private createPickerItems(filter: AgentSessionsFilter): (ISessionPickItem | IQuickPickSeparator)[] { const sessions = this.agentSessionsService.model.sessions - .filter(session => session.status !== AgentSessionStatus.Completed && !filter.exclude(session)) + .filter(session => shouldShowSessionInPicker(session, filter)) .sort(this.sorter.compare.bind(this.sorter)); const items: (ISessionPickItem | IQuickPickSeparator)[] = []; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsQuickAccess.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsQuickAccess.ts index 7ab8f018143af..125cc9e6c49f9 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsQuickAccess.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsQuickAccess.ts @@ -15,7 +15,7 @@ import { IAgentSession } from './agentSessionsModel.js'; import { openSession } from './agentSessionsOpener.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { AGENT_SESSION_DELETE_ACTION_ID, AGENT_SESSION_RENAME_ACTION_ID } from './agentSessions.js'; -import { archiveButton, deleteButton, getSessionButtons, getSessionDescription, renameButton, unarchiveButton } from './agentSessionsPicker.js'; +import { archiveButton, deleteButton, getSessionButtons, getSessionDescription, renameButton, shouldShowSessionInPicker, unarchiveButton } from './agentSessionsPicker.js'; import { AgentSessionsFilter } from './agentSessionsFilter.js'; export const AGENT_SESSIONS_QUICK_ACCESS_PREFIX = 'agent '; @@ -44,7 +44,7 @@ export class AgentSessionsQuickAccessProvider extends PickerQuickAccessProvider< const picks: Array = []; const sessions = this.agentSessionsService.model.sessions - .filter(session => !this.filter.exclude(session)) + .filter(session => shouldShowSessionInPicker(session, this.filter)) .sort(this.sorter.compare.bind(this.sorter)); const groupedSessions = groupAgentSessionsByDate(sessions); diff --git a/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts b/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts index e13bdbb7cb532..0ae6214f0da3a 100644 --- a/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts @@ -639,6 +639,23 @@ suite('AgentHostChatContribution', () => { assert.strictEqual(listController.items.length, 0); }); + + test('refresh marks archived sessions as archived items', async () => { + const { listController, agentHostService } = createContribution(disposables); + + agentHostService.addSession({ + session: AgentSession.uri('copilot', 'archived'), + startTime: 1000, + modifiedTime: 2000, + summary: 'Archived session', + isArchived: true, + }); + + await listController.refresh(CancellationToken.None); + + assert.strictEqual(listController.items.length, 1); + assert.strictEqual(listController.items[0].archived, true); + }); }); // ---- Session ID resolution in _invokeAgent -------------------------- diff --git a/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentSessionsDataSource.test.ts b/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentSessionsDataSource.test.ts index 16ca999555b4d..ceb3d70c97b6d 100644 --- a/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentSessionsDataSource.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentSessionsDataSource.test.ts @@ -13,6 +13,7 @@ import { ITreeSorter } from '../../../../../../base/browser/ui/tree/tree.js'; import { Codicon } from '../../../../../../base/common/codicons.js'; import { Event } from '../../../../../../base/common/event.js'; import { AgentSessionsGrouping, AgentSessionsSorting } from '../../../browser/agentSessions/agentSessionsFilter.js'; +import { shouldShowSessionInPicker } from '../../../browser/agentSessions/agentSessionsPicker.js'; suite('sessionDateFromNow', () => { @@ -1348,6 +1349,62 @@ suite('AgentSessionsSorter', () => { }); }); +suite('AgentSessionsPicker', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + + function createSession(overrides: Partial<{ + id: string; + status: ChatSessionStatus; + isArchived: boolean; + }>): IAgentSession { + return { + providerType: 'test', + providerLabel: 'Test', + resource: URI.parse(`test://session/${overrides.id ?? 'default'}`), + status: overrides.status ?? ChatSessionStatus.Completed, + label: `Session ${overrides.id ?? 'default'}`, + icon: Codicon.terminal, + timing: { + created: Date.now(), + lastRequestStarted: undefined, + lastRequestEnded: undefined, + }, + changes: undefined, + metadata: undefined, + isArchived: () => overrides.isArchived ?? false, + setArchived: () => { }, + isPinned: () => false, + setPinned: () => { }, + isRead: () => true, + isMarkedUnread: () => false, + setRead: () => { }, + }; + } + + const filter: IAgentSessionsFilter = { + onDidChange: Event.None, + exclude: () => false, + getExcludes: () => ({ providers: [], states: [], archived: true, read: false, repositoryGroupCapped: true }), + isDefault: () => true, + limitResults: () => undefined, + notifyResults: () => { }, + reset: () => { }, + sortResults: () => undefined, + }; + + test('keeps completed sessions but excludes archived sessions', () => { + const completed = createSession({ id: 'completed', status: ChatSessionStatus.Completed }); + const inProgress = createSession({ id: 'in-progress', status: ChatSessionStatus.InProgress }); + const archived = createSession({ id: 'archived', status: ChatSessionStatus.Completed, isArchived: true }); + + assert.deepStrictEqual( + [completed, inProgress, archived].filter(session => shouldShowSessionInPicker(session, filter)).map(session => session.label), + ['Session completed', 'Session in-progress'] + ); + }); +}); + suite('groupAgentSessionsByDate with sortBy', () => { ensureNoDisposablesAreLeakedInTestSuite();