diff --git a/apps/desktop/src/components/assistant-ui/clarify-tool.test.tsx b/apps/desktop/src/components/assistant-ui/clarify-tool.test.tsx
index cf9e35450191..cdf592b16b8e 100644
--- a/apps/desktop/src/components/assistant-ui/clarify-tool.test.tsx
+++ b/apps/desktop/src/components/assistant-ui/clarify-tool.test.tsx
@@ -1,8 +1,9 @@
import type { ToolCallMessagePartProps } from '@assistant-ui/react'
-import { cleanup, render, screen } from '@testing-library/react'
+import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import type { ReactNode } from 'react'
import { afterEach, describe, expect, it, vi } from 'vitest'
+import { onComposerInsertRequest } from '@/app/chat/composer/focus'
import { I18nProvider } from '@/i18n'
import { ClarifyTool, readClarifyResult } from './clarify-tool'
@@ -114,4 +115,70 @@ describe('ClarifyTool settled view', () => {
expect(screen.getByText('Anything else?')).toBeTruthy()
expect(screen.getByText('Skipped')).toBeTruthy()
})
+
+ it('keeps the original choices visible and clickable after a skip', async () => {
+ const inserts: string[] = []
+
+ const stop = onComposerInsertRequest(detail => {
+ inserts.push(detail.text)
+ })
+
+ try {
+ renderClarify(
+
+ )
+
+ // The skip label renders AND the original options are still on screen.
+ expect(screen.getByText('Skipped')).toBeTruthy()
+ const group = document.querySelector('[data-clarify-late-choices]')
+ expect(group).toBeTruthy()
+ expect(screen.getByText('staging')).toBeTruthy()
+ expect(screen.getByText('prod')).toBeTruthy()
+
+ // Picking one drafts a quoted follow-up into the composer. The insert
+ // bus defers dispatch by a macrotask, so flush one tick.
+ fireEvent.click(screen.getByText('prod'))
+ await new Promise(resolve => window.setTimeout(resolve, 0))
+
+ expect(inserts).toHaveLength(1)
+ expect(inserts[0]).toContain('Which deployment target?')
+ expect(inserts[0]).toContain('prod')
+ } finally {
+ stop()
+ }
+ })
+
+ it('does not render late choices on an answered clarify', () => {
+ renderClarify(
+
+ )
+
+ expect(document.querySelector('[data-clarify-late-choices]')).toBeNull()
+ })
+
+ it('does not render late choices for a free-text (no-choice) skip', () => {
+ renderClarify(
+
+ )
+
+ expect(document.querySelector('[data-clarify-late-choices]')).toBeNull()
+ })
})
diff --git a/apps/desktop/src/components/assistant-ui/clarify-tool.tsx b/apps/desktop/src/components/assistant-ui/clarify-tool.tsx
index 72b6fbbdfa81..d5c04d7acdc4 100644
--- a/apps/desktop/src/components/assistant-ui/clarify-tool.tsx
+++ b/apps/desktop/src/components/assistant-ui/clarify-tool.tsx
@@ -13,11 +13,13 @@ import {
useState
} from 'react'
+import { requestComposerFocus, requestComposerInsert } from '@/app/chat/composer/focus'
import { useSessionView } from '@/app/chat/session-view'
import { ToolFallback } from '@/components/assistant-ui/tool/fallback'
import { Button } from '@/components/ui/button'
import { Kbd } from '@/components/ui/kbd'
import { Textarea } from '@/components/ui/textarea'
+import { Tip } from '@/components/ui/tooltip'
import { useI18n } from '@/i18n'
import { triggerHaptic } from '@/lib/haptics'
import { CircleLetterA, Loader2, MessageQuestion } from '@/lib/icons'
@@ -125,6 +127,48 @@ function KeyBadge({ char, preview, selected }: { char: string; preview?: boolean
)
}
+/** A letter-badged option row. Shared by the live pending card (where a click
+ * selects an answer) and the settled skip card (where a click drafts a
+ * follow-up), so both stay visually identical. */
+function ChoiceButton({
+ char,
+ choice,
+ disabled,
+ onClick,
+ selected = false,
+ title
+}: {
+ char: string
+ choice: string
+ disabled?: boolean
+ onClick: () => void
+ selected?: boolean
+ title?: string
+}) {
+ // `Tip` is the repo's themed replacement for native `title=` (a native
+ // tooltip on a
) : null}
+ {skipped && choices.length > 0 ? (
+
+ {choices.map((choice, index) => (
+
followUp(choice)}
+ title={copy.lateAnswerTip}
+ />
+ ))}
+ {copy.lateAnswerHint}
+
+ ) : null}
)
}
@@ -385,21 +459,14 @@ function ClarifyToolPending({ args }: ToolCallMessagePartProps) {
{hasChoices ? (
{choices.map((choice, index) => (
- selectChoice(choice)}
- type="button"
- >
-
- {choice}
-
+ selected={selectedChoice === choice}
+ />
))}