Fold task state into one server field; add ready cancel and dismiss

This commit is contained in:
Ian Gulliver
2026-10-20 08:51:32 -07:00
parent 224a0d5a4b
commit e7724977c8
12 changed files with 506 additions and 388 deletions
+19 -41
View File
@@ -33,11 +33,21 @@ struct TaskState {
}
}
private let workingTitles: [ByreTask.StatePayload: (label: String, title: String)] = [
.running: ("Working", "The agent is mid-turn or its subagents are running"),
.reviewPending: ("Reviewing", "A review of the turn's work is about to start"),
.reviewing: ("Reviewing", "A review is running"),
.discarding: ("Discarding", "The agent is writing the task summary, then byre removes the task"),
private let stateTitles: [ByreTask.StatePayload: TaskState] = [
.asking: TaskState(kind: .answer, label: "Needs your answer", title: "The agent asked a question"),
.merging: TaskState(kind: .merging, label: "Merging", title: "The merge is under way"),
.mergeHeld: TaskState(kind: .held, label: "Merge held", title: "Waiting for the merge in progress in this project to finish"),
.mergeAfterReview: TaskState(kind: .held, label: "Merge after review", title: "Merges when the running review finishes with no findings"),
.running: TaskState(kind: .working, label: "Working", title: "The agent is mid-turn or its subagents are running"),
.reviewPending: TaskState(kind: .working, label: "Reviewing", title: "A review of the turn's work is about to start"),
.reviewing: TaskState(kind: .working, label: "Reviewing", title: "A review is running"),
.discarding: TaskState(kind: .working, label: "Discarding", title: "The agent is writing the task summary, then byre removes the task"),
.readyToMerge: TaskState(kind: .ready, label: "Ready to merge", title: "The agent says the task is ready to merge"),
.discardSuggested: TaskState(kind: .ready, label: "Ready to discard", title: "The agent suggests discarding the task"),
.idle: TaskState(kind: .idle, label: "Idle", title: "Waiting for a message"),
.noAgent: TaskState(kind: .idle, label: "Idle", title: "Waiting for a message"),
.merged: TaskState(kind: .idle, label: "Merged", title: "The task was merged"),
.discarded: TaskState(kind: .idle, label: "Discarded", title: "The task was discarded"),
]
@MainActor
@@ -207,44 +217,12 @@ final class Store {
}
func taskState(_ task: ByreTask) -> TaskState {
if inbox.contains(where: { $0.taskId == task.id }) {
return TaskState(kind: .answer, label: "Needs your answer", title: "The agent asked a question")
}
let busy = progress(task)
if let busy, busy.kind == .merging {
return busy
}
if task.mergeQueuedAt != nil {
return TaskState(kind: .held, label: "Merge held", title: "Waiting for the merge in progress in this project to finish")
}
if task.mergeAfterReview {
return TaskState(kind: .held, label: "Merge after review", title: "Merges when the running review finishes with no findings")
}
if let busy {
return busy
}
switch task.ready {
case .merge:
return TaskState(kind: .ready, label: "Ready to merge", title: "The agent says the task is ready to merge")
case .discard:
return TaskState(kind: .ready, label: "Ready to discard", title: "The agent suggests discarding the task")
case nil:
break
}
return TaskState(kind: .idle, label: "Idle", title: "Waiting for a message")
stateTitles[task.state]!
}
func progress(_ task: ByreTask) -> TaskState? {
if task.merging {
return TaskState(kind: .merging, label: "Merging", title: "The merge turn is running")
}
if task.mergingIntoParent {
return TaskState(kind: .merging, label: "Merging", title: "Waiting for the parent task's agent to merge it")
}
if let working = workingTitles[task.state] {
return TaskState(kind: .working, label: working.label, title: working.title)
}
return nil
let state = taskState(task)
return state.kind == .merging || state.kind == .working ? state : nil
}
func taskRank(_ task: ByreTask) -> Int {
@@ -634,7 +612,7 @@ final class Store {
spawn("load projects") {
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":
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", "task.ready_cleared", "snapshot.created":
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)
}