mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 20:03:05 +00:00
Merge hide-thinking branch (PR #113)
This commit is contained in:
commit
4c6d3b0bf6
6 changed files with 88 additions and 15 deletions
|
|
@ -5,6 +5,7 @@
|
|||
### Added
|
||||
|
||||
- **`--append-system-prompt` Flag**: Append additional text or file contents to the system prompt. Supports both inline text and file paths. Complements `--system-prompt` for layering custom instructions without replacing the base system prompt. ([#114](https://github.com/badlogic/pi-mono/pull/114) by [@markusylisiurunen](https://github.com/markusylisiurunen))
|
||||
- **Thinking Block Toggle**: Added `Ctrl+T` shortcut to toggle visibility of LLM thinking blocks. When toggled off, shows a static "Thinking..." label instead of full content. Useful for reducing visual clutter during long conversations. ([#113](https://github.com/badlogic/pi-mono/pull/113) by [@markusylisiurunen](https://github.com/markusylisiurunen))
|
||||
|
||||
## [0.12.10] - 2025-12-04
|
||||
|
||||
|
|
|
|||
|
|
@ -684,6 +684,7 @@ Change queue mode with `/queue` command. Setting is saved in `~/.pi/agent/settin
|
|||
- **Shift+Tab**: Cycle thinking level (for reasoning-capable models)
|
||||
- **Ctrl+P**: Cycle models (use `--models` to scope)
|
||||
- **Ctrl+O**: Toggle tool output expansion (collapsed ↔ full output)
|
||||
- **Ctrl+T**: Toggle thinking block visibility (shows full content ↔ static "Thinking..." label)
|
||||
|
||||
## Project Context Files
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -34,21 +41,33 @@ export class AssistantMessageComponent extends Container {
|
|||
}
|
||||
|
||||
// Render content in order
|
||||
for (const content of message.content) {
|
||||
for (let i = 0; i < message.content.length; i++) {
|
||||
const content = message.content[i];
|
||||
if (content.type === "text" && content.text.trim()) {
|
||||
// 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()) {
|
||||
// Thinking traces in muted color, italic
|
||||
// Use Markdown component with default text style for consistent styling
|
||||
this.contentContainer.addChild(
|
||||
new Markdown(content.thinking.trim(), 1, 0, getMarkdownTheme(), {
|
||||
color: (text: string) => theme.fg("muted", text),
|
||||
italic: true,
|
||||
}),
|
||||
);
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
// Check if there's text content after this thinking block
|
||||
const hasTextAfter = message.content.slice(i + 1).some((c) => c.type === "text" && c.text.trim());
|
||||
|
||||
if (this.hideThinkingBlock) {
|
||||
// Show static "Thinking..." label when hidden
|
||||
this.contentContainer.addChild(new Text(theme.fg("muted", "Thinking..."), 1, 0));
|
||||
if (hasTextAfter) {
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
}
|
||||
} else {
|
||||
// Thinking traces in muted color, italic
|
||||
// Use Markdown component with default text style for consistent styling
|
||||
this.contentContainer.addChild(
|
||||
new Markdown(content.thinking.trim(), 1, 0, getMarkdownTheme(), {
|
||||
color: (text: string) => theme.fg("muted", text),
|
||||
italic: true,
|
||||
}),
|
||||
);
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue