acpmux inbox notice: received lines in the transcript, less text for the agent

Merged
TE
5d ago
+1336-57

Leo (2026-10-31), with a screenshot of an agent chat that showed three inbox notices as the person's own bubbles: "isn't this rendered pretty terribly? why do we have this like this? why is there so much additional text?"

Takes back #28749: its inbox part only. #28749 drew an inbox_notice as a message card named "inbox" that opens to the notice's text, and folded adjacent notices into a LaneNoticeBatch ("3 inbox threads"). That is the text Leo called out, so here an inbox_notice becomes kind inbox (each thread under its real sender, the messages whole) and adjacent notices fold through mergeInboxNotices. #28749's inbox branch in incomingPrompt could no longer run and is removed. Its lane reports, their batching and LaneNoticeBatch are unchanged.

What changes

Webview. A prompt whose provenance is acpmux's inbox_notice (hub/inbox.rs, #27686) is no longer drawn as its text. incomingMessage.ts had no case for it, so it fell through to a user bubble. Now:

  • Each thread is another agent's received line, as IncomingMessageCard draws a message: the newest sender's mark and name (a click opens that chat), the thread's label (#PR or the topic), the newest message's first line, and "+N more". A click opens the thread's new messages whole, oldest first. They come from the notice's own copy, or from _acpmux/inbox_thread (new chat.inbox.thread action, AcpmuxDirectClient.inboxThread) without marking anything read.
  • Two or more threads, or notices next to each other (mergeInboxNotices), fold into one line, "N messages from M sessions" plus the senders, in the waiting-messages group's look (PendingMessagesCard). Find, the row estimate and the open state follow the existing patterns (incomingOpened.ts, joined).
  • No text written for the agent is shown. A failed turn the notice started never sends the notice's text again as if the person typed it (no composer resend, as for notice); acpmux's own turn retry (_acpmux/retry), which reruns the turn and sends nothing from the person, is still offered. IncomingMessageCard and the agent_message cards are not restyled.

Daemon (hub/inbox.rs render).

  • The instruction sentence ("They need no turn of your own: …") is gone from every notice. The inbox_read tool description says it now.
  • When the new messages total 4 KB or less (their text as sent), the notice holds them whole, messages untrimmed: a one-line message on its thread's line, longer ones quoted under it. That fixes the agent that has no inbox_read tool and saw only a 120-character preview.
  • Over 4 KB, previews stay, and the header says how to read a thread from any harness: inbox_read, or acpmux session inbox "$ACPMUX_SESSION_ID" --thread ID --mark-read (asked for by the lane that owns the Labs gating fix, #28707; it does not touch render).
  • The provenance threads keep threadId/new/from/promptIds and add label, blocker, preview, newestAt, fromSession and, when whole, messages. A notice logged before this change still renders: the webview reads the label and preview back from its text.

Design spec: leo-workspace design/chat-transcript.md gets the rule "Never draw a system or agent-to-agent notice as the person's own bubble" (leo-workspace PR to follow).

Screenshots

Gallery entry agent-pane.inbox-notice, 2x, synthetic names and messages. Before is the base rendering of the same three notices (variant before-six).

LightDark
Before: three notices in a row, as acpmux wrote them (base)before, lightbefore, dark
After: the same six threads, one lineafter, lightafter, dark
After: opened, a thread of three messages openedafter open, lightafter open, dark
After: a notice of one thread, openedone thread open, lightone thread open, dark
After: three threads (closed)three threads, light

Versions

Three versions are in the gallery (theme.inboxNoticeLook): group (the default, shown above), lines (a received line per thread, no head) and card (the lines in one bordered card). I picked group: it matches the spec's waiting-messages group, and six threads take one line until opened. lines reads well at three threads but stacks at six. card adds a box the rest of the transcript doesn't use.

linescard
lines versioncard version

I viewed every after image above, light and dark, at 2x.

Tests

  • cargo test -p acpmux --lib -- hub::inbox acpmux_mcp: 21 passed. a_notice_is_one_line_per_thread_blockers_first_then_the_newest now checks the whole-text form and the new parts; a_long_notice_has_previews_and_says_how_to_read_a_thread_from_any_harness and a_whole_notice_keeps_every_message_as_it_was_sent (a blank message keeps its quote line, an indented one its indent, the 4 KB counts untrimmed text) are new.
  • cargo test -p acpmux --test hub_integration -- agent_inbox: 11 passed (300-message notice, blocker order, threads read whole).
  • bun test conversation/incomingMessage.test.ts conversation/inboxNotice.test.ts: 40 passed (inbox_notice → threads, the fallback for old notices, a notice with no thread → hidden, the merge of adjacent notices, label rules).
  • bun test conversation/InboxNoticeCard.test.tsx: 2 passed, both red on the first head's component: a thread read from acpmux reads again when a later notice brings new messages, and a read that finds nothing keeps the preview.
  • Every tracked webviews/src/agent-session/acpmux test file, run one file at a time: all pass.
  • bun run check: type check clean. The remaining reds (check:layers, check:design-tokens, vp fmt --check and vp lint warnings) name only src/pages/settings/*, which this PR does not touch.

Observed / Not run

  • Ran: everything above, on a lane VM. The screenshots come from the local gallery dev server with Playwright Chromium.
  • Not run: a tagged Mac build. This changes only the webview and the acpmux daemon's notice text; there is no Swift change.

Changelog

  • Changed: Messages other agents leave in a chat's inbox show as sender lines that open to the messages, not as raw notice text in your own bubble.

risk: normal (webview rendering, and the text of the agent-facing notice).

Agent session: agent session

šŸ¤– Generated with Claude Code