Structured Output
Force the model to return a typed Swift struct instead of free-form text. Guaranteed to decode with no parsing and no guard chains.
How It Works
Under the hood, runStructured() registers a hidden tool whose input schema is your type's jsonSchema. The model must call that tool to respond and cannot return free text. The SDK then decodes the tool's input directly into your Swift type.
Conforming a Struct
Conform your struct to StructuredOutput and Codable, then provide a jsonSchema that describes its properties:
struct Recipe: Codable, StructuredOutput {
let name: String
let ingredients: [String]
let steps: [String]
let prepTimeMinutes: Int
let note: String?
static var jsonSchema: JSONSchema {
[
"type": "object",
"properties": [
"name": ["type": "string"],
"ingredients": ["type": "array", "items": ["type": "string"]],
"steps": ["type": "array", "items": ["type": "string"]],
"prepTimeMinutes": ["type": "integer"],
"note": ["type": "string"],
],
"required": ["name", "ingredients", "steps", "prepTimeMinutes"]
]
}
}
let agent = Agent(model: provider)
let recipe: Recipe = try await agent.runStructured("Give me a pasta recipe")
print(recipe.name) // "Spaghetti Carbonara"
print(recipe.ingredients[0]) // "200g spaghetti"
print(recipe.prepTimeMinutes) // 20
print(recipe.note ?? "") // may be nil
Type Mapping Reference
Use these mappings when writing your jsonSchema:
| Swift Type | JSON Schema | In required? |
|---|---|---|
String | {"type":"string"} | Yes |
Int, Int64, … | {"type":"integer"} | Yes |
Double, Float | {"type":"number"} | Yes |
Bool | {"type":"boolean"} | Yes |
[T] / Array<T> | {"type":"array","items":{...T's schema...}} | Yes |
T? / Optional<T> | Same as T | No |
| Other types | {"type":"object"} | Yes |
Array types
Arrays of primitives work automatically. Each element's schema is derived recursively:
struct Report: Codable, StructuredOutput {
let title: String
let tags: [String] // → {"type":"array","items":{"type":"string"}}
let scores: [Double] // → {"type":"array","items":{"type":"number"}}
let flags: [Bool] // → {"type":"array","items":{"type":"boolean"}}
// ...jsonSchema omitted for brevity
}
Optional fields
Optional properties are included in the schema but excluded from required, so the model can choose to omit them:
struct ProductReview: Codable, StructuredOutput {
let productName: String
let rating: Int
let summary: String
let pros: [String]
let cons: [String]
let verdict: String? // optional -- omit from "required" in jsonSchema
static var jsonSchema: JSONSchema {
[
"type": "object",
"properties": [
"productName": ["type": "string"],
"rating": ["type": "integer"],
"summary": ["type": "string"],
"pros": ["type": "array", "items": ["type": "string"]],
"cons": ["type": "array", "items": ["type": "string"]],
"verdict": ["type": "string"],
],
"required": ["productName", "rating", "summary", "pros", "cons"]
]
}
}
Manual Conformance
For nested types, polymorphic schemas, or any schema the macro cannot express, conform to StructuredOutput manually:
struct WeatherReport: StructuredOutput {
let city: String
let temperature: Double
let condition: String
let humidity: Int
static var jsonSchema: JSONSchema {
[
"type": "object",
"properties": [
"city": ["type": "string"],
"temperature": ["type": "number", "description": "Celsius"],
"condition": ["type": "string", "enum": ["sunny","cloudy","rainy","snowy"]],
"humidity": ["type": "integer", "minimum": 0, "maximum": 100],
],
"required": ["city", "temperature", "condition", "humidity"],
]
}
}
let report: WeatherReport = try await agent.runStructured("What's the weather in London?")
print("\(report.city): \(report.temperature)°C, \(report.condition)")
Use enum constraints in manual schemas to restrict the values the model can produce. This is especially useful for status fields, categories, and ratings.
Nested Types
The macro maps unknown types to {"type":"object"} without a nested schema. For structs with nested types, define jsonSchema manually to give the model the full schema:
// Nested type: define manually so the schema is complete
struct OrderSummary: StructuredOutput {
struct LineItem: Codable {
let product: String
let quantity: Int
let price: Double
}
let orderId: String
let items: [LineItem]
let total: Double
static var jsonSchema: JSONSchema {
[
"type": "object",
"properties": [
"orderId": ["type": "string"],
"items": [
"type": "array",
"items": [
"type": "object",
"properties": [
"product": ["type": "string"],
"quantity": ["type": "integer"],
"price": ["type": "number"],
],
"required": ["product", "quantity", "price"],
]
],
"total": ["type": "number"],
],
"required": ["orderId", "items", "total"],
]
}
}