Skip to content

Model Management ​

Download models from HuggingFace Hub, manage local cache, and discover available models.

Overview ​

Conduit provides a comprehensive model management system through ModelManager, DownloadTask, and ModelRegistry. Download any HuggingFace model for local inference, track progress with @Observable download tasks, and manage cache storage.

Downloading Models ​

Use the shared ModelManager actor to download models:

swift
let manager = ModelManager.shared

// Download a pre-configured model
let url = try await manager.download(.llama3_2_1b) { progress in
    print("Downloading: \(progress.percentComplete)%")
    if let speed = progress.formattedSpeed {
        print("Speed: \(speed)")
    }
    if let eta = progress.formattedETA {
        print("ETA: \(eta)")
    }
}

// Download any HuggingFace model by repository ID
let model = ModelIdentifier.mlx("mlx-community/Mistral-7B-Instruct-v0.3-4bit")
let url = try await manager.download(model)

Download with Validation ​

Validate model compatibility before downloading:

swift
do {
    let url = try await manager.downloadValidated(.llama3_2_1b) { progress in
        print("Progress: \(progress.percentComplete)%")
    }
} catch AIError.incompatibleModel(let model, let reasons) {
    print("Cannot download \(model.rawValue):")
    for reason in reasons {
        print("  - \(reason)")
    }
}

Size Estimation ​

Check download size before committing bandwidth:

swift
if let size = await manager.estimateDownloadSize(.llama3_2_1b) {
    print("Download size: \(size.formatted)")  // e.g. "2.1 GB"
}

DownloadTask ​

DownloadTask is an @Observable type that tracks download progress in real time:

swift
let task = await manager.downloadTask(for: .llama3_2_1b)

// Observe progress
task.progress.fractionCompleted  // 0.0...1.0
task.progress.percentComplete    // 0...100
task.progress.formattedSpeed     // "12.5 MB/s"
task.progress.formattedETA       // "2m 30s"

// Control the download
task.cancel()
task.pause()
task.resume()

// Wait for completion
let url = try await task.result()

DownloadProgress Fields ​

PropertyTypeDescription
bytesDownloadedInt64Bytes received so far
totalBytesInt64?Total expected bytes
fractionCompletedDoubleProgress from 0.0 to 1.0
percentCompleteIntProgress from 0 to 100
bytesPerSecondDoubleCurrent download speed
formattedSpeedString?Human-readable speed (e.g. "12.5 MB/s")
formattedETAString?Human-readable time remaining (e.g. "2m 30s")
currentFileString?Name of the file currently downloading
filesCompletedIntNumber of files completed
totalFilesIntTotal number of files to download

DownloadState ​

StateDescription
.pendingQueued, not yet started
.downloadingActively downloading
.pausedPaused by user
.completed(URL)Finished, local URL available
.failed(Error)Failed with error
.cancelledCancelled by user

SwiftUI Integration ​

Since DownloadTask is @Observable, it works seamlessly with SwiftUI:

swift
struct ModelDownloadView: View {
    @State private var downloadTask: DownloadTask?

    var body: some View {
        if let task = downloadTask {
            VStack {
                ProgressView(value: task.progress.fractionCompleted)
                Text("\(task.progress.percentComplete)%")

                if let speed = task.progress.formattedSpeed {
                    Text(speed)
                }

                HStack {
                    Button("Pause") { task.pause() }
                    Button("Cancel") { task.cancel() }
                }
            }
        } else {
            Button("Download Model") {
                Task {
                    downloadTask = await ModelManager.shared.downloadTask(for: .llama3_2_1b)
                }
            }
        }
    }
}

Cache Management ​

Manage locally stored models:

swift
let manager = ModelManager.shared

// Check if a model is cached
if await manager.isCached(.llama3_2_1b) {
    print("Model ready")
}

// Get local path
if let path = await manager.localPath(for: .llama3_2_1b) {
    print("Model at: \(path)")
}

// List all cached models
let cached = try await manager.cachedModels()
for model in cached {
    print("\(model.identifier.displayName): \(model.size.formatted)")
}

// Total cache size
let size = await manager.cacheSize()
print("Cache size: \(size.formatted)")

Eviction and Cleanup ​

swift
// Evict least-recently-used models to fit a storage limit
try await manager.evictToFit(maxSize: .gigabytes(30))

// Remove a specific model
try await manager.delete(.llama3_2_1b)

// Clear the entire cache
try await manager.clearCache()

Storage Paths ​

Models are stored under the user's cache directory:

  • MLX models: ~/Library/Caches/Conduit/Models/mlx/
  • HuggingFace models: ~/Library/Caches/Conduit/Models/huggingface/

ModelRegistry ​

ModelRegistry provides metadata about known models:

swift
// All known models
let allModels = ModelRegistry.allModels

// Filter by provider
let mlxModels = ModelRegistry.models(for: .mlx)
let cloudModels = ModelRegistry.models(for: .huggingFace)

// Filter by capability
let embeddingModels = ModelRegistry.models(with: .embeddings)
let reasoningModels = ModelRegistry.models(with: .reasoning)

// Get recommended models
let recommended = ModelRegistry.recommendedModels()

// Look up model info
if let info = ModelRegistry.info(for: .llama3_2_1b) {
    print("Name: \(info.name)")
    print("Context: \(info.contextWindow) tokens")
    print("Disk: \(info.diskSize?.formatted ?? "N/A")")
    print("Capabilities: \(info.capabilities)")
}

Model Capabilities ​

ModelCapability defines what a model can do:

  • .textGeneration — Standard text output
  • .embeddings — Vector embeddings
  • .transcription — Audio-to-text
  • .codeGeneration — Code-optimized
  • .reasoning — Enhanced reasoning
  • .multimodal — Vision and other modalities

Released under the MIT License.