Streaming and partial previews

streamStructured is for providers that expose text deltas. It yields raw chunks as they arrive and validates the accumulated output once the stream completes.

const stream = streamStructured({ provider, schema, messages })

for await (const chunk of stream) {
  process.stdout.write(chunk)
}

const { value, rawText } = await stream.return()

Final validation

After the last chunk, the full text goes through the same path as non-streaming calls:

  1. extractJson
  2. JSON.parse
  3. schema.safeParse

If validation fails, streamStructured throws ValidationError. Validation repair retries are intentionally not run mid-stream.

Partial previews

Pass a looser schema to receive best-effort previews while tokens arrive:

const stream = streamStructured({
  provider,
  schema: UserSchema,
  partialSchema: UserSchema.partial(),
  onPartial: value => renderPreview(value),
  messages,
})

The partial parser repairs only structural truncation: an unterminated string and unclosed objects/arrays. It does not invent missing fields, and a preview is emitted only when the repaired prefix parses and passes partialSchema.

Use partial previews for UI progress. Never treat them as final data.

Provider notes

  • OpenAI chat.completions streams raw JSON text in json_schema/json_object modes.
  • tool_call streams fall back to raw JSON text because tool-call deltas are not a stable text stream.
  • OpenAI Responses currently yields the final text once; incremental Responses events are not normalized yet.