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.contentAll 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.