# Ask tool contract `ask_user` is a pi-native clarification tool for cases where implementation depends on user preference or missing requirements. This document defines the stable external behavior. It does not explain internal helper-by-helper implementation. ## Input ```ts { title?: string; questions: Array<{ id: string; label?: string; prompt: string; type?: "single" | "multi" | "preview"; required?: boolean; options: Array<{ value: string; label: string; description?: string; preview?: string; recommended?: boolean; }>; }>; } ``` ## 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 - blank optional `title`, question `label`, option `description`, and option `preview` fields are treated as omitted - question `label` falls back to `Q1`, `Q2`, ... - option `label` is required in the public schema; before schema validation, a missing or blank string label is derived from a non-empty `value` by replacing hyphens and underscores with spaces and capitalizing the first character - `recommended` is optional presentation metadata; zero, one, or multiple options may set it to `true` - recommended options render warning-colored `(recommended)` followed by muted ` | `, or only `(recommended)` when no description exists, but are not preselected - `type` defaults to `single` - `required` defaults to `false` - `required` is metadata only; it never blocks submission - preview questions require preview text for every declared option; option descriptions do not satisfy this requirement, and invalid preview payloads report a fix hint to add preview text or switch to `type: "single"` - all questions get an internal `Type your own` option ## Output ```ts { content: [{ type: "text"; text: string }]; details: { title?: string; cancelled: boolean; error?: { kind: "invalid_input"; issues: Array<{ path: string; message: string; }>; }; mode: "submit" | "elaborate"; questions: Array<{ id: string; label: string; prompt: string; type: "single" | "multi" | "preview"; presentedType?: "single" | "multi" | "preview"; }>; answers: Record< string, { values: string[]; labels: string[]; indices: number[]; customText?: string; note?: string; optionNotes?: Record; } >; continuation?: { strategy: "refine_only" | "resume"; affectedQuestionIds: string[]; preservedAnswers: Record; }>; questionStates: Record; }; elaboration?: { instruction: string; nextAction: "clarify" | "clarify_then_reask"; items: Array< | { target: { kind: "question" }; question: { id: string; label: string; prompt: string; type: "single" | "multi" | "preview"; presentedType?: "single" | "multi" | "preview"; options: Array<{ value: string; label: string; description?: string; preview?: string; recommended?: boolean; }>; }; answered: boolean; answer?: { values: string[]; labels: string[]; indices: number[]; customText?: string; note?: string; optionNotes?: Record; }; note: string; } | { target: { kind: "option"; optionValue: string }; question: { id: string; label: string; prompt: string; type: "single" | "multi" | "preview"; presentedType?: "single" | "multi" | "preview"; options: Array<{ value: string; label: string; description?: string; preview?: string; recommended?: boolean; }>; }; option: { value: string; label: string; description?: string; preview?: string; recommended?: boolean; }; selected: boolean; answered: boolean; answer?: { values: string[]; labels: string[]; indices: number[]; customText?: string; note?: string; optionNotes?: Record; }; note: string; } >; }; }; } ``` ## Output rules - `cancelled: true` means the user dismissed the flow, UI was unavailable, or the payload was invalid before UI opened - semantically invalid payloads that reach tool execution return `error.kind === "invalid_input"` with structured `issues` and a transcript-friendly `Invalid ask_user payload:` message; their rendered status is `Invalid tool payload` - payloads missing schema-required fields fail Pi's schema validation before tool execution and use Pi's standard tool-error result without structured `details` - `mode: "submit"` is normal completion; `mode: "elaborate"` means the user asked the agent to continue with follow-up clarification based on notes - unanswered questions are omitted from `answers`, but non-cancelled submitted result text includes `