Skip to the content.

Sessions

A Session wraps Apple’s LanguageModelSession: it keeps the conversation (transcript) and runs requests.

const session = await createSession({
  instructions: 'You are a concise financial assistant.',
  model: 'system',                 // default
  tools: [],                       // see tools.md
  transcript: undefined,           // restore (transcripts.md)
  messages: undefined,             // or start from plain messages (transcripts.md)
  profiles: undefined,             // iOS 27 (dynamic-profiles.md)
  transcriptErrorHandling: undefined, // iOS 27: 'revert' | 'preserve'
  queueRequests: true,
  prewarm: false,
});

await session.respond('What is compound interest?');
await session.respond('Give me an example.'); // remembers the previous turn

respond(prompt, options?)

prompt is a string or { prompt, images } (multimodal.md). Returns:

{
  text: string;
  usage: { inputTokens, cachedInputTokens, outputTokens, reasoningTokens, totalTokens } | null; // iOS 27
  transcriptEntries: TranscriptEntry[]; // what this request added: prompt, tool calls, tool outputs, response
  rawContent: unknown;                  // Apple GeneratedContent
}

Options (GenerationOptions + ContextOptions)

Option Apple API Min iOS
temperature GenerationOptions.temperature 26
maximumResponseTokens GenerationOptions.maximumResponseTokens 26
samplingMode: { type: 'greedy' } .greedy 26
samplingMode: { type: 'topK', k, seed? } .random(top:seed:) 26
samplingMode: { type: 'probabilityThreshold', probabilityThreshold, seed? } .random(probabilityThreshold:seed:) 26
toolCallingMode: 'allowed' \| 'required' \| 'disallowed' GenerationOptions.ToolCallingMode 27
reasoningLevel: 'light' \| 'moderate' \| 'deep' \| { custom } ContextOptions.ReasoningLevel 27
includeSchemaInPrompt ContextOptions.includeSchemaInPrompt / includeSchemaInPrompt: 26
metadata prompt metadata: 27
signal task cancellation 26

Use greedy sampling (optionally with a fixed prompt) for the most repeatable output. Output is still not guaranteed identical across OS versions.

Advanced requests: respondAdvanced / streamAdvanced

respond() takes Apple’s options as one flat object. The advanced methods mirror Apple’s signature respond(to:schema:options:contextOptions:metadata:) instead: one request object with options (GenerationOptions) and contextOptions (ContextOptions) kept separate, an optional schema, and a response that carries everything Apple returns.

const response = await session.respondAdvanced({
  prompt: 'Extract: Ada, 36',
  images: undefined,                                   // iOS 27
  schema: Person,                                      // optional: Zod, Standard JSON Schema or JSON Schema
  schemaName: 'Person',
  options: { temperature: 0, samplingMode: { type: 'greedy' }, maximumResponseTokens: 200, toolCallingMode: 'allowed' },
  contextOptions: { reasoningLevel: 'deep', includeSchemaInPrompt: false }, // iOS 27
  metadata: { screen: 'import' },                      // iOS 27
  signal,
});

response.text;              // the text, or the object as JSON when a schema was given
response.object;            // typed by the schema; undefined without one
response.rawContent;        // Apple's GeneratedContent, before validation
response.isComplete;
response.usage;             // iOS 27, else null
response.transcriptEntries;
response.model;             // 'system' | 'privateCloudCompute'
response.durationMs;        // includes time spent queued behind other requests

streamAdvanced(request) takes the same request and yields { text, delta, replaced, partial, rawContent, isComplete, isFinal }; stream.result resolves to the same response object. Without a schema partial is undefined; with one, delta is null and text is the partial object as JSON.

Use these when one code path must handle both text and structured requests, or when you want Apple’s option grouping. They run through the same queue and cancellation as respond() and stream().

Concurrency

Apple sessions handle one request at a time. With queueRequests: true (default) calls on the same session run in order. With false, a second concurrent call rejects with CONCURRENT_REQUESTS. Multiple sessions run independently; each has its own native identifier.

State

session.isResponding;      // LanguageModelSession.isResponding
session.transcript;        // LanguageModelSession.transcript, synchronous snapshot (transcripts.md)
session.contextSize;       // context window of the session's model in tokens, or null if unknown
session.usage;             // cumulative usage (iOS 27) or null
session.getState();        // { isResponding, model, usage, profiles, activeProfile }
session.model;             // 'system' | 'privateCloudCompute' (what `auto` resolved to)
await session.getUsage();  // same as session.usage

Prewarming

await session.prewarm();                                   // load resources
await session.prewarm({ promptPrefix: 'Summarize this:' }); // also cache a known prefix

Maps to LanguageModelSession.prewarm(promptPrefix:). Call it when a request is likely soon (e.g. the user focuses the input). It is a hint, not a guarantee: don’t prewarm speculatively on every screen.

Lifecycle

session.dispose();   // cancels in-flight requests & pending tool calls, frees native memory
session.isDisposed;

Native sessions are Expo SharedObjects: forgotten sessions are also released when garbage collected, but call dispose() for deterministic cleanup. Using a disposed session throws SESSION_DISPOSED.

Feedback attachments

const bytes: Uint8Array = await session.createFeedbackAttachment({
  sentiment: 'negative',
  issues: [{ category: 'incorrect', explanation: 'Wrong year' }],
  desiredResponse: 'It was 1969.',
});

Maps to LanguageModelSession.logFeedbackAttachment(...). Returns the attachment data (includes the transcript) for Apple’s Feedback Assistant. Save it to a file and attach it to a Feedback Assistant report. Nothing is sent automatically.