Skip to main content
New in version 3.2.0 FormInput generates a validated form from a Pydantic model. The user fills it out, and the submission is validated against the model before being returned. Structured elicitation that can’t be hallucinated.
The FormInput provider shown in Goose, with a bug report form
This registers two tools: The tool name is derived from the model class name, lowercased: collect_{modelname}. So BugReport becomes collect_bugreport, ShippingAddress becomes collect_shippingaddress. Use tool_name to override if needed. The LLM calls it with a prompt explaining what it needs, and the user gets a form with fields matching the model. The LLM can also pass title and submit_text to override the card heading and button label, and default, a partial dict of field values that pre-fills the form for the user to confirm or edit. default requires prefab-ui>=0.19.1 and is ignored on older versions.

Field mapping

FormInput uses Prefab’s Form.from_model(), which maps Pydantic types to form components: Use Field() metadata to control labels (title), placeholders (description), and validation (min_length, max_length, ge, le). Use json_schema_extra={"ui": {"type": "textarea"}} for multiline text.

Callback

By default, the validated model is returned as JSON. Provide an on_submit callback to process the data server-side:
The callback receives a validated model instance and returns a string that becomes the result of the submit_form call.

Configuration

Set send_message=True to push the result back into the conversation via SendMessage, triggering the LLM’s next turn. Without it, the result goes only to the form UI, which shows β€œSubmitted.”, and the LLM does not see the submission.

Multiple forms

Add multiple providers for different models β€” each gets its own tool: