spb/zyquo-local Public MIT
Native macOS AI chat that runs LLMs 100% locally on Apple Silicon with MLX — no cloud, no API keys.
Swift 97.2%
Shell 1.8%
Makefile 1%
1//2// HubPoCRunner.swift3// Zyquo Local4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//89import Foundation1011/// Phase 3 gate: `ZyquoLocal --hub-poc` proves search → download with live12/// progress → pause mid-flight → resume → validate → delete, end to end,13/// against the live Hugging Face Hub, in an isolated temporary Models root.14enum HubPoCRunner {15 private static let testRepo = "mlx-community/Qwen3-0.6B-4bit"1617 @MainActor18 static func run() async {19 let hub = HubService(token: nil)2021 // 1 — live search22 log("1) Live Hub search: “qwen” in mlx-community, by downloads…")23 do {24 let results = try await hub.search(query: "qwen", scope: .mlxCommunity, limit: 5)25 for r in results {26 log(" • \(r.id) ↓\(r.downloads ?? 0) arch=\(r.architecture ?? "?")\(r.isSupportedArchitecture ? "" : " ⚠️ unsupported")")27 }28 guard !results.isEmpty else { return fail("search returned nothing") }29 } catch {30 return fail("search: \(error.localizedDescription)")31 }3233 // Isolated store for the test34 let root = FileManager.default.temporaryDirectory35 .appendingPathComponent("ZyquoLocalHubPoC-\(UUID().uuidString)")36 let store = ModelStore(root: root)37 let manager = DownloadManager(hub: hub, store: store)38 defer { try? FileManager.default.removeItem(at: root) }3940 // 2 — file listing + size41 log("2) File listing for \(testRepo)…")42 do {43 let (files, total) = try await hub.requiredFiles(of: testRepo)44 log(" \(files.count) required files, total \(gb(total))")45 } catch {46 return fail("file listing: \(error.localizedDescription)")47 }4849 // 3 — download with live progress, pause at ≥25 %50 log("3) Downloading with live progress; pausing mid-flight…")51 await manager.download(repoID: testRepo)52 var paused = false53 while !paused {54 try? await Task.sleep(for: .milliseconds(200))55 guard let t = manager.task(for: testRepo) else { return fail("task vanished") }56 if t.state == .failed { return fail("download failed: \(t.errorDescription ?? "?")") }57 if t.fractionCompleted >= 0.25 {58 manager.pause(repoID: testRepo)59 paused = true60 let speed = manager.speeds[testRepo].map { "\(gb(Int64($0)))/s" } ?? "n/a"61 log(" paused at \(pct(t.fractionCompleted)) (speed was \(speed))")62 }63 }64 try? await Task.sleep(for: .milliseconds(400))6566 // 4 — verify partials survive, then resume67 guard let pausedTask = manager.task(for: testRepo), pausedTask.state == .paused else {68 return fail("expected paused state")69 }70 let partialBytes = pausedTask.receivedBytes71 guard partialBytes > 0 else { return fail("no partial bytes on disk") }72 log("4) Resuming from \(gb(partialBytes)) (HTTP Range)…")73 manager.resume(repoID: testRepo)7475 var completed = false76 var lastLogged = -177 while !completed {78 try? await Task.sleep(for: .milliseconds(300))79 guard let t = manager.task(for: testRepo) else { return fail("task vanished") }80 switch t.state {81 case .completed:82 completed = true83 case .failed:84 return fail("resume failed: \(t.errorDescription ?? "?")")85 default:86 let percent = Int(t.fractionCompleted * 100)87 if percent / 20 != lastLogged / 20 {88 lastLogged = percent89 log(" … \(percent)% (\(gb(t.receivedBytes))/\(gb(t.totalBytes)))")90 }91 }92 }93 log(" download completed + size-verified ✅")9495 // 5 — store validation96 log("5) Validating model directory + store scan…")97 store.rescan()98 guard let model = store.model(for: testRepo) else {99 return fail("ModelStore did not recognize the downloaded model")100 }101 log(" \(model.repoID): \(gb(model.sizeBytes)), arch=\(model.architecture ?? "?"), quant=\(model.quantization ?? "?"), ctx=\(model.contextWindow ?? 0), verdict=\(MemoryAdvisor.verdict(weightsBytes: model.sizeBytes).label)")102103 // 6 — delete104 log("6) Deleting…")105 let reclaimed = store.delete(repoID: testRepo)106 guard store.model(for: testRepo) == nil,107 !FileManager.default.fileExists(atPath: root.appendingPathComponent(testRepo).path)108 else { return fail("delete left files behind") }109 log(" reclaimed \(gb(reclaimed)) ✅")110111 log("\nHUB POC: ALL STEPS GREEN")112 exit(0)113 }114115 private static func log(_ text: String) {116 FileHandle.standardError.write(Data((text + "\n").utf8))117 }118119 private static func fail(_ text: String) {120 log("FAIL: \(text)")121 exit(1)122 }123124 private static func gb(_ bytes: Int64) -> String {125 ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file)126 }127128 private static func pct(_ fraction: Double) -> String {129 "\(Int(fraction * 100))%"130 }131}132