Skip to content

feat(a2a): warn senders when the receiver is mid-turn with messages waiting - #426

Merged
Jacksondr5 merged 4 commits into
j5/mainfrom
t3code/a2a-message-queue-backpressure
Oct 3, 2026
Merged

Jacksondr5 merged 4 commits into
j5/mainfrom
t3code/a2a-message-queue-backpressure

Conversation

@Jacksondr5

Copy link
Copy Markdown
Owner

Problem

A message to an agent whose turn is running is queued as its own run, so a stream of small updates becomes a stream of turns for the receiver. Agents, Astra senders most of all, have queued up to 11 messages on one Claude thread here (40 seen elsewhere), and the receiver tends to answer each one. Our own Crew instruction invited it ("share intermediate findings … as soon as useful"). Letting peer messages steer Claude instead is not an option: a live test on Claude Code 2.1.287 showed a priority: "now" steer cancels a pending sibling tool call with a fake "The user doesn't want to take this action" refusal (see #424).

Closes #424.

What changed

  • Warning in the send result. send_message and t3_thread_send_attachments return a deliveryNotice when the receiver is mid-turn and won't take the message into that turn. It says how many messages are waiting for the receiver, how many are the caller's, that each runs as its own turn, and to put further updates in one message. A send to an idle receiver or a running Astra turn gets no notice.
  • How it's measured. apps/server/src/j5/a2a/receiverBacklog.ts reads it when the tool is called. It counts the receiver's queued A2A runs plus committed deliveries the worker hasn't handed over yet. Nothing is stored. The read is advisory, so a failure is logged and the send still succeeds.
  • No notice in three cases:
  • Wording. The send_message description gains one sentence. The Crew coordination line stops asking for findings "as soon as useful" and asks for them grouped into one message. The seat brief and the propose_crew description drop "intermediate findings" to match. envelopes.v1.json is bumped to version 20.
  • Definition. docs/j5/product/a2a/index.md gains one Delivery paragraph, AC29 and a History line. agent-tools.md follows the tool description and result.

Rejected in #424: merging queued messages into one turn, refusing sends past a limit, and a "queue cleared" notice.

For Jackson to approve here (the A2A wording in envelopes.v1.json is human-owned):

  • the notice text: "{{receiverId}} is in the middle of a turn, with {{waiting}} message(s) waiting for it ({{fromYou}} from you). It will handle each one as a separate turn after its current turn ends, so put any further updates for it in one message."
  • the tool-description sentence;
  • the Crew line;
  • AC29 and the Delivery paragraph.

Review and testing

Independent panel: Opus 5.5 (code lead) and Astra (code review plus live test), each in its own checkout.

What they found and how it was fixed:

  • Retried send (both reviewers): a retry with the same client_request_id counted a message that had already run. Fixed; it now reports the current state.
  • Held queue (Opus): got a notice that wasn't true. Fixed; no notice.
  • Pending deliveries (Astra): deliveries the worker hadn't handed over yet weren't counted. Fixed; counted and attributed to their real sender.
  • Astra startup (Astra): a message accepted into the queue while an Astra turn was starting stays queued, but wasn't counted. Fixed.
  • Read order (Opus re-review): a message could slip between the two reads. Fixed by reading pending deliveries first.
  • Docs and wording: dropped the peer-server gap from the definition (it's tracked as an issue), clarified the tool-description wording, and wired the attachment-send path.

Every reproduction is kept as a regression test.

Live test (Astra). An isolated dev server with a scratch project and real agents:

  • Idle Luna receiver: no notice.
  • Busy Luna receiver: three sends gave counts of 1/1, 2/2 and 3/3.
  • Running Astra receiver: no notice.

Automated. 80 tests pass across the touched test files, including integration tests against a real orchestrator: idle, the message's own run, retry, pending before drain, pending plus queued, another sender, Astra queued while starting, running Astra, held queue, and an unknown receiver. Server typecheck and lint are clean.

Upstream impact

  • apps/server/src/provider/T3OrchestrationInstructions.ts: wording change to the J5 Crew line inside the existing seam, FORK.md case 8. Case 8 already covers authorized wording changes and the file-table row exists, so FORK.md is unchanged.

Checklist

  • One concern: the description has no "also"
  • Tests cover the changed behavior (backend changes ship with focused tests)
  • UI changes: not applicable. No UI change: the new field is on an agent tool result, which web and mobile don't render.
  • Upstream-owned files: each one is recorded in FORK.md (case text and file-table row) in this PR (existing case 8; no new edit needed)
  • Upstream product: no change to what upstream's product does
  • Surfaces:
    • Entry points: both agent send paths (send_message, t3_thread_send_attachments). The machine HTTP sender is unchanged.
    • Providers: the read is provider-neutral; only Astra is exempt, by the existing D4 rule.
    • Contracts: one optional result field.
    • Clients: none affected.
    • Connection modes: server-only, with no network on the send path.
  • Docs: the A2A definition and agent-tools.md are updated. No user docs, since this is agent-facing behavior.

Built by Claude Opus 5.5 (1M context) in Claude Code. Reviewed by Claude Opus 5.5 and GPT-6-Astra peer agents.

🤖 Generated with Claude Code

Jacksondr5 and others added 4 commits October 3, 2026 02:42
…aiting

A message to a busy agent queues as its own run, so a stream of small
updates becomes a stream of receiver turns. send_message now returns a
deliveryNotice when the receiver is an agent on this server that is
mid-turn and won't take the message into that turn (anything but a
running Astra turn): how many A2A messages are waiting, how many are the
caller's, and to put further updates in one message. The read is
advisory and never fails the send.

The send tool description, the Crew coordination instruction, the seat
brief and the propose_crew description stop inviting a message per
intermediate finding. The A2A definition gains AC29.

Refs #424.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Opus review of #424. A replayed send of a message that already ran no
longer counts it as waiting, and a held queue gets no notice, since it
drains only when someone resumes the thread (#272 owns telling the
sender). t3_thread_send_attachments returns the same notice through a
shared helper. The definition drops the peer-server gap (#425 tracks it)
and the tool description says the notice is about waiting, not busyness.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Astra review of #424. The backlog now counts committed deliveries the
worker has not handed to the receiver yet (it can sit behind a 30-second
Astra steer acknowledgement), attributes them to their real sender, and
counts the sent message from its own ledger state instead of assuming
it waits. A message already queued for an Astra receiver stays queued
when that turn becomes steerable, so it is counted. Astra's three
reproductions are kept as regression cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Opus re-review of #424. The worker commits a run before it marks the
delivery delivered, so reading pending rows first means every message
shows up in at least one read.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
j5-code Ready Ready Preview Oct 3, 2026 3:14am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

This review includes 16 billable files and costs up to $4.00.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 34 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 52 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: Jacksondr5/j5code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: cdeb2cd3-1604-4b3b-9a7e-6570ee4625cb
📥 Commits

Reviewing files that changed from the base of the PR and between 7ae83f1 and 1645010.

📒 Files selected for processing (16)
  • apps/server/src/j5/a2a/DeliveryTransport.integration.test.ts
  • apps/server/src/j5/a2a/DeliveryTransport.ts
  • apps/server/src/j5/a2a/EnvelopeFormatter.test.ts
  • apps/server/src/j5/a2a/EnvelopeFormatter.ts
  • apps/server/src/j5/a2a/contracts.ts
  • apps/server/src/j5/a2a/envelopes.v1.json
  • apps/server/src/j5/a2a/mcp/attachments.ts
  • apps/server/src/j5/a2a/mcp/handlers.test.ts
  • apps/server/src/j5/a2a/mcp/handlers.ts
  • apps/server/src/j5/a2a/mcp/tools.ts
  • apps/server/src/j5/a2a/receiverBacklog.ts
  • apps/server/src/j5/a2a/spawnIds.test.ts
  • apps/server/src/j5/a2a/spawnIds.ts
  • apps/server/src/provider/T3OrchestrationInstructions.ts
  • docs/j5/product/a2a/agent-tools.md
  • docs/j5/product/a2a/index.md
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 effective changed lines (test files excluded in mixed PRs). labels Oct 3, 2026
@Jacksondr5
Jacksondr5 merged commit 9bd7e09 into j5/main Oct 3, 2026
28 checks passed
@Jacksondr5
Jacksondr5 deleted the t3code/a2a-message-queue-backpressure branch October 3, 2026 03:28

This branch was successfully deployed

1 active deployment
Preview — 1645010c Deployed Oct 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A2A senders: warn when the receiver is mid-turn with messages waiting, and stop inviting chatty updates

1 participant