diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts index 8c9a150dd65..b1e2a61ec8a 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts @@ -327,18 +327,87 @@ export class AgentSessionRenderer implements ICompressibleTreeRenderer, template: IAgentSessionItemTemplate): void { - const tooltip = session.element.tooltip; - if (tooltip) { - template.elementDisposable.add( - this.hoverService.setupDelayedHover(template.element, () => ({ - content: tooltip, - style: HoverStyle.Pointer, - position: { - hoverPosition: this.options.getHoverPosition() - } - }), { groupId: 'agent.sessions' }) - ); + template.elementDisposable.add( + this.hoverService.setupDelayedHover(template.element, () => ({ + content: this.buildTooltip(session.element), + style: HoverStyle.Pointer, + position: { + hoverPosition: this.options.getHoverPosition() + } + }), { groupId: 'agent.sessions' }) + ); + } + + private buildTooltip(session: IAgentSession): IMarkdownString { + const lines: string[] = []; + + // Title + lines.push(`**${session.label}**`); + + // Tooltip (from provider) + if (session.tooltip) { + const tooltip = typeof session.tooltip === 'string' ? session.tooltip : session.tooltip.value; + lines.push(tooltip); + } else { + + // Description + if (session.description) { + const description = typeof session.description === 'string' ? session.description : session.description.value; + lines.push(description); + } + + // Badge + if (session.badge) { + const badge = typeof session.badge === 'string' ? session.badge : session.badge.value; + lines.push(badge); + } } + + // Details line: Status • Provider • Duration/Time + const details: string[] = []; + + // Status + details.push(toStatusLabel(session.status)); + + // Provider + details.push(session.providerLabel); + + // Duration or start time + if (session.timing.finishedOrFailedTime && session.timing.inProgressTime) { + const duration = this.toDuration(session.timing.inProgressTime, session.timing.finishedOrFailedTime); + if (duration) { + details.push(duration); + } + } else { + details.push(fromNow(session.timing.startTime)); + } + + lines.push(details.join(' • ')); + + // Diff information + const diff = getAgentChangesSummary(session.changes); + if (diff && hasValidDiff(session.changes)) { + const diffParts: string[] = []; + if (diff.files > 0) { + diffParts.push(diff.files === 1 ? localize('tooltip.file', "1 file") : localize('tooltip.files', "{0} files", diff.files)); + } + if (diff.insertions > 0) { + diffParts.push(`+${diff.insertions}`); + } + if (diff.deletions > 0) { + diffParts.push(`-${diff.deletions}`); + } + if (diffParts.length > 0) { + lines.push(`$(diff) ${diffParts.join(', ')}`); + } + } + + // Archived status + if (session.isArchived()) { + lines.push(`$(archive) ${localize('tooltip.archived', "Archived")}`); + } + + return new MarkdownString(lines.join('\n\n'), { supportThemeIcons: true }); } renderCompressedElements(node: ITreeNode, FuzzyScore>, index: number, templateData: IAgentSessionItemTemplate, details?: ITreeElementRenderDetails): void { @@ -354,6 +423,25 @@ export class AgentSessionRenderer implements ICompressibleTreeRenderer