feat(macos): load models from gateway
This commit is contained in:
@@ -17,6 +17,7 @@ struct ConfigSettings: View {
|
|||||||
@State private var models: [ModelChoice] = []
|
@State private var models: [ModelChoice] = []
|
||||||
@State private var modelsLoading = false
|
@State private var modelsLoading = false
|
||||||
@State private var modelError: String?
|
@State private var modelError: String?
|
||||||
|
@State private var modelsSourceLabel: String?
|
||||||
@AppStorage(modelCatalogPathKey) private var modelCatalogPath: String = ModelCatalogLoader.defaultPath
|
@AppStorage(modelCatalogPathKey) private var modelCatalogPath: String = ModelCatalogLoader.defaultPath
|
||||||
@AppStorage(modelCatalogReloadKey) private var modelCatalogReloadBump: Int = 0
|
@AppStorage(modelCatalogReloadKey) private var modelCatalogReloadBump: Int = 0
|
||||||
@State private var allowAutosave = false
|
@State private var allowAutosave = false
|
||||||
@@ -142,6 +143,12 @@ struct ConfigSettings: View {
|
|||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let modelsSourceLabel {
|
||||||
|
Text("Model catalog: \(modelsSourceLabel)")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var anthropicAuthHelpText: String {
|
private var anthropicAuthHelpText: String {
|
||||||
@@ -410,20 +417,44 @@ struct ConfigSettings: View {
|
|||||||
guard !self.modelsLoading else { return }
|
guard !self.modelsLoading else { return }
|
||||||
self.modelsLoading = true
|
self.modelsLoading = true
|
||||||
self.modelError = nil
|
self.modelError = nil
|
||||||
|
self.modelsSourceLabel = nil
|
||||||
do {
|
do {
|
||||||
let loaded = try await ModelCatalogLoader.load(from: self.modelCatalogPath)
|
let res: ModelsListResult =
|
||||||
self.models = loaded
|
try await GatewayConnection.shared
|
||||||
if !self.configModel.isEmpty, !loaded.contains(where: { $0.id == self.configModel }) {
|
.requestDecoded(
|
||||||
|
method: .modelsList,
|
||||||
|
timeoutMs: 15000)
|
||||||
|
self.models = res.models
|
||||||
|
self.modelsSourceLabel = "gateway"
|
||||||
|
if !self.configModel.isEmpty,
|
||||||
|
!res.models.contains(where: { $0.id == self.configModel })
|
||||||
|
{
|
||||||
self.customModel = self.configModel
|
self.customModel = self.configModel
|
||||||
self.configModel = "__custom__"
|
self.configModel = "__custom__"
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.modelError = error.localizedDescription
|
do {
|
||||||
self.models = []
|
let loaded = try await ModelCatalogLoader.load(from: self.modelCatalogPath)
|
||||||
|
self.models = loaded
|
||||||
|
self.modelsSourceLabel = "local fallback"
|
||||||
|
if !self.configModel.isEmpty,
|
||||||
|
!loaded.contains(where: { $0.id == self.configModel })
|
||||||
|
{
|
||||||
|
self.customModel = self.configModel
|
||||||
|
self.configModel = "__custom__"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
self.modelError = error.localizedDescription
|
||||||
|
self.models = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.modelsLoading = false
|
self.modelsLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct ModelsListResult: Decodable {
|
||||||
|
let models: [ModelChoice]
|
||||||
|
}
|
||||||
|
|
||||||
private var selectedContextLabel: String? {
|
private var selectedContextLabel: String? {
|
||||||
let chosenId = (self.configModel == "__custom__") ? self.customModel : self.configModel
|
let chosenId = (self.configModel == "__custom__") ? self.customModel : self.configModel
|
||||||
guard
|
guard
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ struct DebugSettings: View {
|
|||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
Text("Used by the Config tab model picker; point at a different build when debugging.")
|
Text("Local fallback for model picker when gateway models.list is unavailable.")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.tertiary)
|
.foregroundStyle(.tertiary)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ actor GatewayConnection {
|
|||||||
case setHeartbeats = "set-heartbeats"
|
case setHeartbeats = "set-heartbeats"
|
||||||
case systemEvent = "system-event"
|
case systemEvent = "system-event"
|
||||||
case health
|
case health
|
||||||
|
case providersStatus = "providers.status"
|
||||||
|
case configGet = "config.get"
|
||||||
|
case configSet = "config.set"
|
||||||
|
case webLoginStart = "web.login.start"
|
||||||
|
case webLoginWait = "web.login.wait"
|
||||||
|
case webLogout = "web.logout"
|
||||||
|
case telegramLogout = "telegram.logout"
|
||||||
|
case modelsList = "models.list"
|
||||||
case chatHistory = "chat.history"
|
case chatHistory = "chat.history"
|
||||||
case chatSend = "chat.send"
|
case chatSend = "chat.send"
|
||||||
case chatAbort = "chat.abort"
|
case chatAbort = "chat.abort"
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ extension SessionRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelChoice: Identifiable, Hashable {
|
struct ModelChoice: Identifiable, Hashable, Codable {
|
||||||
let id: String
|
let id: String
|
||||||
let name: String
|
let name: String
|
||||||
let provider: String
|
let provider: String
|
||||||
|
|||||||
Reference in New Issue
Block a user