diff --git a/cmd/tui/chat/debug.go b/cmd/tui/chat/debug.go index 796626240..c61fa1067 100644 --- a/cmd/tui/chat/debug.go +++ b/cmd/tui/chat/debug.go @@ -16,9 +16,11 @@ import ( ) type chatPromptDebug struct { - request api.ChatRequest - tokens int - scroll int + request api.ChatRequest + tokens int + scroll int + lines []string + linesWidth int } const maxPromptDebugToolResultRunes = 400 @@ -220,10 +222,13 @@ func (m chatModel) previewChatRequest(opts coreagent.RunOptions, messages []api. return req } -func (m chatModel) promptDebugLines(width int) []string { +func (m *chatModel) promptDebugLines(width int) []string { if m.promptDebug == nil { return nil } + if m.promptDebug.lines != nil && m.promptDebug.linesWidth == width { + return m.promptDebug.lines + } req := m.promptDebug.request innerWidth := max(20, width-2) lines := []string{ @@ -259,15 +264,17 @@ func (m chatModel) promptDebugLines(width int) []string { lines = append(lines, "", chatHeaderStyle.Render("Tools")) if len(req.Tools) == 0 { lines = append(lines, chatMetaStyle.Render("none")) - return lines - } - for i, tool := range req.Tools { - if i > 0 { - lines = append(lines, "") + } else { + for i, tool := range req.Tools { + if i > 0 { + lines = append(lines, "") + } + lines = append(lines, promptDebugToolLines(i+1, tool, innerWidth)...) } - lines = append(lines, promptDebugToolLines(i+1, tool, innerWidth)...) } - return lines + m.promptDebug.lines = lines + m.promptDebug.linesWidth = width + return m.promptDebug.lines } func promptDebugFieldLine(label, value string, width int) string { diff --git a/cmd/tui/chat/input_test.go b/cmd/tui/chat/input_test.go index fb8b90ac7..3138d82a0 100644 --- a/cmd/tui/chat/input_test.go +++ b/cmd/tui/chat/input_test.go @@ -370,6 +370,36 @@ func TestChatPromptDebugMouseWheelScrolls(t *testing.T) { } } +func TestChatPromptDebugCachesLinesByWidth(t *testing.T) { + m := chatModel{ + promptDebug: &chatPromptDebug{ + request: api.ChatRequest{ + Model: "llama3.2", + Messages: []api.Message{{ + Role: "user", + Content: strings.Repeat("a long prompt line ", 20), + }}, + }, + }, + } + + first := m.promptDebugLines(80) + if len(first) == 0 || m.promptDebug.linesWidth != 80 { + t.Fatalf("prompt cache = %#v, want lines cached at width 80", m.promptDebug) + } + if &first[0] != &m.promptDebugLines(80)[0] { + t.Fatal("prompt debug should reuse cached lines at the same width") + } + + resized := m.promptDebugLines(120) + if m.promptDebug.linesWidth != 120 { + t.Fatalf("prompt cache width = %d, want 120", m.promptDebug.linesWidth) + } + if &first[0] == &resized[0] { + t.Fatal("prompt debug should rebuild lines after a width change") + } +} + func TestTruncateInputLineUsesDisplayWidth(t *testing.T) { line := truncateInputLine(strings.Repeat("界", 10), 10) if got := lipgloss.Width(line); got > 10 {