Skip to content

fix(gateway): activate source-reply delivery for direct webchat turns (#96840)#97456

Closed
ly-wang19 wants to merge 1 commit into
openclaw:mainfrom
ly-wang19:fix/webchat-targetless-message-send-96840
Closed

fix(gateway): activate source-reply delivery for direct webchat turns (#96840)#97456
ly-wang19 wants to merge 1 commit into
openclaw:mainfrom
ly-wang19:fix/webchat-targetless-message-send-96840

Conversation

@ly-wang19

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes #96840.

A targetless message(action="send") from a direct WebChat turn (Control UI chat tab / SwiftUI app) fails with Action send requires a target. even though docs/web/webchat.md states:

Harnesses that require visible replies through tools.message still use WebChat as a current-run internal source reply sink. A targetless message.send from that active WebChat run is projected into the same chat and mirrored to the session transcript.

The root cause: resolveGatewayScopedTools only activates sourceReplyDeliveryMode = "message_tool_only" for non-webchat room-event turns. Direct WebChat turns get sourceReplyDeliveryMode = undefined, so shouldUseInternalSourceReplySink short-circuits at its first guard clause and normalizeMessageActionInput throws the missing-target error.

Why This Change Was Made

Extend the source-reply activation to also cover direct WebChat turns (any non-room-event WebChat inbound). The original webchat exclusion in the room-event branch stays in place so the existing "automatic source delivery" contract for WebChat room-event turns (regression test at src/gateway/tool-resolution.test.ts) is preserved.

The actual send-vs-skip decision still belongs to shouldUseInternalSourceReplySink, which already knows how to gate on hasCurrentSourceReplyContext and external session routes — this PR only ensures the request reaches that gate for direct WebChat turns.

User Impact

Targetless message.send calls during an active WebChat run now project into the same chat (matching the documented contract) instead of failing with a missing-target error. Non-webchat room-event behavior is unchanged. WebChat room-event turns continue to use automatic delivery.

Evidence

  • New regression test force-allows the message tool for direct webchat turns so targetless send projects to the same chat (#96840) — asserts the message tool is force-allowed with the source-reply description for an inboundEventKind: "user_request" WebChat session.
  • Existing keeps webchat room-event turns on automatic source delivery regression test still passes — the room-event webchat exclusion is preserved.
  • Existing force-allows the message tool for room-event loopback turns test still passes — non-webchat room-event behavior is unchanged.
  • pnpm test src/gateway/tool-resolution.test.ts — 24/24 pass across 4 files.
  • pnpm tsgo:core — clean.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS labels Jun 28, 2026
@clawsweeper

clawsweeper Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close: the same WebChat targetless-send bug is already covered by a stronger open landing candidate, and this branch does not cover the direct WebChat automatic-mode path well enough to remain the preferred PR.

Canonical path: Use #97167 as the landing candidate, then close the duplicate PRs and the linked bug after the selected fix merges.

So I’m closing this here and keeping the remaining discussion on #97167.

Review details

Best possible solution:

Use #97167 as the landing candidate, then close the duplicate PRs and the linked bug after the selected fix merges.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows direct internal WebChat runs can carry sourceReplyDeliveryMode: "automatic", while the targetless sink only accepts message_tool_only before target validation.

Is this the best way to solve the issue?

No. This PR adjusts Gateway fallback mode selection, but the better fix is the existing sibling's message-tool-boundary defaulting with Control UI WebSocket proof.

Security review:

Security review cleared: The diff only changes Gateway tool-resolution logic and a focused test; it does not touch dependencies, workflows, credentials, permissions, lockfiles, or artifact execution paths.

AGENTS.md: found and applied where relevant.

What I checked:

  • Repository policy read: Root and scoped Gateway AGENTS.md were read fully; the review applied the Gateway hot-path and best-fix guidance. (AGENTS.md:1, d17b970bb50d)
  • Documented behavior: WebChat docs say targetless message.send from an active WebChat run should project into the same chat through the current-run internal source reply sink. Public docs: docs/web/webchat.md. (docs/web/webchat.md:55, d17b970bb50d)
  • Sink contract: The existing internal source-reply sink requires sourceReplyDeliveryMode === "message_tool_only" before it accepts a targetless current-source send. (src/infra/outbound/internal-source-reply.ts:86, d17b970bb50d)
  • Direct WebChat run mode: Current direct internal WebChat runs default to automatic when no explicit source-reply mode is requested, so a fix that only fills in undefined modes misses that path. (src/auto-reply/reply/get-reply-run.ts:538, d17b970bb50d)
  • MCP mode propagation: The CLI/MCP bridge forwards the run's sourceReplyDeliveryMode to the loopback tool server, which means an explicit automatic value can reach Gateway tool resolution. (src/agents/cli-runner/prepare.ts:459, d17b970bb50d)
  • Current PR diff: This PR preserves explicit params.sourceReplyDeliveryMode with ?? and only changes the fallback branch, so the new test covers an omitted-mode WebChat request rather than the automatic-mode direct WebChat path. (src/gateway/tool-resolution.ts:84, 0cd5cbd05364)

Likely related people:

  • pashpashpash: Authored the merged WebChat/TUI internal UI message-tool sink and WebChat documentation contract that the linked bug relies on. (role: feature-history owner; confidence: high; commits: 78eb92e62277; files: src/infra/outbound/message-action-runner.ts, src/agents/tools/message-tool.ts, docs/web/webchat.md)
  • steipete: Authored adjacent WebChat source-delivery behavior that created the current automatic versus message-tool-only Gateway split. (role: recent related behavior owner; confidence: high; commits: 0cfccdb0c7ee; files: src/gateway/tool-resolution.ts, src/gateway/tool-resolution.test.ts, src/auto-reply/reply/source-reply-delivery-mode.ts)
  • vincentkoc: Recently extracted and maintained the internal source-reply sink path that gates targetless current-source sends on message_tool_only. (role: recent adjacent owner; confidence: medium; commits: 0ea08076c3b5; files: src/infra/outbound/internal-source-reply.ts, src/infra/outbound/message-action-runner.ts)

Codex review notes: model internal, reasoning high; reviewed against d17b970bb50d.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 28, 2026
@clawsweeper

clawsweeper Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Targetless message.send fails with 'Action send requires a target' in WebChat despite docs stating source-reply sink should handle it

1 participant