Add Away mode and an agent fork tool
This commit is contained in:
@@ -68,6 +68,7 @@ struct ByreApp: App {
|
||||
ServerWindow()
|
||||
}
|
||||
.defaultSize(width: 1280, height: 820)
|
||||
.windowToolbarStyle(.unifiedCompact)
|
||||
.restorationBehavior(.disabled)
|
||||
.defaultLaunchBehavior(.presented)
|
||||
.commands {
|
||||
|
||||
@@ -1619,7 +1619,7 @@ private struct SnapshotRow: View {
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.disabled(forking)
|
||||
.help("Start a new task from this snapshot, its agent continuing the conversation as it stood here")
|
||||
if snap.trigger != .answer {
|
||||
if ![.answer, .fork].contains(snap.trigger) {
|
||||
reviewButton
|
||||
}
|
||||
Rectangle().fill(Palette.border).frame(height: 1)
|
||||
|
||||
@@ -160,7 +160,7 @@ private func reviewWarnings(_ taskId: String, _ store: Store, _ leave: @escaping
|
||||
async let snapsCall = client.listSnapshots(path: .init(taskId: taskId)).ok.body.json
|
||||
async let reviewsCall = client.listReviews(path: .init(taskId: taskId)).ok.body.json
|
||||
let (snaps, reviews) = try await (snapsCall, reviewsCall)
|
||||
guard let latest = snaps.last(where: { $0.trigger != .answer }) else {
|
||||
guard let latest = snaps.last(where: { ![.answer, .fork].contains($0.trigger) }) else {
|
||||
return ([MergeWarning(text: "These changes haven't been reviewed")], false)
|
||||
}
|
||||
var items: [MergeWarning] = []
|
||||
|
||||
@@ -494,12 +494,56 @@ struct ServerPicker: View {
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 3)
|
||||
.help("Add Server")
|
||||
AwayToggle()
|
||||
}
|
||||
.font(Fonts.font(13))
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
private struct AwayToggle: View {
|
||||
@ViewState private var hover = false
|
||||
@ViewState private var busy = false
|
||||
|
||||
var body: some View {
|
||||
let stores = Servers.shared.origins.compactMap { Servers.shared.connections[$0]?.store }
|
||||
let away = stores.contains { $0.me?.away == true }
|
||||
if !stores.isEmpty {
|
||||
Button {
|
||||
set(!away, stores)
|
||||
} label: {
|
||||
Text("Away")
|
||||
.foregroundStyle(away ? Palette.accent : hover ? Palette.text : Palette.muted)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 3)
|
||||
.background(away ? Palette.accentTint : .clear, in: RoundedRectangle(cornerRadius: 6))
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(busy)
|
||||
.padding(.leading, 8)
|
||||
.help(away
|
||||
? "You're away: byre answers your agents' questions at once, telling them to pick the most likely answer. Click when you're back."
|
||||
: "Go away: byre answers your agents' questions at once, telling them to pick the most likely answer, on every server")
|
||||
.onHover { hover = $0 }
|
||||
}
|
||||
}
|
||||
|
||||
private func set(_ away: Bool, _ stores: [Store]) {
|
||||
busy = true
|
||||
Task {
|
||||
for store in stores {
|
||||
do {
|
||||
store.me = try await store.api.client.updateAway(body: .json(.init(away: away))).ok.body.json
|
||||
} catch {
|
||||
log.error("set away: \(errorText(error), privacy: .public)")
|
||||
}
|
||||
}
|
||||
busy = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ServerChip: View {
|
||||
let origin: String
|
||||
@ViewState private var hover = false
|
||||
|
||||
@@ -624,7 +624,7 @@ final class Store {
|
||||
try await self.loadProjects()
|
||||
}
|
||||
case "task.created", "task.merge_title", "task.merge_queued", "task.merge_unqueued", "task.merge_after_review", "task.merge_after_review_ended", "task.merge_after_review_cancelled", "task.parent_merge_started", "task.parent_merge_stopped", "task.merge_started", "task.merge_ended", "task.discard_started", "task.merged", "task.discarded", "task.state", "task.ready", "task.discard_suggested", "snapshot.created":
|
||||
if let taskId = ev.taskId, ["task.merged", "task.discarded"].contains(ev.kind) || (ev.kind == "snapshot.created" && str(ev.payload.value, "trigger") != "answer") {
|
||||
if let taskId = ev.taskId, ["task.merged", "task.discarded"].contains(ev.kind) || (ev.kind == "snapshot.created" && !["answer", "fork"].contains(str(ev.payload.value, "trigger"))) {
|
||||
clearTask(self, taskId)
|
||||
}
|
||||
notifyTask(self, ev)
|
||||
|
||||
@@ -467,7 +467,7 @@ final class TranscriptBuilder {
|
||||
let snap = try! decodePayload(ev.payload, as: Snapshot.self)
|
||||
let row = Row(.snapshot(snap), taskId: taskId)
|
||||
ctx.reviewButtons[snap.n] = row
|
||||
if snap.trigger != .answer && sink == nil {
|
||||
if ![.answer, .fork].contains(snap.trigger) && sink == nil {
|
||||
lastReady = nil
|
||||
}
|
||||
put(row)
|
||||
|
||||
Reference in New Issue
Block a user