@@ -131,6 +131,86 @@ public struct PreparedModel: Sendable {
131131 return url
132132 }
133133
134+ // MARK: - Cache Inspection
135+
136+ /// File extensions that identify a Core AI model asset (source or compiled).
137+ private static let assetExtensions : Set < String > = [ " aimodel " , " aimodelc " ]
138+
139+ /// Enumerates the Core AI model asset(s) reachable from `url`.
140+ ///
141+ /// A model directory (e.g. an LLM bundle) contains one or more asset components alongside
142+ /// other files (tokenizer, metadata); we can't assume specific component filenames, so scan
143+ /// the directory for every `.aimodel`/`.aimodelc` entry. If `url` is itself an asset, it is
144+ /// returned as the sole component. This filename-agnostic approach stays correct as new model
145+ /// families add differently-named components.
146+ ///
147+ /// - Parameter url: Either a bundle directory containing asset components, or a single asset.
148+ /// - Returns: The asset URLs to operate on, sorted for stable output. Empty only if `url` is a
149+ /// directory with no asset components.
150+ public static func modelAssetURLs( at url: URL ) throws -> [ URL ] {
151+ // A path ending in a known asset extension IS the asset (asset bundles are themselves
152+ // directories, so this must be checked before treating `url` as a container to scan).
153+ if assetExtensions. contains ( url. pathExtension) {
154+ return [ url]
155+ }
156+ let entries = try FileManager . default. contentsOfDirectory (
157+ at: url,
158+ includingPropertiesForKeys: nil
159+ )
160+ return
161+ entries
162+ . filter { assetExtensions. contains ( $0. pathExtension) }
163+ . sorted { $0. path < $1. path }
164+ }
165+
166+ /// Clears the Core AI specialization cache for every model asset reachable from `url`,
167+ /// forcing re-specialization on the next load.
168+ ///
169+ /// Discovers components via ``modelAssetURLs(at:)`` — pass either a bundle directory or a
170+ /// single asset. Used by CLI tools implementing `--clear-coreai-cache`.
171+ ///
172+ /// - Parameter url: A bundle directory containing asset components, or a single asset.
173+ /// - Returns: The asset URLs whose cache entries were cleared.
174+ @discardableResult
175+ public static func clearCache( at url: URL ) throws -> [ URL ] {
176+ let assetURLs = try modelAssetURLs ( at: url)
177+ for assetURL in assetURLs {
178+ let coreaiURL = resolveCoreAIModelURL ( from: assetURL)
179+ try AIModelCache . default. deleteEntries ( for: coreaiURL)
180+ }
181+ return assetURLs
182+ }
183+
184+ /// Reports whether the default Core AI cache already holds a specialized asset for `url`
185+ /// under the given `options`.
186+ ///
187+ /// This only inspects the cache via `AIModelCache.model(for:options:)`; it never triggers
188+ /// specialization. Returns `false` if no entry exists, or if an entry exists but fails to load.
189+ ///
190+ /// - Important: `options` must match the options the loader will use for `url`, otherwise a
191+ /// real cached specialization won't be found. Callers that load via `prepare(at:)` should use
192+ /// the ``isCached(at:)`` overload; callers that load via `AIModel(contentsOf:)` or a custom
193+ /// `SpecializationOptions` must pass the same value here.
194+ public static func isCached( at url: URL , options: SpecializationOptions ) -> Bool {
195+ let coreaiURL = resolveCoreAIModelURL ( from: url)
196+ do {
197+ return try AIModelCache . default. model ( for: coreaiURL, options: options) != nil
198+ } catch {
199+ return false
200+ }
201+ }
202+
203+ /// Reports whether the default Core AI cache already holds a specialized asset for `url`,
204+ /// using the same structure-derived `SpecializationOptions` that ``prepare(at:)`` uses.
205+ ///
206+ /// Use this only for models loaded through ``prepare(at:)``. For other loaders, use
207+ /// ``isCached(at:options:)`` with the matching options.
208+ public static func isCached( at url: URL ) -> Bool {
209+ let coreaiURL = resolveCoreAIModelURL ( from: url)
210+ let options = probeStructure ( at: coreaiURL) . specializationOptions
211+ return isCached ( at: coreaiURL, options: options)
212+ }
213+
134214 // MARK: - Asset Preparation
135215
136216 /// Prepares a Core AI model asset by loading via `AIModel` and detecting its structure.
0 commit comments