LedgeKitDocs
iOS SDK
Developer documentation

Record Foundation Models requests

Preserve native responses, structured generation, tools, and multi-turn capture.

Create a recorded session with client.session(model:tools:instructions:agent:). Use trace.session to put its calls into an existing trace. The factory installs recording at the model executor boundary before the native session is created.

import FoundationModels
import LedgeKit

@available(iOS 27.0, macOS 27.0, *)
func summarize(_ text: String, client: LedgeClient) async throws -> String {
    let agent = try LedgeAgent(name: "summarizer", version: 1)
    let session = client.session(
        instructions: "Summarize the text in one sentence.",
        agent: agent
    )
    let response = try await session.respond(to: "Summarize: \(text)")
    return response.content
}

Check native model availability as shown in the quickstart. LedgeSession returns Apple's original response. Native errors and cancellation pass through; telemetry failures do not replace them.

Structured responses

@available(iOS 27.0, macOS 27.0, *)
@Generable
struct Summary {
    @Guide(description: "A one-sentence summary")
    var sentence: String
}

let response = try await session.respond(to: text, generating: Summary.self)
let summary: Summary = response.content

All six native response forms are supported: String or Prompt, with text, Generable, or GenerationSchema output. Generation options pass through. Schema forms default to ContextOptions(includeSchemaInPrompt: true).

let response = try await session.respond(
    to: prompt,
    schema: responseSchema,
    options: GenerationOptions(temperature: 0.2),
    contextOptions: ContextOptions(includeSchemaInPrompt: true)
)

Multi-turn sessions and tools

Reuse the same adapter for later turns. Each attempt produces a span; its capture retains a stable session ID, increasing call index, and native transcript boundaries. Model input includes prior native history. session.transcript exposes the native transcript. Input is saved exactly once, before the model executor runs. Both String and native Prompt calls use the same prepared-request representation.

Native tools, definitions, calls, results, instructions, and response formats remain in provider capture. Pass the actual model and tools to the session factory. The SDK records the Foundation Models provider but leaves model identity/version unknown when the wrapped session does not expose them; it does not guess guardrails or use-case settings.

Pass application context through the optional recording argument.

Streaming

Use the native streaming API within a recorded scope:

try await session.withSession(recording: .init(input: input)) { native in
    for try await snapshot in native.streamResponse(to: prompt) {
        print(snapshot.content)
    }
}

Await the complete operation inside the closure. Do not retain the native session or stream outside it. Each model generation after a tool result receives its own span and immutable request snapshot.

Framework or tool failures outside the executor are recorded with application context and a providerCapture.failurePhase, without inventing model input.

On this page