fix(messages): use best-effort for implicit tool-only source replies#84232
Conversation
|
Codex review: needs maintainer review before merge. Reviewed May 30, 2026, 11:02 PM ET / 03:02 UTC. Summary PR surface: Source +87, Tests +162. Total +249 across 2 files. Reproducibility: yes. Source inspection on current main shows Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Merge the bounded current-source best-effort policy if maintainers accept that visible source replies should favor delivery over durable fail-closed semantics, with optional full Slack inbound proof if they want extra assurance. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection on current main shows Is this the best way to solve the issue? Yes, with maintainer acceptance. The patch keeps the change local to AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 4dad7bd93b6c. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +87, Tests +162. Total +249 across 2 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 asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
ClawSweeper PR egg ✨ Hatched: 🥚 common Velvet Merge Sprite Hatch commandComment Hatchability rules:
Rarity: 🥚 common. What is this egg doing here?
|
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Maintainer verification before merge: Behavior addressed: Slack |
…n-rotation-current * origin/main: (52 commits) fix(agents): prevent embedded runtime shadowing fix(outbound): route source replies through configured channels refactor(cron): split tool and doctor repair helpers perf: reduce tui refresh work feat: default exec shell snapshots fix(ui): keep chat usable during session loading fix(cron): guard flat atMs canonicalization refactor(cron): keep runtime on canonical sqlite rows fix(codex): restore bounded recovery continuity refactor: clean up ACP package metadata and helpers (#88659) fix(discord): ping mention-bearing final replies fix(telegram): preserve usage footer for tool-only replies fix(agents): avoid alias setup load for matching refs chore(ui): translate thinking default label fix(agents): preserve runtime tools in lean mode (#88381) fix(messages): use best-effort for implicit tool-only source replies (#84232) docs: raise bulk PR close threshold feat: add exec shell snapshot cache fix: use typed tui empty session defaults perf: speed up tui session refresh ... # Conflicts: # src/tui/tui-command-handlers.test.ts
…penclaw#84232) fix(messages): use best-effort for implicit tool-only source replies Preserve durable required-send semantics for explicit non-current targets while allowing current-source `message_tool_only` replies to be delivered through best-effort outbound sends. This fixes Slack source replies that otherwise fail when the adapter has no `reconcileUnknownSend` hook. Fixes openclaw#84078.
…penclaw#84232) fix(messages): use best-effort for implicit tool-only source replies Preserve durable required-send semantics for explicit non-current targets while allowing current-source `message_tool_only` replies to be delivered through best-effort outbound sends. This fixes Slack source replies that otherwise fail when the adapter has no `reconcileUnknownSend` hook. Fixes openclaw#84078.
…penclaw#84232) fix(messages): use best-effort for implicit tool-only source replies Preserve durable required-send semantics for explicit non-current targets while allowing current-source `message_tool_only` replies to be delivered through best-effort outbound sends. This fixes Slack source replies that otherwise fail when the adapter has no `reconcileUnknownSend` hook. Fixes openclaw#84078.
Summary
message_tool_onlyreplies through best-effort delivery before target normalization.bestEffort: false.reconcileUnknownSend.Root Cause
For Slack group/channel source replies with visible replies routed through the
messagetool, a source-channel reply could still carrybestEffort: false, including the case where the tool explicitly supplied the current source channel astarget. That made the outbound runner request required durable delivery, which then failed preflight on Slack because required durable sends needreconcileUnknownSend.Current-source replies are user-visible conversational replies, not explicit cross-channel durable sends, so they should use best-effort delivery even when the target equals the current source conversation. Explicit external targeted sends keep the existing required durable semantics.
Fixes #84078.
Real behavior proof
message_tool_onlyvisible source replies that omit an explicit target, or explicitly target the current source Slack channel, no longer fail the durable-send preflight when Slack lacksreconcileUnknownSend; explicit external targeted sends still keep required durable fail-closed behavior.aff69bbcc622, macOS arm64, Node.jsv24.15.0, OpenClaw runtime loaded from this branch, real Slack channel adapter, real Slack Web API delivery into a dedicated test channel. Tokens, workspace URL, channel name, and full channel id are redacted.runMessageAction -> core outbound -> real Slack adapter -> Slack Web API.node --import tsx --input-type=module <real-slack-source-reply-proof>with the active plugin registry set to the real Slack channel plugin,sourceReplyDeliveryMode: "message_tool_only",toolContext.currentChannelProvider: "slack", andtoolContext.currentChannelIdset to the same redacted test channel for the two source-reply cases.{ "status": "PASS", "pr": 84232, "branch": "fix/slack-message-tool-durable-fallback", "head": "aff69bbcc622", "route": "runMessageAction -> core outbound -> real Slack adapter -> Slack Web API", "channel": { "id": "C0B5...B7T", "name": "[redacted-test-channel]" }, "marker": "OC84232_1779243865565", "sends": [ { "name": "omitted-target-source-reply", "kind": "send", "channel": "slack", "to": "[redacted-test-channel]", "handledBy": "core", "messageId": "1779243866.436879", "via": "direct" }, { "name": "explicit-current-source-target", "kind": "send", "channel": "slack", "to": "[redacted-test-channel]", "handledBy": "core", "messageId": "1779243867.013869", "via": "direct" } ], "externalFailure": { "name": "external-required-durable", "failedClosed": true, "error": "Required durable message send is unsupported for slack: missing reconcileUnknownSend" }, "observedCount": 2, "observed": [ { "ts": "1779243866.436879", "text": "OC84232_1779243865565 omitted target source reply", "bot_id": "[present]", "user": "[present]" }, { "ts": "1779243867.013869", "text": "OC84232_1779243865565 explicit current-source target reply", "bot_id": "[present]", "user": "[present]" } ] }message_tool_onlysends completed through the core outbound path and posted to a real Slack test channel even when the input carriedbestEffort: false: one omitted the target and one explicitly used the current Slack source channel astarget. The explicit external targeted send withbestEffort: falsefailed before delivery withmissing reconcileUnknownSend, preserving the required durable guard for non-source targets.Tests
node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/outbound/message-action-runner.core-send.test.ts src/infra/outbound/message-action-runner.send-validation.test.ts src/infra/outbound/outbound-send-service.test.ts src/infra/outbound/message.test.tsnode scripts/run-vitest.mjs run --config test/vitest/vitest.agents-tools.config.ts src/agents/tools/message-tool.test.tsnode scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo