Schema Builder
The schema builder provides a fluent API for defining JSON Schema objects. It is used in two places:
- Structured output — tell the model to return validated JSON
- Tool input schema — define what parameters a tool accepts
Basic usage
import { agent } from '@daedalus-ai-dev/ai-sdk';
const response = await agent({
instructions: 'Extract product details from the text.',
schema: (s) => ({
name: s.string().required(),
price: s.number().min(0).required(),
inStock: s.boolean().required(),
tags: s.array().items(s.string().toSchema()),
}),
}).prompt<{ name: string; price: number; inStock: boolean; tags: string[] }>(
'Product: "Blue Widget — $12.99, available, tags: widget, blue"'
);
console.log(response.structured);
// { name: 'Blue Widget', price: 12.99, inStock: true, tags: ['widget', 'blue'] }Property types
s.string()
s.string()
.description('Human-readable description for the model')
.minLength(1)
.maxLength(500)
.pattern('^[a-z]+$') // regex pattern
.required()s.integer()
s.integer()
.description('A whole number')
.min(0)
.max(100)
.required()s.number()
s.number()
.description('A decimal number')
.min(0.0)
.max(1.0)
.required()s.boolean()
s.boolean()
.description('true or false')
.required()s.enum(values)
s.enum(['pending', 'active', 'cancelled'])
.description('Current status of the order')
.required()s.array()
s.array()
.description('List of tags')
.items(s.string().toSchema()) // Note: call .toSchema() on nested builders
.required()Nested builders
When passing a builder as .items(), call .toSchema() on it to convert it to a plain JSON Schema object. This is because .items() accepts a JsonSchemaProperty, not a builder.
// ✅ Correct
s.array().items(s.string().toSchema())
// ❌ Wrong — passes a builder object, not a schema
s.array().items(s.string())The required() modifier
Call .required() on any property to mark it as required in the output schema. Properties without .required() are optional.
schema: (s) => ({
title: s.string().required(), // included in "required" array
subtitle: s.string(), // optional — model may omit it
})Descriptions
Add .description() to give the model context about what each field means. This significantly improves extraction accuracy for structured output.
schema: (s) => ({
sentiment: s.enum(['positive', 'neutral', 'negative'])
.description('Overall emotional tone of the text')
.required(),
confidence: s.number().min(0).max(1)
.description('Model confidence from 0.0 (uncertain) to 1.0 (certain)')
.required(),
})Using buildSchema() directly
You can also call buildSchema() to get a raw JsonSchemaObject:
import { buildSchema } from '@daedalus-ai-dev/ai-sdk';
const schema = buildSchema((s) => ({
name: s.string().required(),
age: s.integer().min(0).required(),
}));
console.log(JSON.stringify(schema, null, 2));
// {
// "type": "object",
// "properties": {
// "name": { "type": "string" },
// "age": { "type": "integer", "minimum": 0 }
// },
// "required": ["name", "age"],
// "additionalProperties": false
// }TypeScript generics
Pass the expected output type as a generic to .prompt<T>() to get full type safety:
type Review = {
score: number;
approved: boolean;
issues: string[];
};
const response = await agent({
instructions: 'Review the content.',
schema: (s) => ({
score: s.integer().min(1).max(10).required(),
approved: s.boolean().required(),
issues: s.array().items(s.string().toSchema()).required(),
}),
}).prompt<Review>('Review this article...');
// response.structured is typed as Review
const { score, approved, issues } = response.structured;TIP
The generic type and the schema definition are independent — TypeScript does not validate that they match at compile time. Ensure they stay in sync, or use a library like Zod to derive both from a single source of truth.