Kaede AkinoandClaude Opus 5 2ec0e123a3 Let the user answer something the model did not offer
`request_user_input` took a prompt and an array of bare strings and drew a
`Picker`. When none of the choices fit — which is exactly when asking was
worth doing — Cancel was the only move available, and a cancelled run
tells the agent nothing about why. So a free-form field now sits in the
list alongside the options rather than under them as an afterthought, on
by default, and `allow_custom` has to be set false to take it away.

Options become objects. A bare string left the model nowhere to put the
tradeoff, so it either crammed the reasoning into the label or dropped
it, and the reader chose between four words with no way to tell them
apart. Each option now carries an id, a label, a sentence on what it
costs, and a `recommended` flag — a flag rather than a `(Recommended)`
suffix, so the convention lives in the schema instead of in prose the
model has to remember, and the label keeps its whole budget. The ceiling
drops from twenty choices to four; twenty was never a decision anyone was
being asked to make.

Nothing is preselected, the recommendation included. A recommendation is
a label, not a default, and a preselected answer is one the user can
submit without reading — so Continue stays disabled until they actually
answer. Where one answer is wanted the two routes are exclusive and each
clears the other, because a half-typed "something else" left sitting
under a chosen radio is a second answer contradicting the first. Where
several are wanted they are additive, since "these two, plus this other
thing" is a real reply.

Selected ids come back in the order the request listed them rather than
the order they were clicked: the model wrote the list and reads the
answer against it. Alongside them the tool returns `custom_text` and a
canonical `answer`, so a model that reads only one field still reads the
right one. Malformed and duplicated options are rejected rather than
dropped — a menu quietly missing the option the user wanted is a worse
failure than an error the model can see and retry.

`request_user_secret` shares the interaction handler, so it now refuses
`.choice` explicitly. A secret has to come back through `SecureField` and
the broker; anything else means it travelled the ordinary-answer path,
where it would have been echoed on screen and left in plain view state.

None of this is persisted, so there is nothing to migrate. Two things
were deliberately left out. Several questions per call does not fit a
tool that blocks mid-run on a single `pendingUserInput` — it would need a
queue and a multi-question card, and one question per call is right for
an agent that is already holding the user up. Per-option previews need a
two-pane layout, and this card is a narrow strip above the composer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 08:37:09 +08:00
2026-08-24 18:20:20 +08:00
2026-08-24 18:20:20 +08:00
2026-08-24 18:20:20 +08:00
S
Description
AI-driven remote workspace for Mac, iPhone, and iPad.
https://termind.akinokaede.com
GPL-3.0
23 MiB
0 Stars 1 Watchers 0 Forks
Languages
Swift 98.9%
Python 0.8%
Ruby 0.3%