Watch: notification switches, a model list and Ask before acting on new threads, and Ask before acting on a thread
This commit is contained in:
1 parent
3cc7e40852
commit
6bc9cac6ca
14 files changed
+623
-81
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// One thread: the agent's latest message large, older messages one scroll up, the pending approval
|
||||
// or question with its options, Reply by dictation or Scribble, Stop while a run is active, and
|
||||
// Settle once it finished or failed. A subagent's request shows first, labeled with the subagent.
|
||||
// or question with its options, Reply by dictation or Scribble, Settle once it finished or failed,
|
||||
// an Ask before acting switch, and Stop while a run is active. A subagent's request shows first,
|
||||
// labeled with the subagent.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@@ -19,6 +20,10 @@ struct ThreadView: View {
|
||||
/// Options ticked so far on multi-select questions, by question id.
|
||||
@State private var selections: [String: Set<String>] = [:]
|
||||
@State private var scrolledToLatest = false
|
||||
/// Why the last Ask before acting change failed. It shows under the switch.
|
||||
@State private var modeError: String?
|
||||
/// The Ask before acting value still being sent, which a poll landing meanwhile keeps.
|
||||
@State private var pendingAskFirst: Bool?
|
||||
|
||||
/// Snapshots render the column without its ScrollView, which ImageRenderer leaves blank.
|
||||
private let scrolls: Bool
|
||||
@@ -149,6 +154,15 @@ struct ThreadView: View {
|
||||
.disabled(sending)
|
||||
}
|
||||
|
||||
if let askFirst = detail.askFirst {
|
||||
SwitchCard(title: "Ask before acting", isOn: Binding(get: { askFirst }, set: { setAskFirst($0) }))
|
||||
if let modeError {
|
||||
Text(modeError)
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(Theme.bad)
|
||||
}
|
||||
}
|
||||
|
||||
if detail.canStop {
|
||||
Button(role: .destructive) { stop() } label: {
|
||||
Label("Stop", systemImage: "stop.fill")
|
||||
@@ -300,7 +314,9 @@ struct ThreadView: View {
|
||||
|
||||
private func load() async {
|
||||
do {
|
||||
detail = try await model.api.thread(hostId: hostId, threadId: threadId)
|
||||
var fresh = try await model.api.thread(hostId: hostId, threadId: threadId)
|
||||
if let pendingAskFirst { fresh.askFirst = pendingAskFirst }
|
||||
detail = fresh
|
||||
error = nil
|
||||
} catch {
|
||||
self.error = model.message(for: error)
|
||||
@@ -357,6 +373,23 @@ struct ThreadView: View {
|
||||
perform { try await model.api.stop(hostId: hostId, threadId: threadId) }
|
||||
}
|
||||
|
||||
/// Flips the switch at once and tells the gateway. If it refuses, the switch flips back and the
|
||||
/// line under it shows why.
|
||||
private func setAskFirst(_ on: Bool) {
|
||||
detail?.askFirst = on
|
||||
pendingAskFirst = on
|
||||
modeError = nil
|
||||
Task {
|
||||
do {
|
||||
try await model.api.setAskFirst(hostId: hostId, threadId: threadId, askFirst: on)
|
||||
} catch {
|
||||
detail?.askFirst = !on
|
||||
modeError = model.message(for: error)
|
||||
}
|
||||
pendingAskFirst = nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Settles the thread and goes back to the feed. On failure the screen stays and shows why.
|
||||
private func settle() {
|
||||
sending = true
|
||||
|
||||
Reference in new issue
Block a user