allow toggling visibility of the assistant's thinking block

This commit is contained in:
Markus Ylisiurunen 2025-12-04 20:48:56 +02:00
parent 029a04c43b
commit 590db4b6cf
4 changed files with 65 additions and 6 deletions

View file

@ -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();
}
}

View file

@ -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(

View file

@ -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();

View file

@ -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();