ready to merge and ready to discard as states

This commit is contained in:
Ian Gulliver
2026-10-19 17:53:54 -07:00
parent fb79919ebb
commit 2bb527aca0
11 changed files with 394 additions and 293 deletions
+5
View File
@@ -1288,6 +1288,11 @@ components:
merging_into_parent: { type: boolean, description: "Whether a merge of this subtask into its parent was requested and the parent hasn't merged it yet." }
merge_after_review: { type: boolean, description: "Whether a Merge with after_review is waiting for the running review of the latest snapshot to finish." }
summary_seq: { type: integer, format: int64, description: "The seq of the task's latest turn.ended event with summary: true; 0 when it has none." }
ready:
type: string
description: "What the agent last told the human to do with the task: merge (ready_for_merge) or discard (suggest_discard); absent when it hasn't, or when a snapshot other than an answer's or a new question came after."
enum: [merge, discard]
x-enum-varnames: [TaskReadyMerge, TaskReadyDiscard]
Todo:
type: object
+3 -1
View File
@@ -41,6 +41,8 @@ An implementer says its task is ready to merge with the `ready_for_merge` MCP to
An implementer that thinks its task shouldn't land at all (the approach failed, the task turned out unnecessary or already done) says so with the `suggest_discard` MCP tool (also `internal/agents/ready.go`), whose `reason` explains why; `readyPrompt` offers it as the alternative to `ready_for_merge`. Each call records a `task.discard_suggested` event, which the lead gets as a signal and the transcript draws with the same `ReadyBubble`, headed "suggests discarding". It takes part in "latest" with the ready-for-merge overviews, so whichever of the two came last is the current one, drawn and cleared under the same rules, and it carries only the Discard button. It only suggests: the task stays open until the human discards it.
A Task's `ready` (`tasks.ready`) is `merge` or `discard` after the latest of these two calls, set in the same transaction as its event, and is cleared (absent in the API) by the same things that clear the latest bubble: a snapshot other than an answer snapshot, or a new inbox item. The switcher's and the Project tab's task rows show it as a **Ready to merge** or **Ready to discard** state, in the warn colour with a warn dot like **Needs your answer**, when no question, merge or running work outranks it (`taskState` in `mac/Sources/Byre/Store.swift`). The app reloads a project's tasks on `task.ready`, `task.discard_suggested`, `snapshot.created` and `inbox.created`.
Agents find closed tasks with the `search_closed_tasks` MCP tool, which task agents get for their own project and the lead for one project (`project_id`) or all: a case-insensitive substring match of `query` on title, merge title, TODO item, summary and merge commit (`Store.SearchClosedTasks`), newest closed first, at most `limit` (default 20, at most 100), each with its id, outcome, merge commit, close time, creator, titles, TODO item, fork source and summary. The lead reads a closed task's transcript with `read_transcript`. There is no closed-task list in the UI; the human asks the lead.
**Knowledge base.** How byre features work that agents need only now and then lives in articles they fetch on demand instead of in their guidance: the Markdown files in `internal/agents/kb/`, embedded in the binary (`kb.go`). A file's name without `.md` is its topic, its first line a one-line summary and the rest the article. The `read_knowledge` MCP tool, which task agents and the lead get, lists every topic with its summary in its description and returns the article for `topic`. Adding an article is adding a file; the index follows. The articles are `signing` (turning on signed merge commits), `usage-commands` (the usage command's JSON format, see "Usage" under "Status"), `workflow-files` (a workflow's YAML, see "Workflows"; `read_workflow` and `save_workflow` point at it) and `todo-file` (the `TODO.md` format; the task guidance points at it).
@@ -276,7 +278,7 @@ Messages byre itself sends an agent (actor `byre`: the restart notice, Sync and
**Drafts.** Unsent composer text (task and lead) and unsent inbox answers (checked choices and Other text) are kept in memory by `Drafts` (`mac/Sources/Byre/Drafts.swift`) and saved to a SwiftData `DraftRecord` per server and login (`docs/macos.md`, "Drafts"), one JSON object with `composer` (keyed by `message:<task id>` or `message:lead`, each `{text, images}`), `checked` and `texts` (both keyed by inbox item id), and `comments`, the Changes view's pending line comments keyed by task id, each `{anchor: {path, line, old, quote}, text}`. A comment shows only under a diff line whose path, line number, side and text all still match, so after the agent moves lines a comment never attaches to a different line. Every pending comment not shown under a line (its file closed or not loaded, or its line gone from the diff) is listed at the top of the Changes view with its `path:line`, the quoted line, its editable text and **remove**, so nothing is sent unseen. Writes are debounced (400 ms) and flushed at once when a composer or answer box loses focus, on send and on quit. A composer draft is cleared only once its send succeeds, and an inbox answer only once its response is accepted; each send in flight is tracked on its own and the stored draft holds the text of every unconfirmed send (oldest first, then the composer's current text, separated by blank lines) and counts its images, so a relaunch mid-send brings back everything not yet confirmed. A failed send's text goes back into the composer ahead of whatever is there now (text typed since, or earlier failures), separated by a blank line, rather than replacing it. The composer follows its `Drafts` text as it changes, so text put back from outside it (a withdrawn queued message, a draft synced in from another Mac) shows at once. Drafts for tasks that are no longer active and for inbox items no longer open are pruned whenever the task list or inbox reloads. A record that doesn't decode is logged and ignored, as is a write that fails; drafts then live only in memory. Pending images are not stored, only their count: after a relaunch the composer shows how many need re-attaching, until dismissed or the next successful send.
The task switcher (⌘K, or the project ▸ task picker centred in the right pane's top row) lists active tasks with their task state and open inbox item count (the Project tab shows the same state), live while it is open. Tasks with inbox items come first; within each group, the task least recently visited comes first (never-visited tasks before all others, the right pane's own task after all others, ties in the server's order: projects by name, tasks newest first), so ⌘K Enter repeated cycles through the tasks. Visit times are SwiftData `VisitRecord`s synced through iCloud (`docs/macos.md`, "Persistence"), stamped when a task is selected and again when it is left. After the tasks come the projects, one row each; picking one points the right pane at the project with no task, on the Project tab. Typing filters both and adds a last row that creates a task with the typed text as its title, in the right pane's project (the first project when there is none); Enter picks the highlighted row. Text before a first colon that starts at least one project's name (ignoring case, no spaces) picks those projects instead: `by: fix` lists only their tasks whose titles contain "fix", their project rows that match, and one row per project creating the task titled "fix" there. When no project name starts with it, the whole text is the title, so "Fix: login" stays as typed. A create row shows the user's default model (see "Agent sessions"), the model the composer offers first for the new task's first message; the task itself starts with no session. Below each create row, a "Start in …" row creates the same task and starts its agent on the default model with the title as its first message, through `POST /api/projects/{id}/tasks` with `prompt` set to the title. Picking a task points the right pane at it on the Transcript tab, scrolled to its oldest open question when it has open inbox items, otherwise to its latest summary when that is unread (see below and "Lead agent").
The task switcher (⌘K, or the project ▸ task picker centred in the right pane's top row) lists active tasks with their task state and open inbox item count (the Project tab shows the same state), live while it is open. Tasks are grouped by state (`taskRank` in `mac/Sources/Byre/Store.swift`, which also orders the Project tab's task list, ties in the server's order, subtasks sorted among their siblings under their parent): with inbox items first, then **Ready to merge** or **Ready to discard**, then idle, then working or reviewing, and merging, held or discarding last; within each group, the task least recently visited comes first (never-visited tasks before all others, the right pane's own task after all others, ties in the server's order: projects by name, tasks newest first), so ⌘K Enter repeated cycles through the tasks. Visit times are SwiftData `VisitRecord`s synced through iCloud (`docs/macos.md`, "Persistence"), stamped when a task is selected and again when it is left. After the tasks come the projects, one row each; picking one points the right pane at the project with no task, on the Project tab. Typing filters both and adds a last row that creates a task with the typed text as its title, in the right pane's project (the first project when there is none); Enter picks the highlighted row. Text before a first colon that starts at least one project's name (ignoring case, no spaces) picks those projects instead: `by: fix` lists only their tasks whose titles contain "fix", their project rows that match, and one row per project creating the task titled "fix" there. When no project name starts with it, the whole text is the title, so "Fix: login" stays as typed. A create row shows the user's default model (see "Agent sessions"), the model the composer offers first for the new task's first message; the task itself starts with no session. Below each create row, a "Start in …" row creates the same task and starts its agent on the default model with the title as its first message, through `POST /api/projects/{id}/tasks` with `prompt` set to the title. Picking a task points the right pane at it on the Transcript tab, scrolled to its oldest open question when it has open inbox items, otherwise to its latest summary when that is unread (see below and "Lead agent").
**Task state.** The switcher and the Project tab show one label per task in place of its raw session state, the first that applies (`taskState` in `mac/Sources/Byre/Store.swift`), with a dot and a tooltip saying why: **Needs your answer** (an open `question` inbox item), **Merging** (`merging` or `merging_into_parent`), **Merge held** (`merge_queued_at`), **Merge after review** (`merge_after_review`), **Reviewing** (the task's `state` is `review_pending` or `reviewing`), **Working** (`running`), **Discarding** (`discarding`; see "Task state in the store" for both), **Idle** (anything else, including no session). The Project tab, in its task list and TODO items, draws a spinner in place of the dot for **Reviewing**, **Working**, **Discarding** and **Merging**. The label follows the tasks and inbox state the app already holds, so it needs no extra fetch.
+299 -273
View File
@@ -423,6 +423,24 @@ func (e StageAttemptState) Valid() bool {
}
}
// Defines values for TaskReady.
const (
TaskReadyDiscard TaskReady = "discard"
TaskReadyMerge TaskReady = "merge"
)
// Valid indicates whether the value is a known member of the TaskReady enum.
func (e TaskReady) Valid() bool {
switch e {
case TaskReadyDiscard:
return true
case TaskReadyMerge:
return true
default:
return false
}
}
// Defines values for TaskState.
const (
TaskStateDiscarded TaskState = "discarded"
@@ -1300,6 +1318,9 @@ type Task struct {
PortBase int `json:"port_base"`
ProjectId string `json:"project_id"`
// Ready What the agent last told the human to do with the task: merge (ready_for_merge) or discard (suggest_discard); absent when it hasn't, or when a snapshot other than an answer's or a new question came after.
Ready *TaskReady `json:"ready,omitempty"`
// State What the task is doing, kept by the store in the same transaction as every change to it (a task.state event carries each change): merged or discarded once closed, else discarding, merging, the state of its agent's latest live session when that isn't idle, reviewing while a review runs, review_pending between a turn's end and its snapshot's review starting or being skipped, idle, or no_agent.
State TaskState `json:"state"`
Status TaskStatus `json:"status"`
@@ -1322,6 +1343,9 @@ type Task struct {
WorktreePath string `json:"worktree_path"`
}
// TaskReady What the agent last told the human to do with the task: merge (ready_for_merge) or discard (suggest_discard); absent when it hasn't, or when a snapshot other than an answer's or a new question came after.
type TaskReady string
// TaskState What the task is doing, kept by the store in the same transaction as every change to it (a task.state event carries each change): merged or discarded once closed, else discarding, merging, the state of its agent's latest live session when that isn't idle, reviewing while a review runs, review_pending between a turn's end and its snapshot's review starting or being skipped, idle, or no_agent.
type TaskState string
@@ -4002,279 +4026,281 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
// const string: with thousands of chunks the chained `+` fold is several
// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
"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",
"IET5dDmtt2jGzlLNg/v8XtV63r//PwMA",
"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",
"cJ/fq1rP+/f/cwA=",
}
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+4
View File
@@ -27,6 +27,10 @@ func (s *Store) CreateInboxItem(ctx context.Context, item api.InboxItem) error {
if err != nil {
return err
}
_, err = tx.ExecContext(ctx, `UPDATE tasks SET ready = '' WHERE id = ?`, item.TaskId)
if err != nil {
return err
}
return emitItem(ctx, tx, emit, "inbox.created", item.Id, agentActor)
})
@@ -0,0 +1,10 @@
ALTER TABLE tasks ADD COLUMN ready TEXT NOT NULL DEFAULT '';
UPDATE tasks SET ready = coalesce((
SELECT CASE e.kind WHEN 'task.ready' THEN 'merge' ELSE 'discard' END FROM events e
WHERE e.task_id = tasks.id AND e.kind IN ('task.ready', 'task.discard_suggested')
AND NOT EXISTS (
SELECT 1 FROM events l WHERE l.task_id = tasks.id AND l.seq > e.seq
AND (l.kind = 'inbox.created' OR (l.kind = 'snapshot.created' AND json_extract(l.payload, '$.trigger') != 'answer'))
)
ORDER BY e.seq DESC LIMIT 1
), '') WHERE status = 'active';
+6
View File
@@ -17,6 +17,12 @@ func (s *Store) CreateSnapshot(ctx context.Context, snap api.Snapshot, projectID
if err != nil {
return err
}
if snap.Trigger != api.SnapshotTriggerAnswer {
_, err = tx.ExecContext(ctx, `UPDATE tasks SET ready = '' WHERE id = ?`, snap.TaskId)
if err != nil {
return err
}
}
return emit(api.Event{
Kind: "snapshot.created",
ProjectId: &projectID,
+11 -6
View File
@@ -761,17 +761,17 @@ func (s *Store) SetReadyPromptN(ctx context.Context, id string, snapshotN int) e
}
func (s *Store) MarkReady(ctx context.Context, id, overview, actor string) error {
return s.emitActive(ctx, id, actor, "task.ready", map[string]any{"id": id, "overview": overview})
return s.setReady(ctx, id, actor, api.TaskReadyMerge, "task.ready", map[string]any{"id": id, "overview": overview})
}
func (s *Store) SuggestDiscard(ctx context.Context, id, reason, actor string) error {
return s.emitActive(ctx, id, actor, "task.discard_suggested", map[string]any{"id": id, "reason": reason})
return s.setReady(ctx, id, actor, api.TaskReadyDiscard, "task.discard_suggested", map[string]any{"id": id, "reason": reason})
}
func (s *Store) emitActive(ctx context.Context, id, actor, kind string, payload map[string]any) error {
func (s *Store) setReady(ctx context.Context, id, actor string, ready api.TaskReady, kind string, payload map[string]any) error {
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
projectID := ""
err := tx.QueryRowContext(ctx, `SELECT project_id FROM tasks WHERE id = ? AND status = ?`, id, string(api.TaskStatusActive)).Scan(&projectID)
err := tx.QueryRowContext(ctx, `UPDATE tasks SET ready = ? WHERE id = ? AND status = ? RETURNING project_id`, string(ready), id, string(api.TaskStatusActive)).Scan(&projectID)
if errors.Is(err, sql.ErrNoRows) {
return ErrNotFound
}
@@ -1491,7 +1491,7 @@ func (s *Store) ClearReviewRequests(ctx context.Context) error {
const projectColumns = `id, name, repo_path, default_branch, remote, created_by, created_at`
const taskColumns = `id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, closed_at, merge_commit, todo_item, forked_from, forked_at, merge_queued_at, workflow_name, workflow_run, workflow_stage, parent_task_id, parent_merge_by, merge_after_review_by != '', state, merging_by != '' OR finalizing != '', discard_state != '' AND status = 'active', (SELECT coalesce(max(seq), 0) FROM events WHERE events.task_id = tasks.id AND kind = 'turn.ended' AND json_extract(payload, '$.summary') = 1)`
const taskColumns = `id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, closed_at, merge_commit, todo_item, forked_from, forked_at, merge_queued_at, workflow_name, workflow_run, workflow_stage, parent_task_id, parent_merge_by, merge_after_review_by != '', state, merging_by != '' OR finalizing != '', discard_state != '' AND status = 'active', (SELECT coalesce(max(seq), 0) FROM events WHERE events.task_id = tasks.id AND kind = 'turn.ended' AND json_extract(payload, '$.summary') = 1), ready`
const sessionColumns = `id, coalesce(task_id, ''), owner, vendor, model, vendor_session_id, state, role, member, created_by, created_at, forked_from, forked_at, subagents`
@@ -1526,11 +1526,16 @@ func scanTask(row scanner) (api.Task, error) {
parentTaskID := ""
parentMergeBy := ""
taskState := ""
err := row.Scan(&t.Id, &t.ProjectId, &t.Title, &t.MergeTitle, &t.Branch, &t.WorktreePath, &t.BaseRef, &t.PortBase, &t.Color, &status, &t.CreatedBy, &createdAt, &closedAt, &mergeCommit, &todoItem, &forkedFrom, &forkedAt, &mergeQueuedAt, &workflowName, &workflowRun, &workflowStage, &parentTaskID, &parentMergeBy, &t.MergeAfterReview, &taskState, &t.Merging, &t.Discarding, &t.SummarySeq)
ready := ""
err := row.Scan(&t.Id, &t.ProjectId, &t.Title, &t.MergeTitle, &t.Branch, &t.WorktreePath, &t.BaseRef, &t.PortBase, &t.Color, &status, &t.CreatedBy, &createdAt, &closedAt, &mergeCommit, &todoItem, &forkedFrom, &forkedAt, &mergeQueuedAt, &workflowName, &workflowRun, &workflowStage, &parentTaskID, &parentMergeBy, &t.MergeAfterReview, &taskState, &t.Merging, &t.Discarding, &t.SummarySeq, &ready)
if err != nil {
return t, err
}
t.State = api.TaskState(taskState)
if ready != "" {
r := api.TaskReady(ready)
t.Ready = &r
}
if parentTaskID != "" {
t.ParentTaskId = &parentTaskID
}
+1 -1
View File
@@ -512,7 +512,7 @@ struct StateMark: View {
switch state.kind {
case .working, .merging:
Spinner(color: color)
case .answer:
case .answer, .ready:
StateDot(filled: Palette.warn)
default:
StateDot(filled: nil)
+6 -5
View File
@@ -98,16 +98,17 @@ private struct ProjectBlock: View {
}
}
private func nested(_ active: [ByreTask]) -> [(task: ByreTask, depth: Int)] {
@MainActor
private func nested(_ store: Store, _ active: [ByreTask]) -> [(task: ByreTask, depth: Int)] {
let ids = Set(active.map(\.id))
var out: [(task: ByreTask, depth: Int)] = []
func add(_ task: ByreTask, _ depth: Int) {
out.append((task, depth))
for child in active.filter({ $0.parentTaskId == task.id }).reversed() {
for child in store.byRank(active.filter({ $0.parentTaskId == task.id }).reversed()) {
add(child, depth + 1)
}
}
for task in active where task.parentTaskId == nil || !ids.contains(task.parentTaskId!) {
for task in store.byRank(active.filter { $0.parentTaskId == nil || !ids.contains($0.parentTaskId!) }) {
add(task, 0)
}
return out
@@ -125,7 +126,7 @@ private struct TaskRows: View {
.padding(.vertical, 6)
} else {
VStack(alignment: .leading, spacing: 0) {
ForEach(nested(active), id: \.task.id) { row in
ForEach(nested(store, active), id: \.task.id) { row in
TaskRow(task: row.task, depth: row.depth)
}
}
@@ -197,7 +198,7 @@ private struct TaskRow: View {
}
Text(ts.label)
.font(Fonts.font(11))
.foregroundStyle(ts.kind == .answer ? Palette.warn : Palette.muted)
.foregroundStyle(ts.needsYou ? Palette.warn : Palette.muted)
.help(ts.title)
}
}
+44 -2
View File
@@ -22,12 +22,16 @@ private let routeHash = Re(#"^#/(task|project)/(\w+)(?:/(\w+))?$"#)
struct TaskState {
enum Kind {
case answer, merging, held, working, idle
case answer, merging, held, working, ready, idle
}
let kind: Kind
let label: String
let title: String
var needsYou: Bool {
kind == .answer || kind == .ready
}
}
private let workingTitles: [ByreTask.StatePayload: (label: String, title: String)] = [
@@ -222,9 +226,42 @@ final class Store {
if let working = workingTitles[task.state] {
return TaskState(kind: .working, label: working.label, title: working.title)
}
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")
}
func taskRank(_ task: ByreTask) -> Int {
if task.discarding {
return 4
}
switch taskState(task).kind {
case .answer: return 0
case .ready: return 1
case .idle: return 2
case .working: return 3
case .merging, .held: return 4
}
}
func byRank(_ tasks: [ByreTask]) -> [ByreTask] {
tasks.enumerated()
.sorted { a, b in
let ra = taskRank(a.element), rb = taskRank(b.element)
if ra != rb {
return ra < rb
}
return a.offset < b.offset
}
.map(\.element)
}
func currentLead() -> AgentSession? {
leadSessions.last(where: { $0.state != .completed }) ?? leadSessions.last
}
@@ -613,7 +650,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":
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 projectId = ev.projectId {
spawn("load tasks") {
try await self.loadTasks(projectId)
@@ -634,6 +671,11 @@ final class Store {
spawn("load inbox") {
try await self.loadInbox()
}
if let projectId = ev.projectId {
spawn("load tasks") {
try await self.loadTasks(projectId)
}
}
case "inbox.updated":
clearInbox(try! decodePayload(ev.payload, as: InboxItem.self))
spawn("load inbox") {
+5 -5
View File
@@ -183,11 +183,11 @@ final class SwitcherModel {
}
.enumerated()
.map { i, row in
(i: i, project: row.project, task: row.task, count: store.inbox.filter { $0.taskId == row.task.id }.count, visited: row.task.id == store.selectedTaskId ? Double.infinity : visits[row.task.id] ?? 0)
(i: i, project: row.project, task: row.task, count: store.inbox.filter { $0.taskId == row.task.id }.count, rank: store.taskRank(row.task), visited: row.task.id == store.selectedTaskId ? Double.infinity : visits[row.task.id] ?? 0)
}
.sorted { a, b in
if (a.count > 0) != (b.count > 0) {
return a.count > 0
if a.rank != b.rank {
return a.rank < b.rank
}
if a.visited != b.visited {
return a.visited < b.visited
@@ -409,7 +409,7 @@ private struct SwitcherRowView: View {
case .task(let project, let task, let count):
let ts = store.taskState(task)
let color = taskPalette[task.color]
StateDot(filled: ts.kind == .working || ts.kind == .merging ? Palette.ok : ts.kind == .answer ? Palette.warn : nil)
StateDot(filled: ts.kind == .working || ts.kind == .merging ? Palette.ok : ts.needsYou ? Palette.warn : nil)
.help(ts.title)
Text(taskTitle(project, task, color))
.lineLimit(1)
@@ -427,7 +427,7 @@ private struct SwitcherRowView: View {
}
Text(ts.label)
.font(Fonts.font(11))
.foregroundStyle(ts.kind == .answer ? Palette.warn : Palette.muted)
.foregroundStyle(ts.needsYou ? Palette.warn : Palette.muted)
.help(ts.title)
case .project(let p):
StateDot(filled: nil)