Skip to content

Render peer agent messages as teammate cards instead of steering (#309) - #328

Open
cboos wants to merge 5 commits into
mainfrom
dev/agent-message-origin
Open

Render peer agent messages as teammate cards instead of steering (#309)#328
cboos wants to merge 5 commits into
mainfrom
dev/agent-message-origin

Conversation

@cboos

@cboos cboos commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #309.

Issue #309 shows a peer agent message arriving as a queued_command attachment with origin.kind == "peer" being rendered as "User (steering)" with the outer <agent-message> XML wrapper tags leaked into the card body (the issue screenshot displays the exact fixture uuid covered by our test case).

This change:

  • Reuses TeammateMessage and TeammateMessageBlock for peer queued_command attachments.
  • Sets teammate_id from origin.from or origin.name, and preserves sender_task_id (origin.senderTaskId) on TeammateMessageBlock for subagent transcript correlation.
  • Extracts clean body prose from origin.body, with fallback to unwrapping outer <agent-message> tags via ATTR_RUN from teammate_factory (ensuring attribute values containing > do not truncate the opening tag).
  • Preserves the is_system invariant when the peer sender is system.
  • Preserves existing UserSteeringMessage handling for human steering (origin.kind == "human") and legacy origin-less attachments.

Validation

  • Synthetic test suite added in test/test_steering_queued_command.py covering HTML and Markdown rendering, attribute parsing with >, is_system class rendering, and human/absent origin retention.
  • Mutation tested: verified that reverting regex or is_system logic causes targeted tests to fail.
  • All unit, TUI, browser, integration, and benchmark tests pass cleanly (just ci).

Summary by CodeRabbit

  • New Features

    • Peer-agent messages in queued commands are displayed as teammate message cards with sender identity, task information, system status, and message content.
    • Peer-message attribution is supported in HTML and Markdown output.
    • Message wrapper markup is removed from displayed peer-message text.
  • Bug Fixes

    • Human-authored and legacy queued-command messages continue to appear as user steering cards.
    • Peer messages without message bodies now fall back gracefully.
  • Documentation

    • Added documentation covering peer-agent message attribution and supported message formats.

cboos and others added 3 commits September 11, 2026 00:22
Specification only, no implementation. Peer agent messages arrive as a
`queued_command` attachment whose `origin` object the attachment factory
never reads, so they render as "User (steering)" with the
`<agent-message from=…>` wrapper visible in the card body.

The brief records the data shape, a structural census of `origin.kind`
(human 2554, no-origin 2431, peer 29), the 29/29 resolution of
`origin.senderTaskId` to the sender's subagent transcript, why `channel`
is out of scope, the delicate parts of the steering path, and the test
and cache obligations.

Based on the Agent-spawn linking branch: the two share no code, but the
cross-link from a peer card to its sender's transcript only resolves once
subagent transcripts are linked at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#309)

Peer agent messages arrive as a `type: "attachment"` entry with
`attachment.type: "queued_command"` carrying an `origin` object with
`kind: "peer"`. Previously, `_create_queued_command_message` ignored
`origin` and converted all queued commands into `UserSteeringMessage`
using the raw `prompt`, causing two defects:
  1. Misattribution: rendered as "User (steering)" (attributed to the human).
  2. Leaked markup: the raw `<agent-message from="...">` wrapper rendered
     literally in the card body.

Reuse `TeammateMessage` and `TeammateMessageBlock` for peer agent messages:
  - Add optional `sender_task_id` on `TeammateMessageBlock` to preserve
    `origin.senderTaskId` (for future subagent transcript linking).
  - In `attachment_factory._create_queued_command_message`, promote
    `origin.kind == "peer"` attachments to `TeammateMessage` with clean
    prose from `origin.body` (falling back to stripping the wrapper tags
    via `ATTR_RUN` from `teammate_factory` to safely handle attributes
    containing `>`).
  - Set `is_system=(sender == SYSTEM_ID)` on the teammate block.
  - Common human steering (`origin.kind == "human"`) and legacy
    origin-less entries remain untouched.

Covered with synthetic HTML/Markdown test cases and mutation checks.

Co-Authored-By: Antigravity (Gemini 3.8 Flash) <antigravity@google.com>
- F4: 'teammate-system' appears in inlined CSS stylesheets, so
  asserting 'teammate-system' in html passed even when the element
  lacked the class. Anchor the assertion to the element's class attribute
  (class="teammate-message teammate-system"), which genuinely discriminates.
- F5: Drop redundant _ATTR_RUN and _SYSTEM_ID aliases in teammate_factory.py.

Co-Authored-By: Antigravity (Gemini 3.8 Flash) <antigravity@google.com>
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 2f68939d-f579-4b76-8108-09c2c522be28

📥 Commits

Reviewing files that changed from the base of the PR and between c013090 and afa9911.

📒 Files selected for processing (1)
  • work/agent-message-origin.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • work/agent-message-origin.md

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

Queued-command attachments now distinguish peer origins from human or absent origins. Peer messages render as attributed teammate cards, preserve sender task IDs, identify system senders, and strip outer <agent-message> markup. Tests cover HTML, Markdown, fallbacks, and regressions.

Changes

Peer message rendering

Layer / File(s) Summary
Message contracts and teammate constants
claude_code_log/models.py, claude_code_log/factories/teammate_factory.py
TeammateMessageBlock now stores an optional sender_task_id. Teammate parsing uses public ATTR_RUN and SYSTEM_ID constants.
Peer attachment routing and body extraction
claude_code_log/factories/attachment_factory.py, work/agent-message-origin.md
Peer-origin queued_command attachments create attributed TeammateMessage cards. The factory strips outer <agent-message> wrappers and falls back to cleaned prompt text when origin.body is unavailable.
Rendering and fallback coverage
test/test_steering_queued_command.py
Tests cover HTML and Markdown attribution, body extraction, system styling, missing origins, missing bodies, wrapper attributes containing >, and existing human steering behavior.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QueuedCommand
  participant AttachmentFactory
  participant TeammateMessage
  participant Renderer
  QueuedCommand->>AttachmentFactory: provide peer origin and prompt text
  AttachmentFactory->>AttachmentFactory: strip outer agent-message wrapper
  AttachmentFactory->>TeammateMessage: create sender-attributed message
  TeammateMessage->>Renderer: provide sender, task ID, status, and body
  Renderer-->>QueuedCommand: render teammate card
Loading

Merge Risk: ⚪ Minimal · up to afa99

This increment has no reviewer findings to act on and no supplied change details indicating new risk, so there is no merge-blocking concern identified at this time.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: rendering peer agent messages as teammate cards instead of steering messages.
Linked Issues check ✅ Passed The changes address issue #309 by identifying peer queued-command messages, extracting their content, preserving sender metadata, and rendering them as teammate cards. Tests cover peer, system, human,…
Out of Scope Changes check ✅ Passed The changes are within scope for issue #309. The parser updates, model field, tests, and design note directly support peer-agent message recognition and rendering.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 4 files. (1 skipped: 1 …
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/agent-message-origin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

cboos and others added 2 commits September 11, 2026 00:55
Replace private session identifier and entry UUID in work/agent-message-origin.md
with descriptive references to the issue's screenshot and local session shape.

Co-Authored-By: Antigravity (Gemini 3.8 Flash) <antigravity@google.com>
Clean up duplicated descriptions and remove stale '#316 has merged'
clause in work/agent-message-origin.md.

Co-Authored-By: Antigravity (Gemini 3.8 Flash) <antigravity@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Team mate agent message not recognized as such

1 participant