SPB Git

spb/zyquo-agent Public MIT

The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.

Swift 94.7% Shell 4.1% Python 0.7% Makefile 0.5%
4.5 KB · 115 lines swift
Raw Blame History
1//2//  AIModel.swift3//  Zyquo Agent4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//8//  Ported verbatim from Zyquo Cloud. Zyquo Agent adds the `agentCapable`9//  marking (see AgentModelSupport.swift) on top of the identical catalog.10//1112import Foundation1314/// A chat-capable model offered by a provider. Instances come exclusively from15/// `ModelCatalog` (built-in data generated from docs/PROVIDERS.md, dynamic16/// `/models` refreshes, and user-defined custom models) — never hardcode these17/// in views or clients.18struct AIModel: Codable, Identifiable, Hashable {19    /// Exact model ID as sent in API requests (e.g. "gpt-5.6-terra").20    let id: String21    let provider: ProviderID22    /// Human-friendly name shown in the UI (e.g. "GPT-5.6 Terra").23    let displayName: String24    /// Context window in tokens.25    let contextWindow: Int26    /// Maximum output tokens, when documented.27    let maxOutputTokens: Int?28    let capabilities: ModelCapabilities29    let pricing: ModelPricing?30    let parameterSupport: ParameterSupport31    /// Deprecated or superseded models stay selectable but are ranked last and badged.32    var isLegacy: Bool = false33    /// Featured/flagship models surface at the top of pickers.34    var isRecommended: Bool = false35    /// Base URL override for user-defined custom models; nil for built-ins.36    var customBaseURL: URL? = nil3738    /// Short badge text for the model chip (e.g. "1M ctx").39    var contextBadge: String {40        switch contextWindow {41        case 1_000_000...: return "\(contextWindow / 1_000_000)M ctx"42        case 1_000...: return "\(contextWindow / 1_000)K ctx"43        default: return "\(contextWindow) ctx"44        }45    }46}4748/// What a model can do. Drives UI affordances (attach button, thinking section…)49/// and request construction.50struct ModelCapabilities: Codable, Hashable {51    /// Accepts image input.52    var vision: Bool = false53    /// Supports function calling / tools.54    var tools: Bool = false55    /// Produces reasoning/thinking output (shown in the collapsible section).56    var reasoning: Bool = false57    /// Supports SSE streaming (true for every catalog model; custom endpoints may vary).58    var streaming: Bool = true59    /// Supports JSON mode / structured output.60    var jsonMode: Bool = false61    /// Returns web-search citations (Perplexity sonar family).62    var citations: Bool = false63}6465/// USD per 1M tokens. Cached/tiered pricing is intentionally simplified to the66/// base rate — cost figures in the UI are labeled as estimates.67struct ModelPricing: Codable, Hashable {68    var inputPerMTok: Double69    var outputPerMTok: Double7071    /// Estimated cost in USD for a usage record.72    func cost(inputTokens: Int, outputTokens: Int) -> Double {73        (Double(inputTokens) * inputPerMTok + Double(outputTokens) * outputPerMTok) / 1_000_00074    }75}7677/// Which sampling/control parameters a model accepts. Providers reject requests78/// carrying unsupported parameters, so requests only include what's supported —79/// and Settings only shows sliders that apply.80struct ParameterSupport: Codable, Hashable {81    var temperature: Bool = true82    var topP: Bool = true83    var frequencyPenalty: Bool = false84    var presencePenalty: Bool = false85    /// Send "max_completion_tokens" instead of "max_tokens" (OpenAI reasoning models, Cerebras).86    var usesMaxCompletionTokens: Bool = false87    /// Accepts `reasoning_effort` (OpenAI, xAI, Mistral, DeepSeek, Kimi K-series, Cerebras…).88    var reasoningEffort: Bool = false89    /// Anthropic `thinking` / Qwen `enable_thinking` style explicit thinking toggle.90    var thinkingToggle: Bool = false91    /// Model rejects non-streaming calls (Qwen qwq/qvq, DashScope-hosted models92    /// on Together…) — `complete` aggregates a stream instead.93    var requiresStreaming: Bool = false9495    static let openAIDefault = ParameterSupport(frequencyPenalty: true, presencePenalty: true)96}9798/// Token usage reported by a provider for one exchange.99struct TokenUsage: Codable, Hashable {100    var inputTokens: Int = 0101    var outputTokens: Int = 0102    var reasoningTokens: Int? = nil103104    var totalTokens: Int { inputTokens + outputTokens }105106    static func + (lhs: TokenUsage, rhs: TokenUsage) -> TokenUsage {107        TokenUsage(108            inputTokens: lhs.inputTokens + rhs.inputTokens,109            outputTokens: lhs.outputTokens + rhs.outputTokens,110            reasoningTokens: (lhs.reasoningTokens ?? 0) + (rhs.reasoningTokens ?? 0) == 0111                ? nil : (lhs.reasoningTokens ?? 0) + (rhs.reasoningTokens ?? 0)112        )113    }114}115