fix(agents): stabilize message send loop detection#89143
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 1, 2026, 1:45 PM ET / 17:45 UTC. Summary PR surface: Source +78, Tests +224. Total +302 across 4 files. Reproducibility: yes. Current main hashes full message send details/text while critical loop paths require stable result hashes, and the linked issue provides production warning-only duplicate-send logs; I did not run commands in this read-only review. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land one canonical, proof-backed fix for the message-send result-hash path, preserving stable routing facts while stripping volatile delivery ids and keeping blocked loop outcomes from resetting the detector. Do we have a high-confidence way to reproduce the issue? Yes. Current main hashes full message send details/text while critical loop paths require stable result hashes, and the linked issue provides production warning-only duplicate-send logs; I did not run commands in this read-only review. Is this the best way to solve the issue? Yes. The targeted shared result-hash normalization is the narrowest maintainable fix for AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against ba88b7a1780f. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +78, Tests +224. Total +302 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review I added full local Gateway/qa-channel runtime proof and pushed an additional fix found by that proof: The proof starts a real Gateway child process, qa-channel plugin, qa-lab bus, and local OpenAI-compatible provider that keeps requesting the same Also rerun: |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
78750dd to
97944d9
Compare
|
@clawsweeper re-review Re-requesting after a no-content force-push to retrigger CI on the same patch. Current head includes the Gateway/qa-channel runtime proof described in the PR body and the comment above. Key proof lines: |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Closing as superseded by the landed canonical fix in #89109. #89109 merged as 697d2d0 and fixes #89090 by normalizing volatile delivery fields for send-like message outcomes across the core message tool, sessions_send, and provider-docked messaging tools. It also includes the wrapped message-tool action-runner proof that this PR supplied as its strongest runtime coverage signal. Thanks for the focused fix and proof here; that evidence helped shape the final landed coverage. |
AI-assisted: yes (Codex prepared the patch and verification).
Summary
message(action=send)tool outcomes before loop-detection result hashing, including qa-channel message-objectid/timestampfields while preserving stable routing facts such asconversation.id.tool-loopblock stays sticky instead of being treated as fresh progress.createMessageTool()action-runner send results.Fixes #89090.
Linked context
Issue #89090 reports that repeated
message.sendcalls can warn forever without escalating to a critical block because each successful send returns a unique delivery id, producing a differentresultHashevery time.Real behavior proof
Behavior addressed: Repeated
message(action=send)calls with identical arguments now escalate to a critical loop block even when every successful send returns a different delivery id, and repeated calls after the first block stay blocked instead of sending more messages.Real environment tested: Local full QA runtime with qa-lab bus, qa-channel plugin, real Gateway child process, and a local OpenAI-compatible provider that intentionally keeps requesting the same
message.sendtool call. Also tested focused local Vitest coverage for the message tool action-runner and before-tool-call loop-detection runtime paths.Exact steps or command run after this patch:
pnpm tsx .artifacts/proof-89143-message-loop-runtime.ts node scripts/run-vitest.mjs src/agents/tool-loop-detection.test.ts src/agents/tools/message-tool.test.ts src/agents/agent-tools.before-tool-call.e2e.test.ts node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo git diff --check .agents/skills/autoreview/scripts/autoreview --mode localEvidence after fix:
Observed result after fix: In the full Gateway/qa-channel proof, the first 20 repeated sends were delivered to the qa-channel bus, then Gateway emitted a critical
tool=message level=critical action=block detector=generic_repeat count=20event. The same looping provider continued requestingmessage.send, and qa-channel delivery stayed at exactly 20 outbound marker messages, proving later retries were blocked rather than sent.What was not tested: No live Feishu/Lark/Telegram external transport send was run. The real-process proof used qa-channel because it exercises the Gateway child, channel plugin action dispatch, qa-lab bus, and message tool loop detector without live credentials.
Tests and validation
pnpm tsx .artifacts/proof-89143-message-loop-runtime.tsnode scripts/run-vitest.mjs src/agents/tool-loop-detection.test.ts src/agents/tools/message-tool.test.ts src/agents/agent-tools.before-tool-call.e2e.test.tsnode scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfogit diff --check.agents/skills/autoreview/scripts/autoreview --mode localRisk checklist
Current review state
Fresh local autoreview passed with no accepted/actionable findings. The earlier proof gap was closed with full local Gateway/qa-channel runtime proof; the remaining disclosed gap is live external Feishu/Lark/Telegram transport replay.