Skip to main content
By default, the chat endpoint returns a free-form natural language answer. When your application needs machine-readable output, parsing that string yourself can be fragile and model-dependent. In this case you can use structured Dialectic outputs: pass a schema with your query, and the answer is guaranteed to conform to it. The agent still runs its full reasoning loop and only the final synthesized answer is formatted to your schema.

Basic Usage

Pass a Pydantic model (Python) or Zod schema (TypeScript) as response_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:
At the API level, 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 a 422 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 in required may be left out by the model entirely; the parsed answer will contain it as null.
  • Nullability is controlled by the field’s type. An anyOf/oneOf with a {"type": "null"} member (or the shorthand "type": ["string", "null"]) means the field’s value may be null even 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.
In this schema:
  • favorite_food is required and must be a string.
  • dietary_restriction is required but nullable: the key is always present in the answer, and the model can answer null when it has no evidence. This is the recommended way to give the model an escape hatch (see Best Practices).
  • years_vegetarian is the same thing written with the type-list shorthand (["integer", "null"] is equivalent to an anyOf of the two).
  • confidence is not in required, so the model may omit it; if it does, the field comes back as null.
If a property declares a 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.
  1. The dialectic agent runs its normal tool loop in free-form text. It will search conclusions, grep messages, and traverse reasoning chains
  2. Once the agent has gathered enough context, the final answer generation is constrained to your schema using the provider’s native structured output support.
  3. The conforming JSON is returned as the response content and parsed into a typed object by the SDK when you passed a Pydantic model or Zod schema.
This means answer quality is unaffected by the schema: the agent reasons exactly as it would for a free-form answer, and reasoning levels (minimal through max) work the same way alongside response_format.

Best Practices

Add descriptions to your fields

Field descriptions 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 returns None/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.

Keep schemas focused

A schema with three well-described fields outperforms one with twenty. If you need many distinct insights, consider making separate chat calls.