Repository navigation
MCP send_dm creates duplicate messages because idempotency_key stops at the process boundary - #1875
agent-relay-code[bot] wants to merge 2 commits into
Conversation
Align RelayAgentThinClient.dm with the sibling relaycast-client.ts option. Cover the MCP forwarding contract and session-stamping proxy, and prove base/head behavior with fresh processes against a local HTTP service.
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
Relaycast trims the idempotency key upstream and falls back to a generated key when the trimmed value is empty, so a whitespace-only send_dm key passed the local replay cache as an explicit stable key while reaching Relaycast as a fresh key in every process — storing a second message on retry. Trim the key at the schema boundary so the replay cache and the forwarded call agree with upstream normalization, and reject a key that is empty once trimmed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Superseded by #1882, which includes the explicit idempotency-key forwarding from this PR and also fixes the Bun standalone's duplicate MCP server startup, covers unkeyed sends, and adds a compiled-binary regression test. |
Summary
Fixes #1874. Forward MCP
send_dm's explicitidempotency_keythroughRelayAgentThinClient.dmto Relaycast, bringing the thin client into line withrelaycast-client.ts. This makes the keyed retry path safe across MCP process boundaries; it does not establish what issued the second dispatch in the reported incident.Re-lands the focused fix from #1866, head
ba1ada05def104a6291f9a5f36698ee46df124f8. Related: AgentWorkforce/relay-desktop#100 and AgentWorkforce/relay-desktop#101.send_group_dmexposes no idempotency-key input, so there is no key to forward on that sibling path.The issue's live trace also notes "earlier ordinary one-call sends from multiple
agents showed the same two-row/two-injection pattern" — i.e. unkeyed sends
duplicating. Those remain two rows after this change, by design, and the
acceptance criteria require that. Making a duplicate MCP dispatch safe without a
caller-supplied key is a different problem (a server-side or
argument-derived key), and is adjacent to the non-idempotent fleet-invocation
work tracked in #1604. This plan does not widen into it.
Test Plan
npm run typecheckandnpm run lintpass (lint reports existing warnings).outcome: bug, two keyed rows and different message IDs; patched code exits zero withoutcome: fixed, one keyed row and identical message/conversation IDs. Both preserve two distinct unkeyed sends.git diff --check.sdk-client.test.tsandfleet-lifecycle-integration.test.tsfailures reproduce on the unchanged base checkout.plan.mdandreviewed-plan.md; left unchanged.The prior PR's suppressed Devin Review flag could not be retrieved through GitHub comments/check APIs; no readable review link was returned. Its contents remain unverified.
RelayFlow Proof
bugfix1874-mcp-dm-idempotencyThe harness runs a fresh Vitest/MCP process per attempt with the real replay cache, session-stamping proxy, and Relaycast SDK. A local HTTP server records rows and idempotency headers; the runner derives the outcome from those observations and verifies receipt IDs. No workflow files changed.
Screenshots
Not applicable.
Checks
Relayflow ran this repository's checks (.relayflow/check.sh) and they passed.
What ran (.relayflow/check.sh)
Fixes #1874
Note
Medium Risk
Changes DM retry/idempotency semantics on a protocol path agents rely on; mitigated by focused forwarding, whitespace rejection, and cross-process proof tests, but incorrect key handling could still cause duplicate or blocked sends.
Overview
Fixes duplicate DMs when MCP
send_dmretries outlive the process-local replay cache by forwarding the caller’s explicitidempotency_keythroughRelayAgentThinClient.dmto Relaycast, aligned with the existing relaycast client behavior. Unkeyed sends stay separate.The MCP tool now trims
idempotency_keybefore replay and upstream use and rejects whitespace-only keys, so a padded key cannot trim to empty and get a new random key per process (which would create a second message).Coverage adds MCP protocol tests (replay boundaries, trim/reject, SDK option forwarding), SDK thin-client expectations, a startup regression on keyed retries, a RelayFlow fresh-process proof (
1874-mcp-dm-idempotency), and a changelog note. Agent-workforce trajectory compaction files record the review/fix narrative but are not runtime code.Reviewed by Cursor Bugbot for commit 040e655. Bugbot is set up for automated code reviews on this repo. Configure here.