78 lines
2.9 KiB
Swift
78 lines
2.9 KiB
Swift
import Foundation
|
|
import Observation
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class SybilSettingsStore {
|
|
private enum Keys {
|
|
static let apiBaseURL = "sybil.ios.apiBaseURL"
|
|
static let adminToken = "sybil.ios.adminToken"
|
|
static let preferredProvider = "sybil.ios.preferredProvider"
|
|
static let preferredOpenAIModel = "sybil.ios.preferredOpenAIModel"
|
|
static let preferredAnthropicModel = "sybil.ios.preferredAnthropicModel"
|
|
static let preferredXAIModel = "sybil.ios.preferredXAIModel"
|
|
}
|
|
|
|
private let defaults: UserDefaults
|
|
|
|
var apiBaseURL: String
|
|
var adminToken: String
|
|
var preferredProvider: Provider
|
|
var preferredModelByProvider: [Provider: String]
|
|
|
|
init(defaults: UserDefaults = .standard) {
|
|
self.defaults = defaults
|
|
|
|
let storedBaseURL = defaults.string(forKey: Keys.apiBaseURL)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let fallbackBaseURL = "http://127.0.0.1:8787"
|
|
self.apiBaseURL = storedBaseURL?.isEmpty == false ? storedBaseURL! : fallbackBaseURL
|
|
|
|
self.adminToken = defaults.string(forKey: Keys.adminToken) ?? ""
|
|
|
|
let provider = defaults.string(forKey: Keys.preferredProvider).flatMap(Provider.init(rawValue:)) ?? .openai
|
|
self.preferredProvider = provider
|
|
|
|
self.preferredModelByProvider = [
|
|
.openai: defaults.string(forKey: Keys.preferredOpenAIModel) ?? "gpt-4.1-mini",
|
|
.anthropic: defaults.string(forKey: Keys.preferredAnthropicModel) ?? "claude-3-5-sonnet-latest",
|
|
.xai: defaults.string(forKey: Keys.preferredXAIModel) ?? "grok-3-mini"
|
|
]
|
|
}
|
|
|
|
func persist() {
|
|
defaults.set(apiBaseURL.trimmingCharacters(in: .whitespacesAndNewlines), forKey: Keys.apiBaseURL)
|
|
|
|
let trimmedToken = adminToken.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if trimmedToken.isEmpty {
|
|
defaults.removeObject(forKey: Keys.adminToken)
|
|
} else {
|
|
defaults.set(trimmedToken, forKey: Keys.adminToken)
|
|
}
|
|
|
|
defaults.set(preferredProvider.rawValue, forKey: Keys.preferredProvider)
|
|
defaults.set(preferredModelByProvider[.openai], forKey: Keys.preferredOpenAIModel)
|
|
defaults.set(preferredModelByProvider[.anthropic], forKey: Keys.preferredAnthropicModel)
|
|
defaults.set(preferredModelByProvider[.xai], forKey: Keys.preferredXAIModel)
|
|
}
|
|
|
|
var trimmedTokenOrNil: String? {
|
|
let value = adminToken.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
return value.isEmpty ? nil : value
|
|
}
|
|
|
|
var normalizedAPIBaseURL: URL? {
|
|
var raw = apiBaseURL.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard !raw.isEmpty else { return nil }
|
|
|
|
while raw.hasSuffix("/") {
|
|
raw.removeLast()
|
|
}
|
|
|
|
guard var components = URLComponents(string: raw) else {
|
|
return nil
|
|
}
|
|
|
|
return components.url
|
|
}
|
|
}
|