68 lines
2.2 KiB
Swift
68 lines
2.2 KiB
Swift
// SPDX-FileCopyrightText: 2026 Kaede Akino
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import AgentKit
|
|
import Foundation
|
|
import Observation
|
|
import TermindApplication
|
|
import TermindPresentation
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class MobileModelDiscovery {
|
|
private(set) var candidates: [AIModel] = []
|
|
private(set) var running = false
|
|
var error: String?
|
|
private var task: Task<Void, Never>?
|
|
private var generation = UUID()
|
|
typealias Fetch = @Sendable (ModelProvider, String) async throws -> [AIModel]
|
|
private let fetch: Fetch
|
|
|
|
init(fetch: @escaping Fetch = { try await ModelCatalogClient().models(for: $0, secret: $1) }) {
|
|
self.fetch = fetch
|
|
}
|
|
|
|
func start(ai: AIConfigurationModel, provider: ModelProvider) {
|
|
cancel()
|
|
do {
|
|
guard let secret = ai.modelSecret(for: provider) else {
|
|
throw MobileEditorError.message(
|
|
ai.secretStorageError ?? String(localized: AppStrings.Settings.providerCredentialUnavailable))
|
|
}
|
|
start(provider: provider, secret: secret, isCurrent: { ai.modelProvider(provider.id) == provider })
|
|
} catch { self.error = error.localizedDescription }
|
|
}
|
|
|
|
func start(provider: ModelProvider, secret: String, isCurrent: @escaping @MainActor () -> Bool = { true }) {
|
|
cancel()
|
|
let token = generation
|
|
running = true
|
|
error = nil
|
|
task = Task { [weak self, fetch] in
|
|
defer { if self?.generation == token { self?.running = false } }
|
|
do {
|
|
let values = try await fetch(provider, secret)
|
|
guard let self, generation == token, !Task.isCancelled,
|
|
isCurrent()
|
|
else { return }
|
|
var seen = Set<String>()
|
|
candidates = values.filter { seen.insert($0.id).inserted }
|
|
running = false
|
|
} catch {
|
|
guard let self, generation == token, !Task.isCancelled, isCurrent() else { return }
|
|
self.error = error.localizedDescription
|
|
running = false
|
|
}
|
|
}
|
|
}
|
|
|
|
func cancel() {
|
|
generation = UUID()
|
|
task?.cancel()
|
|
task = nil
|
|
candidates = []
|
|
error = nil
|
|
running = false
|
|
}
|
|
}
|