From d2f5f4e624db91c61551b6cd6c57ea6d494ee5fd Mon Sep 17 00:00:00 2001 From: pnkcaht Date: Mon, 19 Jan 2026 11:12:45 -0500 Subject: [PATCH 1/5] tui(edit_file): skip diff rendering on tool failure Signed-off-by: pnkcaht --- pkg/tui/components/tool/editfile/editfile.go | 54 ++++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/pkg/tui/components/tool/editfile/editfile.go b/pkg/tui/components/tool/editfile/editfile.go index fc4267cb4..75a9810bf 100644 --- a/pkg/tui/components/tool/editfile/editfile.go +++ b/pkg/tui/components/tool/editfile/editfile.go @@ -15,13 +15,26 @@ import ( type ToggleDiffViewMsg struct{} +// New creates the edit_file tool UI model. func New(msg *types.Message, sessionState *service.SessionState) layout.Model { return toolcommon.NewBase(msg, sessionState, render) } -func render(msg *types.Message, s spinner.Spinner, sessionState *service.SessionState, width, _ int) string { +// render displays the edit_file tool output in the TUI. +// It prioritizes the agent-provided friendly header when available, +// hides results when collapsed by the user, and skips diff rendering +// on tool execution errors to avoid layout issues. +func render( + msg *types.Message, + s spinner.Spinner, + sessionState *service.SessionState, + width, + _ int, +) string { + // Parse tool arguments to extract the file path for display. var args builtin.EditFileArgs if err := json.Unmarshal([]byte(msg.ToolCall.Function.Arguments), &args); err != nil { + // If arguments cannot be parsed, fail silently to avoid breaking the TUI. return "" } @@ -30,22 +43,43 @@ func render(msg *types.Message, s spinner.Spinner, sessionState *service.Session if header, ok := toolcommon.RenderFriendlyHeader(msg, s); ok { content = header } else { - content = fmt.Sprintf("%s%s %s", + content = fmt.Sprintf( + "%s%s %s", toolcommon.Icon(msg, s), styles.ToolName.Render(msg.ToolDefinition.DisplayName()), - styles.ToolMessageStyle.Render(toolcommon.ShortenPath(args.Path))) + styles.ToolMessageStyle.Render(toolcommon.ShortenPath(args.Path)), + ) } - if !sessionState.HideToolResults() { - if msg.ToolCall.Function.Arguments != "" { - contentWidth := width - styles.ToolCallResult.GetHorizontalFrameSize() - content += "\n" + styles.ToolCallResult.Render( - renderEditFile(msg.ToolCall, contentWidth, sessionState.SplitDiffView(), msg.ToolStatus)) - } + // Tool results are hidden when the user collapses them. + if sessionState.HideToolResults() { + return content + } - if (msg.ToolStatus == types.ToolStatusError) && msg.Content != "" { + // Skip diff rendering when the edit fails. + // Rendering a diff on failed edits can break layout/scroll calculations. + if msg.ToolStatus == types.ToolStatusError { + if msg.Content != "" { content += toolcommon.FormatToolResult(msg.Content, width) } + return content + } + + // Successful (or pending/confirmation) execution: + // render the diff output inside the ToolCallResult container. + if msg.ToolCall.Function.Arguments != "" { + // Calculate available width for diff rendering, accounting for + // ToolCallResult frame padding. + contentWidth := width - styles.ToolCallResult.GetHorizontalFrameSize() + + content += "\n" + styles.ToolCallResult.Render( + renderEditFile( + msg.ToolCall, + contentWidth, + sessionState.SplitDiffView(), + msg.ToolStatus, + ), + ) } return content From cbf95dce761097be9c1243c0b9e96850aad76925 Mon Sep 17 00:00:00 2001 From: pnkcaht Date: Wed, 21 Jan 2026 10:38:27 -0500 Subject: [PATCH 2/5] tui(edit_file): improve error rendering and truncate long messages Signed-off-by: pnkcaht --- pkg/tui/components/tool/editfile/editfile.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/tui/components/tool/editfile/editfile.go b/pkg/tui/components/tool/editfile/editfile.go index 75a9810bf..3daf69288 100644 --- a/pkg/tui/components/tool/editfile/editfile.go +++ b/pkg/tui/components/tool/editfile/editfile.go @@ -56,11 +56,21 @@ func render( return content } - // Skip diff rendering when the edit fails. - // Rendering a diff on failed edits can break layout/scroll calculations. + // When the edit fails, do not render a diff. + // Instead, render the error/rejection as a single-line tool message. + // Rendering diffs on failed edits can break layout and scroll calculations. if msg.ToolStatus == types.ToolStatusError { if msg.Content != "" { - content += toolcommon.FormatToolResult(msg.Content, width) + // Render error/rejection as a single-line tool message + // with consistent spacing and styling. + errorText := fmt.Sprintf(" %s", msg.Content) + + // Truncate to available width to avoid wrapping + errorLine := styles.ToolMessageStyle. + MaxWidth(width). + Render(errorText) + + content += "\n" + errorLine } return content } From 1c5bb9b1133ce5b2149718210ae9b2764b92a221 Mon Sep 17 00:00:00 2001 From: pnkcaht Date: Wed, 21 Jan 2026 12:20:47 -0500 Subject: [PATCH 3/5] tui(edit_file): align error styling with other tool errors Signed-off-by: pnkcaht --- pkg/tui/components/tool/editfile/editfile.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/tui/components/tool/editfile/editfile.go b/pkg/tui/components/tool/editfile/editfile.go index 3daf69288..e3efd08b4 100644 --- a/pkg/tui/components/tool/editfile/editfile.go +++ b/pkg/tui/components/tool/editfile/editfile.go @@ -61,12 +61,12 @@ func render( // Rendering diffs on failed edits can break layout and scroll calculations. if msg.ToolStatus == types.ToolStatusError { if msg.Content != "" { - // Render error/rejection as a single-line tool message + // Render error/rejection as a single-line tool error message // with consistent spacing and styling. errorText := fmt.Sprintf(" %s", msg.Content) // Truncate to available width to avoid wrapping - errorLine := styles.ToolMessageStyle. + errorLine := styles.ToolErrorMessageStyle. MaxWidth(width). Render(errorText) From 5121375b0ceea20342879bef3c2b7b2d181e9cf0 Mon Sep 17 00:00:00 2001 From: pnkcaht Date: Wed, 21 Jan 2026 13:26:29 -0500 Subject: [PATCH 4/5] tui(edit_file): render tool error on a single line with consistent styling Signed-off-by: pnkcaht --- pkg/tui/components/tool/editfile/editfile.go | 49 +++++++++++--------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/pkg/tui/components/tool/editfile/editfile.go b/pkg/tui/components/tool/editfile/editfile.go index e3efd08b4..a40a7a1ac 100644 --- a/pkg/tui/components/tool/editfile/editfile.go +++ b/pkg/tui/components/tool/editfile/editfile.go @@ -22,8 +22,8 @@ func New(msg *types.Message, sessionState *service.SessionState) layout.Model { // render displays the edit_file tool output in the TUI. // It prioritizes the agent-provided friendly header when available, -// hides results when collapsed by the user, and skips diff rendering -// on tool execution errors to avoid layout issues. +// hides results when collapsed by the user, and renders tool errors +// in a single-line error style consistent with other tools. func render( msg *types.Message, s spinner.Spinner, @@ -38,6 +38,32 @@ func render( return "" } + // When the tool failed, render a single-line error header + // consistent with other tool error renderings. + if msg.ToolStatus == types.ToolStatusError { + if msg.Content == "" { + return "" + } + + // Render everything on a single line: + // - error icon + // - tool name in error style + // - rejection/error message + line := fmt.Sprintf( + "%s%s %s", + styles.ToolErrorIcon.Render("✖ "), + styles.ToolNameError.Render(msg.ToolDefinition.DisplayName()), + styles.ToolErrorMessageStyle.Render(msg.Content), + ) + + // Truncate to terminal width to avoid wrapping + return styles.BaseStyle. + MaxWidth(width). + Render(line) + } + + // ---- Normal (non-error) rendering ---- + // Check for friendly description first var content string if header, ok := toolcommon.RenderFriendlyHeader(msg, s); ok { @@ -56,25 +82,6 @@ func render( return content } - // When the edit fails, do not render a diff. - // Instead, render the error/rejection as a single-line tool message. - // Rendering diffs on failed edits can break layout and scroll calculations. - if msg.ToolStatus == types.ToolStatusError { - if msg.Content != "" { - // Render error/rejection as a single-line tool error message - // with consistent spacing and styling. - errorText := fmt.Sprintf(" %s", msg.Content) - - // Truncate to available width to avoid wrapping - errorLine := styles.ToolErrorMessageStyle. - MaxWidth(width). - Render(errorText) - - content += "\n" + errorLine - } - return content - } - // Successful (or pending/confirmation) execution: // render the diff output inside the ToolCallResult container. if msg.ToolCall.Function.Arguments != "" { From adcdd1bc1bfa0a9576887e31f8aa6584aee7be87 Mon Sep 17 00:00:00 2001 From: pnkcaht Date: Wed, 21 Jan 2026 13:44:58 -0500 Subject: [PATCH 5/5] tui(edit_file): render errors using standard tool error header Signed-off-by: pnkcaht --- pkg/tui/components/tool/editfile/editfile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tui/components/tool/editfile/editfile.go b/pkg/tui/components/tool/editfile/editfile.go index a40a7a1ac..3c9bc0db9 100644 --- a/pkg/tui/components/tool/editfile/editfile.go +++ b/pkg/tui/components/tool/editfile/editfile.go @@ -51,7 +51,7 @@ func render( // - rejection/error message line := fmt.Sprintf( "%s%s %s", - styles.ToolErrorIcon.Render("✖ "), + toolcommon.Icon(msg, s), styles.ToolNameError.Render(msg.ToolDefinition.DisplayName()), styles.ToolErrorMessageStyle.Render(msg.Content), )