Form.from_model().
Building Forms by Hand
CombineInput, Label, and Button components to create a form with full control over layout and behavior. Named inputs automatically sync their values to client state, so {{ name }} interpolation references the current value of the input with name="name".
This approach gives you complete control, but it requires wiring up every label, input type, and argument template yourself. For models with many fields, Form.from_model() handles all of that automatically.
Generating Forms from Pydantic Models
Form.from_model() introspects a Pydantic model and generates a complete form — labels, inputs, validation constraints, and submit button — from the model’s field definitions.
Each field in the model becomes a labeled input. The field’s type determines what kind of input is rendered, and Pydantic Field() metadata controls labels, placeholders, and constraints.
Metadata Mapping
PydanticField() parameters map directly to form behavior:
| Field metadata | Form effect |
|---|---|
Field(title="...") | Label text (fallback: humanized field name) |
Field(description="...") | Placeholder text |
Field(min_length=..., max_length=...) | HTML input constraints |
Field(ge=..., le=...) | Number input min/max |
Field(json_schema_extra={"ui": {"type": "textarea", "rows": 4}}) | Textarea override |
Field(exclude=True) | Skip field entirely |
Type Mapping
The field’s Python type determines the input component:| Python type | Input component |
|---|---|
str | Text input (auto-detects email, password, tel, url from field name) |
int, float | Number input |
bool | Checkbox |
Literal["a", "b", "c"] | Select dropdown |
SecretStr | Password input |
datetime.date | Date picker |
datetime.time | Time picker |
datetime.datetime | Datetime picker |
Auto-Fill Arguments
Whenon_submit is a ToolCall with no arguments, from_model() auto-generates the arguments from the model’s fields, wrapped under a data key.
Auto-Fill
ToolCall is equivalent to writing this explicitly:
Self-Calling Tool Pattern
A single tool can serve as both the form renderer and the form handler. On the first call (no data), it returns the form. When the user submits, the auto-filled arguments pass the form values back to the same tool as a validated Pydantic model.Self-Calling Tool
data is None (the initial call), the tool returns a form. When the user fills in the fields and clicks submit, the renderer calls create_contact again with data populated from the form values. Pydantic validates the input automatically, so data arrives as a fully validated Contact instance.
Error Handling
Whenon_submit is auto-filled and no on_error is specified, from_model() adds a default error toast:
$error variable captures the error message from a failed tool call, making validation errors visible to the user without any extra configuration.
You can override this with your own on_error:
Custom Error Handling
Unsupported Types
from_model() skips fields with complex types that have no natural form input mapping: list, dict, set, tuple, and nested BaseModel instances. If you need these, build those parts of the form manually and handle the arguments yourself.