// // SelfTest.swift // Zyquo Atlas // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // Headless end-to-end check of the Phase 3 gate: load a real page in an // offscreen WKWebView, extract a PageContext, and stream a grounded summary // with a live Cloud model. Proves ContentExtractor + Summarizer + AIService + // the ported provider client work together. Invoked via // `ZyquoAtlas --selftest-summarize [--provider ] [--model ]`; // the API key comes from the environment (never logged). // import Foundation import WebKit import AppKit @MainActor enum SelfTest { private static let envKeys: [ProviderID: String] = [ .openai: "OPENAI_API_KEY", .anthropic: "ANTHROPIC_API_KEY", .xai: "XAI_API_KEY", .mistral: "MISTRAL_API_KEY", .gemini: "GEMINI_API_KEY", .qwen: "DASHSCOPE_API_KEY", .deepseek: "DEEPSEEK_API_KEY", .kimi: "MOONSHOT_API_KEY", .perplexity: "PERPLEXITY_API_KEY", .together: "TOGETHER_API_KEY", .deepinfra: "DEEPINFRA_API_KEY", .cerebras: "CEREBRAS_API_KEY", ] static func summarize(arguments: [String]) async -> Int32 { guard let urlString = value(after: "--selftest-summarize", in: arguments), let url = URL(string: urlString) else { printErr("usage: --selftest-summarize [--provider ] [--model ]") return 2 } let catalog = ModelCatalog() let providerArg = value(after: "--provider", in: arguments).flatMap { ProviderID(rawValue: $0) } let modelArg = value(after: "--model", in: arguments) let model: AIModel if let id = modelArg, let provider = providerArg, let m = catalog.model(id: id, provider: provider) { model = m } else if let provider = providerArg, let m = catalog.cheapestModel(for: provider) { model = m } else if let m = catalog.defaultModel { model = m } else { printErr("no model available in catalog"); return 1 } guard let keyName = envKeys[model.provider], let apiKey = ProcessInfo.processInfo.environment[keyName], !apiKey.isEmpty else { printErr("no API key in env for \(model.provider.rawValue) (expected \(envKeys[model.provider] ?? "?"))") return 1 } print("→ loading \(url.absoluteString)") let config = ProfileStore.shared.makeConfiguration(for: .defaultProfile) let loader = PageLoader(configuration: config) do { try await loader.load(url) } catch { printErr("page load failed: \(error.localizedDescription)"); return 1 } // Let late/lazy content settle before extracting. try? await Task.sleep(nanoseconds: 1_500_000_000) let context: PageContext do { context = try await ContentExtractor.extract(from: loader.webView) } catch { printErr("extraction failed: \(error.localizedDescription)"); return 1 } print("✓ extracted: \"\(context.title)\" — quality=\(context.quality.rawValue), " + "words=\(context.wordCount), ~\(context.estimatedTokens) tokens, " + "headings=\(context.headings.count), truncated=\(context.truncated)") let plan = Summarizer.plan(for: context, model: model) print("✓ model=\(model.id) (\(model.provider.rawValue)), plan=\(plan)") print("---- extracted markdown (first 400 chars) ----") print(String(context.markdown.prefix(400))) print("---- streaming summary ----") let service = AIService() service.run(.summarize, on: context, model: model, apiKey: apiKey) // Drain the stream, printing new text as it arrives. var printed = 0 while service.isStreaming || printed < service.output.count { let current = service.output if current.count > printed { let start = current.index(current.startIndex, offsetBy: printed) FileHandle.standardOutput.write(Data(String(current[start...]).utf8)) printed = current.count } if let err = service.errorText { printErr("\n\nAI error: \(err)"); return 1 } if !service.isStreaming && printed >= service.output.count { break } try? await Task.sleep(nanoseconds: 80_000_000) } print("\n---- end ----") print("✓ summary chars=\(service.output.count)") return service.output.isEmpty ? 1 : 0 } private static func value(after flag: String, in args: [String]) -> String? { guard let i = args.firstIndex(of: flag), i + 1 < args.count else { return nil } return args[i + 1] } private static func printErr(_ s: String) { FileHandle.standardError.write(Data((s + "\n").utf8)) } } /// Loads a URL in an offscreen, windowed WKWebView (a window ensures WebKit /// runs layout/timers/JS the same as onscreen) and resolves when navigation /// finishes. @MainActor final class PageLoader: NSObject, WKNavigationDelegate { let webView: WKWebView private let window: NSWindow private var continuation: CheckedContinuation? init(configuration: WKWebViewConfiguration) { webView = WKWebView(frame: NSRect(x: 0, y: 0, width: 1200, height: 900), configuration: configuration) window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 1200, height: 900), styleMask: [.borderless], backing: .buffered, defer: false) super.init() window.contentView = webView window.orderOut(nil) webView.navigationDelegate = self } func load(_ url: URL) async throws { try await withCheckedThrowingContinuation { (c: CheckedContinuation) in continuation = c webView.load(URLRequest(url: url)) } } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { continuation?.resume(); continuation = nil } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { continuation?.resume(throwing: error); continuation = nil } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { continuation?.resume(throwing: error); continuation = nil } }