Skip to content

Commit f04ec6a

Browse files
bpaserojoaomorenomrleemurray
authored
Chat view improvements (#281447)
* agent sessions - add and use `getSession` * agent sessions - fix `changes` serialisation * agent sessions - have a dedicated `agentSessionsList.background` color * agent sessions - update session title based on viewer state * style - update icons and adjust sidebar widths * refactor - simplify chat editor retrieval logic * style - add archived state styling to session items * chore - add group to menu for agent session actions * fix - adjust auxiliary bar maximization behavior * fixes #281448 * feat - add new actions for agent sessions viewer * Add new codicons: collectionSmall, vmSmall, and cloudSmall * fix cyclic * style - remove unused background color from `agentSessionsList` * refactor - simplify session serialization logic * style - correct label text for session viewer link * fix broken status update --------- Co-authored-by: João Moreno <[email protected]> Co-authored-by: mrleemurray <[email protected]>
1 parent a9bcdfb commit f04ec6a

23 files changed

+225
-121
lines changed

build/lib/stylelint/vscode-known-variables.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
"--vscode-editor-foldPlaceholderForeground",
160160
"--vscode-editor-foreground",
161161
"--vscode-editor-hoverHighlightBackground",
162+
"--vscode-editor-inactiveLineHighlightBackground",
162163
"--vscode-editor-inactiveSelectionBackground",
163164
"--vscode-editor-inlineValuesBackground",
164165
"--vscode-editor-inlineValuesForeground",
@@ -303,9 +304,9 @@
303304
"--vscode-editorOverviewRuler-background",
304305
"--vscode-editorOverviewRuler-border",
305306
"--vscode-editorOverviewRuler-bracketMatchForeground",
307+
"--vscode-editorOverviewRuler-commentDraftForeground",
306308
"--vscode-editorOverviewRuler-commentForeground",
307309
"--vscode-editorOverviewRuler-commentUnresolvedForeground",
308-
"--vscode-editorOverviewRuler-commentDraftForeground",
309310
"--vscode-editorOverviewRuler-commonContentForeground",
310311
"--vscode-editorOverviewRuler-currentContentForeground",
311312
"--vscode-editorOverviewRuler-deletedForeground",
@@ -345,7 +346,6 @@
345346
"--vscode-editorWarning-background",
346347
"--vscode-editorWarning-border",
347348
"--vscode-editorWarning-foreground",
348-
"--vscode-editorWatermark-foreground",
349349
"--vscode-editorWhitespace-foreground",
350350
"--vscode-editorWidget-background",
351351
"--vscode-editorWidget-border",
492 Bytes
Binary file not shown.

src/vs/base/common/codiconsLibrary.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,4 +644,7 @@ export const codiconsLibrary = {
644644
clockface: register('clockface', 0xec75),
645645
unarchive: register('unarchive', 0xec76),
646646
sessionInProgress: register('session-in-progress', 0xec77),
647+
collectionSmall: register('collection-small', 0xec78),
648+
vmSmall: register('vm-small', 0xec79),
649+
cloudSmall: register('cloud-small', 0xec7a),
647650
} as const;

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { Registry } from '../../../../../platform/registry/common/platform.js';
2020
import { LocalAgentsSessionsProvider } from './localAgentSessionsProvider.js';
2121
import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../../common/contributions.js';
2222
import { ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from '../../../../../platform/actions/common/actions.js';
23-
import { ArchiveAgentSessionAction, UnarchiveAgentSessionAction, RefreshAgentSessionsViewAction, FindAgentSessionAction, OpenAgentSessionInEditorGroupAction, OpenAgentSessionInNewEditorGroupAction, OpenAgentSessionInNewWindowAction, ShowAgentSessionsSidebar, HideAgentSessionsSidebar } from './agentSessionsActions.js';
23+
import { ArchiveAgentSessionAction, UnarchiveAgentSessionAction, RefreshAgentSessionsViewAction, FindAgentSessionAction, OpenAgentSessionInEditorGroupAction, OpenAgentSessionInNewEditorGroupAction, OpenAgentSessionInNewWindowAction, ShowAgentSessionsSidebar, HideAgentSessionsSidebar, RefreshAgentSessionsViewerAction, FindAgentSessionInViewerAction } from './agentSessionsActions.js';
2424

2525
//#region View Container and View Registration
2626

@@ -70,6 +70,8 @@ registerAction2(OpenAgentSessionInEditorGroupAction);
7070
registerAction2(OpenAgentSessionInNewEditorGroupAction);
7171
registerAction2(RefreshAgentSessionsViewAction);
7272
registerAction2(FindAgentSessionAction);
73+
registerAction2(RefreshAgentSessionsViewerAction);
74+
registerAction2(FindAgentSessionInViewerAction);
7375
registerAction2(ShowAgentSessionsSidebar);
7476
registerAction2(HideAgentSessionsSidebar);
7577

@@ -85,10 +87,10 @@ MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
8587
command: {
8688
id: ShowAgentSessionsSidebar.ID,
8789
title: ShowAgentSessionsSidebar.TITLE,
88-
icon: Codicon.layoutSidebarRight,
90+
icon: Codicon.layoutSidebarRightOff,
8991
},
9092
group: 'navigation',
91-
order: 1,
93+
order: 5,
9294
when: ContextKeyExpr.and(
9395
ChatContextKeys.agentSessionsViewerOrientation.isEqualTo(AgentSessionsViewerOrientation.Stacked),
9496
ChatContextKeys.agentSessionsViewerPosition.isEqualTo(AgentSessionsViewerPosition.Right)
@@ -99,10 +101,10 @@ MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
99101
command: {
100102
id: ShowAgentSessionsSidebar.ID,
101103
title: ShowAgentSessionsSidebar.TITLE,
102-
icon: Codicon.layoutSidebarLeft,
104+
icon: Codicon.layoutSidebarLeftOff,
103105
},
104106
group: 'navigation',
105-
order: 1,
107+
order: 5,
106108
when: ContextKeyExpr.and(
107109
ChatContextKeys.agentSessionsViewerOrientation.isEqualTo(AgentSessionsViewerOrientation.Stacked),
108110
ChatContextKeys.agentSessionsViewerPosition.isEqualTo(AgentSessionsViewerPosition.Left)
@@ -113,10 +115,10 @@ MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
113115
command: {
114116
id: HideAgentSessionsSidebar.ID,
115117
title: HideAgentSessionsSidebar.TITLE,
116-
icon: Codicon.layoutSidebarRightOff,
118+
icon: Codicon.layoutSidebarRight,
117119
},
118120
group: 'navigation',
119-
order: 1,
121+
order: 5,
120122
when: ContextKeyExpr.and(
121123
ChatContextKeys.agentSessionsViewerOrientation.isEqualTo(AgentSessionsViewerOrientation.SideBySide),
122124
ChatContextKeys.agentSessionsViewerPosition.isEqualTo(AgentSessionsViewerPosition.Right)
@@ -127,10 +129,10 @@ MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
127129
command: {
128130
id: HideAgentSessionsSidebar.ID,
129131
title: HideAgentSessionsSidebar.TITLE,
130-
icon: Codicon.layoutSidebarLeftOff,
132+
icon: Codicon.layoutSidebarLeft,
131133
},
132134
group: 'navigation',
133-
order: 1,
135+
order: 5,
134136
when: ContextKeyExpr.and(
135137
ChatContextKeys.agentSessionsViewerOrientation.isEqualTo(AgentSessionsViewerOrientation.SideBySide),
136138
ChatContextKeys.agentSessionsViewerPosition.isEqualTo(AgentSessionsViewerPosition.Left)

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,8 @@ export enum AgentSessionsViewerPosition {
6767
Left = 1,
6868
Right,
6969
}
70+
71+
export interface IAgentSessionsControl {
72+
refresh(): void;
73+
openFind(): void;
74+
}

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

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Action2, MenuId } from '../../../../../platform/actions/common/actions.
1515
import { Codicon } from '../../../../../base/common/codicons.js';
1616
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
1717
import { ViewAction } from '../../../../browser/parts/views/viewPane.js';
18-
import { AGENT_SESSIONS_VIEW_ID, AgentSessionProviders } from './agentSessions.js';
18+
import { AGENT_SESSIONS_VIEW_ID, AgentSessionProviders, IAgentSessionsControl } from './agentSessions.js';
1919
import { AgentSessionsView } from './agentSessionsView.js';
2020
import { URI } from '../../../../../base/common/uri.js';
2121
import { IChatService } from '../../common/chatService.js';
@@ -202,7 +202,8 @@ export class OpenAgentSessionInEditorGroupAction extends BaseOpenAgentSessionAct
202202
title: localize('chat.openSessionInEditorGroup.label', "Open as Editor"),
203203
menu: {
204204
id: MenuId.AgentSessionsContext,
205-
order: 1
205+
order: 1,
206+
group: 'navigation'
206207
}
207208
});
208209
}
@@ -226,7 +227,8 @@ export class OpenAgentSessionInNewEditorGroupAction extends BaseOpenAgentSession
226227
title: localize('chat.openSessionInNewEditorGroup.label', "Open to the Side"),
227228
menu: {
228229
id: MenuId.AgentSessionsContext,
229-
order: 2
230+
order: 2,
231+
group: 'navigation'
230232
}
231233
});
232234
}
@@ -250,7 +252,8 @@ export class OpenAgentSessionInNewWindowAction extends BaseOpenAgentSessionActio
250252
title: localize('chat.openSessionInNewWindow.label', "Open in New Window"),
251253
menu: {
252254
id: MenuId.AgentSessionsContext,
253-
order: 3
255+
order: 3,
256+
group: 'navigation'
254257
}
255258
});
256259
}
@@ -310,7 +313,49 @@ export class FindAgentSessionAction extends ViewAction<AgentSessionsView> {
310313

311314
//#endregion
312315

313-
//#region Recent Sessions in Chat View Actions
316+
//#region Sessions Control Toolbar
317+
318+
export class RefreshAgentSessionsViewerAction extends Action2 {
319+
320+
constructor() {
321+
super({
322+
id: 'agentSessionsViewer.refresh',
323+
title: localize2('refresh', "Refresh Agent Sessions"),
324+
icon: Codicon.refresh,
325+
menu: {
326+
id: MenuId.AgentSessionsToolbar,
327+
group: 'navigation',
328+
order: 1,
329+
when: ChatContextKeys.agentSessionsViewerExpanded
330+
},
331+
});
332+
}
333+
334+
override run(accessor: ServicesAccessor, agentSessionsControl: IAgentSessionsControl) {
335+
agentSessionsControl.refresh();
336+
}
337+
}
338+
339+
export class FindAgentSessionInViewerAction extends Action2 {
340+
341+
constructor() {
342+
super({
343+
id: 'agentSessionsViewer.find',
344+
title: localize2('find', "Find Agent Session"),
345+
icon: Codicon.search,
346+
menu: {
347+
id: MenuId.AgentSessionsToolbar,
348+
group: 'navigation',
349+
order: 2,
350+
when: ChatContextKeys.agentSessionsViewerExpanded
351+
}
352+
});
353+
}
354+
355+
override run(accessor: ServicesAccessor, agentSessionsControl: IAgentSessionsControl) {
356+
return agentSessionsControl.openFind();
357+
}
358+
}
314359

315360
abstract class UpdateChatViewWidthAction extends Action2 {
316361

@@ -323,6 +368,10 @@ abstract class UpdateChatViewWidthAction extends Action2 {
323368
return; // only applicable for sidebar or auxiliary bar
324369
}
325370

371+
if (chatLocation === ViewContainerLocation.AuxiliaryBar) {
372+
layoutService.setAuxiliaryBarMaximized(false); // Leave maximized state if applicable
373+
}
374+
326375
const part = getPartByLocation(chatLocation);
327376
const currentSize = layoutService.getSize(part);
328377
layoutService.setSize(part, {
@@ -351,7 +400,7 @@ export class ShowAgentSessionsSidebar extends UpdateChatViewWidthAction {
351400
override getNewWidth(accessor: ServicesAccessor): number {
352401
const layoutService = accessor.get(IWorkbenchLayoutService);
353402

354-
return Math.max(610, Math.round(layoutService.mainContainerDimension.width / 2));
403+
return Math.max(600 + 1 /* account for possible theme border */, Math.round(layoutService.mainContainerDimension.width / 2));
355404
}
356405
}
357406

@@ -369,7 +418,7 @@ export class HideAgentSessionsSidebar extends UpdateChatViewWidthAction {
369418
}
370419

371420
override getNewWidth(accessor: ServicesAccessor): number {
372-
return 300;
421+
return 300 + 1 /* account for possible theme border */;
373422
}
374423
}
375424

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@ import { ITelemetryService } from '../../../../../platform/telemetry/common/tele
3535
import { IListStyles } from '../../../../../base/browser/ui/list/listWidget.js';
3636
import { IStyleOverride } from '../../../../../platform/theme/browser/defaultStyles.js';
3737
import { ChatEditorInput } from '../chatEditorInput.js';
38-
import { isEqual } from '../../../../../base/common/resources.js';
38+
import { IAgentSessionsControl } from './agentSessions.js';
3939

4040
export interface IAgentSessionsControlOptions {
4141
readonly overrideStyles?: IStyleOverride<IListStyles>;
4242
readonly filter?: IAgentSessionsFilter;
4343
readonly allowNewSessionFromEmptySpace?: boolean;
4444
readonly allowOpenSessionsInPanel?: boolean; // TODO@bpasero retire this option eventually
45-
readonly allowFiltering?: boolean;
4645
readonly trackActiveEditor?: boolean;
4746
}
4847

@@ -58,7 +57,7 @@ type AgentSessionOpenedEvent = {
5857
providerType: string;
5958
};
6059

61-
export class AgentSessionsControl extends Disposable {
60+
export class AgentSessionsControl extends Disposable implements IAgentSessionsControl {
6261

6362
private sessionsContainer: HTMLElement | undefined;
6463
private sessionsList: WorkbenchCompressibleAsyncDataTree<IAgentSessionsModel, IAgentSession, FuzzyScore> | undefined;
@@ -109,8 +108,7 @@ export class AgentSessionsControl extends Disposable {
109108
return;
110109
}
111110

112-
const sessions = this.agentSessionsService.model.sessions;
113-
const matchingSession = sessions.find(session => isEqual(session.resource, sessionResource));
111+
const matchingSession = this.agentSessionsService.model.getSession(sessionResource);
114112
if (matchingSession && this.sessionsList?.hasNode(matchingSession)) {
115113
if (this.sessionsList.getRelativeTop(matchingSession) === null) {
116114
this.sessionsList.reveal(matchingSession, 0.5); // only reveal when not already visible
@@ -140,7 +138,7 @@ export class AgentSessionsControl extends Disposable {
140138
identityProvider: new AgentSessionsIdentityProvider(),
141139
horizontalScrolling: false,
142140
multipleSelectionSupport: false,
143-
findWidgetEnabled: this.options?.allowFiltering,
141+
findWidgetEnabled: true,
144142
defaultFindMode: TreeFindMode.Filter,
145143
keyboardNavigationLabelProvider: new AgentSessionsKeyboardNavigationLabelProvider(),
146144
sorter,

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

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface IAgentSessionsModel {
2929
readonly onDidChangeSessions: Event<void>;
3030

3131
readonly sessions: IAgentSession[];
32+
getSession(resource: URI): IAgentSession | undefined;
3233

3334
resolve(provider: string | string[] | undefined): Promise<void>;
3435
}
@@ -176,6 +177,10 @@ export class AgentSessionsModel extends Disposable implements IAgentSessionsMode
176177
}));
177178
}
178179

180+
getSession(resource: URI): IAgentSession | undefined {
181+
return this._sessions.get(resource);
182+
}
183+
179184
async resolve(provider: string | string[] | undefined): Promise<void> {
180185
if (Array.isArray(provider)) {
181186
for (const p of provider) {
@@ -385,11 +390,10 @@ interface ISerializedAgentSession {
385390
readonly endTime?: number;
386391
};
387392

388-
readonly statistics?: {
393+
readonly changes?: readonly IChatSessionFileChange[] | {
389394
readonly files: number;
390395
readonly insertions: number;
391396
readonly deletions: number;
392-
readonly details: readonly IChatSessionFileChange[];
393397
};
394398
}
395399

@@ -410,36 +414,27 @@ class AgentSessionsCache {
410414
//#region Sessions
411415

412416
saveCachedSessions(sessions: IInternalAgentSessionData[]): void {
413-
const serialized: ISerializedAgentSession[] = sessions
414-
.filter(session =>
415-
// Only consider providers that we own where we know that
416-
// we can also invalidate the data after startup
417-
// Other providers are bound to a different lifecycle (extensions)
418-
session.providerType === AgentSessionProviders.Local ||
419-
session.providerType === AgentSessionProviders.Background ||
420-
session.providerType === AgentSessionProviders.Cloud
421-
)
422-
.map(session => ({
423-
providerType: session.providerType,
424-
providerLabel: session.providerLabel,
417+
const serialized: ISerializedAgentSession[] = sessions.map(session => ({
418+
providerType: session.providerType,
419+
providerLabel: session.providerLabel,
425420

426-
resource: session.resource.toJSON(),
421+
resource: session.resource.toJSON(),
427422

428-
icon: session.icon.id,
429-
label: session.label,
430-
description: session.description,
431-
tooltip: session.tooltip,
423+
icon: session.icon.id,
424+
label: session.label,
425+
description: session.description,
426+
tooltip: session.tooltip,
432427

433-
status: session.status,
434-
archived: session.archived,
428+
status: session.status,
429+
archived: session.archived,
435430

436-
timing: {
437-
startTime: session.timing.startTime,
438-
endTime: session.timing.endTime,
439-
},
431+
timing: {
432+
startTime: session.timing.startTime,
433+
endTime: session.timing.endTime,
434+
},
440435

441-
changes: session.changes,
442-
}));
436+
changes: session.changes,
437+
}));
443438

444439
this.storageService.store(AgentSessionsCache.SESSIONS_STORAGE_KEY, JSON.stringify(serialized), StorageScope.WORKSPACE, StorageTarget.MACHINE);
445440
}
@@ -471,7 +466,12 @@ class AgentSessionsCache {
471466
endTime: session.timing.endTime,
472467
},
473468

474-
changes: session.statistics,
469+
changes: Array.isArray(session.changes) ? session.changes.map((change: IChatSessionFileChange) => ({
470+
modifiedUri: URI.revive(change.modifiedUri),
471+
originalUri: change.originalUri ? URI.revive(change.originalUri) : undefined,
472+
insertions: change.insertions,
473+
deletions: change.deletions,
474+
})) : session.changes,
475475
}));
476476
} catch {
477477
return []; // invalid data in storage, fallback to empty sessions list

0 commit comments

Comments
 (0)