Path: blob/main/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugHookContentRenderer.ts
13406 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 * as DOM from '../../../../../base/browser/dom.js';6import { DisposableStore } from '../../../../../base/common/lifecycle.js';7import { localize } from '../../../../../nls.js';8import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';9import { ILanguageService } from '../../../../../editor/common/languages/language.js';10import { ChatDebugHookResult, IChatDebugEventHookContent } from '../../common/chatDebugService.js';11import { renderSection, tokenizeContent } from './chatDebugToolCallContentRenderer.js';1213const $ = DOM.$;1415/**16* Render a resolved hook execution content with structured sections for17* hook type, command, result, duration, input, and output.18* When JSON is detected in input/output, renders it with syntax highlighting.19*/20export async function renderHookContent(content: IChatDebugEventHookContent, languageService: ILanguageService, clipboardService?: IClipboardService, scrollable?: { scanDomNode(): void }): Promise<{ element: HTMLElement; disposables: DisposableStore }> {21const disposables = new DisposableStore();22const container = $('div.chat-debug-message-content');23container.tabIndex = 0;2425// Header: hook type26DOM.append(container, $('div.chat-debug-message-content-title', undefined, content.hookType));2728// Status summary line29const statusParts: string[] = [];30if (content.result !== undefined) {31statusParts.push(formatHookResult(content.result));32}33if (content.exitCode !== undefined) {34statusParts.push(localize('chatDebug.hook.exitCode', "Exit Code: {0}", content.exitCode));35}36if (content.durationInMillis !== undefined) {37statusParts.push(localize('chatDebug.hook.duration', "{0}ms", content.durationInMillis));38}39if (statusParts.length > 0) {40DOM.append(container, $('div.chat-debug-message-content-summary', undefined, statusParts.join(' \u00b7 ')));41}4243// Build collapsible sections for command, input, output, and error44const sectionsContainer = DOM.append(container, $('div.chat-debug-message-sections'));4546if (content.command) {47const { plainText, tokenizedHtml } = await tokenizeContent(content.command, languageService);48renderSection(sectionsContainer, localize('chatDebug.hook.command', "Command"), plainText, tokenizedHtml, disposables, false, clipboardService, scrollable);49}5051if (content.input) {52const { plainText, tokenizedHtml } = await tokenizeContent(content.input, languageService);53renderSection(sectionsContainer, localize('chatDebug.hook.input', "Input"), plainText, tokenizedHtml, disposables, false, clipboardService, scrollable);54}5556if (content.output) {57const { plainText, tokenizedHtml } = await tokenizeContent(content.output, languageService);58renderSection(sectionsContainer, localize('chatDebug.hook.output', "Output"), plainText, tokenizedHtml, disposables, false, clipboardService, scrollable);59}6061if (content.errorMessage) {62const { plainText, tokenizedHtml } = await tokenizeContent(content.errorMessage, languageService);63renderSection(sectionsContainer, localize('chatDebug.hook.error', "Error"), plainText, tokenizedHtml, disposables, false, clipboardService, scrollable);64}6566return { element: container, disposables };67}6869function formatHookResult(result: ChatDebugHookResult): string {70switch (result) {71case ChatDebugHookResult.Success:72return localize('chatDebug.hook.result.success', "Success");73case ChatDebugHookResult.Error:74return localize('chatDebug.hook.result.error', "Error");75case ChatDebugHookResult.NonBlockingError:76return localize('chatDebug.hook.result.nonBlockingError', "Non-blocking Error");77default:78return String(result);79}80}8182/**83* Convert a resolved hook content to plain text for clipboard / editor output.84*/85export function hookContentToPlainText(content: IChatDebugEventHookContent): string {86const lines: string[] = [];87lines.push(localize('chatDebug.hook.typeLabel', "Hook Type: {0}", content.hookType));8889if (content.result !== undefined) {90lines.push(localize('chatDebug.hook.resultLabel', "Result: {0}", formatHookResult(content.result)));91}92if (content.exitCode !== undefined) {93lines.push(localize('chatDebug.hook.exitCodeLabel', "Exit Code: {0}", content.exitCode));94}95if (content.durationInMillis !== undefined) {96lines.push(localize('chatDebug.hook.durationLabel', "Duration: {0}ms", content.durationInMillis));97}9899if (content.command) {100lines.push('');101lines.push(`[${localize('chatDebug.hook.command', "Command")}]`);102lines.push(content.command);103}104105if (content.input) {106lines.push('');107lines.push(`[${localize('chatDebug.hook.input', "Input")}]`);108try {109const parsed = JSON.parse(content.input);110lines.push(JSON.stringify(parsed, null, 2));111} catch {112lines.push(content.input);113}114}115116if (content.output) {117lines.push('');118lines.push(`[${localize('chatDebug.hook.output', "Output")}]`);119try {120const parsed = JSON.parse(content.output);121lines.push(JSON.stringify(parsed, null, 2));122} catch {123lines.push(content.output);124}125}126127if (content.errorMessage) {128lines.push('');129lines.push(`[${localize('chatDebug.hook.error', "Error")}]`);130lines.push(content.errorMessage);131}132133return lines.join('\n');134}135136137