SwiftyAISwiftyAI

Search documentation

Find a docs page by title or section

1

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 shapeBest 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
streamObjectUIs 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.

Related docs

Use generation options to control output length and retries. Use multimodal input when the object should be extracted from images, PDFs, or files.