feat: improve ask flow elaboration and validation

This commit is contained in:
Erik Kotsiuba
2026-04-24 19:13:10 +02:00
parent 0ee2d11ec9
commit b7c7301f97
16 changed files with 1270 additions and 134 deletions
+89 -3
View File
@@ -45,7 +45,7 @@ That is enough for the agent to gain this clarification capability. The extensio
You can still add your own agent instruction if you want to further reinforce when and how the tool should be used.
Use `type: "preview"` when an option needs a dedicated preview pane.
Use `type: "preview"` only when every option includes `preview` text for a dedicated preview pane. Descriptions alone are not enough.
### Optional extra agent instruction
@@ -58,7 +58,8 @@ Prefer 2-4 options per question.
Include descriptions for each option.
Use `type: "single"` unless multiple options can genuinely apply.
Use `type: "multi"` only when the user may need to select several answers.
Use `type: "preview"` when an option needs a preview panel.
Always include a non-empty `value` for every option.
Use `type: "preview"` only when every option includes non-empty `preview` text for the preview panel.
After answers are returned, continue the task using those answers explicitly.
```
@@ -135,6 +136,75 @@ After answers are returned, continue the task using those answers explicitly.
## Returned result
The returned result now also includes:
```ts
{
error?: {
kind: "invalid_input"
issues: Array<{ path: string; message: string }>
}
mode: "submit" | "elaborate"
continuation?: {
strategy: "refine_only" | "resume"
affectedQuestionIds: string[]
preservedAnswers: Record<string, AskResultAnswer>
questionStates: Record<string, {
status: "answered" | "needs_clarification" | "unanswered"
}>
}
elaboration?: {
instruction: string
nextAction: "clarify" | "clarify_then_reask"
items: Array<
| {
target: { kind: "question" }
question: {
id: string
label: string
prompt: string
type: "single" | "multi" | "preview"
options: Array<{
value: string
label: string
description?: string
preview?: string
}>
}
answered: boolean
answer?: AskResultAnswer
note: string
}
| {
target: { kind: "option"; optionValue: string }
question: {
id: string
label: string
prompt: string
type: "single" | "multi" | "preview"
options: Array<{
value: string
label: string
description?: string
preview?: string
}>
}
option: {
value: string
label: string
description?: string
preview?: string
}
selected: boolean
answered: boolean
answer?: AskResultAnswer
note: string
}
>
}
}
```
The returned `details.answers[questionId]` object may include:
```ts
@@ -151,7 +221,7 @@ The returned `details.answers[questionId]` object may include:
Behavior details:
- payloads are validated before the UI opens: question ids must be unique, option values must be unique within a question, and required text fields must not be blank
- preview questions require preview text for every option
- preview questions require preview text for every option; descriptions alone are not enough, and invalid preview payloads suggest adding preview text or switching to `type: "single"`
- `required` defaults to `false` and remains advisory only
- question-level notes are submitted whenever authored
- option notes can be authored for any active option during the UI flow
@@ -161,7 +231,23 @@ Behavior details:
- on single-select questions, saving a free-form answer replaces selected options for that question
- on multi-select questions, saving a free-form answer keeps other selected options intact
- on multi-select questions, submitted `values` and `labels` keep selected options first and append the free-form answer last when both exist
- invalid payloads return `details.error.kind === "invalid_input"` with structured `issues` and a transcript-friendly `Invalid ask_user payload:` message
- unanswered questions are omitted from `details.answers`
- in elaborate mode, `details.answers` contains only committed answers; note-only entries move into `details.elaboration.items`
- `details.continuation.strategy === "refine_only"` means the next ask should refine the current flow instead of restarting it
- `details.continuation.preservedAnswers` contains prior answers that should be carried forward without re-asking
- `details.continuation.affectedQuestionIds` lists the only questions that should be revisited
- `details.continuation.questionStates` marks each question as `answered`, `needs_clarification`, or `unanswered`
- submit review tab now offers `Submit`, `Elaborate`, and `Cancel`
- while `Submit` or `Cancel` is highlighted on the review tab, notes are previewed only for questions with selected answers
- while `Elaborate` is highlighted on the review tab, the preview expands to show all question notes and all option notes, including notes on unselected options
- choosing `Elaborate` finishes immediately and returns `mode: "elaborate"`
- `details.elaboration.items` includes all question notes and all option notes, even for unselected options
- every elaboration item carries the full normalized question and option list for that question, so the agent can resolve referential notes like `above` without relying on chat memory alone
- `details.elaboration.instruction` explicitly tells the agent to answer the clarification directly first, then re-ask only the affected questions if needed
- after clarification, agents should prefer another structured follow-up over plain-text multiple choice if a decision is still unresolved
- once prior answers narrow the branch, agents should bundle the next 2-3 related unresolved decisions into one follow-up ask when possible instead of asking a long chain of one-question follow-ups
- elaborate summary/result text now emits direct note-specific lines such as `User asked to elaborate on question "Which option would you like to select?" option "Option A" with note "why this one?"`
- when the free-form option is selected, it becomes an inline input row with the selected-tab background style spanning the full width
- while editing a note or free-form answer, arrow keys and `Tab` stay inside the editor while text is present so the typing cursor can move naturally
- when a note or free-form editor is empty, `Up`/`Down` navigate options and `Tab`/`Shift+Tab`/`Left`/`Right` navigate tabs without closing the editor first