Save a default model per user, set from Settings
This commit is contained in:
@@ -291,7 +291,8 @@ struct ComposerView: View {
|
||||
let offered = live.map { s in models.filter { vendorOf($0) == s.vendor.rawValue } } ?? models
|
||||
let options = !current.isEmpty && !offered.contains(current) ? [current] + offered : offered
|
||||
let modelKey = "message:\(live?.id ?? key)"
|
||||
return ModelState(live: live, current: current, options: options, modelKey: modelKey, selected: pick ?? modelChoices[modelKey] ?? (current.isEmpty ? options[0] : current))
|
||||
let fresh = live == nil ? store.defaultModel : options[0]
|
||||
return ModelState(live: live, current: current, options: options, modelKey: modelKey, selected: pick ?? modelChoices[modelKey] ?? (current.isEmpty ? fresh : current))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -25,6 +25,11 @@ struct SettingsView: View {
|
||||
heading("Notifications")
|
||||
DeviceNotifications()
|
||||
PrefsBox()
|
||||
heading("Default model")
|
||||
Text("New tasks you start from byre run on this model.")
|
||||
.foregroundStyle(Palette.muted)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
DefaultModelMenu()
|
||||
heading("What your lead has learned")
|
||||
Text("Your lead notes your priorities and preferences as it works with you, and starts every session with them.")
|
||||
.foregroundStyle(Palette.muted)
|
||||
@@ -132,6 +137,42 @@ private struct PrefsBox: View {
|
||||
}
|
||||
}
|
||||
|
||||
private struct DefaultModelMenu: View {
|
||||
@Environment(Store.self) private var store
|
||||
@Environment(Overlays.self) private var overlays
|
||||
|
||||
var body: some View {
|
||||
Menu {
|
||||
ForEach(models, id: \.self) { m in
|
||||
Button(m) {
|
||||
Task {
|
||||
do {
|
||||
store.me = try await store.api.client.updateDefaultModel(body: .json(.init(model: m))).ok.body.json
|
||||
} catch {
|
||||
overlays.showAlert(errorText(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 8) {
|
||||
Text(store.defaultModel)
|
||||
Image(systemName: "chevron.up.chevron.down")
|
||||
.font(.system(size: 9, weight: .semibold))
|
||||
}
|
||||
.foregroundStyle(Palette.text)
|
||||
.modifier(FieldStyle())
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.menuStyle(.button)
|
||||
.buttonStyle(.plain)
|
||||
.menuIndicator(.hidden)
|
||||
.fixedSize()
|
||||
.help("Model for new tasks")
|
||||
.padding(.top, 8)
|
||||
}
|
||||
}
|
||||
|
||||
private struct LeadNotes: View {
|
||||
@Environment(Store.self) private var store
|
||||
@Environment(Overlays.self) private var overlays
|
||||
|
||||
@@ -92,7 +92,7 @@ final class Store {
|
||||
todoBusy[key] = discuss ? "discuss" : "start"
|
||||
Task {
|
||||
do {
|
||||
_ = try await api.client.startTodoItem(path: .init(projectId: projectId), body: .json(.init(title: title, model: models[0], discuss: discuss))).created
|
||||
_ = try await api.client.startTodoItem(path: .init(projectId: projectId), body: .json(.init(title: title, model: defaultModel, discuss: discuss))).created
|
||||
} catch {
|
||||
overlays.showAlert(errorText(error))
|
||||
}
|
||||
@@ -108,7 +108,7 @@ final class Store {
|
||||
todoBusy[key] = "start"
|
||||
Task {
|
||||
do {
|
||||
_ = try await api.client.createTask(path: .init(projectId: projectId), body: .json(.init(title: title, prompt: brief, model: models[0]))).created
|
||||
_ = try await api.client.createTask(path: .init(projectId: projectId), body: .json(.init(title: title, prompt: brief, model: defaultModel))).created
|
||||
} catch {
|
||||
overlays.showAlert(errorText(error))
|
||||
}
|
||||
@@ -126,7 +126,7 @@ final class Store {
|
||||
let live = lead != nil && lead!.state != .completed
|
||||
Task {
|
||||
do {
|
||||
_ = try await api.client.messageLead(body: .json(.init(text: "Let's discuss your suggestion \"\(title)\" before starting it:\n\n\(brief)", model: live ? nil : models[0]))).accepted
|
||||
_ = try await api.client.messageLead(body: .json(.init(text: "Let's discuss your suggestion \"\(title)\" before starting it:\n\n\(brief)", model: live ? nil : defaultModel))).accepted
|
||||
} catch {
|
||||
overlays.showAlert(errorText(error))
|
||||
}
|
||||
@@ -208,6 +208,10 @@ final class Store {
|
||||
focusTab(.reviews)
|
||||
}
|
||||
|
||||
var defaultModel: String {
|
||||
me!.defaultModel
|
||||
}
|
||||
|
||||
func loadMe() async throws {
|
||||
me = try await api.client.getMe().ok.body.json
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ final class SwitcherModel {
|
||||
case .newTask(let p, let title):
|
||||
create(p.id, .init(title: title))
|
||||
case .startTask(let p, let title):
|
||||
create(p.id, .init(title: title, prompt: title, model: models[0]))
|
||||
create(p.id, .init(title: title, prompt: title, model: store.defaultModel))
|
||||
case .startWorkflow(let p, let title):
|
||||
pickWorkflow(p, title)
|
||||
case .workflow(let p, let title, let w):
|
||||
@@ -442,7 +442,7 @@ private struct SwitcherRowView: View {
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
state(models[0])
|
||||
state(store.defaultModel)
|
||||
.help("Model for the first message")
|
||||
case .startTask(let p, let title):
|
||||
Text(created([("Start in ", nil), (p.name, Palette.muted), (": \(title)", nil)]))
|
||||
@@ -450,7 +450,7 @@ private struct SwitcherRowView: View {
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
state(models[0])
|
||||
state(store.defaultModel)
|
||||
.help("The title is the agent's first message")
|
||||
case .startWorkflow(let p, let title):
|
||||
Text(created([("Start workflow… in ", nil), (p.name, Palette.muted), (": \(title)", nil)]))
|
||||
|
||||
Reference in New Issue
Block a user