feat(desktop): skipped clarify keeps its choices visible and answerable - #69769
Merged
Conversation
When a clarify prompt times out, the settled card collapsed to just
'Skipped' — the options were unrecoverable (the args carry them, the
renderer dropped them) and there was no way to answer late.
The skipped card now:
- renders the original choices, letter-badged like the live card
- clicking one drafts a quoted follow-up ('Re: "<question>" — my
answer: <choice>') into the composer via the insert bus. Enter sends
it; if the agent is mid-turn it queues like any other prompt.
- a hint line explains the question timed out and what picking does
No retroactive resolution of the expired request: the tool already
returned empty and the turn moved on — injecting into past context
would break prompt-cache and role-alternation invariants, and
clarify.respond on an expired id hard-errors (#56558). The follow-up
message path needs no backend change and works against old backends.
Answered clarifies and free-text (no-choice) skips are unchanged.
Interim UX for #44845 (durable ID-addressable clarify decisions).
Builds on the skipped-clarify card so it holds up beyond the timeout case:
- Extract a shared `ChoiceButton` (letter badge + label + row chrome) used
by both the live pending card and the settled skip card. The two blocks
had drifted into duplicated markup; now they can't diverge.
- Fix the hint copy. An empty `user_response` is emitted for BOTH a
server-side timeout AND a manual Skip (tools/clarify_tool.py) — there is
no field on the result that tells them apart — so asserting "This question
timed out" was wrong half the time. Neutral wording ("This prompt is no
longer waiting…") is correct for either, and the recover-your-answer path
now also helps someone who mis-clicked Skip. Updated en/ja/zh/zh-hant.
No behavior change to the live prompt or the follow-up-message flow.
Co-authored-by: SHL0MS <SHL0MS@users.noreply.github.com>
13 tasks
Contributor
૮ >ﻌ< ა ci reviewran on e80e036 all good! |
The no-native-title guard (added on main after this PR's first CI run) bans native title= on <button>. Wrap the shared ChoiceButton in the themed <Tip>, which renders the child untouched when the label is falsy so the live card is unaffected.
This was referenced Jul 23, 2026
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…720-clarify-late feat(desktop): skipped clarify keeps its choices visible and answerable
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.
Supersedes #69720 (by @SHL0MS — whose commit is preserved here via cherry-pick, with a follow-up refactor on top).
What this does
When a
clarifyprompt settles without an answer, the card collapsed to just the question and an italic "Skipped" — the choices vanished even though they're still in the tool-call args, and there was no way to see or act on what the agent asked. This keeps them on the settled card and makes them actionable:Re: "<question>" — my answer: <choice>— and focuses it. Enter sends it as a normal user message; if the agent is mid-turn it queues like any other prompt.This is not retroactive resolution of the expired request: by the time the card settles, the tool has already returned empty and the turn moved on. Injecting a late answer into past context would break the prompt-cache and role-alternation invariants, and
clarify.respondagainst an expired id hard-errors today (#56558). The follow-up-message path needs zero backend changes and behaves identically against older backends. Interim UX for #44845 (durable, ID-addressable clarify decisions); #56571 is the complementary backend fix for the raw 4009 error and is not obsoleted by this.What changed vs #69720
Two refinements on top of SHL0MS's original:
user_responseis emitted for both a server-side timeout AND a manual Skip (tools/clarify_tool.py), with no field distinguishing them — so the original "This question timed out" hint was wrong for the manual-skip case. The wording is now neutral ("This prompt is no longer waiting…"), correct for either, and the recover-your-answer path now also helps a mis-clicked Skip. Updated en/ja/zh/zh-hant.ChoiceButton(letter badge + label + row chrome) used by both the live pending card and the settled skip card, which had drifted into two copies of the same button.Answered clarifies and free-text (no-choice) skips render exactly as before.
Test
apps/desktop:npx vitest run src/components/assistant-ui/clarify-tool.test.tsx --project ui— 8/8 pass (skipped-with-choices renders options and a click emits the drafted follow-up on the insert bus; answered clarifies and choice-less skips render no late-choice group).npx tsc -p . --noEmitclean; eslint clean on the touched component.Type of change