Client SDK · Chat

Structured output.

Constrain a chat response to a zod schema and get a typed object back.

Structured output constrains the model's response to a JSON Schema, server-side (grammar-constrained decoding), and then validates it client-side against your zod schema. Pass a zod schema, receive a fully-typed object — no prompt engineering, no brittle JSON extraction.

chat.streamObject(params, schema, options?)

Streams exactly like chat.stream() — you receive every MatildaChatStreamEvent — plus one final event with the parsed, schema-validated object. The schema argument is any zod schema (z is bundled with the SDK); the SDK converts it to JSON Schema and constrains generation server-side.

TypeScript
import { z } from 'zod';

const recipe = z.object({
  name: z.string(),
  prepTimeMinutes: z.number(),
  ingredients: z.array(z.string()),
});

for await (const event of client.chat.streamObject(
  { input: 'Give me a recipe for pavlova.' },
  recipe,
)) {
  if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta); // raw JSON streaming in
  }
  if (event.type === 'object') {
    console.log('\nValidated:', event.object); // typed as z.infer<typeof recipe>
  }
}

The final event:

TypeScript
{ type: 'object'; object: T } // T = z.infer<typeof schema>

chat.createObject(params, schema, options?)

Non-streaming convenience. Returns a MatildaObjectResponse<T> — everything chat.create() returns, plus the validated object.

TypeScript
const response = await client.chat.createObject(
  { input: 'Extract the invoice total: $1,250.00 AUD due 30 Sep.', conversationId },
  z.object({ total: z.number(), currency: z.string() }),
);

console.log(response.object.total);    // 1250 (number)
console.log(response.object.currency); // "AUD" (string)
console.log(response.outputText);      // raw JSON text as returned

MatildaObjectResponse<T>

Extends MatildaChatResponse with one additional field:

Fieldtypedescription
objectTThe response text parsed as JSON and validated against your schema.

Raw JSON Schema via responseSchema

If you don't want zod validation, pass a stringified JSON Schema directly as responseSchema on any chat call:

TypeScript
const response = await client.chat.create({
  input: 'List three Australian birds.',
  responseSchema: JSON.stringify({
    type: 'object',
    properties: { birds: { type: 'array', items: { type: 'string' } } },
    required: ['birds'],
    additionalProperties: false,
  }),
});
JSON.parse(response.outputText); // guaranteed valid, schema-conforming JSON

With responseSchema set, the response text is guaranteed to be valid JSON conforming to the schema — but parsing and validation are up to you.

OpenAI-compatible endpoint

The OpenAI-compatible endpoint (POST /api/v1/chat/completions) also honours structured output via the standard response_format parameter, so the OpenAI JS SDK's structured-output option works against Matilda as-is:

  • { "type": "json_schema", "json_schema": { "name": "...", "schema": {...} } } — grammar-constrained to your schema (the schema is applied with strict: true server-side; the strict and name fields you supply are re-wrapped downstream).
  • { "type": "json_object" } — guarantees valid JSON output without a schema (OpenAI JSON mode).
Note

Safety replace and structured output. If the server replaces the output mid-stream (safety filter), streamObject throws SafetyReplaceError — the replacement text is in .message and the triggering categories in .categories. Deltas already yielded to your consumer are not rolled back; if you render streamed JSON, handle response.output_text.replace events (or choose non-streaming createObject) to avoid showing half-rendered output that is later discarded.

Caution

Truncation throws. If the stream is truncated before the JSON completes, both helpers throw MatildaObjectParseError with the partial text in .raw. See Error handling.

Caution

Stream errors throw. If the server emits an error event mid-stream, both helpers throw an Error with the server's error code and message (${code}: ${message}).