Make every question blocking and drop inbox priority
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
# M7 — Inbox triage
|
||||
|
||||
- Human-facing task state
|
||||
Switcher and Project rows show one derived label instead of the raw session state, by precedence: "Needs your answer" (a blocked or gate item), "Merging" or "Merge held", "Error", "Working", "Idle".
|
||||
Switcher and Project rows show one derived label instead of the raw session state, by precedence: "Needs your answer" (an open inbox item), "Merging" or "Merge held", "Error", "Working", "Idle".
|
||||
- Unread summary marker
|
||||
Switcher and Project rows show a "New summary" marker, with text and an accessible label, when a task has a summary the user hasn't read. Selecting it opens the Transcript at that summary. Read state is per browser and per user, by event seq; a summary counts as read only when shown in a visible transcript or through "Mark seen", not by opening another tab or switching tasks. Task carries its latest summary seq so the marker survives reload without loading transcripts.
|
||||
- Answer refinements
|
||||
|
||||
+5
-11
@@ -715,7 +715,7 @@ paths:
|
||||
get:
|
||||
operationId: listInbox
|
||||
description: >
|
||||
Inbox items, highest priority first (blocked, gate, review, fyi), then oldest first.
|
||||
Inbox items, oldest first.
|
||||
Filters narrow the one query to a project's or a task's view.
|
||||
parameters:
|
||||
- { name: project_id, in: query, required: false, schema: { type: string } }
|
||||
@@ -748,7 +748,7 @@ paths:
|
||||
operationId: respondInbox
|
||||
description: >
|
||||
Answers one or more items in one submission. Answers reach the agent as one message once
|
||||
it is idle and none of its blocking questions are unanswered.
|
||||
it is idle and none of its questions are unanswered.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -873,10 +873,9 @@ components:
|
||||
NotificationPrefs:
|
||||
type: object
|
||||
description: Which new inbox items and finished turns notify this user in their open byre pages.
|
||||
required: [blocking_questions, questions, reports, errors, rate_limits]
|
||||
required: [questions, reports, errors, rate_limits]
|
||||
properties:
|
||||
blocking_questions: { type: boolean, description: "Questions asked with blocking: true. On by default." }
|
||||
questions: { type: boolean, description: Non-blocking questions. }
|
||||
questions: { type: boolean, description: Questions. On by default. }
|
||||
reports: { type: boolean, description: "Task turns that end with a summary (turn.ended with summary: true)." }
|
||||
errors: { type: boolean, description: session_error items. }
|
||||
rate_limits: { type: boolean, description: rate_limited items. }
|
||||
@@ -1219,7 +1218,7 @@ components:
|
||||
|
||||
InboxItem:
|
||||
type: object
|
||||
required: [id, project_id, task_id, agent_session_id, thread_id, kind, priority, blocking, payload, state, created_at, responses, reviews]
|
||||
required: [id, project_id, task_id, agent_session_id, thread_id, kind, payload, state, created_at, responses, reviews]
|
||||
properties:
|
||||
id: { type: string }
|
||||
project_id: { type: string }
|
||||
@@ -1227,11 +1226,6 @@ components:
|
||||
agent_session_id: { type: string }
|
||||
thread_id: { type: string }
|
||||
kind: { type: string, enum: [question, session_error, rate_limited] }
|
||||
priority:
|
||||
type: string
|
||||
enum: [blocked, gate, review, fyi]
|
||||
x-enum-varnames: [Blocked, Gate, ReviewPriority, Fyi]
|
||||
blocking: { type: boolean }
|
||||
payload:
|
||||
type: object
|
||||
description: >
|
||||
|
||||
+8
-8
@@ -104,11 +104,11 @@ A session runs on one of two vendors, picked by the model it is created with (`w
|
||||
|
||||
For Claude, byre chooses the session ID (`vendor_session_id`) up front. Codex picks its own thread id: a Codex session is created with an empty `vendor_session_id`, and byre stores the thread id when its first process starts (`startCodex`); a session with an id resumes it with `thread/resume`. Processes start on demand: the first message after a restart resumes the session (`--resume` for Claude). Sessions are `running` from the moment a turn is sent until it ends (Claude's `result`, Codex's `turn/completed`); on startup, every session still marked `running` was cut off mid-turn, and byre resumes it and sends a message telling the agent to re-check the working tree. Stopping the server kills all agent processes. Merging or discarding a task kills its sessions and marks them `completed`.
|
||||
|
||||
Every session gets byre's guidance (`guidance` in `internal/agents/guidance.go`): ask questions with `ask_human`, end each turn with a final message that summarizes it (including every departure from the plan), put everything the human needs in a blocking question's context since that turn has no summary, don't commit (byre commits each turn), and don't push, touch other branches or run git maintenance. A task agent's guidance also names its port range and tells it to do the setup AGENTS.md describes in a new worktree (see "Worktree setup and ports"). A task started from a `TODO.md` item gets one more line naming the item and telling the agent to remove it from `TODO.md` in its worktree when the work is done (`taskGuidance`; see "TODO"). For Claude it is passed as `--append-system-prompt`, which Claude Code records on a session's first request and reuses on resume, so a running session keeps the text it started with; a `UserPromptSubmit` hook also attaches it as `additionalContext` to every user turn, which reaches existing sessions too. For Codex it is the thread's `developerInstructions`, and every `turn/start` also carries it as `additionalContext` under the key `byre`. The guidance names byre's tools vendor-neutrally ("byre's ask_human tool"): Claude sees them as `mcp__byre__<name>`, Codex as `<name>` in the namespace `byre` (Codex reserves the `mcp__` prefix).
|
||||
Every session gets byre's guidance (`guidance` in `internal/agents/guidance.go`): ask questions with `ask_human`, end each turn with a final message that summarizes it (including every departure from the plan), put everything the human needs in a question's context since that turn has no summary, don't commit (byre commits each turn), and don't push, touch other branches or run git maintenance. A task agent's guidance also names its port range and tells it to do the setup AGENTS.md describes in a new worktree (see "Worktree setup and ports"). A task started from a `TODO.md` item gets one more line naming the item and telling the agent to remove it from `TODO.md` in its worktree when the work is done (`taskGuidance`; see "TODO"). For Claude it is passed as `--append-system-prompt`, which Claude Code records on a session's first request and reuses on resume, so a running session keeps the text it started with; a `UserPromptSubmit` hook also attaches it as `additionalContext` to every user turn, which reaches existing sessions too. For Codex it is the thread's `developerInstructions`, and every `turn/start` also carries it as `additionalContext` under the key `byre`. The guidance names byre's tools vendor-neutrally ("byre's ask_human tool"): Claude sees them as `mcp__byre__<name>`, Codex as `<name>` in the namespace `byre` (Codex reserves the `mcp__` prefix).
|
||||
|
||||
A turn whose final message asks the human something in prose is bounced once (`takeBounce` in `internal/agents/guidance.go`): if `ask_human` wasn't called during the turn and the final message has a sentence ending in `?` outside code spans, code blocks, quotes and blockquotes, the agent is told to ask through `ask_human` and carries on. For Claude this is a Stop hook (`bounceProseQuestion`) that blocks the stop; Claude Code reports the block as a "Stop hook error" notification, which is expected. For Codex, byre doesn't end its turn on `turn/completed`: it records the nudge as a `byre` `user.message` with `mid_turn: true` and starts another Codex turn with it, and only that turn's end ends byre's turn. The per-turn flags reset when the next user message is sent. An agent told explicitly to ask in plain text will refuse the bounce.
|
||||
|
||||
A turn's final message is its summary, and it lives only in the transcript: nothing is filed in the inbox, so the human reads it once. When a task turn ends normally (not an error, not interrupted, not a handoff) with non-empty `result` text and didn't call `ask_human` with `blocking` true, its `turn.ended` event carries `summary: true`. That flag drives the lead's "finished a turn" signal and the "Turn summaries" notification (see "Lead agent" and "Notifications"). A turn that asked a blocking question has no summary, since the final message comes after the question it explains; the guidance tells agents to put everything the human needs in the question's context. There is no report tool: models write a closing recap whatever they are told, so byre uses it rather than asking for a second one.
|
||||
A turn's final message is its summary, and it lives only in the transcript: nothing is filed in the inbox, so the human reads it once. When a task turn ends normally (not an error, not interrupted, not a handoff) with non-empty `result` text and didn't call `ask_human`, its `turn.ended` event carries `summary: true`. That flag drives the lead's "finished a turn" signal and the "Turn summaries" notification (see "Lead agent" and "Notifications"). A turn that asked a question has no summary, since the final message comes after the question it explains; the guidance tells agents to put everything the human needs in the question's context. There is no report tool: models write a closing recap whatever they are told, so byre uses it rather than asking for a second one.
|
||||
|
||||
Every turn starts as soon as it is sent; byre doesn't cap how many run at once. Whether a turn resumes the Claude conversation is decided by whether the session has ever sent one.
|
||||
|
||||
@@ -165,9 +165,9 @@ The **Project** tab is the dashboard of the right pane's project (the focused ta
|
||||
|
||||
## Inbox
|
||||
|
||||
Agents ask questions with the `ask_human` MCP tool. Each question carries a `context` with the background the human needs to answer without reading the transcript, and its choices are written inline in that context as Markdown list items: `- ( ) text` for pick-one choices, with exactly one `- (*) text` marking the recommendation, or `- [ ] text` for pick-any choices, with `- [x] text` marking the recommended ones. There is no separate list of options. byre parses the choices out of `context` (`internal/agents/choices.go`; list items inside code fences and blockquotes don't count) and stores their text in the payload as `options`, with `multiple` (pick-any) and `recommended`. The UI renders the context as Markdown with a radio button or checkbox in place of each choice's marker. The tool's description tells agents to keep everything about one choice (what it does, its example, code, trade-offs) in lines indented beneath that choice rather than in text above the list; those lines render inside the option, and only the marker line's text is the option. A malformed call (no `context` or `why_blocked`, fewer than two choices, pick-one and pick-any choices mixed, a pick-one question without exactly one recommendation, two choices with the same text, an unknown attachment kind, a foreign `thread_id`) is rejected with a message saying what to fix, and nothing is filed. The call returns the item's id as `question_id`. An agent withdraws a question it no longer needs answered (the human answered it in a chat message, say) with the `cancel_question` MCP tool and that id: an `open` question of its own session becomes `dismissed` with no `resolved_by` (its `inbox.updated` event has actor `agent`), which also stops a blocking one from holding back delivery; anything else is rejected with a message saying why. Each agent error (a turn that ends in error without a human interrupt, a process that dies mid-turn) also files an item.
|
||||
Agents ask questions with the `ask_human` MCP tool. Each question carries a `context` with the background the human needs to answer without reading the transcript, and its choices are written inline in that context as Markdown list items: `- ( ) text` for pick-one choices, with exactly one `- (*) text` marking the recommendation, or `- [ ] text` for pick-any choices, with `- [x] text` marking the recommended ones. There is no separate list of options. byre parses the choices out of `context` (`internal/agents/choices.go`; list items inside code fences and blockquotes don't count) and stores their text in the payload as `options`, with `multiple` (pick-any) and `recommended`. The UI renders the context as Markdown with a radio button or checkbox in place of each choice's marker. The tool's description tells agents to keep everything about one choice (what it does, its example, code, trade-offs) in lines indented beneath that choice rather than in text above the list; those lines render inside the option, and only the marker line's text is the option. A malformed call (no `context` or `why_blocked`, fewer than two choices, pick-one and pick-any choices mixed, a pick-one question without exactly one recommendation, two choices with the same text, an unknown attachment kind, a foreign `thread_id`) is rejected with a message saying what to fix, and nothing is filed. All questions are alike: the tool's description and its result tell the agent to end its turn after asking, and the answer arrives as its next message. The call returns the item's id as `question_id`. An agent withdraws a question it no longer needs answered (the human answered it in a chat message, say) with the `cancel_question` MCP tool and that id: an `open` question of its own session becomes `dismissed` with no `resolved_by` (its `inbox.updated` event has actor `agent`), which also stops it from holding back delivery; anything else is rejected with a message saying why. Each agent error (a turn that ends in error without a human interrupt, a process that dies mid-turn) also files an item.
|
||||
|
||||
`GET /api/inbox` is one query over open items, oldest first; `project_id` and `task_id` narrow it to a project or task view, and `state` picks another state. Blocking questions and errors are `blocked`; non-blocking questions are `fyi`. The Inbox tab is task-specific: it shows one of the selected task's open items at a time, the oldest, and the next one once that is answered or dismissed; it shows nothing when no task is selected. The tab is hidden while the task has no open items, unless it is selected. While the selected task has open items, the Inbox tab's button is highlighted in the warn colours (`.attention` in `web/style.css`) and carries their count. Answering or dismissing the task's last open item from the Inbox tab switches the pane to the Transcript tab. The other way round, a new question from the selected task arriving while the Transcript tab is shown switches the pane to the Inbox tab; questions already open when the page loaded don't.
|
||||
`GET /api/inbox` is one query over open items, oldest first; `project_id` and `task_id` narrow it to a project or task view, and `state` picks another state. The Inbox tab is task-specific: it shows one of the selected task's open items at a time, the oldest, and the next one once that is answered or dismissed; it shows nothing when no task is selected. The tab is hidden while the task has no open items, unless it is selected. While the selected task has open items, the Inbox tab's button is highlighted in the warn colours (`.attention` in `web/style.css`) and carries their count. Answering or dismissing the task's last open item from the Inbox tab switches the pane to the Transcript tab. The other way round, a new question from the selected task arriving while the Transcript tab is shown switches the pane to the Inbox tab; questions already open when the page loaded don't.
|
||||
|
||||
`POST /api/inbox/responses` answers any number of items in one submission. Response types and what they do to the item:
|
||||
|
||||
@@ -177,13 +177,13 @@ Agents ask questions with the `ask_human` MCP tool. Each question carries a `con
|
||||
| `other` (free text in `text`: an answer, a question back, or new instructions) | questions, errors | `answered` |
|
||||
| `dismiss` | errors | `dismissed` |
|
||||
|
||||
Answers reach the agent as one message holding every undelivered `option` and `other` response of the session (`deliveryMessage` in `internal/agents/inbox.go`), never while one of its blocking questions is still open; until then they stay held (`inbox_responses.delivered_at` empty). While a turn is running, the task session's PostToolUse hook (`afterTool` in `internal/agents/snapshots.go`, through `deliverMidTurn`) hands them over after the agent's next tool call as the hook's `additionalContext`, after any queued messages (see "Agent sessions"), so the agent reads them alongside that tool's result without being interrupted (for Codex, after each completed tool item, `deliverMidTurn` hands them over with `turn/steer` instead); the `user.message` event recording it carries `mid_turn: true` and no `head`, and the transcript doesn't treat it as a turn start. A turn that makes no further tool call leaves them to `Deliver`, which runs after each submission and when a turn ends, and sends them as a new turn once the session is `idle`. The log traces each answer: `inbox response recorded` when it is stored, `deliver held` with the reason, `deliver sent mid-turn`, `deliver sent` with the session's state and whether its agent process had exited or byre was closing, and `undelivered responses` with a reason wherever a session has held answers when its turn ends in a handoff or merge, its agent process ends, startup resumes it, or startup finds it idle. `sqlite3 byre.db "SELECT * FROM inbox_responses WHERE delivered_at IS NULL"` lists the answers held now.
|
||||
Answers reach the agent as one message holding every undelivered `option` and `other` response of the session (`deliveryMessage` in `internal/agents/inbox.go`), never while one of its questions is still open and unanswered (`AwaitingHuman` in `internal/store/inbox.go`); until then they stay held (`inbox_responses.delivered_at` empty). While a turn is running, the task session's PostToolUse hook (`afterTool` in `internal/agents/snapshots.go`, through `deliverMidTurn`) hands them over after the agent's next tool call as the hook's `additionalContext`, after any queued messages (see "Agent sessions"), so the agent reads them alongside that tool's result without being interrupted (for Codex, after each completed tool item, `deliverMidTurn` hands them over with `turn/steer` instead); the `user.message` event recording it carries `mid_turn: true` and no `head`, and the transcript doesn't treat it as a turn start. A turn that makes no further tool call leaves them to `Deliver`, which runs after each submission and when a turn ends, and sends them as a new turn once the session is `idle`. The log traces each answer: `inbox response recorded` when it is stored, `deliver held` with the reason, `deliver sent mid-turn`, `deliver sent` with the session's state and whether its agent process had exited or byre was closing, and `undelivered responses` with a reason wherever a session has held answers when its turn ends in a handoff or merge, its agent process ends, startup resumes it, or startup finds it idle. `sqlite3 byre.db "SELECT * FROM inbox_responses WHERE delivered_at IS NULL"` lists the answers held now.
|
||||
|
||||
## Notifications
|
||||
|
||||
An open byre page shows a browser notification for each new inbox item, raised by the page itself from the `inbox.created` events on its SSE stream (`notifyInbox` in `web/src/notifications.ts`). With no byre page open, nothing notifies. byre has no service worker and never uses one; on load the page unregisters any worker left in the browser from earlier versions and, if one was controlling the page, reloads.
|
||||
|
||||
- **Preferences.** `users.notification_prefs` holds which item kinds notify the user, returned as `notification_prefs` on `GET /api/me` and set with `PUT /api/me/notifications`: `blocking_questions` (on by default), `questions` (non-blocking), `reports` (task turns that end with `summary: true` on `turn.ended`, labelled "Turn summaries"), `errors` (`session_error`) and `rate_limits`. The page checks them against each item or `turn.ended` event as it arrives.
|
||||
- **Preferences.** `users.notification_prefs` holds which item kinds notify the user, returned as `notification_prefs` on `GET /api/me` and set with `PUT /api/me/notifications`: `questions` (on by default), `reports` (task turns that end with `summary: true` on `turn.ended`, labelled "Turn summaries"), `errors` (`session_error`) and `rate_limits`. The page checks them against each item or `turn.ended` event as it arrives.
|
||||
- **Content.** The title is `byre · <task title>` and the body the question (or the turn summary's first line, the error, or "Rate limited"), cut at 200 characters. The notification's tag is the item's ID, or `turn-<seq>` for a turn summary, so several byre pages open in one browser show it once.
|
||||
- **Clicking** a notification focuses the page and points the right pane at the item's task.
|
||||
|
||||
@@ -191,7 +191,7 @@ The left pane's **Settings** tab asks the browser for notification permission an
|
||||
|
||||
The Inbox tab shows one item at a time, the task's oldest, filling the tab without a card frame; the next appears when it is answered. Each item is answered on its own; there is no batch submission. A pick-one question's choices are clickable blocks, and clicking one sends that answer at once. A choice's block (or a pick-any choice's checkbox label) holds the whole list item: its first line, which is the choice's text, and everything under it, such as an example's paragraph or code block. A pick-any question's choices are checkboxes, sent with the Submit button at the bottom of the card. Below the choices, an "Other…" block in the same style opens the only text field. A card has at most one Submit button: on a pick-any question it sends the checked choices with the Other text alongside (one `option` response), or the Other text alone as `other` when nothing is checked. An error has a "Reply…" block (`other`) and a Dismiss button. The Other and Reply text boxes send with the Submit button under them or on Enter (Shift+Enter for a newline), like the message box, and fold back into their block when left empty. The list updates in place: a card stays attached while its item is unchanged, so task and inbox updates from other agents don't pull focus out of a text box being typed in.
|
||||
|
||||
There is no snoozing. The `snoozed_until` and `snooze_until` columns are still in the schema, always empty, so builds from older branches keep working against the same database; nothing reads them.
|
||||
There is no snoozing. The `snoozed_until` and `snooze_until` columns are still in the schema, always empty, so builds from older branches keep working against the same database; nothing reads them. For the same reason `inbox_items` keeps its `priority` and `blocking` columns, which nothing reads or writes; new rows take their defaults (0 and 1, which older builds read as a blocking question).
|
||||
|
||||
Every Markdown view (inbox items and the transcript) renders a line `<details><summary>Title</summary>` (or `<details>` with the `<summary>` on the next line), Markdown content, and a line `</details>` as a collapsed section (`web/src/markdown.ts`; sections nest) showing only the title; session guidance and the `ask_human` schema tell agents to put long supporting detail in them.
|
||||
|
||||
@@ -199,7 +199,7 @@ Markdown images (``, or ``; the plain form also accepts
|
||||
|
||||
A code block fenced as `mermaid`, and an inbox `diagram` attachment, render as a Mermaid diagram (`web/src/mermaid.ts`). The library is vendored: `web/package.json` pins `mermaid` as a devDependency, and `go generate ./web` copies `node_modules/mermaid/dist/mermaid.min.js` and its LICENSE into `web/vendor/`, which is committed and embedded. To upgrade, change the pinned version, `npm --prefix web install`, and regenerate. Nothing loads it until the first diagram is drawn; that injects one `<script src="/vendor/mermaid.min.js">` and initializes Mermaid with `securityLevel: "strict"` and the `base` theme, coloured from the custom properties in `web/style.css` as they resolve at that moment (so a light/dark switch applies from the next page load). Each diagram shows its source until its SVG is ready; source Mermaid rejects stays as source with "diagram not rendered: <error>" under it. The endpoint (`internal/server/images.go`) serves PNG, JPEG, GIF, WebP and SVG by extension, resolves symlinks on both the worktree and the file and answers 403 for anything outside the worktree, 404 for a missing file, 400 for another extension or a non-file, and 409 once the task is closed (its worktree is gone). Responses carry `X-Content-Type-Options: nosniff` and a sandboxing `Content-Security-Policy`, so an SVG opened directly runs no script, and `Cache-Control: no-cache` with `Last-Modified`, so a changed file is refetched.
|
||||
|
||||
Answers reach the agent as one message, listing each answer under the question or error it responds to, once the session is idle and none of its blocking questions are still waiting for the human. An `other` answer to a question tells the agent that if it asks something back, it should answer with `ask_human` using the item's `thread_id`. `thread_id` only groups items: filing an item never changes any other, so several questions on one thread stay open until each is answered, withdrawn or dismissed. Nothing sets the `superseded` state; it stays in the spec because old items hold it. Every item change is an `inbox.created` or `inbox.updated` event carrying the whole item, including who resolved it.
|
||||
Answers reach the agent as one message, listing each answer under the question or error it responds to, once the session is idle and none of its questions are still waiting for the human. An `other` answer to a question tells the agent that if it asks something back, it should answer with `ask_human` using the item's `thread_id`. `thread_id` only groups items: filing an item never changes any other, so several questions on one thread stay open until each is answered, withdrawn or dismissed. Nothing sets the `superseded` state; it stays in the spec because old items hold it. Every item change is an `inbox.created` or `inbox.updated` event carrying the whole item, including who resolved it.
|
||||
|
||||
## Changes
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
const guidance = `You are running inside byre. The human reads your work in byre's web UI, not a terminal.
|
||||
- Ask every question with byre's ask_human tool, never in prose.
|
||||
- End every turn with a short final message for the human: what you did, anything you departed from in the plan or instructions, risks, and what's next. byre shows it as the turn's summary at the end of the transcript. State every departure from the plan.
|
||||
- A turn that asks a blocking question has no summary; put everything the human needs in the question's context.
|
||||
- A turn that asks a question has no summary; put everything the human needs in the question's context.
|
||||
- In that final message and in ask_human context, put long supporting detail (logs, full lists, data) in collapsed sections the human expands on demand: a line <details><summary>Title</summary>, the Markdown content, then a line </details>.
|
||||
- Don't commit. byre commits everything in the worktree at the end of each turn, using the turn's final message.
|
||||
- Don't push, don't switch or touch other branches, and don't run git maintenance (gc, prune, worktree prune). byre handles merging and pushing.`
|
||||
|
||||
+11
-28
@@ -25,7 +25,6 @@ type askArgs struct {
|
||||
Question string `json:"question"`
|
||||
WhyBlocked string `json:"why_blocked"`
|
||||
Attachments []api.Attachment `json:"attachments"`
|
||||
Blocking *bool `json:"blocking"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
}
|
||||
|
||||
@@ -43,8 +42,7 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
"its first line is a short name, and the lines indented beneath it say what it would concretely do, " +
|
||||
"its example, code, commands and trade-offs, so the human never has to match a paragraph above to an option below. " +
|
||||
"Text above the list covers only what all the choices share. " +
|
||||
"If blocking is true, end your turn after asking; " +
|
||||
"the answer arrives as your next message. If blocking is false, continue with work that doesn't depend on the answer. " +
|
||||
"End your turn after asking; the answer arrives as your next message. " +
|
||||
"One call is one decision, answered by picking from its own choices. When you have several decisions, such as a design with several choices, " +
|
||||
"never bundle them into one call that asks for approval of them all: call this once per decision, each with its own context and choices; they are answered together. " +
|
||||
"To answer a follow-up question from the human, call this again with the thread_id they gave you.",
|
||||
@@ -70,10 +68,9 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
},
|
||||
"required": ["kind"]
|
||||
}},
|
||||
"blocking": {"type": "boolean"},
|
||||
"thread_id": {"type": "string"}
|
||||
},
|
||||
"required": ["context", "question", "why_blocked", "blocking"]
|
||||
"required": ["context", "question", "why_blocked"]
|
||||
}`),
|
||||
Handler: func(ctx context.Context, raw json.RawMessage) (string, error) {
|
||||
return m.ask(ctx, l, raw)
|
||||
@@ -99,11 +96,6 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
thread = id
|
||||
}
|
||||
|
||||
priority := api.Fyi
|
||||
if *args.Blocking {
|
||||
priority = api.Blocked
|
||||
}
|
||||
|
||||
attachments := args.Attachments
|
||||
if attachments == nil {
|
||||
attachments = []api.Attachment{}
|
||||
@@ -129,21 +121,17 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
"attachments": attachments,
|
||||
}
|
||||
|
||||
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, priority, *args.Blocking, store.ToPayload(payload)))
|
||||
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, store.ToPayload(payload)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
l.asked = true
|
||||
l.askedBlock = l.askedBlock || *args.Blocking
|
||||
m.mu.Unlock()
|
||||
|
||||
cancel := fmt.Sprintf("If the human answers it some other way, such as in a chat message, withdraw it with cancel_question and question_id %q.", id)
|
||||
if *args.Blocking {
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. It is blocking: end your turn now. The answer will arrive as your next message. %s", id, cancel), nil
|
||||
}
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. Continue with work that doesn't depend on it; the answer will arrive as a later message. %s", id, cancel), nil
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. End your turn now. The answer will arrive as your next message. "+
|
||||
"If the human answers it some other way, such as in a chat message, withdraw it with cancel_question and question_id %q.", id, id), nil
|
||||
}
|
||||
|
||||
type cancelArgs struct {
|
||||
@@ -233,9 +221,6 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
if radios == len(choices) && len(choices) > 0 && recommendedRadios != 1 {
|
||||
problems = append(problems, "mark exactly one pick-one choice as recommended with `- (*) choice`")
|
||||
}
|
||||
if args.Blocking == nil {
|
||||
problems = append(problems, "blocking is required")
|
||||
}
|
||||
for i, a := range args.Attachments {
|
||||
if !slices.Contains(attachmentKinds, a.Kind) {
|
||||
problems = append(problems, fmt.Sprintf("attachments[%d].kind %q is not one of %v", i, a.Kind, attachmentKinds))
|
||||
@@ -262,7 +247,7 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
|
||||
func (m *Manager) fileError(l *live, msg string) {
|
||||
id := store.NewID()
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, api.Blocked, true, map[string]any{"error": msg}))
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, map[string]any{"error": msg}))
|
||||
if err != nil {
|
||||
slog.Error("file session error", "session", l.id, "err", err)
|
||||
}
|
||||
@@ -271,13 +256,13 @@ func (m *Manager) fileError(l *live, msg string) {
|
||||
func (m *Manager) fileRateLimited(l *live, info map[string]any, failure string) {
|
||||
id := store.NewID()
|
||||
payload := map[string]any{"vendor": string(l.vendor), "rate_limit": info, "error": failure}
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, api.Blocked, true, payload))
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, payload))
|
||||
if err != nil {
|
||||
slog.Error("file rate limit", "session", l.id, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, priority api.InboxItemPriority, blocking bool, payload map[string]any) api.InboxItem {
|
||||
func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, payload map[string]any) api.InboxItem {
|
||||
return api.InboxItem{
|
||||
Id: id,
|
||||
ProjectId: l.projectID,
|
||||
@@ -285,8 +270,6 @@ func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, pr
|
||||
AgentSessionId: l.id,
|
||||
ThreadId: thread,
|
||||
Kind: kind,
|
||||
Priority: priority,
|
||||
Blocking: blocking,
|
||||
Payload: payload,
|
||||
State: api.Open,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
@@ -329,7 +312,7 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
|
||||
return err
|
||||
}
|
||||
if waiting > 0 {
|
||||
slog.Info("deliver held: blocking question waiting", "session", sessionID, "waiting", waiting, "responses", ids)
|
||||
slog.Info("deliver held: question waiting", "session", sessionID, "waiting", waiting, "responses", ids)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -399,11 +382,11 @@ func (m *Manager) responsesMidTurn(ctx context.Context, l *live) string {
|
||||
|
||||
waiting, err := m.store.AwaitingHuman(ctx, l.id)
|
||||
if err != nil {
|
||||
slog.Error("count blocking questions", "session", l.id, "err", err)
|
||||
slog.Error("count waiting questions", "session", l.id, "err", err)
|
||||
return ""
|
||||
}
|
||||
if waiting > 0 {
|
||||
slog.Info("deliver held mid-turn: blocking question waiting", "session", l.id, "waiting", waiting, "responses", ids)
|
||||
slog.Info("deliver held mid-turn: question waiting", "session", l.id, "waiting", waiting, "responses", ids)
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
const leadGuidance = `You are the human's lead agent in byre, shown in the left pane of byre's web UI. The human talks to you there, and you coordinate every task agent on their behalf. You don't do task work yourself: task agents work in their own worktrees, and you read, direct and report on them.
|
||||
- Signals: byre sends you, as messages from byre, what happens across tasks: questions and errors that task agents file, turns they finish with their final message, questions the human answered, tasks created, merged or discarded. Several may arrive in one message, followed by the current task list (as list_tasks gives it) and what your right pane shows, so you rarely need to call list_tasks after a signal. The human doesn't see signals. Messages from the human arrive separately.
|
||||
- Don't respond to what the human just did. A signal about their own action (a question they answered, a task they created, merged or discarded) tells them nothing new: don't report, confirm or comment on it. Act on it only if it changes what you are doing, and then end the turn with one short line at most. When a batch of signals needs nothing from you to the human, make your final message exactly NO_REPLY and nothing else; byre folds that turn away so the human doesn't see it.
|
||||
- "Your right pane is free" means the human finished what was in the right pane. Show them the next thing that needs them, most urgent first (blocked questions and errors, then finished turns, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's project tab, then post a short status: one line per active task (what it's doing or waiting on), then up to three TODO items you'd start next (from list_tasks), each with a one-line reason. Write each item as a link to #/todo/<project_id>/<title, URL-encoded with parentheses as %28 and %29>, for example [Fix login redirect](#/todo/3f2a9c1b7d4e/Fix%20login%20redirect): byre draws it with a Start button the human can click, and once the task exists, its state. Start one with start_todo only when the human picks it. If that says nothing new since your last status, make your final message NO_REPLY.
|
||||
- "Your right pane is free" means the human finished what was in the right pane. Show them the next thing that needs them, most urgent first (questions and errors, then finished turns, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's project tab, then post a short status: one line per active task (what it's doing or waiting on), then up to three TODO items you'd start next (from list_tasks), each with a one-line reason. Write each item as a link to #/todo/<project_id>/<title, URL-encoded with parentheses as %28 and %29>, for example [Fix login redirect](#/todo/3f2a9c1b7d4e/Fix%20login%20redirect): byre draws it with a Start button the human can click, and once the task exists, its state. Start one with start_todo only when the human picks it. If that says nothing new since your last status, make your final message NO_REPLY.
|
||||
- Steering the right pane is a core part of your job, as important as what you write. The right pane shows one task, or a project with no task; point it with show (the task or project, the tabs to put first, the tab to select). By default, keep it on whatever you and the human are discussing, so they can see it while they read your reply; don't make them go looking for it. Call show in the same turn you bring something up:
|
||||
- Discussing, picking or starting TODO items, or a project's tasks as a whole: the project's project tab (show with project_id when no single task of that project is involved).
|
||||
- A question that needs the human: that task's inbox tab, with one line naming it and what you recommend.
|
||||
@@ -462,7 +462,7 @@ func (m *Manager) itemText(ctx context.Context, item api.InboxItem) string {
|
||||
switch item.Kind {
|
||||
case api.Question:
|
||||
b := &strings.Builder{}
|
||||
fmt.Fprintf(b, "%s asked question %s (%s): %v\n", label, item.Id, item.Priority, p["question"])
|
||||
fmt.Fprintf(b, "%s asked question %s: %v\n", label, item.Id, p["question"])
|
||||
recommended := map[string]bool{}
|
||||
for _, r := range anyStrings(p["recommended"]) {
|
||||
recommended[r] = true
|
||||
|
||||
@@ -107,7 +107,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
m.mu.Unlock()
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("Responded to %s. The agent gets it once it is idle and has no other blocking question waiting.", c.ItemId), nil
|
||||
return fmt.Sprintf("Responded to %s. The agent gets it once it is idle and has no other question waiting.", c.ItemId), nil
|
||||
}),
|
||||
|
||||
tool("send_message",
|
||||
@@ -563,18 +563,13 @@ func (m *Manager) listTasksText(ctx context.Context) (string, error) {
|
||||
agent += " on " + sess.Model
|
||||
}
|
||||
}
|
||||
blocked, fyi := 0, 0
|
||||
open := 0
|
||||
for _, i := range items {
|
||||
if i.TaskId != t.Id {
|
||||
continue
|
||||
}
|
||||
if i.Priority == api.Blocked {
|
||||
blocked++
|
||||
} else {
|
||||
fyi++
|
||||
if i.TaskId == t.Id {
|
||||
open++
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "- %s %q: %s; inbox %d blocked, %d fyi; worktree %s", t.Id, t.Title, agent, blocked, fyi, t.WorktreePath)
|
||||
fmt.Fprintf(b, "- %s %q: %s; inbox %d open; worktree %s", t.Id, t.Title, agent, open, t.WorktreePath)
|
||||
if t.TodoItem != nil {
|
||||
fmt.Fprintf(b, "; from TODO item %q", *t.TodoItem)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ type live struct {
|
||||
stopping bool
|
||||
interrupted bool
|
||||
asked bool
|
||||
askedBlock bool
|
||||
bounced bool
|
||||
compacting bool
|
||||
wantCompact bool
|
||||
@@ -489,7 +488,6 @@ func (m *Manager) message(ctx context.Context, l *live, actor, text string, imag
|
||||
m.mu.Lock()
|
||||
l.interrupted = false
|
||||
l.asked = false
|
||||
l.askedBlock = false
|
||||
l.bounced = false
|
||||
l.wantCompact = false
|
||||
l.compacting = compacting
|
||||
@@ -771,7 +769,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
interrupted := l.interrupted
|
||||
rateLimited := l.rateLimited
|
||||
compacting := l.compacting
|
||||
askedBlock := l.askedBlock
|
||||
asked := l.asked
|
||||
m.mu.Unlock()
|
||||
|
||||
finished := !res.isError && !interrupted && strings.TrimSpace(res.result) != ""
|
||||
@@ -788,7 +786,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
switch {
|
||||
case handoff:
|
||||
payload["handoff"] = true
|
||||
case finished && !compacting && !askedBlock:
|
||||
case finished && !compacting && !asked:
|
||||
payload["summary"] = true
|
||||
}
|
||||
err = m.emit(ctx, l, agentActor, "turn.ended", payload)
|
||||
|
||||
+172
-206
@@ -204,30 +204,6 @@ func (e InboxItemKind) Valid() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for InboxItemPriority.
|
||||
const (
|
||||
Blocked InboxItemPriority = "blocked"
|
||||
Fyi InboxItemPriority = "fyi"
|
||||
Gate InboxItemPriority = "gate"
|
||||
ReviewPriority InboxItemPriority = "review"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the InboxItemPriority enum.
|
||||
func (e InboxItemPriority) Valid() bool {
|
||||
switch e {
|
||||
case Blocked:
|
||||
return true
|
||||
case Fyi:
|
||||
return true
|
||||
case Gate:
|
||||
return true
|
||||
case ReviewPriority:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for InboxResponseType.
|
||||
const (
|
||||
Dismiss InboxResponseType = "dismiss"
|
||||
@@ -605,14 +581,12 @@ type Focus struct {
|
||||
// InboxItem defines model for InboxItem.
|
||||
type InboxItem struct {
|
||||
AgentSessionId string `json:"agent_session_id"`
|
||||
Blocking bool `json:"blocking"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Id string `json:"id"`
|
||||
Kind InboxItemKind `json:"kind"`
|
||||
|
||||
// Payload question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error.
|
||||
Payload map[string]interface{} `json:"payload"`
|
||||
Priority InboxItemPriority `json:"priority"`
|
||||
ProjectId string `json:"project_id"`
|
||||
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
||||
ResolvedBy *string `json:"resolved_by,omitempty"`
|
||||
@@ -628,9 +602,6 @@ type InboxItem struct {
|
||||
// InboxItemKind defines model for InboxItem.Kind.
|
||||
type InboxItemKind string
|
||||
|
||||
// InboxItemPriority defines model for InboxItem.Priority.
|
||||
type InboxItemPriority string
|
||||
|
||||
// InboxRespond defines model for InboxRespond.
|
||||
type InboxRespond struct {
|
||||
Responses []InboxResponseCreate `json:"responses"`
|
||||
@@ -682,13 +653,10 @@ type MessageCreate struct {
|
||||
|
||||
// NotificationPrefs Which new inbox items and finished turns notify this user in their open byre pages.
|
||||
type NotificationPrefs struct {
|
||||
// BlockingQuestions Questions asked with blocking: true. On by default.
|
||||
BlockingQuestions bool `json:"blocking_questions"`
|
||||
|
||||
// Errors session_error items.
|
||||
Errors bool `json:"errors"`
|
||||
|
||||
// Questions Non-blocking questions.
|
||||
// Questions Questions. On by default.
|
||||
Questions bool `json:"questions"`
|
||||
|
||||
// RateLimits rate_limited items.
|
||||
@@ -2926,179 +2894,177 @@ 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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",
|
||||
"xys/2uMZe6tHdxjynYobfvz4fwMAAP//",
|
||||
"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",
|
||||
}
|
||||
|
||||
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
|
||||
|
||||
+7
-20
@@ -11,17 +11,6 @@ import (
|
||||
"g.fc.run/misc/byre/internal/api"
|
||||
)
|
||||
|
||||
var priorities = []api.InboxItemPriority{api.Blocked, api.Gate, api.ReviewPriority, api.Fyi}
|
||||
|
||||
func priorityRank(p api.InboxItemPriority) int {
|
||||
for i, q := range priorities {
|
||||
if q == p {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic("unknown inbox priority " + string(p))
|
||||
}
|
||||
|
||||
func DeliverableResponse(t api.InboxResponseType) bool {
|
||||
switch t {
|
||||
case api.Option, api.Other:
|
||||
@@ -38,10 +27,10 @@ func (s *Store) CreateInboxItem(ctx context.Context, item api.InboxItem) error {
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO inbox_items (id, project_id, task_id, agent_session_id, thread_id, kind, priority, blocking, payload, state, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, item.Id, item.ProjectId, item.TaskId, item.AgentSessionId, item.ThreadId, string(item.Kind), priorityRank(item.Priority),
|
||||
item.Blocking, string(payload), string(item.State), formatTime(item.CreatedAt))
|
||||
INSERT INTO inbox_items (id, project_id, task_id, agent_session_id, thread_id, kind, payload, state, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, item.Id, item.ProjectId, item.TaskId, item.AgentSessionId, item.ThreadId, string(item.Kind),
|
||||
string(payload), string(item.State), formatTime(item.CreatedAt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -218,7 +207,7 @@ func (s *Store) AwaitingHuman(ctx context.Context, sessionID string) (int, error
|
||||
n := 0
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*) FROM inbox_items i
|
||||
WHERE i.agent_session_id = ? AND i.kind = ? AND i.blocking AND i.state = ?
|
||||
WHERE i.agent_session_id = ? AND i.kind = ? AND i.state = ?
|
||||
AND NOT EXISTS (SELECT 1 FROM inbox_responses r WHERE r.item_id = i.id AND r.type IN (?, ?))
|
||||
`, sessionID, string(api.Question), string(api.Open),
|
||||
string(api.Option), string(api.Other)).Scan(&n)
|
||||
@@ -293,7 +282,6 @@ type querier interface {
|
||||
func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
|
||||
item := api.InboxItem{}
|
||||
kind := ""
|
||||
priority := 0
|
||||
payload := ""
|
||||
state := ""
|
||||
createdAt := ""
|
||||
@@ -301,17 +289,16 @@ func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
|
||||
resolvedAt := sql.NullString{}
|
||||
|
||||
err := q.QueryRowContext(ctx, `
|
||||
SELECT id, project_id, task_id, agent_session_id, thread_id, kind, priority, blocking, payload, state,
|
||||
SELECT id, project_id, task_id, agent_session_id, thread_id, kind, payload, state,
|
||||
created_at, resolved_by, resolved_at
|
||||
FROM inbox_items WHERE id = ?
|
||||
`, id).Scan(&item.Id, &item.ProjectId, &item.TaskId, &item.AgentSessionId, &item.ThreadId, &kind, &priority, &item.Blocking,
|
||||
`, id).Scan(&item.Id, &item.ProjectId, &item.TaskId, &item.AgentSessionId, &item.ThreadId, &kind,
|
||||
&payload, &state, &createdAt, &resolvedBy, &resolvedAt)
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
|
||||
item.Kind = api.InboxItemKind(kind)
|
||||
item.Priority = priorities[priority]
|
||||
item.State = api.InboxState(state)
|
||||
err = json.Unmarshal([]byte(payload), &item.Payload)
|
||||
if err != nil {
|
||||
|
||||
@@ -374,6 +374,45 @@ UPDATE users SET focus = json_set(focus,
|
||||
'$.tab', CASE json_extract(focus, '$.tab') WHEN 'preview' THEN 'transcript' ELSE json_extract(focus, '$.tab') END,
|
||||
'$.tabs', json((SELECT json_group_array(value) FROM json_each(users.focus, '$.tabs') WHERE value != 'preview')));
|
||||
UPDATE users SET focus = json_set(focus, '$.tabs', json('["transcript"]')) WHERE json_array_length(focus, '$.tabs') = 0;
|
||||
`}, {"drop-inbox-priority", `
|
||||
CREATE TABLE inbox_items_next (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(id),
|
||||
task_id TEXT NOT NULL REFERENCES tasks(id),
|
||||
agent_session_id TEXT NOT NULL REFERENCES agent_sessions(id),
|
||||
thread_id TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
blocking INTEGER NOT NULL DEFAULT 1,
|
||||
payload TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
snoozed_until TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
resolved_by TEXT REFERENCES users(login),
|
||||
resolved_at TEXT
|
||||
);
|
||||
INSERT INTO inbox_items_next SELECT id, project_id, task_id, agent_session_id, thread_id, kind, priority, blocking, payload, state, snoozed_until, created_at, resolved_by, resolved_at FROM inbox_items;
|
||||
DROP TABLE inbox_items;
|
||||
ALTER TABLE inbox_items_next RENAME TO inbox_items;
|
||||
CREATE INDEX inbox_items_open ON inbox_items(state, created_at);
|
||||
CREATE INDEX inbox_items_session ON inbox_items(agent_session_id, state);
|
||||
|
||||
CREATE TABLE users_next (
|
||||
login TEXT PRIMARY KEY,
|
||||
display_name TEXT NOT NULL,
|
||||
git_name TEXT NOT NULL DEFAULT '',
|
||||
git_email TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
notification_prefs TEXT NOT NULL DEFAULT '{"questions":true,"reports":false,"errors":false,"rate_limits":false}',
|
||||
focus TEXT NOT NULL DEFAULT '{"tabs":["transcript"],"tab":"transcript"}'
|
||||
);
|
||||
INSERT INTO users_next (login, display_name, git_name, git_email, created_at, notification_prefs, focus)
|
||||
SELECT login, display_name, git_name, git_email, created_at,
|
||||
json_remove(json_set(notification_prefs, '$.questions', json(CASE WHEN json_extract(notification_prefs, '$.blocking_questions') THEN 'true' ELSE 'false' END)), '$.blocking_questions'),
|
||||
focus
|
||||
FROM users;
|
||||
DROP TABLE users;
|
||||
ALTER TABLE users_next RENAME TO users;
|
||||
`}}
|
||||
|
||||
const (
|
||||
|
||||
Vendored
+1
-1
@@ -90,7 +90,7 @@ function card(item) {
|
||||
const p = item.payload;
|
||||
const body = h("div", { class: "card-body" });
|
||||
const actions = h("div", { class: "card-actions" });
|
||||
const el = h("article", { class: `card ${item.kind} ${item.priority}` }, h("header", {}, h("span", { class: `priority ${item.priority}` }, item.priority), h("span", { class: "kind" }, item.kind.replace("_", " ")), h("time", { dateTime: item.created_at, title: item.created_at }, ago(item.created_at))), body, item.reviews.length > 0 ? h("section", { class: "card-reviews" }, ...item.reviews.map((r) => reviewCard(r, item.task_id))) : null, thread(item), actions);
|
||||
const el = h("article", { class: `card ${item.kind}` }, h("header", {}, h("span", { class: "kind" }, item.kind.replace("_", " ")), h("time", { dateTime: item.created_at, title: item.created_at }, ago(item.created_at))), body, item.reviews.length > 0 ? h("section", { class: "card-reviews" }, ...item.reviews.map((r) => reviewCard(r, item.task_id))) : null, thread(item), actions);
|
||||
const busy = () => el.classList.contains("submitting");
|
||||
const lock = (on) => {
|
||||
el.classList.toggle("submitting", on);
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -2,7 +2,7 @@ import { findTask, focusTask, state } from "./state.js";
|
||||
function wants(p, item) {
|
||||
switch (item.kind) {
|
||||
case "question":
|
||||
return item.blocking ? p.blocking_questions : p.questions;
|
||||
return p.questions;
|
||||
case "session_error":
|
||||
return p.errors;
|
||||
case "rate_limited":
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExD,SAAS,KAAK,CAAC,CAAoB,EAAE,IAAe;IAClD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,SAAS,CAAC;QACrB,KAAK,eAAe;YAClB,OAAO,CAAC,CAAC,MAAM,CAAC;QAClB,KAAK,cAAc;YACjB,OAAO,CAAC,CAAC,WAAW,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAe;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IACvB,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QAC3D,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE;YACtE,CAAC,CAAC,cAAc,CAAC;AACrB,CAAC;AAED,SAAS,IAAI,CAAC,MAAc,EAAE,GAAW,EAAE,IAAY;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnI,CAAC,CAAC,OAAO,GAAG,GAAG,EAAE;QACf,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,IAAI,MAAM,EAAE,CAAC;YACX,SAAS,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;IACZ,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,OAAO;IACd,OAAO,cAAc,IAAI,MAAM,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7D,OAAO;IACT,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAG,CAAC,kBAAkB,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;QACzG,OAAO;IACT,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACzE,CAAC"}
|
||||
Vendored
+1
-2
@@ -2,8 +2,7 @@ import { put } from "./api.js";
|
||||
import { errorText, h, replace, showAlert } from "./dom.js";
|
||||
import { on, state } from "./state.js";
|
||||
const kinds = [
|
||||
{ key: "blocking_questions", label: "Blocking questions" },
|
||||
{ key: "questions", label: "Non-blocking questions" },
|
||||
{ key: "questions", label: "Questions" },
|
||||
{ key: "reports", label: "Turn summaries" },
|
||||
{ key: "errors", label: "Session errors" },
|
||||
{ key: "rate_limits", label: "Rate limits" },
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAA0B,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,KAAK,GAAsD;IAC/D,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;IACxC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE;IAC3C,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE;IAC1C,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;CAC7C,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;IAErD,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QACD,OAAO,CACL,KAAK,EACL,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,iBAAiB,CAAC,EAClC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;YAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClF,GAAG,CAAC,QAAQ,GAAG,KAAK,IAAI,EAAE;gBACxB,IAAI,CAAC;oBACH,KAAK,CAAC,EAAE,GAAG,MAAM,GAAG,CAAC,uBAAuB,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAC5G,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjC,CAAC;gBACD,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC;YACF,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,CAAC,CAAC,cAAc,IAAI,MAAM,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,6CAA6C,CAAC,CAAC,CAAC;YAC1F,OAAO;QACT,CAAC;QACD,IAAI,YAAY,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACzC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,oEAAoE,CAAC,CAAC,CAAC;YACjH,OAAO;QACT,CAAC;QACD,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,6DAA6D,CAAC,CAAC,CAAC;YAC3F,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,0BAA0B,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;YAC1B,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;YACvB,MAAM,YAAY,CAAC,iBAAiB,EAAE,CAAC;YACvC,YAAY,EAAE,CAAC;QACjB,CAAC,CAAC;QACF,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,0CAA0C,CAAC,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC,CAAC;IAEF,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACjG,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAClC,WAAW,EAAE,CAAC;IACd,YAAY,EAAE,CAAC;IAEf,OAAO,GAAG,CAAC;AACb,CAAC"}
|
||||
Vendored
+1
-1
@@ -872,7 +872,7 @@ function renderEvent(ev, ctx) {
|
||||
const kind = p["kind"];
|
||||
if (kind === "question") {
|
||||
const q = p["payload"];
|
||||
return h("div", { class: "note ask" }, `asked${p["blocking"] ? " (blocking)" : ""}: `, String(q["question"]));
|
||||
return h("div", { class: "note ask" }, "asked: ", String(q["question"]));
|
||||
}
|
||||
if (kind === "session_error" || kind === "rate_limited") {
|
||||
const q = p["payload"];
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+3
-8
@@ -674,7 +674,7 @@ export interface paths {
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** @description Inbox items, highest priority first (blocked, gate, review, fyi), then oldest first. Filters narrow the one query to a project's or a task's view. */
|
||||
/** @description Inbox items, oldest first. Filters narrow the one query to a project's or a task's view. */
|
||||
get: operations["listInbox"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
@@ -711,7 +711,7 @@ export interface paths {
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** @description Answers one or more items in one submission. Answers reach the agent as one message once it is idle and none of its blocking questions are unanswered. */
|
||||
/** @description Answers one or more items in one submission. Answers reach the agent as one message once it is idle and none of its questions are unanswered. */
|
||||
post: operations["respondInbox"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
@@ -803,9 +803,7 @@ export interface components {
|
||||
};
|
||||
/** @description Which new inbox items and finished turns notify this user in their open byre pages. */
|
||||
NotificationPrefs: {
|
||||
/** @description Questions asked with blocking: true. On by default. */
|
||||
blocking_questions: boolean;
|
||||
/** @description Non-blocking questions. */
|
||||
/** @description Questions. On by default. */
|
||||
questions: boolean;
|
||||
/** @description Task turns that end with a summary (turn.ended with summary: true). */
|
||||
reports: boolean;
|
||||
@@ -1131,9 +1129,6 @@ export interface components {
|
||||
thread_id: string;
|
||||
/** @enum {string} */
|
||||
kind: "question" | "session_error" | "rate_limited";
|
||||
/** @enum {string} */
|
||||
priority: "blocked" | "gate" | "review" | "fyi";
|
||||
blocking: boolean;
|
||||
/** @description question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. */
|
||||
payload: Record<string, never>;
|
||||
state: components["schemas"]["InboxState"];
|
||||
|
||||
+1
-2
@@ -101,11 +101,10 @@ function card(item: InboxItem): HTMLElement {
|
||||
const actions = h("div", { class: "card-actions" });
|
||||
const el = h(
|
||||
"article",
|
||||
{ class: `card ${item.kind} ${item.priority}` },
|
||||
{ class: `card ${item.kind}` },
|
||||
h(
|
||||
"header",
|
||||
{},
|
||||
h("span", { class: `priority ${item.priority}` }, item.priority),
|
||||
h("span", { class: "kind" }, item.kind.replace("_", " ")),
|
||||
h("time", { dateTime: item.created_at, title: item.created_at }, ago(item.created_at)),
|
||||
),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { findTask, focusTask, state } from "./state.js";
|
||||
function wants(p: NotificationPrefs, item: InboxItem): boolean {
|
||||
switch (item.kind) {
|
||||
case "question":
|
||||
return item.blocking ? p.blocking_questions : p.questions;
|
||||
return p.questions;
|
||||
case "session_error":
|
||||
return p.errors;
|
||||
case "rate_limited":
|
||||
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { errorText, h, replace, showAlert } from "./dom.js";
|
||||
import { on, state } from "./state.js";
|
||||
|
||||
const kinds: { key: keyof NotificationPrefs; label: string }[] = [
|
||||
{ key: "blocking_questions", label: "Blocking questions" },
|
||||
{ key: "questions", label: "Non-blocking questions" },
|
||||
{ key: "questions", label: "Questions" },
|
||||
{ key: "reports", label: "Turn summaries" },
|
||||
{ key: "errors", label: "Session errors" },
|
||||
{ key: "rate_limits", label: "Rate limits" },
|
||||
|
||||
+1
-1
@@ -1027,7 +1027,7 @@ function renderEvent(ev: ByreEvent, ctx: Ctx): HTMLElement | null {
|
||||
const kind = p["kind"];
|
||||
if (kind === "question") {
|
||||
const q = p["payload"] as Record<string, unknown>;
|
||||
return h("div", { class: "note ask" }, `asked${p["blocking"] ? " (blocking)" : ""}: `, String(q["question"]));
|
||||
return h("div", { class: "note ask" }, "asked: ", String(q["question"]));
|
||||
}
|
||||
if (kind === "session_error" || kind === "rate_limited") {
|
||||
const q = p["payload"] as Record<string, unknown>;
|
||||
|
||||
@@ -1513,14 +1513,6 @@ pre.file-text .line::before {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.priority {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.priority.blocked {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.context {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user