new summary
This commit is contained in:
+1
-1
@@ -102,7 +102,7 @@ Connections belong to `Servers`, not to the window: every saved server's store a
|
||||
- **Questions.** An open question's bubble in the transcript holds its card, rendered from its Markdown context with each choice's marker replaced by a clickable block (pick-one, sends at once, with any Other… text as notes) or checkbox (pick-any, with Submit), the "recommended" tag, image-choice grids, attachments, Let the agent decide and Other…. Arrow keys move between choices. A 409 shows its error. Once answered or dismissed, the bubble shrinks to the question and who answered what.
|
||||
- **Changes, Files, Workflow, Project, Status, Settings.** Including the pinned-snapshot stepper, open-diff memory, per-task place in Files, nested subtasks, TODO Start and Discuss, rate-limit pace bars and lead notes. The Workflow tab draws its stage graph natively from the `WorkflowRun` (stages as boxes coloured by state, `after` as edges, laid out top to bottom by depth) with the layout and drawing code from "Diagrams", fed from the run's data rather than Mermaid text.
|
||||
- **Terminal.** A terminal view attached to `GET /api/tasks/{taskId}/terminal` with `URLSessionWebSocketTask`: binary input and output, `TerminalSize` JSON on resize, close code 4000 for `shell ended: <status>` with New shell, 1011 for a start failure, reconnect after 2 s while the task is active, one socket per open tab and selected task. Colours come from the palette. Ctrl combinations typed in it go to the shell. The cursor is a steady block (`setCursorStyle(.steadyBlock)` when the view is made): SwiftTerm's blinking cursor restarts its Core Animation fade on every keypress, scheduled 0.7 s out, and on a ProMotion (variable refresh rate) display macOS then holds the window's screen update until that fade starts, so each typed letter appears about 0.7 s late. A program in the shell can still ask for a blinking cursor with DECSCUSR.
|
||||
- **Switcher.** The ⌘K overlay, also opened by clicking the task picker, centred below the picker: tasks with inbox items first, then least recently visited, the selected task last, the `name: title` project prefix, New task, Start in …, Start workflow… and its second step, projects, Escape stepping back, and the list scrolling to keep the highlighted row in view. Picking a task opens its Transcript scrolled to its oldest open question when it has open items, to its unread summary when it has one, and at the end otherwise.
|
||||
- **Switcher.** The ⌘K overlay, also opened by clicking the task picker, centred below the picker: tasks with inbox items first, then least recently visited, the selected task last, the `name: title` project prefix, New task, Start in …, Start workflow… and its second step, projects, Escape stepping back, and the list scrolling to keep the highlighted row in view. Picking a task opens its Transcript scrolled to its oldest open question when it has open items, and at the end otherwise.
|
||||
- **Merge and Discard.** The transcript head's Merge button is enabled once `GET /api/tasks/{taskId}/unmerged` reports commits or files, refetched 1.5 s after a tool result or turn end. `confirmMerge` (`MergeDialog.swift`): the editable commit title (at most 72 characters, kept across a warning link's detour), co-authors, warnings that refetch on the task's snapshot and review events and jump to the review or the oldest open question in the transcript, the parent-or-default-branch choice for subtasks, and Merge now / After review while the latest snapshot's review is running. It is centred in the right pane. Discard confirms below its button, then clears the focused task.
|
||||
|
||||
## Markdown
|
||||
|
||||
+2
-2
@@ -116,7 +116,7 @@ A team task has several agents working at once in its one worktree, branch and p
|
||||
- **Task mutex.** Members run in parallel; byre's own operations on the worktree are what can't, so every task has one in-memory mutex (`lockTask` in `internal/agents/critical.go`) around them: each turn-end commit and the stage record that goes with it (`turnEnded`), each snapshot (`runSnapshots`, taken before the snapshot state's lock), removing the task's worktree when it is discarded (`discardNow`) or merged into its parent (`closeMergedSubtask`, which holds the subtask's mutex across checking that its branch is in the parent's history and removing it), and every merge turn. A turn that is handed a merge prompt (`isMergeInPrompt`: Merge, Sync, or a subtask's merge-in, at the start of a turn in `prepareMessage` or mid-turn in `recordQueued`) takes the mutex for its session (`takeMergeTurn`) and holds it until that turn ends, so no other member's commit can conclude its unresolved merge; the squash, push and worktree removal of a finishing merge run before it is released (`finishMerge`). A merge turn that ends unfinished, or whose process exits mid-turn, runs `git merge --abort` first, so the merge is either concluded or undone. A member whose turn ends meanwhile waits on the mutex, then commits, or skips the commit when the task was closed while it waited. The mutex is in memory; on startup, before resuming sessions, `recoverMergeTurns` gives it back to each running first agent whose worktree has a merge in progress (`git.MergeInProgress`), since merge prompts only go to the first agent, and a resume that fails aborts that merge.
|
||||
- **Board.** Members get `post_to_board` (`text`) and `read_board` (`after_seq`). A post is a `board.posted` event on the task (actor `agent` with `member` and `model` in the payload and the poster's session; or the human's login; or the lead's actor) and is sent to every other member's live session as `"<name>" posted on the board:` and the text, through `Manager.Message` with actor `board`: an idle member starts a turn with it, a working one gets it after its next tool call (headed "While you were working, …"). Posts are delivered in order, one member after another, before the post call returns (`deliverPost`). The roster is every member that ever had a session (`teamSessions`, each member's live session or else its latest), so a post for a member whose first turn hasn't started yet (`SessionStarted`), whose session was just completed by a Compact handoff, or whose delivery fails (a conflict such as the task finishing a merge or being discarded, or its process not starting), is queued in `task_inputs` for that member instead, and every turn end of a team member delivers to the other idle members (`deliverTeam`). `POST /api/tasks/{id}/board` posts as the caller (204; 400 for a task without a team), and the lead's `send_message` to a team task posts as the lead. Each member's guidance names the team and its models, tells it to post only what adds something, that its final message goes to the human, to re-read files before editing them since the others change the same ones, and who finishes a stage. `sqlite3 byre.db "SELECT seq, actor, payload FROM events WHERE kind = 'board.posted' AND task_id = '<task>'"` lists a board.
|
||||
- **State and signals.** The task's state takes the running member's session first (`taskStateExpr`). A member's `turn.ended` carries `member`, and the lead's signal reads "<task>'s agent "<name>" finished a turn"; `list_tasks` lists each member's state and model, and `read_transcript` prefixes a member's lines with `[<name>]` and shows posts as `board post by …` lines, leaving out the `board` deliveries.
|
||||
- **UI.** The Transcript tab of a team task shows one member at a time: its header has a button per member (● while it runs), the pick kept in memory per task (`Store.pickedMembers`, the first member by default, and set to the summary's member when an unread summary is opened, read from its `turn.ended` in the task's feed or else fetched), and the transcript draws only that member's events and events with no session (`ChatModel.shows`), the board deliveries that woke it included. Compact and Interrupt act on the picked member. The composer posts to the board (`postToBoard`; text only, no model picker), and Merge, Sync and Discard are disabled while any member runs. The **Board** tab, shown only on a team task, lists the task's `board.posted` events from its event feed, oldest first, each with its author, model and time.
|
||||
- **UI.** The Transcript tab of a team task shows one member at a time: its header has a button per member (● while it runs), the pick kept in memory per task (`Store.pickedMembers`, the first member by default), and the transcript draws only that member's events and events with no session (`ChatModel.shows`), the board deliveries that woke it included. Compact and Interrupt act on the picked member. The composer posts to the board (`postToBoard`; text only, no model picker), and Merge, Sync and Discard are disabled while any member runs. The **Board** tab, shown only on a team task, lists the task's `board.posted` events from its event feed, oldest first, each with its author, model and time.
|
||||
- **Forks.** A fork of a team task continues the conversation of the member whose snapshot it was cut from, as a task with one agent.
|
||||
|
||||
## Running as a service
|
||||
@@ -282,7 +282,7 @@ The task switcher (⌘K, or the project ▸ task picker centred in the right pan
|
||||
|
||||
**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.
|
||||
|
||||
**Unread summaries.** A Task's `summary_seq` is the seq of its latest `turn.ended` event with `summary: true` (0 for none), read through the partial index `events_summary`, so the app knows of unread summaries without loading transcripts; a `turn.ended` with `summary: true` on the global stream raises it in the app. The switcher's and the Project tab's task rows show a **new summary** state label while `summary_seq` is above the seq the user has read (`unreadSummary` in `mac/Sources/Byre/Store.swift`), except on tasks of a workflow run, which close too soon for their summaries to be read. Picking such a row (in the switcher, only when the task has no open inbox items) points the right pane at the task's Transcript and scrolls it to that turn's final message (`Store.jump`, applied by the transcript once the event is drawn). Read state is per user on the server: `summary_reads` holds one highest-read seq per user and task. `GET /api/me/summary-reads` returns the caller's, for active tasks, as a map from task id to seq, and `PUT /api/tasks/{taskId}/summary-read` with `{seq}` raises it, emitting `summary.read` (`task_id`, `seq`) owned by the user only when it went up, so every Mac the user has byre open on clears the label. A summary counts as read only when the summary turn's end row is on screen in a transcript while that server's window is the key window of the active app (`summaryVisible` in `mac/Sources/Byre/Chat.swift`), so selecting the task on another tab leaves it unread. `sqlite3 byre.db 'SELECT * FROM summary_reads'` shows the read seqs.
|
||||
**Unread summaries.** A Task's `summary_seq` is the seq of its latest `turn.ended` event with `summary: true` (0 for none), read through the partial index `events_summary`, so the app knows of unread summaries without loading transcripts; a `turn.ended` with `summary: true` on the global stream raises it in the app. The switcher's and the Project tab's task rows show a **new summary** state label in place of Idle while the task is idle and `summary_seq` is above the seq the user has read (`unreadSummary` in `mac/Sources/Byre/Store.swift`), except on tasks of a workflow run, which close too soon for their summaries to be read. A summary isn't an attention item: picking such a row opens the Transcript at the end, like any task without open questions, findings or a ready bubble. Read state is per user on the server: `summary_reads` holds one highest-read seq per user and task. `GET /api/me/summary-reads` returns the caller's, for active tasks, as a map from task id to seq, and `PUT /api/tasks/{taskId}/summary-read` with `{seq}` raises it, emitting `summary.read` (`task_id`, `seq`) owned by the user only when it went up, so every Mac the user has byre open on clears the label. A summary counts as read only when the summary turn's end row is on screen in a transcript while that server's window is the key window of the active app (`summaryVisible` in `mac/Sources/Byre/Chat.swift`), so selecting the task on another tab leaves it unread. `sqlite3 byre.db 'SELECT * FROM summary_reads'` shows the read seqs.
|
||||
|
||||
**Task colours.** Each task has a colour, `tasks.color` (`color` in the API), an index into `taskPalette` (`mac/Sources/Byre/Format.swift`), the `Palette.task0` … `Palette.taskN` colours in `Palette.swift`, each with a light and a dark value, all at least 4.5:1 against the backgrounds so they work as text. `CreateTask` assigns it in the same transaction as the task's row: of the `store.TaskColors` colours, one no active task holds, and among those the one given out longest ago (the lowest `max(rowid)` of tasks with that colour, never-used first), so a new task doesn't take the colour of one just closed. Active tasks have distinct colours until more than `TaskColors` are active at once. `TaskColors` must match the number of `taskPalette` entries. The right pane sets its accent (the `paneAccent` environment value, the palette's accent when no task is selected) to the selected task's colour, which tints the picker's row, colours the task picker's text, the selected tab's underline, the composer's border and the running border and scanner. Everywhere a task is named it shows in its colour: task titles in the switcher, the Project tab and the Status tab, and task links, including any Markdown link to `#/task/<id>` or `#/task/<id>/<tab>`. The lead's guidance tells it to link every task it names that way, using `#/task/<id>/questions` when it points the human at a question, and clicking one points the right pane at the task, selecting the named tab if there is one.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user