feat(tui-go): render markdown in chat turns (E)

renderMarkdown wraps charmbracelet/glamour (dark style, per-width memoized) and is
hooked into the router chat-turn render path; falls back to plain content on any
glamour error so the TUI never crashes or loses text. Other roles/UI untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 16:12:16 +00:00
parent 1e6699a360
commit da72ee5b80
5 changed files with 233 additions and 8 deletions
+8 -2
View File
@@ -488,8 +488,14 @@ func (m Model) routerRows(w, h int) []string {
tag := lipgloss.NewStyle().Foreground(t.P.Accent).Background(t.P.Bg).Bold(true).Render("")
rows = append(rows, tag+" "+t.span(e.Content, t.P.FgStrong))
case "router":
for _, ln := range wrap(e.Content, w) {
rows = append(rows, t.span(ln, t.P.Fg))
// The router turn is model output: render it as markdown (bold,
// lists, headings, code) wrapped to the panel width. glamour applies
// its own inline foreground colors; we keep the opaque panel by
// fixing each line's background. On any failure renderMarkdown hands
// back the plain content, which still flows through this path fine.
rendered := renderMarkdown(e.Content, w)
for _, ln := range strings.Split(rendered, "\n") {
rows = append(rows, lipgloss.NewStyle().Background(t.P.Bg).Render(ln))
}
if s := metricsSuffix(e.Metrics); s != "" {
rows = append(rows, t.span(s, t.P.Faint))