Environment setup
Xcode 27. iOS 27 or macOS 27 SwiftUI App. Add Foundation Models. Token counting shipped in the Foundation Models updates described at WWDC26 (from iOS 26.4 onward). Confirm contextSize and tokenCount(for:) in the installed SDK.
xcode-select --install
xcodebuild -version
# Add FoundationModels. Target iOS 27 or macOS 27.
import FoundationModels
// Illustrative. Confirm names in the installed SDK.
struct TokenBudget {
let window: Int
let replyReserve: Int
let question: Int
let instructions: Int
var leftover: Int {
window - replyReserve - question - instructions
}
}
func makeBudget(model: SystemLanguageModel, question: String, instructions: String) async throws -> TokenBudget {
let window = model.contextSize
let q = try await model.tokenCount(for: question)
let i = try await model.tokenCount(for: instructions)
return TokenBudget(
window: window,
replyReserve: max(256, window / 8),
question: q,
instructions: i
)
}
Count with the same model that will answer. A SystemLanguageModel count is wrong for a PrivateCloudComputeLanguageModel pack, and the reverse is also wrong. CoreAILanguageModel has its own window. Read that model's contextSize if the SDK exposes it.
If token counting is missing in your drop, say so and use a conservative character estimate only as a stand-in. Write that fallback in the README. Do not pretend it is exact.
Next, rank the slices that compete for leftover tokens.
Key concepts
- Read
model.contextSizeand count withmodel.tokenCount(for:). - Reserve reply tokens first. A full window leaves no room for the answer.
- Each model type has its own window. Do not mix counts.
- If counting is missing in your SDK drop, use a conservative estimate and say so.
Takeaways
- Count with the same model that will answer.
- A
SystemLanguageModelcount is wrong for a PCC pack. - Budget the window, then the reply reserve, then the question, then ranked slices.