feat: optional preview on question tool options - #41538
Open
adityasasidhar wants to merge 2 commits into
Open
Conversation
1 task
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.
Issue for this PR
Closes #40846
Type of change
What does this PR do?
Adds an optional
previewto a question toolOption: a block of plain monospace text shown beside the option list, tracking whichever option is focused. An option without one behaves exactly as today.The problem it solves: when a choice is between things that are inherently visual — two layouts, two implementations of the same function, two config shapes — a one-line
descriptioncan't carry the difference. So the model dumps every variant into its message text before asking, and the prompt then appears below with bare labels like1. Split 2. Stacked. The content and the choice get separated at the moment you need them together. This puts the comparison inside the prompt.Where the pieces are:
packages/schema/src/question.ts(and the v1QuestionOption) carries the field, plusnormalizePreviewandpreviewLayout.sanitize()inpackages/core/src/tool/question.tsruns once on the way in: strips markdown fence markers, ANSI escapes and control characters, tabs to spaces, trims blank edges, and truncates past 2000 chars with a visible marker. Previews are dropped outright whenmultiple: true, since there's no single focused option for a pane to track. Doing this once at the boundary means no renderer has to defend itself against model output, and a preview can't fail the tool call — worst case it normalizes toundefinedand the option renders as it does today.previewLayout()derives every bound from the viewport, never from the content: rows areheight/3clamped to 4–12, the list column is 42% of content width clamped to 24–48, and the two-pane layout only engages when an option actually carries a preview and both columns clear 24 columns. Below 80 columns it falls back to single column. Long lines clip instead of wrapping so ASCII alignment survives. This part is deliberate — Long question tool makes opencode unusable #11367, [FEATURE]: Add a max % height and ability to scroll to the question pane (TUI) #18673 and [FEATURE]: The question tool takes too much screen real estate #11014 are all "the question UI outgrew my screen", and adding content to that prompt without bounding it would have made them worse.packages/tui/src/routes/session/question.tsx), therunfooter, and the web/desktop question dock.question.txttells the model when not to reach for it; an unnecessary preview pane is noise.The field is additive and optional, so there's no migration and no event version bump — clients that ignore it render exactly as before.
One open question, carried over from the issue and still unanswered: this targets
Question.Optionondev. On the v2 line the question tool lowers into aFormandtoField()maps options through{ value, label, description }, so apreviewwould be silently dropped there.Form.Optionmay be the better home — it would give every form previews rather than just questions. Happy to retarget if that's preferred.How did you verify your code works?
New tests, all passing:
packages/schema/test/question.test.ts(19) — normalization (fences, ANSI, control chars, blank-edge trimming, truncation) and the layout bounds across terminal sizes, including the narrow single-column fallback.packages/core/test/tool-question.test.ts(7) —sanitize(), including previews being dropped for multi-select.packages/opencode/test/tool/question.test.ts(3).Also: full TUI suite passes (193 pass, 0 fail),
bun turbo typecheckis clean acrosstui/core/opencode, andoxlintreports 0 errors on the changed files. Rebased onto currentdevbefore opening.Screenshots / recordings
Checklist