diff --git a/packages/coding-agent/src/settings-manager.ts b/packages/coding-agent/src/settings-manager.ts index a2306854..f9147f28 100644 --- a/packages/coding-agent/src/settings-manager.ts +++ b/packages/coding-agent/src/settings-manager.ts @@ -16,6 +16,7 @@ export interface Settings { queueMode?: "all" | "one-at-a-time"; theme?: string; compaction?: CompactionSettings; + hideThinkingBlock?: boolean; } export class SettingsManager { @@ -143,4 +144,13 @@ export class SettingsManager { keepRecentTokens: this.getCompactionKeepRecentTokens(), }; } + + getHideThinkingBlock(): boolean { + return this.settings.hideThinkingBlock ?? false; + } + + setHideThinkingBlock(hide: boolean): void { + this.settings.hideThinkingBlock = hide; + this.save(); + } } diff --git a/packages/coding-agent/src/tui/assistant-message.ts b/packages/coding-agent/src/tui/assistant-message.ts index e1a33fba..611bbcc0 100644 --- a/packages/coding-agent/src/tui/assistant-message.ts +++ b/packages/coding-agent/src/tui/assistant-message.ts @@ -7,10 +7,13 @@ import { getMarkdownTheme, theme } from "../theme/theme.js"; */ export class AssistantMessageComponent extends Container { private contentContainer: Container; + private hideThinkingBlock: boolean; - constructor(message?: AssistantMessage) { + constructor(message?: AssistantMessage, hideThinkingBlock = false) { super(); + this.hideThinkingBlock = hideThinkingBlock; + // Container for text/thinking content this.contentContainer = new Container(); this.addChild(this.contentContainer); @@ -20,6 +23,10 @@ export class AssistantMessageComponent extends Container { } } + setHideThinkingBlock(hide: boolean): void { + this.hideThinkingBlock = hide; + } + updateContent(message: AssistantMessage): void { // Clear content container this.contentContainer.clear(); @@ -39,7 +46,7 @@ export class AssistantMessageComponent extends Container { // Assistant text messages with no background - trim the text // Set paddingY=0 to avoid extra spacing before tool executions this.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, getMarkdownTheme())); - } else if (content.type === "thinking" && content.thinking.trim()) { + } else if (content.type === "thinking" && content.thinking.trim() && !this.hideThinkingBlock) { // Thinking traces in muted color, italic // Use Markdown component with default text style for consistent styling this.contentContainer.addChild( diff --git a/packages/coding-agent/src/tui/custom-editor.ts b/packages/coding-agent/src/tui/custom-editor.ts index 49e41703..a63932bd 100644 --- a/packages/coding-agent/src/tui/custom-editor.ts +++ b/packages/coding-agent/src/tui/custom-editor.ts @@ -9,8 +9,15 @@ export class CustomEditor extends Editor { public onShiftTab?: () => void; public onCtrlP?: () => void; public onCtrlO?: () => void; + public onCtrlT?: () => void; handleInput(data: string): void { + // Intercept Ctrl+T for thinking block visibility toggle + if (data === "\x14" && this.onCtrlT) { + this.onCtrlT(); + return; + } + // Intercept Ctrl+O for tool output expansion if (data === "\x0f" && this.onCtrlO) { this.onCtrlO(); diff --git a/packages/coding-agent/src/tui/tui-renderer.ts b/packages/coding-agent/src/tui/tui-renderer.ts index 5cba73e7..888d5d94 100644 --- a/packages/coding-agent/src/tui/tui-renderer.ts +++ b/packages/coding-agent/src/tui/tui-renderer.ts @@ -107,6 +107,9 @@ export class TuiRenderer { // Tool output expansion state private toolOutputExpanded = false; + // Thinking block visibility state + private hideThinkingBlock = false; + // Agent subscription unsubscribe function private unsubscribe?: () => void; @@ -211,6 +214,9 @@ export class TuiRenderer { description: "Toggle automatic context compaction", }; + // Load hide thinking block setting + this.hideThinkingBlock = settingsManager.getHideThinkingBlock(); + // Load file-based slash commands this.fileCommands = loadSlashCommands(); @@ -272,6 +278,9 @@ export class TuiRenderer { theme.fg("dim", "ctrl+o") + theme.fg("muted", " to expand tools") + "\n" + + theme.fg("dim", "ctrl+t") + + theme.fg("muted", " to toggle thinking") + + "\n" + theme.fg("dim", "/") + theme.fg("muted", " for commands") + "\n" + @@ -362,6 +371,10 @@ export class TuiRenderer { this.toggleToolOutputExpansion(); }; + this.editor.onCtrlT = () => { + this.toggleThinkingBlockVisibility(); + }; + // Handle editor submission this.editor.onSubmit = async (text: string) => { text = text.trim(); @@ -648,7 +661,7 @@ export class TuiRenderer { this.ui.requestRender(); } else if (event.message.role === "assistant") { // Create assistant component for streaming - this.streamingComponent = new AssistantMessageComponent(); + this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock); this.chatContainer.addChild(this.streamingComponent); this.streamingComponent.updateContent(event.message as AssistantMessage); this.ui.requestRender(); @@ -788,7 +801,7 @@ export class TuiRenderer { const assistantMsg = message; // Add assistant message component - const assistantComponent = new AssistantMessageComponent(assistantMsg); + const assistantComponent = new AssistantMessageComponent(assistantMsg, this.hideThinkingBlock); this.chatContainer.addChild(assistantComponent); } // Note: tool calls and results are now handled via tool_execution_start/end events @@ -834,7 +847,7 @@ export class TuiRenderer { } } else if (message.role === "assistant") { const assistantMsg = message as AssistantMessage; - const assistantComponent = new AssistantMessageComponent(assistantMsg); + const assistantComponent = new AssistantMessageComponent(assistantMsg, this.hideThinkingBlock); this.chatContainer.addChild(assistantComponent); // Create tool execution components for any tool calls @@ -918,7 +931,7 @@ export class TuiRenderer { } } else if (message.role === "assistant") { const assistantMsg = message; - const assistantComponent = new AssistantMessageComponent(assistantMsg); + const assistantComponent = new AssistantMessageComponent(assistantMsg, this.hideThinkingBlock); this.chatContainer.addChild(assistantComponent); for (const content of assistantMsg.content) { @@ -1121,6 +1134,28 @@ export class TuiRenderer { this.ui.requestRender(); } + private toggleThinkingBlockVisibility(): void { + this.hideThinkingBlock = !this.hideThinkingBlock; + this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock); + + // Update all assistant message components and rebuild their content + for (const child of this.chatContainer.children) { + if (child instanceof AssistantMessageComponent) { + child.setHideThinkingBlock(this.hideThinkingBlock); + } + } + + // Rebuild chat to apply visibility change + this.chatContainer.clear(); + this.rebuildChatFromMessages(); + + // Show brief notification + const status = this.hideThinkingBlock ? "hidden" : "visible"; + this.chatContainer.addChild(new Spacer(1)); + this.chatContainer.addChild(new Text(theme.fg("dim", `Thinking blocks: ${status}`), 1, 0)); + this.ui.requestRender(); + } + clearEditor(): void { this.editor.setText(""); this.ui.requestRender();