response_schema. Its fields are merged into the schema the LLM sees, so the model must populate them when it calls that tool, and the reply is validated on receipt — no prompting for a format, no output parsing.
FinishTool still takes message, now alongside description and facts. This works on any tool, including custom and MCP tools.
Reading results
Resolved tools live onagent.tools_map. Use parse_last_response() for the most recent call, or parse_response(action) for a specific one:
parse_last_response() returns None if the tool has not been called. With a JSON Schema dict instead of a model, both methods return a validated dict.
parse_last_response() re-reads the tool call, so it works after a conversation is persisted and reloaded. action.structured_output is in-memory only — it is not serialized with the event and comes back None after a round-trip, so prefer the parse methods.Constraints
- Reserved names. A schema may not declare
kind,security_risk,structured_output, orsummary, nor reuse one of the tool’s own field names (e.g.messageonFinishTool). Both raise aValueErrorwhen the tool is resolved. - One tool per spec. A spec that resolves to a tool set is rejected; attach the schema to the individual tool instead.
- Scoped to its tool. A model may try to send the schema fields when calling other tools; those calls are rejected as unexpected arguments and the agent retries.
Ready-to-run Example
examples/01_standalone_sdk/56_structured_output.py
The model name should follow the LiteLLM convention:
provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o).
The LLM_API_KEY should be the API key for your chosen provider.
