From ca2644374d57f516644e993b2bc3d476f1a74d01 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Wed, 14 Oct 2026 10:37:04 -0700 Subject: [PATCH] Render Markdown, add ask_human context, simplify inbox responses, group inbox by task --- api/openapi.yaml | 10 +- cmd/byre/run.go | 1 - docs/operations.md | 14 +- docs/plan.md | 20 +- internal/agents/inbox.go | 44 ++-- internal/agents/inbox_internal_test.go | 27 ++- internal/agents/manager_test.go | 16 +- internal/agents/ratelimit_internal_test.go | 2 +- internal/api/api.gen.go | 141 ++++++----- internal/report/gate.go | 10 +- internal/server/inbox.go | 36 +-- internal/server/inbox_internal_test.go | 34 +-- internal/store/inbox.go | 14 +- internal/store/store.go | 3 + web/dist/inbox.js | 98 +++++--- web/dist/inbox.js.map | 2 +- web/dist/markdown.js | 226 ++++++++++++++++++ web/dist/markdown.js.map | 1 + web/dist/task.js | 10 +- web/dist/task.js.map | 2 +- web/src/api.gen.ts | 8 +- web/src/inbox.ts | 122 +++++++--- web/src/markdown.ts | 260 +++++++++++++++++++++ web/src/task.ts | 10 +- web/style.css | 122 +++++++++- 25 files changed, 950 insertions(+), 283 deletions(-) create mode 100644 web/dist/markdown.js create mode 100644 web/dist/markdown.js.map create mode 100644 web/src/markdown.ts diff --git a/api/openapi.yaml b/api/openapi.yaml index 9655cce..88a7b49 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -426,7 +426,7 @@ components: InboxState: type: string - enum: [open, answered, redirected, dismissed, superseded] + enum: [open, answered, dismissed, superseded] InboxItem: type: object @@ -443,8 +443,8 @@ components: payload: type: object description: > - question: question, why_blocked, options, recommended_option, attachments. - report: done, open_questions, next_steps, risks, deviations. + question: context, question, why_blocked, options, recommended_option, attachments. + report: done, next_steps, risks, deviations. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. state: { $ref: "#/components/schemas/InboxState" } @@ -458,7 +458,7 @@ components: InboxResponseType: type: string - enum: [option, free_form, redirect, question, snooze, dismiss] + enum: [option, other, snooze, dismiss] InboxResponse: type: object @@ -484,7 +484,7 @@ components: item_id: { type: string } type: { $ref: "#/components/schemas/InboxResponseType" } option: { type: string, description: "option: one of the question's options." } - text: { type: string, description: "Required for free_form, redirect, question; an optional note on option." } + text: { type: string, description: "other: the text sent to the agent." } attachments: type: array items: { $ref: "#/components/schemas/Attachment" } diff --git a/cmd/byre/run.go b/cmd/byre/run.go index 03e926e..938bfec 100644 --- a/cmd/byre/run.go +++ b/cmd/byre/run.go @@ -155,7 +155,6 @@ func printReport(r report.Report) { items []string }{ {"done", r.Done}, - {"open questions", r.OpenQuestions}, {"next steps", r.NextSteps}, {"risks", r.Risks}, {"deviations", r.Deviations}, diff --git a/docs/operations.md b/docs/operations.md index 4350766..232b921 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -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 diff --git a/docs/plan.md b/docs/plan.md index cf25be8..08dca45 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -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. diff --git a/internal/agents/inbox.go b/internal/agents/inbox.go index 36f6bee..abb8235 100644 --- a/internal/agents/inbox.go +++ b/internal/agents/inbox.go @@ -22,6 +22,7 @@ var attachmentKinds = []api.AttachmentKind{ } type askArgs struct { + Context string `json:"context"` Question string `json:"question"` WhyBlocked string `json:"why_blocked"` Options []string `json:"options"` @@ -35,6 +36,8 @@ func (m *Manager) askTool(l *live) mcp.Tool { return mcp.Tool{ Name: "ask_human", Description: "Ask the human a question through their inbox. Use this for every question; never ask in plain prose. " + + "The human answers from their inbox without having read your transcript, so every question must stand on its own: " + + "put the background they need in context. " + "Offer concrete options and recommend one. If blocking is true, call report and 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. " + "Ask several questions in one turn by calling this once per question; they are answered together. " + @@ -42,7 +45,8 @@ func (m *Manager) askTool(l *live) mcp.Tool { InputSchema: json.RawMessage(`{ "type": "object", "properties": { - "question": {"type": "string"}, + "context": {"type": "string", "description": "Everything the human needs to answer well without reading your transcript: what you are working on, what you found, the relevant facts and data, and what each option would concretely do. Several paragraphs is normal. Markdown is rendered."}, + "question": {"type": "string", "description": "The question itself, in one or two sentences. Markdown is rendered."}, "why_blocked": {"type": "string", "description": "What you can't do until this is answered, and why you can't decide it yourself."}, "options": {"type": "array", "items": {"type": "string"}, "minItems": 2}, "recommended_option": {"type": "string", "description": "One of options."}, @@ -65,7 +69,7 @@ func (m *Manager) askTool(l *live) mcp.Tool { "blocking": {"type": "boolean"}, "thread_id": {"type": "string"} }, - "required": ["question", "why_blocked", "options", "recommended_option", "blocking"] + "required": ["context", "question", "why_blocked", "options", "recommended_option", "blocking"] }`), Handler: func(ctx context.Context, raw json.RawMessage) (string, error) { return m.ask(ctx, l, raw) @@ -102,6 +106,7 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string } payload := map[string]any{ + "context": args.Context, "question": args.Question, "why_blocked": args.WhyBlocked, "options": args.Options, @@ -109,7 +114,7 @@ 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.InboxItemKindQuestion, priority, *args.Blocking, store.ToPayload(payload))) + err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, priority, *args.Blocking, store.ToPayload(payload))) if err != nil { return "", err } @@ -123,6 +128,9 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error { problems := []string{} + if strings.TrimSpace(args.Context) == "" { + problems = append(problems, "context is empty: give the background the human needs to answer without reading your transcript") + } if strings.TrimSpace(args.Question) == "" { problems = append(problems, "question is empty") } @@ -164,7 +172,7 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error func (m *Manager) fileReport(l *live, r report.Report) { id := store.NewID() - err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.InboxItemKindReport, api.Fyi, false, store.ToPayload(r))) + err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.Report, api.Fyi, false, store.ToPayload(r))) if err != nil { slog.Error("file report", "session", l.id, "err", err) } @@ -172,7 +180,7 @@ func (m *Manager) fileReport(l *live, r report.Report) { func (m *Manager) fileError(l *live, msg string) { id := store.NewID() - err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.InboxItemKindSessionError, api.Blocked, true, map[string]any{"error": msg})) + err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, api.Blocked, true, map[string]any{"error": msg})) if err != nil { slog.Error("file session error", "session", l.id, "err", err) } @@ -181,7 +189,7 @@ 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.InboxItemKindRateLimited, api.Blocked, true, payload)) + err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, api.Blocked, true, payload)) if err != nil { slog.Error("file rate limit", "session", l.id, "err", err) } @@ -261,28 +269,26 @@ func deliveryMessage(pending []store.Pending) string { b.WriteString("\n") switch p.Item.Kind { - case api.InboxItemKindQuestion: + case api.Question: fmt.Fprintf(b, "Your question %s: %s\n", p.Item.Id, p.Item.Payload["question"]) - case api.InboxItemKindReport: + case api.Report: fmt.Fprintf(b, "Your report %s\n", p.Item.Id) - case api.InboxItemKindSessionError: + case api.SessionError: fmt.Fprintf(b, "Your error %s: %s\n", p.Item.Id, p.Item.Payload["error"]) - case api.InboxItemKindRateLimited: + case api.RateLimited: fmt.Fprintf(b, "Your rate-limited turn %s: %s\n", p.Item.Id, p.Item.Payload["error"]) } switch r.Type { - case api.InboxResponseTypeOption: + case api.Option: fmt.Fprintf(b, "%s chose: %s\n", r.User, *r.Option) - if r.Text != nil && *r.Text != "" { - fmt.Fprintf(b, "Note: %s\n", *r.Text) + case api.Other: + if p.Item.Kind == api.Question { + fmt.Fprintf(b, "%s answered (none of your options): %s\n", r.User, *r.Text) + fmt.Fprintf(b, "If this asks you something back, answer by calling ask_human with thread_id %q.\n", p.Item.ThreadId) + } else { + fmt.Fprintf(b, "%s replied: %s\n", r.User, *r.Text) } - case api.InboxResponseTypeFreeForm: - fmt.Fprintf(b, "%s answered (none of your options): %s\n", r.User, *r.Text) - case api.InboxResponseTypeRedirect: - fmt.Fprintf(b, "%s redirected you. These instructions replace your current direction: %s\n", r.User, *r.Text) - case api.InboxResponseTypeQuestion: - fmt.Fprintf(b, "%s asked a follow-up question: %s\nAnswer it by calling ask_human with thread_id %q.\n", r.User, *r.Text, p.Item.ThreadId) } for _, a := range r.Attachments { diff --git a/internal/agents/inbox_internal_test.go b/internal/agents/inbox_internal_test.go index 3ab942f..e40390d 100644 --- a/internal/agents/inbox_internal_test.go +++ b/internal/agents/inbox_internal_test.go @@ -19,11 +19,11 @@ func TestValidateAsk(t *testing.T) { args askArgs want []string }{ - {"valid", askArgs{Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "a", Blocking: &yes}, nil}, - {"empty", askArgs{}, []string{"question is empty", "why_blocked is empty", "at least two", "recommended_option", "blocking is required"}}, - {"one option", askArgs{Question: "q", WhyBlocked: "w", Options: []string{"a"}, RecommendedOption: "a", Blocking: &yes}, []string{"at least two"}}, - {"bad recommendation", askArgs{Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "c", Blocking: &yes}, []string{"recommended_option"}}, - {"bad attachment", askArgs{Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "a", Blocking: &yes, + {"valid", askArgs{Context: "c", Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "a", Blocking: &yes}, nil}, + {"empty", askArgs{}, []string{"context is empty", "question is empty", "why_blocked is empty", "at least two", "recommended_option", "blocking is required"}}, + {"one option", askArgs{Context: "c", Question: "q", WhyBlocked: "w", Options: []string{"a"}, RecommendedOption: "a", Blocking: &yes}, []string{"at least two"}}, + {"bad recommendation", askArgs{Context: "c", Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "c", Blocking: &yes}, []string{"recommended_option"}}, + {"bad attachment", askArgs{Context: "c", Question: "q", WhyBlocked: "w", Options: []string{"a", "b"}, RecommendedOption: "a", Blocking: &yes, Attachments: []api.Attachment{{Kind: "video"}}}, []string{`attachments[0].kind "video"`}}, } @@ -53,25 +53,24 @@ func TestValidateAsk(t *testing.T) { func TestDeliveryMessage(t *testing.T) { str := func(s string) *string { return &s } - question := api.InboxItem{Id: "q1", ThreadId: "q1", Kind: api.InboxItemKindQuestion, Payload: map[string]any{"question": "Which color?"}} - report := api.InboxItem{Id: "r1", ThreadId: "r1", Kind: api.InboxItemKindReport, Payload: map[string]any{}} + question := api.InboxItem{Id: "q1", ThreadId: "q1", Kind: api.Question, Payload: map[string]any{"question": "Which color?"}} + failure := api.InboxItem{Id: "e1", ThreadId: "e1", Kind: api.SessionError, Payload: map[string]any{"error": "process died"}} msg := deliveryMessage([]store.Pending{ - {Item: question, Response: api.InboxResponse{User: "alice", Type: api.InboxResponseTypeOption, Option: str("blue"), Text: str("navy if possible")}}, - {Item: question, Response: api.InboxResponse{User: "bob", Type: api.InboxResponseTypeQuestion, Text: str("what is it for?"), + {Item: question, Response: api.InboxResponse{User: "alice", Type: api.Option, Option: str("blue")}}, + {Item: question, Response: api.InboxResponse{User: "bob", Type: api.Other, Text: str("what is it for?"), Attachments: []api.Attachment{{Kind: api.AttachmentKindUrl, Url: str("https://example.com")}}}}, - {Item: report, Response: api.InboxResponse{User: "alice", Type: api.InboxResponseTypeRedirect, Text: str("stop and write tests")}}, + {Item: failure, Response: api.InboxResponse{User: "alice", Type: api.Other, Text: str("stop and write tests")}}, }) for _, want := range []string{ "Your question q1: Which color?", "alice chose: blue", - "Note: navy if possible", - "bob asked a follow-up question: what is it for?", + "bob answered (none of your options): what is it for?", `calling ask_human with thread_id "q1"`, `"url":"https://example.com"`, - "Your report r1", - "alice redirected you. These instructions replace your current direction: stop and write tests", + "Your error e1: process died", + "alice replied: stop and write tests", } { if !strings.Contains(msg, want) { t.Fatalf("message missing %q:\n%s", want, msg) diff --git a/internal/agents/manager_test.go b/internal/agents/manager_test.go index 73ebd0d..d31fc42 100644 --- a/internal/agents/manager_test.go +++ b/internal/agents/manager_test.go @@ -317,7 +317,7 @@ func (e *env) openQuestions(sessionID string) []api.InboxItem { } questions := []api.InboxItem{} for _, item := range items { - if item.Kind == api.InboxItemKindQuestion { + if item.Kind == api.Question { questions = append(questions, item) } } @@ -379,7 +379,7 @@ func TestAskHumanRoundTrip(t *testing.T) { t.Fatalf("awaiting human: %d %v", waiting, err) } - e.respond(m, q, api.InboxResponseTypeOption, "blue", "", api.Answered) + e.respond(m, q, api.Option, "blue", "", api.Answered) events := e.waitIdle() delivered := false @@ -423,7 +423,7 @@ func TestFollowUpQuestionThread(t *testing.T) { } first := questions[0] - e.respond(m, first, api.InboxResponseTypeQuestion, "", "Before I pick: which of the two did you recommend, and why?", api.Open) + e.respond(m, first, api.Other, "", "Before I pick: which of the two did you recommend, and why?", api.Answered) e.waitIdle() questions = e.openQuestions(sess.Id) @@ -435,15 +435,7 @@ func TestFollowUpQuestionThread(t *testing.T) { t.Fatalf("follow-up didn't continue the thread: first %s/%s, second %s/%s", first.Id, first.ThreadId, second.Id, second.ThreadId) } - old, err := e.store.GetInboxItem(e.ctx, first.Id) - if err != nil { - t.Fatalf("get first question: %v", err) - } - if old.State != api.Superseded { - t.Fatalf("first question is %s, want superseded", old.State) - } - - e.respond(m, second, api.InboxResponseTypeFreeForm, "", "Use green instead of either.", api.Answered) + e.respond(m, second, api.Other, "", "Use green instead of either.", api.Answered) e.waitIdle() out, err := os.ReadFile(filepath.Join(e.task.WorktreePath, "color.txt")) diff --git a/internal/agents/ratelimit_internal_test.go b/internal/agents/ratelimit_internal_test.go index cd1335f..3b5c153 100644 --- a/internal/agents/ratelimit_internal_test.go +++ b/internal/agents/ratelimit_internal_test.go @@ -68,7 +68,7 @@ func TestRateLimitedTurn(t *testing.T) { if err != nil { t.Fatalf("list inbox: %v", err) } - if len(items) != 1 || items[0].Kind != api.InboxItemKindRateLimited || items[0].Priority != api.Blocked { + if len(items) != 1 || items[0].Kind != api.RateLimited || items[0].Priority != api.Blocked { t.Fatalf("want one blocked rate_limited item, got %+v", items) } limit, ok := items[0].Payload["rate_limit"].(map[string]any) diff --git a/internal/api/api.gen.go b/internal/api/api.gen.go index e26e724..189fffa 100644 --- a/internal/api/api.gen.go +++ b/internal/api/api.gen.go @@ -110,22 +110,22 @@ func (e AttachmentKind) Valid() bool { // Defines values for InboxItemKind. const ( - InboxItemKindQuestion InboxItemKind = "question" - InboxItemKindRateLimited InboxItemKind = "rate_limited" - InboxItemKindReport InboxItemKind = "report" - InboxItemKindSessionError InboxItemKind = "session_error" + Question InboxItemKind = "question" + RateLimited InboxItemKind = "rate_limited" + Report InboxItemKind = "report" + SessionError InboxItemKind = "session_error" ) // Valid indicates whether the value is a known member of the InboxItemKind enum. func (e InboxItemKind) Valid() bool { switch e { - case InboxItemKindQuestion: + case Question: return true - case InboxItemKindRateLimited: + case RateLimited: return true - case InboxItemKindReport: + case Report: return true - case InboxItemKindSessionError: + case SessionError: return true default: return false @@ -158,28 +158,22 @@ func (e InboxItemPriority) Valid() bool { // Defines values for InboxResponseType. const ( - InboxResponseTypeDismiss InboxResponseType = "dismiss" - InboxResponseTypeFreeForm InboxResponseType = "free_form" - InboxResponseTypeOption InboxResponseType = "option" - InboxResponseTypeQuestion InboxResponseType = "question" - InboxResponseTypeRedirect InboxResponseType = "redirect" - InboxResponseTypeSnooze InboxResponseType = "snooze" + Dismiss InboxResponseType = "dismiss" + Option InboxResponseType = "option" + Other InboxResponseType = "other" + Snooze InboxResponseType = "snooze" ) // Valid indicates whether the value is a known member of the InboxResponseType enum. func (e InboxResponseType) Valid() bool { switch e { - case InboxResponseTypeDismiss: + case Dismiss: return true - case InboxResponseTypeFreeForm: + case Option: return true - case InboxResponseTypeOption: + case Other: return true - case InboxResponseTypeQuestion: - return true - case InboxResponseTypeRedirect: - return true - case InboxResponseTypeSnooze: + case Snooze: return true default: return false @@ -191,7 +185,6 @@ const ( Answered InboxState = "answered" Dismissed InboxState = "dismissed" Open InboxState = "open" - Redirected InboxState = "redirected" Superseded InboxState = "superseded" ) @@ -204,8 +197,6 @@ func (e InboxState) Valid() bool { return true case Open: return true - case Redirected: - return true case Superseded: return true default: @@ -308,7 +299,7 @@ type InboxItem struct { Id string `json:"id"` Kind InboxItemKind `json:"kind"` - // Payload question: question, why_blocked, options, recommended_option, attachments. report: done, open_questions, next_steps, risks, deviations. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. + // Payload question: context, question, why_blocked, options, recommended_option, attachments. report: done, next_steps, risks, deviations. 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"` @@ -357,7 +348,7 @@ type InboxResponseCreate struct { // SnoozeUntil snooze: when the item reappears. SnoozeUntil *time.Time `json:"snooze_until,omitempty"` - // Text Required for free_form, redirect, question; an optional note on option. + // Text other: the text sent to the agent. Text *string `json:"text,omitempty"` Type InboxResponseType `json:"type"` } @@ -1261,54 +1252,54 @@ 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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", + "L6a82mz+HwAA//8=", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/report/gate.go b/internal/report/gate.go index 4ee9723..6257815 100644 --- a/internal/report/gate.go +++ b/internal/report/gate.go @@ -14,11 +14,10 @@ const maxNudges = 3 const nudge = "You must call the report tool (mcp__byre__report) before ending your turn." type Report struct { - Done []string `json:"done"` - OpenQuestions []string `json:"open_questions"` - NextSteps []string `json:"next_steps"` - Risks []string `json:"risks"` - Deviations []string `json:"deviations"` + Done []string `json:"done"` + NextSteps []string `json:"next_steps"` + Risks []string `json:"risks"` + Deviations []string `json:"deviations"` } type Gate struct { @@ -50,7 +49,6 @@ func (g *Gate) Tool() mcp.Tool { "type": "object", "properties": { "done": {"type": "array", "items": {"type": "string"}}, - "open_questions": {"type": "array", "items": {"type": "string"}}, "next_steps": {"type": "array", "items": {"type": "string"}}, "risks": {"type": "array", "items": {"type": "string"}}, "deviations": {"type": "array", "items": {"type": "string"}} diff --git a/internal/server/inbox.go b/internal/server/inbox.go index 657b019..9bd6006 100644 --- a/internal/server/inbox.go +++ b/internal/server/inbox.go @@ -145,54 +145,42 @@ func checkResponse(item api.InboxItem, c api.InboxResponseCreate) (api.InboxStat if c.Text != nil { text = strings.TrimSpace(*c.Text) } - question := item.Kind == api.InboxItemKindQuestion + question := item.Kind == api.Question bad := func(format string, args ...any) (api.InboxState, *httpError) { return "", &httpError{http.StatusBadRequest, fmt.Errorf("item %s: "+format, append([]any{item.Id}, args...)...)} } switch c.Type { - case api.InboxResponseTypeOption: + case api.Option: if !question { return bad("only questions have options") } if c.Option == nil || !hasOption(item, *c.Option) { return bad("option must be one of the question's options") } - return api.Answered, nil - - case api.InboxResponseTypeFreeForm: - if !question { - return bad("only questions take answers") - } - if text == "" { - return bad("free_form needs text") + if text != "" { + return bad("option takes no text; use other") } return api.Answered, nil - case api.InboxResponseTypeQuestion: - if !question { - return bad("only questions take follow-up questions") + case api.Other: + if item.Kind == api.Report { + return bad("reports are only dismissed") } if text == "" { - return bad("question needs text") + return bad("other needs text") } - return api.Open, nil + return api.Answered, nil - case api.InboxResponseTypeRedirect: - if text == "" { - return bad("redirect needs text") - } - return api.Redirected, nil - - case api.InboxResponseTypeSnooze: + case api.Snooze: if c.SnoozeUntil == nil || !c.SnoozeUntil.After(time.Now()) { return bad("snooze needs a future snooze_until") } return api.Open, nil - case api.InboxResponseTypeDismiss: + case api.Dismiss: if question { - return bad("questions need an answer or a redirect, not a dismissal") + return bad("questions need an option or other, not a dismissal") } return api.Dismissed, nil } diff --git a/internal/server/inbox_internal_test.go b/internal/server/inbox_internal_test.go index 7811774..e99192a 100644 --- a/internal/server/inbox_internal_test.go +++ b/internal/server/inbox_internal_test.go @@ -11,11 +11,12 @@ import ( func TestCheckResponse(t *testing.T) { question := api.InboxItem{ Id: "q1", - Kind: api.InboxItemKindQuestion, + Kind: api.Question, State: api.Open, Payload: map[string]any{"options": []any{"red", "blue"}}, } - report := api.InboxItem{Id: "r1", Kind: api.InboxItemKindReport, State: api.Open, Payload: map[string]any{}} + report := api.InboxItem{Id: "r1", Kind: api.Report, State: api.Open, Payload: map[string]any{}} + failure := api.InboxItem{Id: "e1", Kind: api.SessionError, State: api.Open, Payload: map[string]any{}} closed := question closed.State = api.Answered @@ -30,21 +31,20 @@ func TestCheckResponse(t *testing.T) { state api.InboxState status int }{ - {"option", question, api.InboxResponseCreate{Type: api.InboxResponseTypeOption, Option: str("blue")}, api.Answered, 0}, - {"option with note", question, api.InboxResponseCreate{Type: api.InboxResponseTypeOption, Option: str("red"), Text: str("but darker")}, api.Answered, 0}, - {"unknown option", question, api.InboxResponseCreate{Type: api.InboxResponseTypeOption, Option: str("green")}, "", http.StatusBadRequest}, - {"missing option", question, api.InboxResponseCreate{Type: api.InboxResponseTypeOption}, "", http.StatusBadRequest}, - {"free form", question, api.InboxResponseCreate{Type: api.InboxResponseTypeFreeForm, Text: str("green")}, api.Answered, 0}, - {"empty free form", question, api.InboxResponseCreate{Type: api.InboxResponseTypeFreeForm, Text: str(" ")}, "", http.StatusBadRequest}, - {"follow-up question", question, api.InboxResponseCreate{Type: api.InboxResponseTypeQuestion, Text: str("why?")}, api.Open, 0}, - {"redirect question", question, api.InboxResponseCreate{Type: api.InboxResponseTypeRedirect, Text: str("stop")}, api.Redirected, 0}, - {"redirect report", report, api.InboxResponseCreate{Type: api.InboxResponseTypeRedirect, Text: str("stop")}, api.Redirected, 0}, - {"snooze", question, api.InboxResponseCreate{Type: api.InboxResponseTypeSnooze, SnoozeUntil: &future}, api.Open, 0}, - {"snooze into past", question, api.InboxResponseCreate{Type: api.InboxResponseTypeSnooze, SnoozeUntil: &past}, "", http.StatusBadRequest}, - {"dismiss report", report, api.InboxResponseCreate{Type: api.InboxResponseTypeDismiss}, api.Dismissed, 0}, - {"dismiss question", question, api.InboxResponseCreate{Type: api.InboxResponseTypeDismiss}, "", http.StatusBadRequest}, - {"option on report", report, api.InboxResponseCreate{Type: api.InboxResponseTypeOption, Option: str("red")}, "", http.StatusBadRequest}, - {"already answered", closed, api.InboxResponseCreate{Type: api.InboxResponseTypeOption, Option: str("red")}, "", http.StatusConflict}, + {"option", question, api.InboxResponseCreate{Type: api.Option, Option: str("blue")}, api.Answered, 0}, + {"option with text", question, api.InboxResponseCreate{Type: api.Option, Option: str("red"), Text: str("but darker")}, "", http.StatusBadRequest}, + {"unknown option", question, api.InboxResponseCreate{Type: api.Option, Option: str("green")}, "", http.StatusBadRequest}, + {"missing option", question, api.InboxResponseCreate{Type: api.Option}, "", http.StatusBadRequest}, + {"other", question, api.InboxResponseCreate{Type: api.Other, Text: str("green")}, api.Answered, 0}, + {"empty other", question, api.InboxResponseCreate{Type: api.Other, Text: str(" ")}, "", http.StatusBadRequest}, + {"other on error", failure, api.InboxResponseCreate{Type: api.Other, Text: str("retry")}, api.Answered, 0}, + {"other on report", report, api.InboxResponseCreate{Type: api.Other, Text: str("stop")}, "", http.StatusBadRequest}, + {"snooze", question, api.InboxResponseCreate{Type: api.Snooze, SnoozeUntil: &future}, api.Open, 0}, + {"snooze into past", question, api.InboxResponseCreate{Type: api.Snooze, SnoozeUntil: &past}, "", http.StatusBadRequest}, + {"dismiss report", report, api.InboxResponseCreate{Type: api.Dismiss}, api.Dismissed, 0}, + {"dismiss question", question, api.InboxResponseCreate{Type: api.Dismiss}, "", http.StatusBadRequest}, + {"option on report", report, api.InboxResponseCreate{Type: api.Option, Option: str("red")}, "", http.StatusBadRequest}, + {"already answered", closed, api.InboxResponseCreate{Type: api.Option, Option: str("red")}, "", http.StatusConflict}, } for _, c := range cases { diff --git a/internal/store/inbox.go b/internal/store/inbox.go index 7bf9fb1..731ac89 100644 --- a/internal/store/inbox.go +++ b/internal/store/inbox.go @@ -24,7 +24,7 @@ func priorityRank(p api.InboxItemPriority) int { func DeliverableResponse(t api.InboxResponseType) bool { switch t { - case api.InboxResponseTypeOption, api.InboxResponseTypeFreeForm, api.InboxResponseTypeRedirect, api.InboxResponseTypeQuestion: + case api.Option, api.Other: return true } return false @@ -116,7 +116,7 @@ func (s *Store) ListInbox(ctx context.Context, f InboxFilter) ([]api.InboxItem, args = append(args, now()) } - rows, err := s.db.QueryContext(ctx, `SELECT id FROM inbox_items WHERE `+strings.Join(where, " AND ")+` ORDER BY priority, created_at`, args...) + rows, err := s.db.QueryContext(ctx, `SELECT id FROM inbox_items WHERE `+strings.Join(where, " AND ")+` ORDER BY created_at`, args...) if err != nil { return nil, err } @@ -195,9 +195,9 @@ func (s *Store) AwaitingHuman(ctx context.Context, sessionID string) (int, error 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 = ? - AND NOT EXISTS (SELECT 1 FROM inbox_responses r WHERE r.item_id = i.id AND r.type IN (?, ?, ?, ?)) - `, sessionID, string(api.InboxItemKindQuestion), string(api.Open), - string(api.InboxResponseTypeOption), string(api.InboxResponseTypeFreeForm), string(api.InboxResponseTypeRedirect), string(api.InboxResponseTypeQuestion)).Scan(&n) + 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) return n, err } @@ -209,9 +209,9 @@ type Pending struct { func (s *Store) Undelivered(ctx context.Context, sessionID string) ([]Pending, error) { rows, err := s.db.QueryContext(ctx, ` SELECT r.id, r.item_id FROM inbox_responses r JOIN inbox_items i ON i.id = r.item_id - WHERE i.agent_session_id = ? AND r.delivered_at IS NULL AND r.type IN (?, ?, ?, ?) + WHERE i.agent_session_id = ? AND r.delivered_at IS NULL AND r.type IN (?, ?) ORDER BY r.created_at - `, sessionID, string(api.InboxResponseTypeOption), string(api.InboxResponseTypeFreeForm), string(api.InboxResponseTypeRedirect), string(api.InboxResponseTypeQuestion)) + `, sessionID, string(api.Option), string(api.Other)) if err != nil { return nil, err } diff --git a/internal/store/store.go b/internal/store/store.go index 42c7015..59c20d3 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -122,6 +122,9 @@ CREATE TABLE turn_queue ( text TEXT NOT NULL, created_at TEXT NOT NULL ); +`, ` +UPDATE inbox_responses SET type = 'other' WHERE type IN ('free_form', 'redirect', 'question'); +UPDATE inbox_items SET state = 'answered' WHERE state = 'redirected'; `} type Store struct { diff --git a/web/dist/inbox.js b/web/dist/inbox.js index 40c6b5b..e130285 100644 --- a/web/dist/inbox.js +++ b/web/dist/inbox.js @@ -1,5 +1,6 @@ import { post } from "./api.js"; import { ago, errorText, h, replace } from "./dom.js"; +import { inlineMarkdown, markdown } from "./markdown.js"; import { findTask, onEach, state } from "./state.js"; import { reportCard } from "./task.js"; const drafts = new Map(); @@ -74,7 +75,7 @@ export function mountInbox(root) { modes.delete(id); } } - const els = items.map((item) => { + const cardFor = (item) => { const sig = JSON.stringify(item); const cached = cards.get(item.id); if (cached && cached.sig === sig) { @@ -85,6 +86,11 @@ export function mountInbox(root) { }); cards.set(item.id, { sig, el }); return el; + }; + const els = groupByTask(items).map((g) => { + const task = findTask(g.taskId); + const project = state.projects.find((p) => p.id === g.projectId); + return h("section", { class: `task-group ${g.blocked ? "blocked" : ""}` }, h("h3", {}, h("span", { class: "project-name" }, project?.name ?? g.projectId, " › "), h("a", { href: `#/task/${g.taskId}` }, task?.title ?? g.taskId)), ...g.items.map(cardFor)); }); replace(list, ...(els.length > 0 ? els : [h("div", { class: "empty" }, "Nothing waiting on you.")])); renderSubmit(); @@ -94,22 +100,50 @@ export function mountInbox(root) { render(); return off; } +function groupByTask(items) { + const groups = new Map(); + for (const item of [...items].sort((a, b) => a.created_at.localeCompare(b.created_at))) { + let g = groups.get(item.task_id); + if (!g) { + g = { taskId: item.task_id, projectId: item.project_id, blocked: false, items: [] }; + groups.set(item.task_id, g); + } + g.items.push(item); + g.blocked ||= item.priority === "blocked"; + } + const projectName = (id) => state.projects.find((p) => p.id === id)?.name ?? id; + return [...groups.values()].sort((a, b) => Number(b.blocked) - Number(a.blocked) || + projectName(a.projectId).localeCompare(projectName(b.projectId)) || + a.items[0].created_at.localeCompare(b.items[0].created_at)); +} function card(item, changed) { - const task = findTask(item.task_id); 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("a", { href: `#/task/${item.task_id}`, class: "card-task" }, task?.title ?? item.task_id), h("time", { dateTime: item.created_at, title: item.created_at }, ago(item.created_at))), body, thread(item), actions); - const allowed = item.kind === "question" ? ["option", "free_form", "question", "redirect", "snooze"] : ["dismiss", "redirect", "snooze"]; + 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, thread(item), actions); + const allowed = item.kind === "question" ? ["pick", "snooze"] : ["dismiss", "reply", "snooze"]; const labels = { - option: "Pick", - free_form: "Other answer", - question: "Ask back", - redirect: "Redirect", + pick: "Pick", + reply: "Reply", snooze: "Snooze", dismiss: "Dismiss", }; const renderActions = () => { + if (item.kind === "report") { + const ok = h("button", { type: "button", class: "primary" }, "OK"); + ok.onclick = async () => { + ok.disabled = true; + try { + await post("/api/inbox/responses", { body: { responses: [{ item_id: item.id, type: "dismiss" }] } }); + } + catch (err) { + alert(errorText(err)); + ok.disabled = false; + } + }; + replace(actions, h("div", { class: "ack" }, ok)); + return; + } const mode = modes.get(item.id) ?? allowed[0]; const tabs = h("div", { class: "modes" }, ...allowed.map((m) => { const b = h("button", { type: "button", class: m === mode ? "active" : "" }, labels[m]); @@ -128,7 +162,7 @@ function card(item, changed) { }; switch (item.kind) { case "question": - replace(body, h("p", { class: "question" }, String(p["question"])), h("p", { class: "why" }, h("strong", {}, "Blocked on: "), String(p["why_blocked"])), attachments(p["attachments"] ?? [])); + replace(body, p["context"] ? markdown(String(p["context"]), "md context") : null, markdown(String(p["question"]), "md question"), h("p", { class: "why" }, h("strong", {}, "Blocked on: "), inlineMarkdown(String(p["why_blocked"]))), attachments(p["attachments"] ?? [])); break; case "report": replace(body, reportCard(p)); @@ -158,33 +192,35 @@ function modeInput(item, mode, changed) { changed(); }; switch (mode) { - case "option": { + case "pick": { const p = item.payload; const options = p["options"] ?? []; - const note = h("input", { placeholder: "Optional note", value: draft?.text ?? "" }); - const choose = (option) => set({ item_id: item.id, type: "option", option, text: note.value || undefined }); - note.oninput = () => { - const current = drafts.get(item.id); - if (current?.type === "option" && current.option) { - choose(current.option); - } + const text = h("textarea", { + rows: 3, + placeholder: "Your answer, a question back, or new instructions", + value: draft?.type === "other" ? (draft.text ?? "") : "", + hidden: draft?.type !== "other", + }); + const setOther = () => set(text.value.trim() ? { item_id: item.id, type: "other", text: text.value } : undefined); + text.oninput = setOther; + const other = h("input", { type: "radio", name: `opt-${item.id}`, checked: draft?.type === "other" }); + other.onchange = () => { + text.hidden = false; + text.focus(); + setOther(); }; return h("div", { class: "options" }, ...options.map((option) => { - const radio = h("input", { type: "radio", name: `opt-${item.id}`, checked: drafts.get(item.id)?.option === option }); - radio.onchange = () => choose(option); - return h("label", { class: "option" }, radio, " ", option, option === p["recommended_option"] && h("span", { class: "recommended" }, "recommended")); - }), note); + const radio = h("input", { type: "radio", name: `opt-${item.id}`, checked: draft?.type === "option" && draft.option === option }); + radio.onchange = () => { + text.hidden = true; + set({ item_id: item.id, type: "option", option }); + }; + return h("label", { class: "option" }, radio, " ", inlineMarkdown(option), option === p["recommended_option"] && h("span", { class: "recommended" }, "recommended")); + }), h("label", { class: "option" }, other, " Other"), text); } - case "free_form": - case "question": - case "redirect": { - const placeholder = { - free_form: "Your answer", - question: "Your question back to the agent", - redirect: "New instructions for the agent", - }[mode]; - const text = h("textarea", { rows: 3, placeholder, value: draft?.type === mode ? (draft.text ?? "") : "" }); - text.oninput = () => set(text.value.trim() ? { item_id: item.id, type: mode, text: text.value } : undefined); + case "reply": { + const text = h("textarea", { rows: 3, placeholder: "Reply to the agent", value: draft?.type === "other" ? (draft.text ?? "") : "" }); + text.oninput = () => set(text.value.trim() ? { item_id: item.id, type: "other", text: text.value } : undefined); return text; } case "snooze": { diff --git a/web/dist/inbox.js.map b/web/dist/inbox.js.map index 0cbb347..4978e4a 100644 --- a/web/dist/inbox.js.map +++ b/web/dist/inbox.js.map @@ -1 +1 @@ -{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/web/dist/markdown.js b/web/dist/markdown.js new file mode 100644 index 0000000..388e53b --- /dev/null +++ b/web/dist/markdown.js @@ -0,0 +1,226 @@ +import { h } from "./dom.js"; +const fence = /^\s*(```|~~~)/; +const heading = /^(#{1,6})\s+(.*)$/; +const bullet = /^(\s*)[-*+]\s+(.*)$/; +const ordered = /^(\s*)(\d+)[.)]\s+(.*)$/; +const quote = /^\s*>\s?(.*)$/; +const rule = /^\s*([-*_])(\s*\1){2,}\s*$/; +const tableSep = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/; +export function markdown(src, className = "md") { + return h("div", { class: className }, ...blocks(src.replace(/\r\n?/g, "\n").split("\n"))); +} +export function inlineMarkdown(src) { + return h("span", { class: "md-inline" }, ...inline(src)); +} +function blocks(lines) { + const out = []; + let i = 0; + while (i < lines.length) { + const line = lines[i]; + if (line.trim() === "") { + i++; + continue; + } + const f = fence.exec(line); + if (f) { + const marker = f[1]; + const body = []; + i++; + while (i < lines.length && !lines[i].trimStart().startsWith(marker)) { + body.push(lines[i]); + i++; + } + i++; + out.push(h("pre", { class: "md-code" }, h("code", {}, body.join("\n")))); + continue; + } + const hd = heading.exec(line); + if (hd) { + const level = Math.min(hd[1].length + 2, 6); + out.push(h(`h${level}`, {}, ...inline(hd[2]))); + i++; + continue; + } + if (rule.test(line)) { + out.push(h("hr")); + i++; + continue; + } + if (quote.test(line)) { + const body = []; + while (i < lines.length && quote.test(lines[i])) { + body.push(quote.exec(lines[i])[1]); + i++; + } + out.push(h("blockquote", {}, ...blocks(body))); + continue; + } + if (bullet.test(line) || ordered.test(line)) { + const [list, next] = parseList(lines, i); + out.push(list); + i = next; + continue; + } + if (line.includes("|") && i + 1 < lines.length && tableSep.test(lines[i + 1])) { + const rows = [cells(line)]; + i += 2; + while (i < lines.length && lines[i].includes("|") && lines[i].trim() !== "") { + rows.push(cells(lines[i])); + i++; + } + out.push(table(rows)); + continue; + } + const para = []; + while (i < lines.length && lines[i].trim() !== "" && !startsBlock(lines, i)) { + para.push(lines[i].trim()); + i++; + } + out.push(h("p", {}, ...joinLines(para))); + } + return out; +} +function startsBlock(lines, i) { + const line = lines[i]; + return (fence.test(line) || + heading.test(line) || + rule.test(line) || + quote.test(line) || + bullet.test(line) || + ordered.test(line) || + (line.includes("|") && i + 1 < lines.length && tableSep.test(lines[i + 1]))); +} +function joinLines(lines) { + const out = []; + lines.forEach((l, n) => { + if (n > 0) { + out.push(h("br")); + } + out.push(...inline(l)); + }); + return out; +} +function indentOf(line) { + return line.length - line.trimStart().length; +} +function parseList(lines, start) { + const first = lines[start]; + const isOrdered = !bullet.test(first); + const base = indentOf(first); + const list = isOrdered ? h("ol") : h("ul"); + if (isOrdered) { + const n = Number(ordered.exec(first)[2]); + if (n !== 1) { + list.start = n; + } + } + let i = start; + while (i < lines.length) { + const line = lines[i]; + const m = isOrdered ? ordered.exec(line) : bullet.exec(line); + if (!m || indentOf(line) !== base) { + break; + } + const text = isOrdered ? m[3] : m[2]; + const body = [text]; + i++; + while (i < lines.length) { + const next = lines[i]; + if (next.trim() === "") { + const after = lines[i + 1]; + if (after !== undefined && indentOf(after) > base && after.trim() !== "") { + body.push(""); + i++; + continue; + } + break; + } + if (indentOf(next) <= base && (bullet.test(next) || ordered.test(next) || startsBlock(lines, i))) { + break; + } + body.push(indentOf(next) > base ? next.slice(Math.min(indentOf(next), base + 2)) : next.trim()); + i++; + } + list.append(item(body)); + while (i < lines.length && lines[i].trim() === "" && lines[i + 1] !== undefined && indentOf(lines[i + 1]) === base && (isOrdered ? ordered : bullet).test(lines[i + 1])) { + i++; + } + } + return [list, i]; +} +function item(body) { + const li = h("li"); + const rest = body.slice(1); + if (rest.every((l) => !startsBlockLine(l)) && !rest.includes("")) { + li.append(...joinLines(body.map((l) => l.trim()))); + return li; + } + const head = [body[0]]; + let k = 1; + while (k < body.length && body[k] !== "" && !startsBlockLine(body[k])) { + head.push(body[k].trim()); + k++; + } + li.append(...joinLines(head), ...blocks(body.slice(k))); + return li; +} +function startsBlockLine(line) { + return fence.test(line) || heading.test(line) || quote.test(line) || bullet.test(line) || ordered.test(line); +} +function cells(line) { + let s = line.trim(); + if (s.startsWith("|")) { + s = s.slice(1); + } + if (s.endsWith("|")) { + s = s.slice(0, -1); + } + return s.split("|").map((c) => c.trim()); +} +function table(rows) { + const [head, ...body] = rows; + return h("div", { class: "md-table" }, h("table", {}, h("thead", {}, h("tr", {}, ...head.map((c) => h("th", {}, ...inline(c))))), h("tbody", {}, ...body.map((r) => h("tr", {}, ...r.map((c) => h("td", {}, ...inline(c)))))))); +} +const inlineToken = /`([^`]+)`|\*\*(.+?)\*\*|__(.+?)__|\*([^*\s][^*]*?)\*|(?()]+[^\s<>().,;:!?'"])/; +function inline(src) { + const out = []; + let rest = src; + while (rest.length > 0) { + const m = inlineToken.exec(rest); + if (!m) { + out.push(document.createTextNode(rest)); + break; + } + if (m.index > 0) { + out.push(document.createTextNode(rest.slice(0, m.index))); + } + const [whole, code, strong1, strong2, em1, em2, linkText, linkHref, bare] = m; + if (code !== undefined) { + out.push(h("code", {}, code)); + } + else if (strong1 !== undefined || strong2 !== undefined) { + out.push(h("strong", {}, ...inline(strong1 ?? strong2))); + } + else if (em1 !== undefined || em2 !== undefined) { + out.push(h("em", {}, ...inline(em1 ?? em2))); + } + else if (linkText !== undefined) { + out.push(link(linkHref, inline(linkText))); + } + else if (bare !== undefined) { + out.push(link(bare, [document.createTextNode(bare)])); + } + rest = rest.slice(m.index + whole.length); + } + return out; +} +function link(href, children) { + if (/^https?:\/\//i.test(href)) { + return h("a", { href, target: "_blank", rel: "noopener noreferrer" }, ...children); + } + if (href.startsWith("#/")) { + return h("a", { href }, ...children); + } + return h("span", {}, ...children); +} +//# sourceMappingURL=markdown.js.map \ No newline at end of file diff --git a/web/dist/markdown.js.map b/web/dist/markdown.js.map new file mode 100644 index 0000000..fd30e2a --- /dev/null +++ b/web/dist/markdown.js.map @@ -0,0 +1 @@ +{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/web/dist/task.js b/web/dist/task.js index f9bb93d..271f9cf 100644 --- a/web/dist/task.js +++ b/web/dist/task.js @@ -1,5 +1,6 @@ import { post } from "./api.js"; import { ago, errorText, h, replace } from "./dom.js"; +import { inlineMarkdown, markdown } from "./markdown.js"; import { currentSession, findTask, onEach, state } from "./state.js"; const models = ["", "opus", "sonnet", "haiku"]; export function mountTranscript(root) { @@ -145,11 +146,11 @@ function renderEvent(ev, tools) { const when = h("time", { dateTime: ev.created_at, title: ev.created_at }, ago(ev.created_at)); switch (ev.kind) { case "user.message": - return h("div", { class: "msg user" }, h("div", { class: "who" }, ev.actor, " ", when), h("div", { class: "text" }, String(p["text"]))); + return h("div", { class: "msg user" }, h("div", { class: "who" }, ev.actor, " ", when), markdown(String(p["text"]), "text md")); case "agent.message": - return h("div", { class: "msg agent" }, h("div", { class: "text" }, String(p["text"]))); + return h("div", { class: "msg agent" }, markdown(String(p["text"]), "text md")); case "agent.thinking": - return h("details", { class: "thinking" }, h("summary", {}, "thinking"), h("div", { class: "text" }, String(p["text"]))); + return h("details", { class: "thinking" }, h("summary", {}, "thinking"), markdown(String(p["text"]), "text md")); case "agent.tool_call": { const result = h("div", { class: "tool-result pending" }, "running…"); tools.set(String(p["id"]), result); @@ -197,7 +198,6 @@ export function reportCard(p) { const sections = [ ["done", "Done"], ["deviations", "Deviations from plan"], - ["open_questions", "Open questions"], ["risks", "Risks"], ["next_steps", "Next steps"], ]; @@ -206,7 +206,7 @@ export function reportCard(p) { if (items.length === 0) { return null; } - return h("div", { class: `report-section ${key}` }, h("h4", {}, label), h("ul", {}, ...items.map((i) => h("li", {}, i)))); + return h("div", { class: `report-section ${key}` }, h("h4", {}, label), h("ul", {}, ...items.map((i) => h("li", {}, inlineMarkdown(i))))); })); } function toolBrief(input) { diff --git a/web/dist/task.js.map b/web/dist/task.js.map index 9da97b8..b00664d 100644 --- a/web/dist/task.js.map +++ b/web/dist/task.js.map @@ -1 +1 @@ -{"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/web/src/api.gen.ts b/web/src/api.gen.ts index 550111e..ebc6ee5 100644 --- a/web/src/api.gen.ts +++ b/web/src/api.gen.ts @@ -383,7 +383,7 @@ export interface components { caption?: string; }; /** @enum {string} */ - InboxState: "open" | "answered" | "redirected" | "dismissed" | "superseded"; + InboxState: "open" | "answered" | "dismissed" | "superseded"; InboxItem: { id: string; project_id: string; @@ -395,7 +395,7 @@ export interface components { /** @enum {string} */ priority: "blocked" | "gate" | "review" | "fyi"; blocking: boolean; - /** @description question: question, why_blocked, options, recommended_option, attachments. report: done, open_questions, next_steps, risks, deviations. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. */ + /** @description question: context, question, why_blocked, options, recommended_option, attachments. report: done, next_steps, risks, deviations. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. */ payload: Record; state: components["schemas"]["InboxState"]; /** Format: date-time */ @@ -408,7 +408,7 @@ export interface components { responses: components["schemas"]["InboxResponse"][]; }; /** @enum {string} */ - InboxResponseType: "option" | "free_form" | "redirect" | "question" | "snooze" | "dismiss"; + InboxResponseType: "option" | "other" | "snooze" | "dismiss"; InboxResponse: { id: string; item_id: string; @@ -429,7 +429,7 @@ export interface components { type: components["schemas"]["InboxResponseType"]; /** @description option: one of the question's options. */ option?: string; - /** @description Required for free_form, redirect, question; an optional note on option. */ + /** @description other: the text sent to the agent. */ text?: string; attachments?: components["schemas"]["Attachment"][]; /** diff --git a/web/src/inbox.ts b/web/src/inbox.ts index 3ab7dd0..6a6030d 100644 --- a/web/src/inbox.ts +++ b/web/src/inbox.ts @@ -1,10 +1,11 @@ import { post, type Attachment, type InboxItem, type InboxResponseCreate } from "./api.js"; import { ago, errorText, h, replace } from "./dom.js"; +import { inlineMarkdown, markdown } from "./markdown.js"; import { findTask, onEach, state } from "./state.js"; import { reportCard } from "./task.js"; type Scope = "all" | "project" | "task"; -type Mode = InboxResponseCreate["type"]; +type Mode = "pick" | "reply" | "snooze" | "dismiss"; const drafts = new Map(); const modes = new Map(); @@ -83,7 +84,7 @@ export function mountInbox(root: HTMLElement): () => void { } } - const els = items.map((item) => { + const cardFor = (item: InboxItem) => { const sig = JSON.stringify(item); const cached = cards.get(item.id); if (cached && cached.sig === sig) { @@ -94,6 +95,17 @@ export function mountInbox(root: HTMLElement): () => void { }); cards.set(item.id, { sig, el }); return el; + }; + + const els = groupByTask(items).map((g) => { + const task = findTask(g.taskId); + const project = state.projects.find((p) => p.id === g.projectId); + return h( + "section", + { class: `task-group ${g.blocked ? "blocked" : ""}` }, + h("h3", {}, h("span", { class: "project-name" }, project?.name ?? g.projectId, " › "), h("a", { href: `#/task/${g.taskId}` }, task?.title ?? g.taskId)), + ...g.items.map(cardFor), + ); }); replace(list, ...(els.length > 0 ? els : [h("div", { class: "empty" }, "Nothing waiting on you.")])); @@ -106,8 +118,29 @@ export function mountInbox(root: HTMLElement): () => void { return off; } +type Group = { taskId: string; projectId: string; blocked: boolean; items: InboxItem[] }; + +function groupByTask(items: InboxItem[]): Group[] { + const groups = new Map(); + for (const item of [...items].sort((a, b) => a.created_at.localeCompare(b.created_at))) { + let g = groups.get(item.task_id); + if (!g) { + g = { taskId: item.task_id, projectId: item.project_id, blocked: false, items: [] }; + groups.set(item.task_id, g); + } + g.items.push(item); + g.blocked ||= item.priority === "blocked"; + } + const projectName = (id: string) => state.projects.find((p) => p.id === id)?.name ?? id; + return [...groups.values()].sort( + (a, b) => + Number(b.blocked) - Number(a.blocked) || + projectName(a.projectId).localeCompare(projectName(b.projectId)) || + a.items[0]!.created_at.localeCompare(b.items[0]!.created_at), + ); +} + function card(item: InboxItem, changed: () => void): HTMLElement { - const task = findTask(item.task_id); const p = item.payload as Record; const body = h("div", { class: "card-body" }); const actions = h("div", { class: "card-actions" }); @@ -119,7 +152,6 @@ function card(item: InboxItem, changed: () => void): HTMLElement { {}, h("span", { class: `priority ${item.priority}` }, item.priority), h("span", { class: "kind" }, item.kind.replace("_", " ")), - h("a", { href: `#/task/${item.task_id}`, class: "card-task" }, task?.title ?? item.task_id), h("time", { dateTime: item.created_at, title: item.created_at }, ago(item.created_at)), ), body, @@ -127,18 +159,29 @@ function card(item: InboxItem, changed: () => void): HTMLElement { actions, ); - const allowed: Mode[] = - item.kind === "question" ? ["option", "free_form", "question", "redirect", "snooze"] : ["dismiss", "redirect", "snooze"]; + const allowed: Mode[] = item.kind === "question" ? ["pick", "snooze"] : ["dismiss", "reply", "snooze"]; const labels: Record = { - option: "Pick", - free_form: "Other answer", - question: "Ask back", - redirect: "Redirect", + pick: "Pick", + reply: "Reply", snooze: "Snooze", dismiss: "Dismiss", }; const renderActions = () => { + if (item.kind === "report") { + const ok = h("button", { type: "button", class: "primary" }, "OK"); + ok.onclick = async () => { + ok.disabled = true; + try { + await post("/api/inbox/responses", { body: { responses: [{ item_id: item.id, type: "dismiss" }] } }); + } catch (err) { + alert(errorText(err)); + ok.disabled = false; + } + }; + replace(actions, h("div", { class: "ack" }, ok)); + return; + } const mode = modes.get(item.id) ?? allowed[0]!; const tabs = h( "div", @@ -164,8 +207,9 @@ function card(item: InboxItem, changed: () => void): HTMLElement { case "question": replace( body, - h("p", { class: "question" }, String(p["question"])), - h("p", { class: "why" }, h("strong", {}, "Blocked on: "), String(p["why_blocked"])), + p["context"] ? markdown(String(p["context"]), "md context") : null, + markdown(String(p["question"]), "md question"), + h("p", { class: "why" }, h("strong", {}, "Blocked on: "), inlineMarkdown(String(p["why_blocked"]))), attachments((p["attachments"] as Attachment[] | undefined) ?? []), ); break; @@ -199,39 +243,49 @@ function modeInput(item: InboxItem, mode: Mode, changed: () => void): HTMLElemen }; switch (mode) { - case "option": { + case "pick": { const p = item.payload as Record; const options = (p["options"] as string[]) ?? []; - const note = h("input", { placeholder: "Optional note", value: draft?.text ?? "" }); - const choose = (option: string) => set({ item_id: item.id, type: "option", option, text: note.value || undefined }); - note.oninput = () => { - const current = drafts.get(item.id); - if (current?.type === "option" && current.option) { - choose(current.option); - } + const text = h("textarea", { + rows: 3, + placeholder: "Your answer, a question back, or new instructions", + value: draft?.type === "other" ? (draft.text ?? "") : "", + hidden: draft?.type !== "other", + }); + const setOther = () => set(text.value.trim() ? { item_id: item.id, type: "other", text: text.value } : undefined); + text.oninput = setOther; + const other = h("input", { type: "radio", name: `opt-${item.id}`, checked: draft?.type === "other" }); + other.onchange = () => { + text.hidden = false; + text.focus(); + setOther(); }; return h( "div", { class: "options" }, ...options.map((option) => { - const radio = h("input", { type: "radio", name: `opt-${item.id}`, checked: drafts.get(item.id)?.option === option }); - radio.onchange = () => choose(option); - return h("label", { class: "option" }, radio, " ", option, option === p["recommended_option"] && h("span", { class: "recommended" }, "recommended")); + const radio = h("input", { type: "radio", name: `opt-${item.id}`, checked: draft?.type === "option" && draft.option === option }); + radio.onchange = () => { + text.hidden = true; + set({ item_id: item.id, type: "option", option }); + }; + return h( + "label", + { class: "option" }, + radio, + " ", + inlineMarkdown(option), + option === p["recommended_option"] && h("span", { class: "recommended" }, "recommended"), + ); }), - note, + h("label", { class: "option" }, other, " Other"), + text, ); } - case "free_form": - case "question": - case "redirect": { - const placeholder = { - free_form: "Your answer", - question: "Your question back to the agent", - redirect: "New instructions for the agent", - }[mode]; - const text = h("textarea", { rows: 3, placeholder, value: draft?.type === mode ? (draft.text ?? "") : "" }); - text.oninput = () => set(text.value.trim() ? { item_id: item.id, type: mode, text: text.value } : undefined); + case "reply": { + const text = h("textarea", { rows: 3, placeholder: "Reply to the agent", value: draft?.type === "other" ? (draft.text ?? "") : "" }); + text.oninput = () => set(text.value.trim() ? { item_id: item.id, type: "other", text: text.value } : undefined); return text; } diff --git a/web/src/markdown.ts b/web/src/markdown.ts new file mode 100644 index 0000000..8d045a8 --- /dev/null +++ b/web/src/markdown.ts @@ -0,0 +1,260 @@ +import { h } from "./dom.js"; + +type Block = HTMLElement; + +const fence = /^\s*(```|~~~)/; +const heading = /^(#{1,6})\s+(.*)$/; +const bullet = /^(\s*)[-*+]\s+(.*)$/; +const ordered = /^(\s*)(\d+)[.)]\s+(.*)$/; +const quote = /^\s*>\s?(.*)$/; +const rule = /^\s*([-*_])(\s*\1){2,}\s*$/; +const tableSep = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/; + +export function markdown(src: string, className = "md"): HTMLElement { + return h("div", { class: className }, ...blocks(src.replace(/\r\n?/g, "\n").split("\n"))); +} + +export function inlineMarkdown(src: string): HTMLElement { + return h("span", { class: "md-inline" }, ...inline(src)); +} + +function blocks(lines: string[]): Block[] { + const out: Block[] = []; + let i = 0; + + while (i < lines.length) { + const line = lines[i]!; + + if (line.trim() === "") { + i++; + continue; + } + + const f = fence.exec(line); + if (f) { + const marker = f[1]!; + const body: string[] = []; + i++; + while (i < lines.length && !lines[i]!.trimStart().startsWith(marker)) { + body.push(lines[i]!); + i++; + } + i++; + out.push(h("pre", { class: "md-code" }, h("code", {}, body.join("\n")))); + continue; + } + + const hd = heading.exec(line); + if (hd) { + const level = Math.min(hd[1]!.length + 2, 6) as 3 | 4 | 5 | 6; + out.push(h(`h${level}`, {}, ...inline(hd[2]!))); + i++; + continue; + } + + if (rule.test(line)) { + out.push(h("hr")); + i++; + continue; + } + + if (quote.test(line)) { + const body: string[] = []; + while (i < lines.length && quote.test(lines[i]!)) { + body.push(quote.exec(lines[i]!)![1]!); + i++; + } + out.push(h("blockquote", {}, ...blocks(body))); + continue; + } + + if (bullet.test(line) || ordered.test(line)) { + const [list, next] = parseList(lines, i); + out.push(list); + i = next; + continue; + } + + if (line.includes("|") && i + 1 < lines.length && tableSep.test(lines[i + 1]!)) { + const rows: string[][] = [cells(line)]; + i += 2; + while (i < lines.length && lines[i]!.includes("|") && lines[i]!.trim() !== "") { + rows.push(cells(lines[i]!)); + i++; + } + out.push(table(rows)); + continue; + } + + const para: string[] = []; + while (i < lines.length && lines[i]!.trim() !== "" && !startsBlock(lines, i)) { + para.push(lines[i]!.trim()); + i++; + } + out.push(h("p", {}, ...joinLines(para))); + } + + return out; +} + +function startsBlock(lines: string[], i: number): boolean { + const line = lines[i]!; + return ( + fence.test(line) || + heading.test(line) || + rule.test(line) || + quote.test(line) || + bullet.test(line) || + ordered.test(line) || + (line.includes("|") && i + 1 < lines.length && tableSep.test(lines[i + 1]!)) + ); +} + +function joinLines(lines: string[]): Node[] { + const out: Node[] = []; + lines.forEach((l, n) => { + if (n > 0) { + out.push(h("br")); + } + out.push(...inline(l)); + }); + return out; +} + +function indentOf(line: string): number { + return line.length - line.trimStart().length; +} + +function parseList(lines: string[], start: number): [HTMLElement, number] { + const first = lines[start]!; + const isOrdered = !bullet.test(first); + const base = indentOf(first); + const list = isOrdered ? h("ol") : h("ul"); + if (isOrdered) { + const n = Number(ordered.exec(first)![2]); + if (n !== 1) { + (list as HTMLOListElement).start = n; + } + } + + let i = start; + while (i < lines.length) { + const line = lines[i]!; + const m = isOrdered ? ordered.exec(line) : bullet.exec(line); + if (!m || indentOf(line) !== base) { + break; + } + const text = isOrdered ? m[3]! : m[2]!; + const body: string[] = [text]; + i++; + while (i < lines.length) { + const next = lines[i]!; + if (next.trim() === "") { + const after = lines[i + 1]; + if (after !== undefined && indentOf(after) > base && after.trim() !== "") { + body.push(""); + i++; + continue; + } + break; + } + if (indentOf(next) <= base && (bullet.test(next) || ordered.test(next) || startsBlock(lines, i))) { + break; + } + body.push(indentOf(next) > base ? next.slice(Math.min(indentOf(next), base + 2)) : next.trim()); + i++; + } + list.append(item(body)); + while (i < lines.length && lines[i]!.trim() === "" && lines[i + 1] !== undefined && indentOf(lines[i + 1]!) === base && (isOrdered ? ordered : bullet).test(lines[i + 1]!)) { + i++; + } + } + return [list, i]; +} + +function item(body: string[]): HTMLElement { + const li = h("li"); + const rest = body.slice(1); + if (rest.every((l) => !startsBlockLine(l)) && !rest.includes("")) { + li.append(...joinLines(body.map((l) => l.trim()))); + return li; + } + const head: string[] = [body[0]!]; + let k = 1; + while (k < body.length && body[k] !== "" && !startsBlockLine(body[k]!)) { + head.push(body[k]!.trim()); + k++; + } + li.append(...joinLines(head), ...blocks(body.slice(k))); + return li; +} + +function startsBlockLine(line: string): boolean { + return fence.test(line) || heading.test(line) || quote.test(line) || bullet.test(line) || ordered.test(line); +} + +function cells(line: string): string[] { + let s = line.trim(); + if (s.startsWith("|")) { + s = s.slice(1); + } + if (s.endsWith("|")) { + s = s.slice(0, -1); + } + return s.split("|").map((c) => c.trim()); +} + +function table(rows: string[][]): HTMLElement { + const [head, ...body] = rows; + return h( + "div", + { class: "md-table" }, + h( + "table", + {}, + h("thead", {}, h("tr", {}, ...head!.map((c) => h("th", {}, ...inline(c))))), + h("tbody", {}, ...body.map((r) => h("tr", {}, ...r.map((c) => h("td", {}, ...inline(c)))))), + ), + ); +} + +const inlineToken = /`([^`]+)`|\*\*(.+?)\*\*|__(.+?)__|\*([^*\s][^*]*?)\*|(?()]+[^\s<>().,;:!?'"])/; + +function inline(src: string): Node[] { + const out: Node[] = []; + let rest = src; + while (rest.length > 0) { + const m = inlineToken.exec(rest); + if (!m) { + out.push(document.createTextNode(rest)); + break; + } + if (m.index > 0) { + out.push(document.createTextNode(rest.slice(0, m.index))); + } + const [whole, code, strong1, strong2, em1, em2, linkText, linkHref, bare] = m; + if (code !== undefined) { + out.push(h("code", {}, code)); + } else if (strong1 !== undefined || strong2 !== undefined) { + out.push(h("strong", {}, ...inline(strong1 ?? strong2!))); + } else if (em1 !== undefined || em2 !== undefined) { + out.push(h("em", {}, ...inline(em1 ?? em2!))); + } else if (linkText !== undefined) { + out.push(link(linkHref!, inline(linkText))); + } else if (bare !== undefined) { + out.push(link(bare, [document.createTextNode(bare)])); + } + rest = rest.slice(m.index + whole.length); + } + return out; +} + +function link(href: string, children: Node[]): Node { + if (/^https?:\/\//i.test(href)) { + return h("a", { href, target: "_blank", rel: "noopener noreferrer" }, ...children); + } + if (href.startsWith("#/")) { + return h("a", { href }, ...children); + } + return h("span", {}, ...children); +} diff --git a/web/src/task.ts b/web/src/task.ts index 2c3210e..9ae148c 100644 --- a/web/src/task.ts +++ b/web/src/task.ts @@ -1,5 +1,6 @@ import { post, type ByreEvent } from "./api.js"; import { ago, errorText, h, replace } from "./dom.js"; +import { inlineMarkdown, markdown } from "./markdown.js"; import { currentSession, findTask, onEach, state } from "./state.js"; const models = ["", "opus", "sonnet", "haiku"]; @@ -163,13 +164,13 @@ function renderEvent(ev: ByreEvent, tools: Map): HTMLElemen switch (ev.kind) { case "user.message": - return h("div", { class: "msg user" }, h("div", { class: "who" }, ev.actor, " ", when), h("div", { class: "text" }, String(p["text"]))); + return h("div", { class: "msg user" }, h("div", { class: "who" }, ev.actor, " ", when), markdown(String(p["text"]), "text md")); case "agent.message": - return h("div", { class: "msg agent" }, h("div", { class: "text" }, String(p["text"]))); + return h("div", { class: "msg agent" }, markdown(String(p["text"]), "text md")); case "agent.thinking": - return h("details", { class: "thinking" }, h("summary", {}, "thinking"), h("div", { class: "text" }, String(p["text"]))); + return h("details", { class: "thinking" }, h("summary", {}, "thinking"), markdown(String(p["text"]), "text md")); case "agent.tool_call": { const result = h("div", { class: "tool-result pending" }, "running…"); @@ -233,7 +234,6 @@ export function reportCard(p: Record): HTMLElement { const sections: [string, string][] = [ ["done", "Done"], ["deviations", "Deviations from plan"], - ["open_questions", "Open questions"], ["risks", "Risks"], ["next_steps", "Next steps"], ]; @@ -245,7 +245,7 @@ export function reportCard(p: Record): HTMLElement { if (items.length === 0) { return null; } - return h("div", { class: `report-section ${key}` }, h("h4", {}, label), h("ul", {}, ...items.map((i) => h("li", {}, i)))); + return h("div", { class: `report-section ${key}` }, h("h4", {}, label), h("ul", {}, ...items.map((i) => h("li", {}, inlineMarkdown(i))))); }), ); } diff --git a/web/style.css b/web/style.css index b797e6b..fe0bb33 100644 --- a/web/style.css +++ b/web/style.css @@ -481,11 +481,101 @@ textarea { text-align: center; } -.msg .text { - white-space: pre-wrap; +.md { word-break: break-word; } +.md > :first-child { + margin-top: 0; +} + +.md > :last-child { + margin-bottom: 0; +} + +.md p, +.md ul, +.md ol, +.md blockquote, +.md pre, +.md .md-table { + margin: 0 0 8px; +} + +.md ul, +.md ol { + padding-left: 22px; +} + +.md li > ul, +.md li > ol { + margin: 2px 0; +} + +.md h3, +.md h4, +.md h5, +.md h6 { + margin: 12px 0 4px; + font-size: 14px; +} + +.md h3 { + font-size: 15px; +} + +.md blockquote { + border-left: 3px solid var(--border); + padding-left: 10px; + color: var(--muted); +} + +.md hr { + border: none; + border-top: 1px solid var(--border); + margin: 10px 0; +} + +.md code { + background: var(--surface); + border-radius: 4px; + padding: 0 4px; +} + +.md pre.md-code { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 6px; + padding: 6px 8px; + overflow-x: auto; + white-space: pre; +} + +.md pre.md-code code { + background: none; + padding: 0; +} + +.md .md-table { + overflow-x: auto; +} + +.md table { + border-collapse: collapse; +} + +.md th, +.md td { + border: 1px solid var(--border); + padding: 3px 8px; + text-align: left; + vertical-align: top; +} + +.md th { + background: var(--surface); +} + .msg.user { align-self: flex-end; max-width: 85%; @@ -518,7 +608,6 @@ textarea { } .thinking .text { - white-space: pre-wrap; color: var(--muted); padding: 6px 0; } @@ -682,17 +771,42 @@ textarea { color: var(--danger); } -.card-task { +.task-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.task-group + .task-group { + margin-top: 8px; +} + +.task-group h3 { + margin: 0; + font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.task-group.blocked h3 a { + color: var(--danger); +} + +.context { + margin: 10px 0; +} + .question { font-weight: 700; margin: 10px 0 4px; } +.ack { + display: flex; + justify-content: flex-end; +} + .why { color: var(--muted); margin: 0 0 8px;