// // ContextBudget.swift // Poche // // Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // import Foundation /// Token accounting for one session (CLAUDE.md §5 — the central concern). /// /// The window holds everything at once: instructions, tool schemas, the /// whole transcript, and the response to come. At 70% we condense; at least /// 30% stays reserved for the response — a prompt that "fits" with no room /// to answer still fails. struct ContextBudget: Sendable { /// iOS 26 window. 8192 on newer OS/devices; keep the pessimistic value /// until the SDK exposes the real one. var windowSize = 4096 var responseReserveRatio = 0.30 var condenseThresholdRatio = 0.70 var responseReserve: Int { Int(Double(windowSize) * responseReserveRatio) } var condenseThreshold: Int { Int(Double(windowSize) * condenseThresholdRatio) } /// Largest prompt (fixed cost + transcript + new message) we allow. var sendableLimit: Int { windowSize - responseReserve } func needsCondensation(estimatedTokens: Int) -> Bool { estimatedTokens >= condenseThreshold } func canSend(estimatedTokens: Int) -> Bool { estimatedTokens < sendableLimit } func usageRatio(estimatedTokens: Int) -> Double { min(1, Double(estimatedTokens) / Double(windowSize)) } }