co-mono/packages/coding-agent/src/tui/assistant-message.ts
Mario Zechner 7beb354337 Add thinking level persistence and fix UI issues
- Save and restore thinking level when continuing sessions
- Fix thinking level confirmation message spacing and styling
- Fix thinking text wrapping to preserve ANSI formatting across lines
2025-11-11 23:18:40 +01:00

59 lines
2 KiB
TypeScript

import type { AssistantMessage } from "@mariozechner/pi-ai";
import { Container, Markdown, Spacer, Text } from "@mariozechner/pi-tui";
import chalk from "chalk";
/**
* Component that renders a complete assistant message
*/
export class AssistantMessageComponent extends Container {
private contentContainer: Container;
constructor(message?: AssistantMessage) {
super();
// Container for text/thinking content
this.contentContainer = new Container();
this.addChild(this.contentContainer);
if (message) {
this.updateContent(message);
}
}
updateContent(message: AssistantMessage): void {
// Clear content container
this.contentContainer.clear();
if (
message.content.length > 0 &&
message.content.some(
(c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()),
)
) {
this.contentContainer.addChild(new Spacer(1));
}
// Render content in order
for (const content of message.content) {
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(), undefined, undefined, undefined, 1, 0));
} else if (content.type === "thinking" && content.thinking.trim()) {
// Thinking traces in dark gray italic
// Use Markdown component because it preserves ANSI codes across wrapped lines
const thinkingText = chalk.gray.italic(content.thinking);
this.contentContainer.addChild(new Markdown(thinkingText, undefined, undefined, undefined, 1, 0));
this.contentContainer.addChild(new Spacer(1));
}
}
// Check if aborted - show after partial content
if (message.stopReason === "aborted") {
this.contentContainer.addChild(new Text(chalk.red("Aborted")));
} else if (message.stopReason === "error") {
const errorMsg = message.errorMessage || "Unknown error";
this.contentContainer.addChild(new Text(chalk.red(`Error: ${errorMsg}`)));
}
}
}