new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

AI SDK · Cookbook · all subjects

structured output

52 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

WorkflowAgent structured output with Output

Parse agent responses into typed objects using Output.object(): ```ts const result = await agent.stream({ messages, output: Output.object({ schema: z.object({ sentiment: z.enum(['positive', 'neutral', 'negative']), summary: z.string(), }), }), }); console.log(result.output); ``` The typed result is available on result.output.

Output.text() for plain text generation

Use Output.text() to generate plain text from a model without enforcing any schema. The result is simply the model's text as a string. This is the default behavior when no output is specified.

Property descriptions with Zod .describe() method

Add .describe("...") to individual schema properties in Zod to provide hints to the model about each property's purpose. This improves the quality and accuracy of generated structured data. Descriptions are useful for clarifying ambiguous names, specifying formats, and providing context for complex nested structures.

Output name and description for provider guidance

Use Output.object({ name, description, schema }) to optionally specify a name and description for the output. These are used by some providers for additional LLM guidance, for example via tool or schema names. This works with Output.object(), Output.array(), Output.choice(), and Output.json().

Accessing reasoning from generateText

Access the model's reasoning used to generate the object via the reasoning property on the result from generateText. This property contains a string with the model's thought process, if available. Requires using a reasoning model.

AI_NoObjectGeneratedError when structured output fails

generateText rejects with AI_NoObjectGeneratedError if the model response cannot be parsed or validated against the schema. This error preserves information including: text (generated text), response (metadata about the language model response), usage (request token usage), and cause (reason for error such as JSON parsing error).

AI_NoOutputGeneratedError when final step has no output

If generateText returns a result without an output, accessing result.output throws AI_NoOutputGeneratedError. This can happen when the final step does not finish with a stop reason, for example when it finishes with tool-calls. The output property is a getter, so destructuring it also triggers this access.

Structured output generation counts as a step

Structured output generation counts as a step in the AI SDK's multi-turn execution model where each model call or tool execution is one step. When combining structured output with tools, account for this in stopWhen configuration.

Example: streamText with Output.object() for streaming recipe

import { streamText, Output } from 'ai'; __PROVIDER_IMPORT__; import { z } from 'zod'; const { partialOutputStream } = streamText({ model: __MODEL__, output: Output.object({ schema: z.object({ recipe: z.object({ name: z.string(), ingredients: z.array( z.object({ name: z.string(), amount: z.string() }), ), steps: z.array(z.string()), }), }), }), prompt: 'Generate a lasagna recipe.', }); for await (const partialObject of partialOutputStream) { console.log(partialObject); }

Example: streamText error handling with onError

import { streamText, Output } from 'ai'; const result = streamText({ // ... output: Output.object({ schema }), onError({ error }) { console.error(error); // log to error tracking service }, });

Example: Output.object() with schema validation

import { generateText, Output } from 'ai'; import { z } from 'zod'; const { output } = await generateText({ // ... output: Output.object({ schema: z.object({ name: z.string(), age: z.number().nullable(), labels: z.array(z.string()), }), }), prompt: 'Generate information for a test user.', });

Example: Output.array() with weather data

import { generateText, Output } from 'ai'; import { z } from 'zod'; const { output } = await generateText({ // ... output: Output.array({ element: z.object({ location: z.string(), temperature: z.number(), condition: z.string(), }), }), prompt: 'List the weather for San Francisco and Paris.', });

Example: streamText with elementStream for array elements

import { streamText, Output } from 'ai'; import { z } from 'zod'; const { elementStream } = streamText({ // ... output: Output.array({ element: z.object({ name: z.string(), class: z.string(), description: z.string(), }), }), prompt: 'Generate 3 hero descriptions for a fantasy role playing game.', }); for await (const hero of elementStream) { console.log(hero); // Each hero is complete and validated }

Example: Output.choice() for weather classification

import { generateText, Output } from 'ai'; const { output } = await generateText({ // ... output: Output.choice({ options: ['sunny', 'rainy', 'snowy'], }), prompt: 'Is the weather sunny, rainy, or snowy today?', });

Example: Output.json() for unstructured JSON

import { generateText, Output } from 'ai'; const { output } = await generateText({ // ... output: Output.json(), prompt: 'For each city, return the current temperature and weather condition as a JSON object.', });

Example: generateText with tools and structured output

import { generateText, Output, tool, isStepCount } from 'ai'; __PROVIDER_IMPORT__; import { z } from 'zod'; const { output } = await generateText({ model: __MODEL__, tools: { weather: tool({ description: 'Get the weather for a location', inputSchema: z.object({ location: z.string() }), execute: async ({ location }) => { return { temperature: 72, condition: 'sunny' }; }, }), }, output: Output.object({ schema: z.object({ summary: z.string(), recommendation: z.string(), }), }), stopWhen: isStepCount(5), prompt: 'What should I wear in San Francisco today?', });

Example: property descriptions with Zod .describe()

import { generateText, Output } from 'ai'; __PROVIDER_IMPORT__; import { z } from 'zod'; const { output } = await generateText({ model: __MODEL__, output: Output.object({ schema: z.object({ name: z.string().describe('The name of the recipe'), ingredients: z .array( z.object({ name: z.string(), amount: z .string() .describe('The amount of the ingredient (grams or ml)'), }), ) .describe('List of ingredients with amounts'), steps: z.array(z.string()).describe('Step-by-step cooking instructions'), }), }), prompt: 'Generate a lasagna recipe.', });

Example: Output.object() with name and description

import { generateText, Output } from 'ai'; __PROVIDER_IMPORT__; import { z } from 'zod'; const { output } = await generateText({ model: __MODEL__, output: Output.object({ name: 'Recipe', description: 'A recipe for a dish.', schema: z.object({ name: z.string(), ingredients: z.array(z.object({ name: z.string(), amount: z.string() })), steps: z.array(z.string()), }), }), prompt: 'Generate a lasagna recipe.', });

Example: accessing reasoning from generateText

import { generateText, Output } from 'ai'; __PROVIDER_IMPORT__; import { z } from 'zod'; const result = await generateText({ model: __MODEL__, // must be a reasoning model output: Output.object({ schema: z.object({ recipe: z.object({ name: z.string(), ingredients: z.array( z.object({ name: z.string(), amount: z.string(), }), ), steps: z.array(z.string()), }), }), }), prompt: 'Generate a lasagna recipe.', }); console.log(result.reasoningText);

Example: error handling for NoObjectGeneratedError and NoOutputGeneratedError

import { generateText, NoObjectGeneratedError, NoOutputGeneratedError, Output, } from 'ai'; try { const result = await generateText({ model, output: Output.object({ schema }), prompt, }); console.log(result.output); } catch (error) { if (NoObjectGeneratedError.isInstance(error)) { console.log('NoObjectGeneratedError'); console.log('Cause:', error.cause); console.log('Text:', error.text); console.log('Response:', error.response); console.log('Usage:', error.usage); } else if (NoOutputGeneratedError.isInstance(error)) { console.log('NoOutputGeneratedError'); } }

Example: accessing response headers and body

import { generateText, Output } from 'ai'; const result = await generateText({ // ... output: Output.object({ schema }), }); console.log(JSON.stringify(result.response.headers, null, 2)); console.log(JSON.stringify(result.response.body, null, 2));

generateText with Output.object() for structured data

Use generateText with Output.object() to generate structured data from a prompt. The schema validates the generated data, ensuring type safety and correctness. Import generateText and Output from 'ai', and pass an output property with Output.object({ schema }) containing a Zod schema.

generateText returns output property with structured data

generateText returns an object with an output property that contains the generated structured data matching the provided schema. The output property is type-validated against the schema.

Output.object() schema parameter is required

Output.object() requires a schema parameter that defines the structure of the data to generate. The schema can be a Zod schema, Valibot schema, or JSON schema.

streamText with Output.object() for streaming structured outputs

Use streamText with Output.object() to stream a model's structured response as it is generated. This reduces latency for interactive use cases. streamText returns partialOutputStream as an async iterable that yields partial objects.

partialOutputStream for streaming partial structured data

streamText with output returns partialOutputStream, an async iterable that yields partial objects as they are generated. Partial outputs cannot be validated against the provided schema since incomplete data may not conform to the expected structure.

Output.array() for generating arrays of typed objects

Use Output.array({ element }) to generate an array of typed objects where each element conforms to a schema defined in the element property. The output will be an array of objects matching the element schema.

elementStream for complete validated array elements

When streaming arrays with streamText, use elementStream to receive each completed element as it is generated. Each element emitted by elementStream is complete and validated against the element schema, unlike partialOutputStream which streams incomplete elements.

Output.choice() for classification and fixed-enum answers

Use Output.choice({ options }) when the model should choose from a specific set of string options. Pass an options array with string values. The output will always be a single string matching one of the specified options. The AI SDK validates and throws if the model returns something invalid.

Output.json() for unstructured JSON without schema validation

Use Output.json() to generate and parse unstructured JSON values from the model without enforcing a specific schema. The AI SDK only checks that the response is valid JSON and does not validate the structure or types of values. Use Output.object() or Output.array() if schema validation is needed.

Combining structured output with tool calling

You can combine structured output with tool calling in the same generateText or streamText request. Use tools property along with output property. Remember that generating the structured output counts as a step in the multi-turn execution model, so configure stopWhen appropriately to allow enough steps for both tool execution and output generation.

Accessing response headers and body from generateText

Access the raw response headers and body from generateText using the response property on the result: result.response.headers and result.response.body. This allows access to provider-specific headers or body content.

Error handling for streamText with onError callback

streamText starts streaming immediately. When errors occur during streaming, they become part of the stream rather than thrown exceptions. Provide an onError callback to handle errors: onError({ error }) { ... }. This prevents stream crashes.

generateText output parameter

The output parameter is optional and specifies parsing of structured outputs from the LLM response. Options: Output.text() (default text generation), Output.object() (typed object using schemas), Output.array() (array generation), Output.choice() (one of choice options), Output.json() (unstructured JSON).

response field in step result metadata

The response field is of type LanguageModelResponseMetadata and contains additional response information. It includes: id (string) for the response identifier, modelId (string) for the model used, timestamp (Date) for when the response was generated, headers (Record<string, string>, optional) for response headers, body (unknown, optional) for the response body, and messages (Array<ResponseMessage>) for response messages generated during the step.

providerMetadata field in step result

The providerMetadata field is of type ProviderMetadata | undefined and contains additional provider-specific metadata passed through from the provider to the AI SDK to enable provider-specific results.

finalStep field in generate text response

The finalStep field is of type StepResult<TOOLS> and is a shortcut for `steps.at(-1)`, providing direct access to the final step in the response.

Output.object configuration

Output.object() generates a typed object matching a schema. Options: schema (Schema<OBJECT>, required), name (optional string for LLM guidance), description (optional string for LLM guidance).

Output.array configuration

Output.array() generates an array of elements. Options: element (Schema<ELEMENT>, required for array element schema), name (optional string for LLM guidance), description (optional string for LLM guidance).

Output.choice configuration

Output.choice() generates one of the choice options. Options: options (Array<string>, required list of available choices), name (optional string for LLM guidance), description (optional string for LLM guidance).

Output.json configuration

Output.json() generates unstructured JSON. Options: name (optional string for LLM guidance), description (optional string for LLM guidance).

inputTokens field in usage

The inputTokens field is a number that represents the total number of input (prompt) tokens used.

inputTokenDetails structure and fields

inputTokenDetails is of type LanguageModelInputTokenDetails and contains detailed information about input (prompt) tokens. It has three fields: noCacheTokens (number | undefined) for non-cached input tokens used, cacheReadTokens (number | undefined) for cached input tokens read, and cacheWriteTokens (number | undefined) for cached input tokens written.

outputTokens field in usage

The outputTokens field is of type number | undefined and represents the total number of output (completion) tokens used.

outputTokenDetails structure and fields

outputTokenDetails is of type LanguageModelOutputTokenDetails and contains detailed information about output (completion) tokens. It has two fields: textTokens (number | undefined) for the number of text tokens used, and reasoningTokens (number | undefined) for the number of reasoning tokens used.

totalTokens field in usage

The totalTokens field is of type number | undefined and represents the total number of tokens used.

raw field in usage metadata

The raw field is of type object | undefined and is optional. It contains raw usage information from the provider, which is the provider's original usage information and may include additional fields.

warnings field in step result

The warnings field is of type Warning[] | undefined and contains warnings from the model provider, such as unsupported settings.

request field in step result metadata

The request field is of type LanguageModelRequestMetadata and contains additional request information. It has two optional fields: messages (Array<ModelMessage>) which contains the input messages sent to the model for that step (undefined by default unless requestMessages is set to true), and body (unknown) which is the request HTTP body sent to the provider API.

Structured output with Output.object

Define structured output schema using Output.object() with a Zod schema. Example: output: Output.object({ schema: z.object({ sentiment: z.enum(['positive', 'neutral', 'negative']), summary: z.string(), keyPoints: z.array(z.string()) }) }). Access output via destructuring: const { output } = await agent.generate({...})

Schema definition imports in AI SDK

The jsonSchema and zodSchema utilities are imported from the 'ai' package and used to define schemas for tools and structured output.

Zod version imports in AI SDK

The SDK supports both Zod 3 and Zod 4. For Zod 3 use import * as z3 from 'zod/v3' (compatibility code only). For Zod 4 use import * as z4 from 'zod/v4' and reference types with z4.core.$ZodType.

Give your agent this brain