Skip to content

feat: add retry button to TUI error messages#3253

Merged
dgageot merged 2 commits into
docker:mainfrom
dgageot:feat/tui-error-retry-button
Jun 26, 2026
Merged

feat: add retry button to TUI error messages#3253
dgageot merged 2 commits into
docker:mainfrom
dgageot:feat/tui-error-retry-button

Conversation

@dgageot

@dgageot dgageot commented Jun 26, 2026

Copy link
Copy Markdown
Member

What

Adds a clickable ↻ retry button to error messages in the TUI. When an agent turn fails (fatal model error, hook block, loop detection, tool-setup failure), the user can click the button to resume the conversation from where it left off — without retyping the last message.

Why

Previously, when the TUI showed an error in the messages view, there was no way to continue the conversation after a failure. The user had to re-enter their message manually. This adds a one-click recovery path.

How

  • pkg/tui/types/types.go: new ErrorRetryLabel ("↻ retry") constant.
  • pkg/tui/components/message/message.go: error messages render the retry affordance on a trailing line.
  • pkg/tui/messages/edit.go: new RetryMsg event.
  • pkg/tui/components/messages/messages.go: isRetryLabelClick detects clicks on the label and emits RetryMsg.
  • pkg/app/app.go: new App.Retry re-runs RunStream on the existing session (no new user message), so the conversation continues from where it stopped.
  • pkg/tui/page/chat/chat.go: handles RetryMsg — starts a fresh cancel context, resets stream tracking, shows the working spinner, and calls App.Retry. Guards against read-only sessions and in-flight turns.

Notable bug fixed during review

RunStream re-emits a UserMessageEvent for the trailing session message before StreamStarted whenever SendUserMessage is set. On retry this would duplicate the user bubble already on screen — or, when the tail is a tool/assistant message, render non-user content inside a spurious user bubble. App.Retry now suppresses any UserMessageEvent observed before StreamStarted, while still forwarding genuine mid-run user messages (steer / follow-up) that arrive afterward.

Testing

  • New unit tests:
    • TestErrorMessageShowsRetryAffordance (message rendering)
    • TestMouseClickOnRetryLabelEmitsRetryMsg (click detection)
    • TestApp_Retry_SuppressesReEmittedUserMessage (re-emission suppression)
  • task lint → 0 issues
  • task test → all green

dgageot added 2 commits June 26, 2026 10:43
RunStream re-emits a UserMessageEvent for the trailing session message
before StreamStarted; on retry this duplicated the user bubble or rendered
tool/assistant content in a spurious user bubble. Suppress pre-StreamStarted
UserMessageEvents while still forwarding genuine mid-run messages.

Assisted-By: Claude
@dgageot dgageot requested a review from a team as a code owner June 26, 2026 09:06
@dgageot dgageot merged commit 9fd31df into docker:main Jun 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants