mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
fix(ui): wrap reasoning blocks to terminal width to prevent clipping
- wrap thinking text in StreamComponent and render.ReasoningBlock - plumb width through renderer and streaming item paths - keeps style consistent with user/assistant blocks and avoids cut-off lines
This commit is contained in:
@@ -156,7 +156,7 @@ func (s *StreamingMessageItem) Render(width int) string {
|
||||
durationMs = time.Since(s.startTime).Milliseconds()
|
||||
}
|
||||
ty := createTypography(style.GetTheme())
|
||||
rendered = render.ReasoningBlock(s.content, durationMs, ty, style.GetTheme())
|
||||
rendered = render.ReasoningBlock(s.content, durationMs, width, ty, style.GetTheme())
|
||||
} else {
|
||||
// Render as assistant message
|
||||
rendered = render.AssistantBlock(s.content, width, style.GetTheme())
|
||||
|
||||
@@ -178,7 +178,7 @@ func (r *MessageRenderer) RenderAssistantMessage(content string, timestamp time.
|
||||
// as live streaming: muted italic text with margin. This is used when resuming
|
||||
// sessions to display saved reasoning content.
|
||||
func (r *MessageRenderer) RenderReasoningBlock(content string, timestamp time.Time) UIMessage {
|
||||
rendered := render.ReasoningBlock(content, 0, r.ty, style.GetTheme())
|
||||
rendered := render.ReasoningBlock(content, 0, r.width, r.ty, style.GetTheme())
|
||||
|
||||
return UIMessage{
|
||||
Type: AssistantMessage,
|
||||
|
||||
@@ -63,14 +63,19 @@ func AssistantBlock(content string, width int, theme style.Theme) string {
|
||||
|
||||
// ReasoningBlock renders a reasoning/thinking block with muted italic text.
|
||||
// If duration > 0, shows "Thought for Xs" label. Otherwise shows just "Thought".
|
||||
func ReasoningBlock(content string, duration int64, ty *herald.Typography, theme style.Theme) string {
|
||||
// The width parameter controls soft-wrapping so long reasoning lines don't get cut off.
|
||||
func ReasoningBlock(content string, duration int64, width int, ty *herald.Typography, theme style.Theme) string {
|
||||
if strings.TrimSpace(content) == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Match live streaming styling: muted italic text
|
||||
// Match live streaming styling: muted italic text. Wrap before styling so
|
||||
// ANSI sequences from italics don't interfere with width calculations.
|
||||
lines := strings.Split(strings.TrimRight(content, "\n"), "\n")
|
||||
contentStr := strings.TrimLeft(strings.Join(lines, "\n"), " \t\n")
|
||||
if width > 4 { // mirror other blocks (User/Assistant) which subtract 4
|
||||
contentStr = lipgloss.Wrap(contentStr, width-4, "")
|
||||
}
|
||||
mutedStyle := lipgloss.NewStyle().Foreground(theme.Muted)
|
||||
contentRendered := mutedStyle.Render(ty.Italic(contentStr))
|
||||
|
||||
|
||||
@@ -472,6 +472,10 @@ func (s *StreamComponent) renderReasoningBlock(reasoning string) string {
|
||||
|
||||
// Main content using Italic with Muted color for visual distinction.
|
||||
content := strings.TrimLeft(strings.Join(lines, "\n"), " \t\n")
|
||||
// Soft-wrap to the available width so long lines don't get cut off.
|
||||
if s.width > 4 {
|
||||
content = lipgloss.Wrap(content, s.width-4, "")
|
||||
}
|
||||
theme := GetTheme()
|
||||
mutedStyle := lipgloss.NewStyle().Foreground(theme.Muted)
|
||||
parts = append(parts, mutedStyle.Render(s.ty.Italic(content)))
|
||||
|
||||
Reference in New Issue
Block a user