feat: add visual thinking level indicator via border colors

The horizontal borders around the input editor now change color based on
the current thinking level, providing immediate visual feedback:

- off: gray (default)
- minimal: dim blue
- low: blue
- medium: cyan
- high: magenta

The more thinking, the brighter/more vibrant the color.

Changes:
- Add public borderColor property to Editor component (packages/tui)
- Use borderColor instead of hardcoded chalk.gray for borders
- Add getThinkingBorderColor() helper in TuiRenderer
- Add updateEditorBorderColor() to apply color changes
- Update border color when:
  - Cycling with Tab key
  - Selecting via /thinking command
  - Restoring session with thinking level set
This commit is contained in:
Tino Ehrich 2025-11-19 10:38:10 +01:00
parent 9e8373b86a
commit 0df48f6b33
2 changed files with 38 additions and 1 deletions

View file

@ -491,6 +491,9 @@ export class TuiRenderer {
// Update footer with loaded state
this.footer.updateState(state);
// Update editor border color based on current thinking level
this.updateEditorBorderColor();
// Render messages
for (let i = 0; i < state.messages.length; i++) {
const message = state.messages[i];
@ -579,6 +582,31 @@ export class TuiRenderer {
}
}
private getThinkingBorderColor(level: ThinkingLevel): (str: string) => string {
// More thinking = more color (gray → dim colors → bright colors)
switch (level) {
case "off":
return chalk.gray;
case "minimal":
return chalk.dim.blue;
case "low":
return chalk.blue;
case "medium":
return chalk.cyan;
case "high":
return chalk.magenta;
default:
return chalk.gray;
}
}
private updateEditorBorderColor(): void {
const level = this.agent.state.thinkingLevel || "off";
const color = this.getThinkingBorderColor(level);
this.editor.borderColor = color;
this.ui.requestRender();
}
private cycleThinkingLevel(): boolean {
// Only cycle if model supports thinking
if (!this.agent.state.model?.reasoning) {
@ -597,6 +625,9 @@ export class TuiRenderer {
// Save thinking level change to session
this.sessionManager.saveThinkingLevelChange(nextLevel);
// Update border color
this.updateEditorBorderColor();
// Show brief notification
this.chatContainer.addChild(new Spacer(1));
this.chatContainer.addChild(new Text(chalk.dim(`Thinking level: ${nextLevel}`), 1, 0));
@ -635,6 +666,9 @@ export class TuiRenderer {
// Save thinking level change to session
this.sessionManager.saveThinkingLevelChange(level);
// Update border color
this.updateEditorBorderColor();
// Show confirmation message with proper spacing
this.chatContainer.addChild(new Spacer(1));
const confirmText = new Text(chalk.dim(`Thinking level: ${level}`), 1, 0);

View file

@ -28,6 +28,9 @@ export class Editor implements Component {
private config: TextEditorConfig = {};
// Border color (can be changed dynamically)
public borderColor: (str: string) => string = chalk.gray;
// Autocomplete support
private autocompleteProvider?: AutocompleteProvider;
private autocompleteList?: SelectList;
@ -61,7 +64,7 @@ export class Editor implements Component {
}
render(width: number): string[] {
const horizontal = chalk.gray("─");
const horizontal = this.borderColor("─");
// Layout the text - use full width
const layoutLines = this.layoutText(width);