Skip to content

fix(auto-reply): restore per-turn message-tool delivery contract#99389

Merged
obviyus merged 1 commit into
mainfrom
fix/messagetool-per-turn-delivery
Jul 3, 2026
Merged

fix(auto-reply): restore per-turn message-tool delivery contract#99389
obviyus merged 1 commit into
mainfrom
fix/messagetool-per-turn-delivery

Conversation

@obviyus

@obviyus obviyus commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes #99371. Under message_tool_only delivery, directly addressed turns carried no per-turn delivery contract after 63cbb35 removed the inbound delivery hint as duplication: the only remaining statement was one line buried in the appended system prompt (for CLI backends, ~line 595 of a ~54KB appended section behind the harness's own system prompt). In production this swallowed visible replies: the model composed answers as plain final text, source-reply/private-final kept them private, and ~25 consecutive addressed turns delivered nothing. Success was only intermittent — resumed CLI sessions with a prior in-context message tool call kept working; fresh sessions coin-flipped. The generalized group etiquette line ("message-tool-only delivery does not require visible output … prefer no channel message", e081028) compounded it by reading as license to answer privately.

Room-event turns were unaffected because they already carry a per-turn delivery directive. The asymmetry was the bug.

Why This Change Was Made

  • One owner now decides the per-turn delivery directive for all turn kinds: resolvePerTurnDeliveryDirective(inboundEventKind, sourceReplyDeliveryMode) in src/auto-reply/reply/prompt-prelude.ts. Room-event wording is moved verbatim (test-pinned, byte-identical); user_request + message_tool_only appends the existing MESSAGE_TOOL_ONLY_DELIVERY_HINT constant to the runtime-only inbound context, adjacent to the current message. Other delivery modes get no directive.
  • Exactly one emission per turn: nothing returns to buildInboundUserContextPrefix, and the pre-63cbb350566 3-5x duplication does not come back. The hint constant is already a recognized strip-inbound-meta sentinel, so replayed shipped transcripts keep stripping with zero stripper changes, and the persisted transcript row for the turn stays bare (proven by regression test: currentInboundContext carries the hint, the transcript row does not).
  • The group etiquette line keeps its reaction/silence guidance but closes the private-answer loophole: when a visible reply is warranted, message(action=send) is the path because final text stays private.

User Impact

message_tool_only deployments (Telegram/Discord group bots) reliably deliver replies to direct mentions again, on both fresh and resumed CLI sessions. Ambient room-event behavior (default-silent, #99144) is unchanged.

Evidence

  • Fail-confirmed regressions: prompt-prelude asserts exactly one hint occurrence for user_request+message_tool_only and zero for other modes (reverted fix: expected +0 to be 1); get-reply-run asserts the hint in currentInboundContext with a bare transcript row (reverted fix: hint missing); existing strip-inbound-meta test covers replayed-row stripping.
  • Live provenance: captured raw claude-cli turn input from the affected deployment shows the addressed envelope with zero delivery instruction while the system prompt carried the contract — confirming the per-turn line is load-bearing for CLI backends.
  • node scripts/run-vitest.mjs (system-prompt, prompt-prelude, get-reply-run.media-only, strip-inbound-meta), pnpm tsgo, pnpm check:test-types, scoped oxlint, pnpm prompt:snapshots:check: exit 0.
  • Blacksmith Testbox check:changed on the rebased branch: exit 0 (run tbx_01kwk9dvqegybpsvbfdhw5fd5q).
  • Prod LOC: prompt-prelude.ts +27/-5, system-prompt.ts +1/-1; the rest is tests.

Addressed source-reply turns now carry the message-tool-only delivery hint in runtime prompt context, matching the room-event per-turn contract without persisting the hint into transcript rows.

Surface: auto-reply prompt envelopes and agent messaging guidance. Fixes #99371.

Release-note: fixes Telegram group replies under message_tool_only delivery being composed privately instead of being prompted to use message(action=send).
@obviyus
obviyus merged commit 4e6933c into main Jul 3, 2026
37 of 38 checks passed
@obviyus
obviyus deleted the fix/messagetool-per-turn-delivery branch July 3, 2026 06:11
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S maintainer Maintainer-authored PR labels Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

message_tool_only addressed turns carry no per-turn delivery contract; visible replies silently swallowed

1 participant