Generate Object
generateObject asks the model for JSON, strips common markdown fences, validates the JSON against an AISchema, and decodes it into your Swift type.
| Output shape | Best fit |
|---|---|
.object(MyType.self) | App-owned structs that should keep schema and decoding together |
.array(Element.self) | Lists, tags, search facets, extracted items |
.enumeration(MyEnum.self) | Routing, priority, sentiment, status, or other closed choices |
Manual Output<T> | Types you do not own or ad-hoc schemas for one feature |
streamObject | UIs that can show partial JSON while waiting for the final value |
Define A Schema
Use AISchemaConvertible when you want the schema beside the type that will be decoded.
import SwiftyAI
struct RecipeSummary: Decodable, AISchemaConvertible {
let title: String
let servings: Int
let steps: [String]
static let aiSchema = AISchema.object(
properties: [
"title": .string(description: "Short recipe title"),
"servings": .integer(description: "Number of servings", minimum: 1),
"steps": .array(of: .string(description: "One preparation step"))
]
)
}Generate And Decode
let result = try await generateObject(
model: model,
prompt: "Turn tomato soup into a simple recipe summary.",
output: .object(RecipeSummary.self),
options: GenerationOptions(temperature: 0.2)
)
print(result.object.title)
print(result.usage?.totalTokens ?? 0)The return value is ObjectResponse<T>, with the decoded object, token usage, finishReason, and provider model when available.
JSONSchemaConvertible Shorthand
When a type already exposes a raw JSON Schema dictionary (for example because it is generated or shared with another platform), it can conform to JSONSchemaConvertible and use the as: overload that skips the Output<T> builder.
struct Recipe: Decodable, JSONSchemaConvertible {
let title: String
let servings: Int
static let schemaName = "Recipe"
static let jsonSchema: [String: Any] = [
"type": "object",
"properties": [
"title": ["type": "string"],
"servings": ["type": "integer"]
],
"required": ["title", "servings"]
]
}
let result = try await generateObject(
model: model,
prompt: "Turn tomato soup into a simple recipe.",
as: Recipe.self
)Use this when the schema lives next to the type as raw JSON. Use AISchemaConvertible and Output<T> when the schema is built with the typed AISchema builders.
Manual Output Schema
You can also pass a schema directly. This is useful for dictionaries, arrays, or types you do not own.
let output = Output<[String]>.array(
String.self,
itemSchema: .string(description: "A short risk label")
)
let labels = try await generateObject(
model: model,
prompt: "Return three risk labels for a failed payment.",
output: output
)
print(labels.object)Enums are supported when they are String raw-value enums:
enum Priority: String, CaseIterable, Decodable {
case low
case medium
case high
}
let priority = try await generateObject(
model: model,
prompt: "Classify this ticket: customer cannot log in.",
output: .enumeration(Priority.self)
)Guide Wrapper
Guide<Value> is a public property wrapper that stores a wrapped value plus optional metadata such as description, minimum, maximum, minLength, maxLength, and pattern.
struct TicketSummary: Codable {
@Guide("Short customer-visible title", minLength: 3, maxLength: 80)
var title: String
}Guide is Codable when Value is Codable, and it encodes or decodes only the wrapped value. It does not automatically generate AISchema entries today, so structured output schemas still need AISchemaConvertible, JSONSchemaConvertible, or a manual Output<T>.
Stream Partial JSON
streamObject is useful when you want to show progress while waiting for a complete object.
for try await chunk in streamObject(
model: model,
prompt: "Create a recipe summary for overnight oats.",
output: .object(RecipeSummary.self)
) {
if let final = chunk.object {
print("done:", final.title)
} else {
print(chunk.partialJSON)
}
}partialObject is only set when the accumulated JSON is already decodable. validationIssues can help explain why a partial value is not valid yet.