Basic Usage
Pass a Pydantic model (Python) or Zod schema (TypeScript) asresponse_format, and the SDK returns a parsed, typed instance:
Using a Raw JSON Schema
You can also pass a plain JSON Schema object instead of a Pydantic/Zod schema. In that case the SDK returns the answer as a JSON string and leaves parsing to you. This is also the shape the REST API accepts directly:content in the response is always a string. When response_format is set, it is a JSON-encoded object conforming to your schema.
Streaming
response_format works with streaming. The stream emits the JSON answer incrementally as raw text chunks; the accumulated text is a valid JSON string once the stream completes. To enable streaming the SDKs cannot parse streamed responses for you, you parse the final string yourself:
Supported Schema Subset
Honcho supports a conservative subset of JSON Schema that enables the kind of Pydantic models used for structured LLM outputs. Schemas outside this subset are rejected with a422 validation error before any reasoning runs.
The root of the schema must be "type": "object".
Schemas may nest at most 20 levels deep and contain at most 500 total nodes.
Constraint keywords like
minItems, maxLength, minimum, pattern, and format are passed through to the model as hints but are not enforced server-side. If you need hard guarantees on these, validate the returned object in your application.Recursive schemas are not supported. A self-referential Pydantic model (
Node.children: list[Node]) or a recursive Zod schema (z.lazy(...)) produces a recursive $ref, which is rejected with a 422 naming the cycle. Restructure recursive shapes as explicit nesting with a fixed depth.Optional Fields and Unions
Two distinct mechanisms control “optionality” in a raw JSON Schema:- Omission is controlled by
required. A property not listed inrequiredmay be left out by the model entirely; the parsed answer will contain it asnull. - Nullability is controlled by the field’s type. An
anyOf/oneOfwith a{"type": "null"}member (or the shorthand"type": ["string", "null"]) means the field’s value may benulleven when the field itself is required.
anyOf and oneOf are treated identically: a plain union of the member schemas. Unions of non-null types (e.g. a string-or-integer field) are also supported.
favorite_foodis required and must be a string.dietary_restrictionis required but nullable: the key is always present in the answer, and the model can answernullwhen it has no evidence. This is the recommended way to give the model an escape hatch (see Best Practices).years_vegetarianis the same thing written with thetype-list shorthand (["integer", "null"]is equivalent to ananyOfof the two).confidenceis not inrequired, so the model may omit it; if it does, the field comes back asnull.
default, that default is used whenever the model omits the field even if the property is listed in required.
Pydantic and Zod produce these shapes for you: str | None in Pydantic emits the anyOf form above, and z.string().nullable() does the same in Zod (z.string().optional() controls presence in required).
Error Handling
How It Works
Structured output constrains the final synthesis step. The reasoning itself works the same in both settings.- The dialectic agent runs its normal tool loop in free-form text. It will search conclusions, grep messages, and traverse reasoning chains
- Once the agent has gathered enough context, the final answer generation is constrained to your schema using the provider’s native structured output support.
- The conforming JSON is returned as the response
contentand parsed into a typed object by the SDK when you passed a Pydantic model or Zod schema.
minimal through max) work the same way alongside response_format.
Best Practices
Add descriptions to your fields
Fielddescriptions are visible to the model when it formats the answer. confidence: float with a provided description of “score how certain the evidence is from 0-5” gets meaningfully better output than a bare field.
Model uncertainty explicitly
The chat endpoint returnsNone/null when it has no relevant information. With a schema, you can force an answer even when evidence is thin. To avoid hallucinations, consider including an escape hatch as an optional field, a "confidence" score, or an enum member like "unknown" so the model isn’t forced to fabricate.