feat: harden ask tool validation and fallback

This commit is contained in:
Erik Kotsiuba
2026-04-19 18:15:19 +02:00
parent 9c559c9084
commit 050e8800cd
8 changed files with 464 additions and 19 deletions
+2 -1
View File
@@ -53,7 +53,8 @@ The codebase is split so the implementation reads through file boundaries and na
- submit is never blocked by unanswered questions
- single-select answers serialize as arrays
- free-form answers replace selected options for that question
- single-select free-form answers replace selected options for that question
- multi-select free-form answers augment selected options instead of clearing them
- preview questions do not get the synthetic custom-answer option
- deselected option notes stay in UI state
- only selected option notes are emitted in the final result
+14 -2
View File
@@ -28,9 +28,16 @@ This document defines the stable external behavior. It does not explain internal
## Input rules
- at least one question is required
- every question must have non-empty trimmed `id` and `prompt`
- every question must have at least one option
- question ids must be unique within one tool call
- option `value`s must be unique within a question
- optional `label`, `description`, and `preview` fields must not be blank when provided
- `label` falls back to `Q1`, `Q2`, ...
- `type` defaults to `single`
- `required` defaults to `false`
- `required` is metadata only; it never blocks submission
- preview questions require preview text for every option
- non-`preview` questions get an internal `Type your own` option
## Output
@@ -64,11 +71,14 @@ This document defines the stable external behavior. It does not explain internal
## Output rules
- `cancelled: true` means the user dismissed the flow or UI was unavailable
- `cancelled: true` means the user dismissed the flow, UI was unavailable, or the payload was invalid before UI opened
- unanswered questions are omitted from `answers`
- single-select answers still use arrays
- `indices` are 1-based rendered option positions
- `customText` stores the free-form answer
- on single-select questions, saving free-form text clears selected options for that question
- on multi-select questions, `values` and `labels` include both selected options and `customText` when both are present
- on multi-select questions, selected options keep their original order and `customText` is appended last
- saving or clearing free-form text on a multi-select question does not clear other selected options
- `note` stores a question-level note
- `optionNotes` includes only notes for selected options
@@ -110,7 +120,9 @@ Editing flow:
## Non-interactive mode
If `ctx.hasUI === false`, the tool returns an error message in `content` and a cancelled result in `details`.
If `ctx.hasUI === false`, the tool returns a `Needs user input` message in `content` and a cancelled result in `details`.
The fallback message includes normalized pending questions and options so the caller can re-ask them manually. `details.questions` still contains normalized question metadata, while `details.answers` stays empty until a user responds.
## Source of truth