feat: add iterative refinement to Reply Drafter (#2298)#2299
Merged
Conversation
Reply Drafter was one-shot — open it, get 3-5 suggestions, tap one. When none fit, the only escape was to close and reopen. This adds a text field + Regenerate button at the bottom of the suggestions list for iterative refinement. The refinement passes the previous reply set AND the user's note to the model, framed as "Here's what you wrote, here's what the user wants different, produce a new set." That framing is unambiguous — the model can't mistake the note for the message to reply to because the actual conversation is in the image and the previous replies clearly bracket what's being refined. First open is unchanged: empty previousReplies collapses to the original RULES_BLOCK + FORMAT_BLOCK, byte-for-byte. Failed-state Retry also uses fresh draft() rather than refinement, since there is nothing useful to refine against. - ReplyDrafterTask: object -> data class with previousReplies + refinement; computed prompt inserts a REFINEMENT block between the rules and format blocks when previousReplies is non-empty - ReplyDrafterViewModel: tracks lastReplies, exposes setGuidance() (200-char cap) + regenerate(); draft() stays fresh, regenerate() refines - ReplyDrafterScreen: pinned GuidanceInputRow with OutlinedTextField + Refresh IconButton, visible in Suggestions and Failed states - Bottom placement is deliberate for switch-access: suggestion cards stay the primary scan targets; the field is the last scan stop - 2 new strings; 14 unit tests pass (11 parser + 3 new prompt-shape) Closes #2298
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.
Summary
Reply Drafter was one-shot today — open it, get 3-5 suggestions, tap one. When none fit, the only escape was to close and reopen and get a fresh roll of the dice. This adds a text field + Regenerate button at the bottom of the suggestions list for iterative refinement.
The key architectural choice: refinement sends the model the image + the previous reply set + the user's note, framed as "Here's what you wrote, here's what the user wants different, produce a new set." The note can't be mistaken for the message to reply to because the actual conversation is in the image and the previous replies clearly bracket what's being refined.
previousRepliescollapses the prompt to the original RULES_BLOCK + FORMAT_BLOCK, byte-for-byte identical to today.draft(), not refinement — nothing useful to refine against if generation failed.Files:
service/llm/ReplyDrafterTask.kt—object→data classwithpreviousReplies+refinement. Computedpromptinserts aREFINEMENTblock between the rules and format blocks whenpreviousRepliesis non-empty. Format block stays last (recency benefit preserved).screens/replydrafter/ReplyDrafterViewModel.kt— trackslastReplies, exposessetGuidance(text)(200-char cap),regenerate().draft()stays fresh;regenerate()refines.screens/replydrafter/ReplyDrafterScreen.kt— pinnedGuidanceInputRow(OutlinedTextField + Refresh IconButton), visible in Suggestions and Failed states.screens/replydrafter/ReplyDrafterActivity.kt— observes guidance state, wiressetGuidanceandregeneratecallbacks.Closes #2298
Test plan
./gradlew compileDebugKotlin testDebugUnitTest installDebug