Render Markdown, add ask_human context, simplify inbox responses, group inbox by task

This commit is contained in:
Ian Gulliver
2026-10-14 10:37:04 -07:00
parent e9fd7de556
commit ca2644374d
25 changed files with 950 additions and 283 deletions
+7 -7
View File
@@ -57,22 +57,22 @@ Agent activity becomes events with `agent_session_id` set: `user.message`, `agen
## Inbox
Agents ask questions with the `ask_human` MCP tool; a malformed call (no `why_blocked`, fewer than two options, a recommendation that isn't one of the options, an unknown attachment kind, a foreign `thread_id`) is rejected with a message saying what to fix, and nothing is filed. Each `report` call and 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; the UI renders it, the question, and the options as Markdown. A malformed call (no `context` or `why_blocked`, fewer than two options, a recommendation that isn't one of the options, an unknown attachment kind, a foreign `thread_id`) is rejected with a message saying what to fix, and nothing is filed. Each `report` call and 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, unsnoozed items, sorted by priority (`blocked`, `gate`, `review`, `fyi`) then age; `project_id` and `task_id` narrow it to a project or task view, and `state` and `include_snoozed` widen it. Blocking questions and errors are `blocked`; reports and non-blocking questions are `fyi`.
`GET /api/inbox` is one query over open, unsnoozed items, oldest first; `project_id` and `task_id` narrow it to a project or task view, and `state` and `include_snoozed` widen it. Blocking questions and errors are `blocked`; reports and non-blocking questions are `fyi`. The inbox view groups items by task, each group headed by project and task: tasks with a blocked item come first, then tasks sort by project name and by their oldest item. Within a task, items are in time order.
`POST /api/inbox/responses` answers any number of items in one submission. Response types and what they do to the item:
| type | allowed on | item becomes |
|---|---|---|
| `option` (with optional note in `text`) | questions | `answered` |
| `free_form` | questions | `answered` |
| `question` (a follow-up from the human) | questions | stays `open` |
| `redirect` | any | `redirected` |
| `option` | questions | `answered` |
| `other` (free text in `text`: an answer, a question back, or new instructions) | questions, errors | `answered` |
| `snooze` | any | stays `open`, hidden until `snooze_until` |
| `dismiss` | reports, errors | `dismissed` |
Answers reach the agent as one message, listing each answer under the question or report it responds to, once the session is idle and none of its blocking questions are still waiting for the human. A follow-up question tells the agent to reply with `ask_human` using the item's `thread_id`; the new item supersedes the open one in that thread. Every item change is an `inbox.created` or `inbox.updated` event carrying the whole item, including who resolved it.
In the UI a question offers its options plus Other, whose text box is the only text field; a report has only an OK button, which dismisses it at once; an error offers Dismiss, Reply (`other`) and Snooze.
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`. Every item change is an `inbox.created` or `inbox.updated` event carrying the whole item, including who resolved it.
## Events
+10 -10
View File
@@ -114,12 +114,13 @@ Vendor specifics live behind adapters. The event model is a **shared core plus v
The Go server hosts an MCP server attached to every agent session.
- `ask_human(question, why_blocked, options[], recommended_option, attachments[], blocking, thread_id?)`
- `ask_human(context, question, why_blocked, options[], recommended_option, attachments[], blocking, thread_id?)`
- `context` carries the background the human needs to answer without reading the transcript.
- Non-blocking at the protocol level: returns immediately with "question filed."
- `blocking: true` means the agent should end its turn; `false` means it continues with unblocked work.
- The human's answer arrives as a structured next turn.
- `thread_id` continues an existing inbox thread.
- `report(done[], open_questions[], next_steps[], risks[], deviations[])`
- `report(done[], next_steps[], risks[], deviations[])`
- `deviations[]` lists every departure from the task's plan.
- `request_review(scope, concerns[], profile?)`
- `export_context(purpose)` → a handoff bundle (see "Handoff bundles").
@@ -165,7 +166,7 @@ InboxItem (id, project_id, task_id, agent_session_id, thread_id, kind,
priority, blocking, payload, snapshot_id, review_id, state,
snoozed_until)
InboxResponse (id, inbox_item_id, user_id, type, text, attachments,
created_at) -- type: option | free_form | redirect | question
created_at) -- type: option | other | snooze | dismiss
Review (id, task_id, snapshot_id, tree_sha, profile, reviewer_vendor,
trigger, state, summary, highlights, attachments, stale)
ReviewProfile (id, name, prompt, vendor, model, output_schema, capture_config)
@@ -407,16 +408,15 @@ In increasing order of how much the UI encourages their use:
- One underlying query with global, per-project, and per-task views.
- Sources: `ask_human` calls, reports, completed reviews, gate approvals, rate-limit states, sessions that went idle or errored.
- Priority: blocked (an agent is idle waiting on this) > gate approval > review ready > FYI/report; then by age.
- Grouped by task, tasks with a blocked item (an agent is idle waiting on it) first, then by project; within a task, items are in time order.
- Everyone sees every item. Resolutions record who resolved them and are broadcast to all clients over SSE.
### Response types
- **Pick an option**, with an optional note.
- **Free-form answer** when none of the options fit.
- **Redirect**: new instructions that change the agent's direction. The item resolves as "redirected," and the agent receives the instructions as its next turn.
- **Reply with a question**: the item becomes a thread; the agent answers through a follow-up `ask_human` with the same `thread_id`, and the item stays open.
- **Pick an option**.
- **Other**: the only text field, for an answer outside the options, a question back, or new instructions. If it asks the agent something, the agent answers through a follow-up `ask_human` with the same `thread_id`.
- **Snooze**: hidden until a set time; the agent stays blocked.
- Reports are FYI and take only an OK.
Responses can carry attachments (pasted images and sketches, file and line references, links to tasks or snapshots, URLs). When an agent asks several questions at once, they are answered as one form with one submit.
@@ -480,8 +480,8 @@ Record transcripts from the spike as the seed of the contract test suite.
- **M0 — Skeleton.** launchd service, tailscale serve auth, SQLite schema, OpenAPI spec, projects, tasks, worktree create/delete, event log, SSE stream with resume, embedded SPA shell, basic server observability.
- **Status: done**, and running as a service on the Mac Studio. Observability is exposed through `GET /api/admin/status` only; the SPA has no admin view yet.
- **M1 — One agent end to end (Claude).** Sessions, streaming, messaging, full-interface rendering for Claude, MCP tools (`ask_human`, `report`), report enforcement, inbox with all views and response types, web push notifications, restart-and-resume, concurrency caps.
- **Done:** sessions, streaming, messaging, interrupt; `ask_human` and `report` with validation; Stop-hook report enforcement; inbox with global, project, and task views and every response type, answered as one batch and delivered to the agent as one message; restart-and-resume; global and per-vendor caps with queueing; rate limits as their own inbox state; the web UI (two panes, task switcher, transcript, inbox).
- **Not done:** full-interface rendering beyond messages, tool calls, and interrupt (slash commands, plan mode, model switching, compaction, todo lists, subagent views, image input, `@`-file mentions, Markdown and Mermaid rendering); web push notifications; bouncing questions asked in plain prose; the synthesized-report fallback (needs the M3 review agent); the session instructions from "Session configuration" (no pushing, no other branches, no git maintenance, no self-attribution; only the attribution setting is applied); pinning the CLI version (auto-update is disabled, the version isn't pinned).
- **Done:** sessions, streaming, messaging, interrupt; `ask_human` and `report` with validation; Stop-hook report enforcement; inbox with global, project, and task views and every response type, answered as one batch and delivered to the agent as one message; restart-and-resume; global and per-vendor caps with queueing; rate limits as their own inbox state; the web UI (two panes, task switcher, transcript, inbox) with Markdown rendering.
- **Not done:** full-interface rendering beyond messages, tool calls, and interrupt (slash commands, plan mode, model switching, compaction, todo lists, subagent views, image input, `@`-file mentions, Mermaid rendering); web push notifications; bouncing questions asked in plain prose; the synthesized-report fallback (needs the M3 review agent); the session instructions from "Session configuration" (no pushing, no other branches, no git maintenance, no self-attribution; only the attribution setting is applied); pinning the CLI version (auto-update is disabled, the version isn't pinned).
- **M2 — Seeing the work.** Temp-index diffs and stats, snapshots, timeline scrubbing, terminals, file browser, previews.
- **M3 — Second vendor and review.** Codex adapter with full-interface rendering, review profiles, review triggers, visual review output, cross-vendor review.
- **M4 — Merging and history.** Full merge cycle with squash, authorship and co-author trailers, drafted commit messages, merge-resolution stage, git notes, task completion and archive, archive search, GitHub Issues integration.