fix(frontend): clear the composer when a retry succeeds - #265
Merged
Conversation
A failed send deliberately leaves the text in the composer -- "Your message is still here" -- so the user does not lose it. Retry then sent that text without clearing it, so the message ended up in the transcript *and* back in the box, one Enter away from being sent a second time. Only `submitDraft` cleared the composer. `retryLastPrompt` called `startGeneration` directly and skipped all of it, including the migration of draft and attachments from the "new chat" placeholder scope to the real thread when a retry is what creates that thread. That settling logic is now a helper both paths use, so they cannot drift. Extracting it changed no behaviour: the existing 33 ChatPage tests passed against the extraction alone, before retry was wired to it. Retry passes the live draft only when it is still the message being retried (`draft.trim() === lastPrompt`, since lastPrompt is the trimmed input). A draft the user has started rewriting since the failure is left alone -- the helper's existing "clear only if unchanged" guard then does the rest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
A failed send deliberately leaves the text in the composer — "Your message is still here" — so the user does not lose it. Retry then sent that text without clearing it, so the message ended up in the transcript and back in the box, one Enter away from being sent a second time.
Root cause
Only
submitDraftsettled the composer.retryLastPromptcalledstartGenerationdirectly and skipped all of it:That skipped more than the draft. The same block also migrates the draft and its attachments from the
"new chat"placeholder scope to the real thread — which matters precisely when the retry is what creates that thread, i.e. when the very first message failed.The fix
The settling logic is now a helper both paths call, so they cannot drift apart:
The extraction changed no behaviour, and I checked that before building on it: the existing 33 ChatPage tests passed against the extraction alone, with retry still unwired.
Retry passes the live draft only when it is still the message being retried:
lastPromptis the trimmed input, hence the trimmed comparison. A draft the user has started rewriting since the failure is left alone, and the helper's existing "clear only if unchanged" guard does the rest.Verification
Being straight about the second: it does not fail against the original code, because there the composer was never cleared at all — so "still holds the rewritten text" was trivially true. It earns its place by constraining the fix, not by demonstrating the bug.
The first test also asserts the text is still present before clicking Retry, so it cannot pass by the send path having cleared it early.
npm test -- --runnpm run typechecknpm run lintpython -m pytest -qCompatibility and rollback
One component. No API contract, stored data, or migration.
submitDraftruns exactly the same code it did before, now via a named function. Reverting the commit restores the previous behaviour exactly.Limits
A retry that fails still leaves the draft in place, which is the same deliberate behaviour as a failed send.
Attachments follow the same rule as the draft: those that were sent are released, and any staged since are kept. That is inherited from the shared helper rather than reasoned about separately for retry, which is the point of sharing it — but it means retry's attachment handling is now as good, and no better, than submit's.
🤖 Generated with Claude Code