diff --git a/src/vs/workbench/api/browser/mainThreadChatSessions.ts b/src/vs/workbench/api/browser/mainThreadChatSessions.ts index ff23264d592..50a510c6c0d 100644 --- a/src/vs/workbench/api/browser/mainThreadChatSessions.ts +++ b/src/vs/workbench/api/browser/mainThreadChatSessions.ts @@ -16,6 +16,7 @@ import { URI, UriComponents } from '../../../base/common/uri.js'; import { localize } from '../../../nls.js'; import { IDialogService } from '../../../platform/dialogs/common/dialogs.js'; import { ILogService } from '../../../platform/log/common/log.js'; +import { hasValidDiff, IAgentSession } from '../../contrib/chat/browser/agentSessions/agentSessionsModel.js'; import { ChatViewPaneTarget, IChatWidgetService, isIChatViewViewContext } from '../../contrib/chat/browser/chat.js'; import { IChatEditorOptions } from '../../contrib/chat/browser/chatEditor.js'; import { ChatEditorInput } from '../../contrib/chat/browser/chatEditorInput.js'; @@ -474,12 +475,14 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat // We can still get stats if there is no model or if fetching from model failed if (!session.changes || !model) { const stats = (await this._chatService.getMetadataForSession(uri))?.stats; - if (stats) { - session.changes = { - files: stats.fileCount, - insertions: stats.added, - deletions: stats.removed - }; + // TODO: we shouldn't be converting this, the types should match + const diffs: IAgentSession['changes'] = { + files: stats?.fileCount || 0, + insertions: stats?.added || 0, + deletions: stats?.removed || 0 + }; + if (hasValidDiff(diffs)) { + session.changes = diffs; } } diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsActions.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsActions.ts index 8c09e5602ee..727e7103553 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsActions.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsActions.ts @@ -5,7 +5,7 @@ import './media/agentsessionsactions.css'; import { localize, localize2 } from '../../../../../nls.js'; -import { getAgentChangesSummary, IAgentSession } from './agentSessionsModel.js'; +import { IAgentSession, getAgentChangesSummary } from './agentSessionsModel.js'; import { Action, IAction } from '../../../../../base/common/actions.js'; import { ActionViewItem, IActionViewItemOptions } from '../../../../../base/browser/ui/actionbar/actionViewItems.js'; import { CommandsRegistry, ICommandService } from '../../../../../platform/commands/common/commands.js'; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts index 637e35728ee..2060d4aed82 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts @@ -64,6 +64,24 @@ interface IAgentSessionData { }; } +/** + * Checks if the provided changes object represents valid diff information. + */ +export function hasValidDiff(changes: IAgentSession['changes']): boolean { + if (!changes) { + return false; + } + + if (changes instanceof Array) { + return changes.length > 0; + } + + return changes.files > 0 || changes.insertions > 0 || changes.deletions > 0; +} + +/** + * Gets a summary of agent session changes, converting from array format to object format if needed. + */ export function getAgentChangesSummary(changes: IAgentSession['changes']) { if (!changes) { return; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts index b25ccb3e2a1..1d77ae313b2 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts @@ -13,7 +13,7 @@ import { ICompressedTreeNode } from '../../../../../base/browser/ui/tree/compres import { ICompressibleKeyboardNavigationLabelProvider, ICompressibleTreeRenderer } from '../../../../../base/browser/ui/tree/objectTree.js'; import { ITreeNode, ITreeElementRenderDetails, IAsyncDataSource, ITreeSorter, ITreeDragAndDrop, ITreeDragOverReaction } from '../../../../../base/browser/ui/tree/tree.js'; import { Disposable, DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js'; -import { IAgentSession, IAgentSessionsModel, isAgentSession, isAgentSessionsModel } from './agentSessionsModel.js'; +import { IAgentSession, IAgentSessionsModel, isAgentSession, isAgentSessionsModel, hasValidDiff } from './agentSessionsModel.js'; import { IconLabel } from '../../../../../base/browser/ui/iconLabel/iconLabel.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; import { Codicon } from '../../../../../base/common/codicons.js'; @@ -162,11 +162,9 @@ export class AgentSessionRenderer implements ICompressibleTreeRenderer 0 : (diff.files > 0 || diff.insertions > 0 || diff.deletions > 0)) { - const diffAction = template.elementDisposable.add(new AgentSessionShowDiffAction(session.element)); - template.detailsToolbar.push([diffAction], { icon: false, label: true }); - } + if (session.element.status !== ChatSessionStatus.InProgress && diff && hasValidDiff(diff)) { + const diffAction = template.elementDisposable.add(new AgentSessionShowDiffAction(session.element)); + template.detailsToolbar.push([diffAction], { icon: false, label: true }); } // Description otherwise @@ -181,17 +179,7 @@ export class AgentSessionRenderer implements ICompressibleTreeRenderer 0; - } - - return diff.files > 0 || diff.insertions > 0 || diff.deletions > 0; - } private getIcon(session: IAgentSession): ThemeIcon { if (session.status === ChatSessionStatus.InProgress) {