fix(agents): deliver agent TTS audio when block streaming is off#78355
Conversation
|
Codex review: passed. Summary Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are not direct-sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Real behavior proof Next step before merge Security Review detailsBest possible solution: Land the narrow media-bearing fallback predicate with the aligned regression coverage once exact-head checks finish, while leaving duplicate MEDIA delivery tracked separately in #78372. Do we have a high-confidence way to reproduce the issue? Yes. Current main's predicate and unit test show captioned media-bearing block replies are not direct-sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Is this the best way to solve the issue? Yes. The PR changes the narrow shared reply-delivery predicate, preserves text-only accumulation, uses existing directlySentBlockKeys suppression, and updates the relevant regression tests without adding config or channel-specific policy. What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against ffafa9008da2. |
5fb1929 to
5dd5fba
Compare
|
@clawsweeper automerge |
|
🦞✅ Source: What merged:
Automerge notes:
The automerge loop is complete. Automerge progress:
|
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb1314fe9104e0ec61090c46e7edecf24499ca. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb1314fe9104e0ec61090c46e7edecf24499ca Review: openclaw/openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb1314fe9104e0ec61090c46e7edecf24499ca. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb1314fe9104e0ec61090c46e7edecf24499ca Review: openclaw/openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb1314fe9104e0ec61090c46e7edecf24499ca. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb1314fe9104e0ec61090c46e7edecf24499ca Review: openclaw/openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
…nclaw#78355) Summary: - The branch changes non-streaming block reply delivery to direct-send all media-bearing block replies, updates reply-delivery/media-path regression tests, and adds a changelog entry. - Reproducibility: yes. Current main's predicate and unit test show captioned media-bearing block replies are ... sent when block streaming is disabled, and the PR body adds real Telegram after-fix proof for the TTS path. Automerge notes: - PR branch already contained follow-up commit before automerge: test(agents): align direct media block delivery coverage Validation: - ClawSweeper review passed for head e9bb131. - Required merge gates passed before the squash merge. Prepared head SHA: e9bb131 Review: openclaw#78355 (comment) Co-authored-by: Clawdbot <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]>
Summary
Describe the problem and fix in 2–5 bullets:
If this PR fixes a plugin beta-release blocker, title it
fix(<plugin-id>): beta blocker - <summary>and link the matchingBeta blocker: <plugin-name> - <summary>issue labeledbeta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.ttstool audio can be generated successfully but never delivered on non-streaming block-reply channels when the block reply has both text and media. In Telegram this shows up as a “bare TTS” request producing no received voice/media message, even though/tts audio ...works and the speech provider produced an.opusfile.ttstool look flaky or provider/channel-specific, but the failing path is actually OpenClaw reply delivery fallback. Users can waste time debugging Fish Audio or Telegram even though media generation and direct Telegram media delivery are healthy./ttscommand behavior, block streaming behavior, or text-only fallback behavior.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Real behavior proof
External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only. Screenshots are encouraged even for CLI, console, text, or log changes; terminal screenshots and copied live output count.
Behavior or issue addressed: Agent
ttstool audio was generated but not delivered as Telegram voice/media for a bare TTS-style agent response when Telegram block streaming was off./tts audio ...worked because the slash command returns a direct media reply through the command path. Mixed text + TTS scenarios were not the observed failure; the problematic case was the agent/tool block fallback for media-bearing block replies that were not media-only.Real environment tested: OpenClaw
2026.5.5-beta.2running in a container/pod, Telegram integration, Fish Audio speech provider, non-streaming block reply delivery. Runtime was patched with the same one-line delivery condition change via boot-time loader hook because/appwas immutable in the pod.Exact steps or command run after this patch:
blockHasMedia && !blockPayload.texttoblockHasMedia.Evidence after fix: redacted runtime log and copied live user confirmation from the patched real Telegram setup:
Live user confirmation after the patched agent path loaded lazily:
Observed result after fix: The TTS-only agent message was received by Telegram after the delivery fallback patch applied dynamically on first lazy import of the agent runner.
What was not tested: Other non-streaming channels besides Telegram; block-streaming-enabled channels; every speech provider. The fix is provider-independent because it only changes reply fallback delivery after media already exists.
Before evidence: Before the patch,
/tts audio ...worked and Fish Audio produced an.opusfile, but a bare agentttsresponse did not arrive as Telegram voice/media. The investigated generated audio path included/tmp/openclaw/tts-wvm6vt/voice-1778050523564.opus, confirming generation succeeded before delivery failed.Root Cause (if applicable)
For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write
N/A. If the cause is unclear, writeUnknown.createBlockReplyDeliveryHandler()only direct-sent non-streaming block replies whenblockHasMedia && !blockPayload.text. That preserves media-only orphaned tool attachments, but drops the direct-send fallback for tool block replies that contain both text/caption metadata and media. Final assistant text can still be reconstructed later, but the media attachment cannot be reconstructed from final text, so the generated audio is effectively consumed before channel delivery./tts audio ...takes a different command path and returns a direct media reply, so it continued to work. The failing agentttspath uses tool/media block reply delivery, where TTS-generated audio can carryaudioAsVoiceand a text/caption-bearing block payload.Regression Test Plan (if applicable)
For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write
N/A.src/auto-reply/reply/reply-delivery.test.tsaudioAsVoicereplies are sent viaonBlockReplyand tracked indirectlySentBlockKeys, while text-only blocks continue to accumulate into final text.createBlockReplyDeliveryHandler(). A focused unit test directly exercises that branch without needing a Telegram or speech-provider fixture.User-visible / Behavior Changes
Agent/tool replies that include both text and media now deliver their media on channels where block streaming is disabled. In practice, agent-sent TTS audio can arrive as Telegram voice/media instead of silently disappearing after successful generation.
Diagram (if applicable)
Security Impact (required)
Yes/No): NoYes/No): NoYes/No): NoYes/No): NoYes/No): NoYes, explain risk + mitigation: N/ARepro + Verification
Environment
2026.5.5-beta.2Steps
/tts audio hellosends a Telegram voice/media message.ttstool.Expected
ttsaudio is delivered to Telegram as voice/media when media generation succeeds.Actual
/tts audio ...worked, but bare agentttsaudio was generated and not delivered as Telegram voice/media.ttsaudio is received by Telegram once the patched agent runner path is loaded.Evidence
Attach at least one:
Targeted local test after source patch:
Runtime patch proof/log is included above. A Telegram screenshot can be added before submission if desired.
Human Verification (required)
What you personally verified (not just CI), and how:
/tts audio ...worked before this change, proving the speech provider and direct media delivery path were healthy.audioAsVoicemedia replies are now direct-sent and dedupe-tracked.Review Conversations
If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.
Compatibility / Migration
Yes/No): YesYes/No): NoYes/No): NoRisks and Mitigations
directlySentBlockKeys, matching existing media-only fallback behavior. Text-only blocks still use the existing final-text accumulation path.ReplyPayloadshape and only extends the same direct fallback already used for media-only payloads to media-bearing payloads.