# Build the "Inline generated form" pattern: `ToolInputForm`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
When the agent needs input, it renders the specific fields it needs instead of asking in prose.

Use it when: Mid-task gaps: missing parameters, ambiguous choices, required confirmations.

## What to build
A compact form the agent places in the conversation when it needs specific inputs to finish a tool call. Fields are generated from the tool's schema, validated before submission, and returned as typed values rather than prose. It renders inline in a chat message.

### Props
- `title`: string, `intro?`: string, and `toolName`: string (shown quietly, e.g. "refunds.create").
- `schema`: a JSON Schema object subset (string, number with min/max, enum, boolean, required) describing the tool's missing parameters.
- `uiHints?`: Record<string, { label: string; help?: string; widget?: "text" | "money" | "radio" | "select" | "checkbox"; optionDetails?: Record<string, string> }>, labels and helper text such as "Up to $1,240.00".
- `suggested?`: Record<string, unknown>, values the agent prefilled, marked as suggestions.
- `status`: "pending" | "submitting" | "submitted" | "cancelled" | "superseded" | "error", controlled by the parent.
- `serverErrors?`: Record<string, string>, field errors returned by the tool.
- `submittedValues?`: Record<string, unknown>, shown in the receipt.
- `onSubmit(values)`, typed from the schema, and `onCancel()`: callbacks. The component never calls the tool itself.

### States it must render
- Pending: the agent's one-line intro, then labelled fields with helper text, and Submit and Cancel.
- Invalid: inline errors under each failing field, from schema rules ("Must be $1,240.00 or less").
- Submitting: fields read-only and Submit busy.
- Submitted: collapses to a receipt listing the values sent.
- Cancelled or superseded: a one-line note ("Cancelled", "Answered in chat instead") with the fields hidden.
- Error: server field errors shown on their fields and the form editable again.

### Interactions
- Submit validates against `schema`; if anything fails, focus moves to the first invalid field and nothing is sent.
- Enter in a text field submits; radio groups use arrow keys.
- Cancel calls `onCancel` so the agent knows the person declined rather than waiting for prose.

### Edge cases
- A schema type with no widget falls back to a text input with a format hint; required fields are never dropped.
- Suggested values are visibly marked and count as unconfirmed until the person submits.
- An enum with an "other" option reveals a free-text field only when chosen.
- More than about six fields: group them into short steps with a progress label rather than one long form.

## Must avoid
Asking three questions in a paragraph and hoping the user answers all of them in order.

## Engineering constraint
Validate against the tool schema client-side; return structured values, not re-parsed prose.

## Accessibility
- The form is labelled by its title; radio groups are `fieldset`s with legends; errors are tied with `aria-describedby`.
- When the form appears mid-conversation, announce it ("The agent needs 3 details") without stealing focus.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
