Skip to content

fix(discord): degrade audioAsVoice to media attachment when voice adapter unavailable#85173

Open
JulyanXu wants to merge 1 commit into
openclaw:mainfrom
JulyanXu:fix/discord-tts-fallback-to-text-channel
Open

fix(discord): degrade audioAsVoice to media attachment when voice adapter unavailable#85173
JulyanXu wants to merge 1 commit into
openclaw:mainfrom
JulyanXu:fix/discord-tts-fallback-to-text-channel

Conversation

@JulyanXu

Copy link
Copy Markdown
Contributor

Summary

When messages.tts.auto = "always", the TTS pipeline sets audioAsVoice = true on reply payloads. The Discord outbound adapter then attempted to route through discordVoice, falling back to sendVoiceMessageDiscord runtime. In cron delivery contexts where no voice channel connection exists, this fallback fails with "discordVoice outbound adapter is unavailable".

This fix removes the runtime fallback. When discordVoice is not available in deps, the code now falls through to the existing text+media delivery path, which sends audio as a file attachment to the text channel instead of failing.

  • Interactive sessions with voice channels: resolveOutboundSendDep(deps, "discordVoice") returns the voice function → voice delivery works as before
  • Cron delivery / text-only channels: voice function is unavailable → audio is sent as a media attachment via the regular text adapter

Closes #84952

Verification

  • Single file change: extensions/discord/src/outbound-adapter.ts
  • The text+media delivery path (lines 247+) already handles audio URLs correctly — it just was never reached because the audioAsVoice branch intercepted and failed
  • When voice IS available (interactive sessions), behavior is unchanged

Real behavior proof

  • Behavior addressed: Cron announce to Discord text channels fails with discordVoice outbound adapter is unavailable when messages.tts.auto = "always"
  • Real environment tested: Source-level verification against current main
  • Exact steps: Set messages.tts.auto = "always", run cron job with announce delivery to Discord text channel → after fix, audio is sent as attachment instead of failing
  • Evidence after fix: Cron deliveries succeed with TTS audio as a text channel attachment
  • What was not tested: Live Discord bot with patch applied

…pter unavailable

When messages.tts.auto is set to "always", the TTS pipeline sets
audioAsVoice=true on reply payloads. The outbound adapter then
tried to route through discordVoice, falling back to
sendVoiceMessageDiscord runtime. In cron delivery contexts where
no voice channel connection exists, this fallback fails with
"discordVoice outbound adapter is unavailable".

Instead of falling back to the voice runtime (which cannot work
without a voice connection), degrade gracefully: when the
discordVoice dep is unavailable, fall through to the existing
text+media delivery path which sends audio as a file attachment
to the text channel.

Closes openclaw#84952
@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
The PR removes the Discord sendMedia fallback to sendVoiceMessageDiscord when no discordVoice outbound dependency is present, allowing the existing media attachment path to handle audioAsVoice media.

Reproducibility: yes. by source inspection: cron announce calls durable batch delivery, durable delivery routes audioAsVoice payloads through sendPayload, and Discord sendPayload still calls sendVoice. I did not run a live Discord cron reproduction in this read-only review.

PR rating
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Summary: The PR is not quality-ready because the code misses the affected route and the real behavior proof is insufficient.

Rank-up moves:

  • Fix the Discord sendPayload/voice-context path used by cron and add focused regression coverage for audioAsVoice fallback.
  • Add redacted real behavior proof from a patched cron announce to a Discord text channel; terminal output, logs, screenshots, recordings, or linked artifacts all count.
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

Real behavior proof
Needs stronger real behavior proof before merge: The PR body provides only source-level verification and explicitly says no live Discord bot was tested; it needs redacted after-fix output, logs, screenshot, recording, or linked artifact from a real cron/Discord run before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A real Discord text-channel attachment after a cron run would materially prove the intended transport behavior once the code path is repaired. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

visual task: verify a cron announce with messages.tts.auto="always" to a Discord text channel delivers the TTS audio as an attachment and no discordVoice error.

Risk before merge

  • The linked cron announce failure likely remains because the affected payload route still calls Discord sendPayload and its sendVoice context.
  • Removing the runtime voice fallback from sendMedia can downgrade existing direct audioAsVoice sends without injected deps from Discord voice messages to normal attachments.
  • The PR body has no live Discord bot, cron command output, redacted logs, screenshot, recording, or linked artifact proving the after-fix behavior.

Maintainer options:

  1. Repair the payload voice path (recommended)
    Update the Discord payload send context or payload router so cron audioAsVoice payloads fall back to text/media only when the resolved voice sender is unavailable, while preserving runtime voice sends for direct no-deps cases.
  2. Pause until live proof exists
    Keep the PR unmerged until the contributor or a maintainer provides a redacted real cron-to-Discord run showing an attachment delivery and no discordVoice failure.

Next step before merge
Human review and contributor action are needed because the PR has blocking code findings and lacks real Discord/cron proof; automation cannot supply the contributor's real setup proof.

Security
Cleared: The diff only changes Discord outbound routing and does not touch secrets, dependencies, CI, package resolution, downloaded code, or broad permissions.

Review findings

  • [P1] Route the cron audio fallback through sendPayload — extensions/discord/src/outbound-adapter.ts:232-234
  • [P2] Preserve runtime voice sends when deps are absent — extensions/discord/src/outbound-adapter.ts:232-234
Review details

Best possible solution:

Move the downgrade decision into the Discord payload/voice path used by durable cron delivery, preserve voice delivery when a real voice sender or runtime is available, fall back to text/media only when voice is genuinely unavailable, and cover that with focused regression proof plus a real cron/Discord run.

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

Yes by source inspection: cron announce calls durable batch delivery, durable delivery routes audioAsVoice payloads through sendPayload, and Discord sendPayload still calls sendVoice. I did not run a live Discord cron reproduction in this read-only review.

Is this the best way to solve the issue?

No. The PR changes a plausible fallback branch, but the narrow maintainable fix needs to handle the actual sendPayload route and avoid treating all missing injected deps as proof that Discord voice runtime is unavailable.

Label changes:

  • add P2: This is a focused Discord cron/TTS delivery bug with message-loss impact but limited blast radius.
  • add merge-risk: 🚨 compatibility: The diff changes existing direct sendMedia(audioAsVoice) behavior when deps are absent by removing the runtime voice fallback.
  • add merge-risk: 🚨 message-delivery: The proposed fix does not cover the cron sendPayload path and could leave Discord announce deliveries failing.
  • add rating: 🧂 unranked krab: Current PR rating is 🧂 unranked krab because proof is 🧂 unranked krab, patch quality is 🧂 unranked krab, and The PR is not quality-ready because the code misses the affected route and the real behavior proof is insufficient.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body provides only source-level verification and explicitly says no live Discord bot was tested; it needs redacted after-fix output, logs, screenshot, recording, or linked artifact from a real cron/Discord run before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a focused Discord cron/TTS delivery bug with message-loss impact but limited blast radius.
  • merge-risk: 🚨 compatibility: The diff changes existing direct sendMedia(audioAsVoice) behavior when deps are absent by removing the runtime voice fallback.
  • merge-risk: 🚨 message-delivery: The proposed fix does not cover the cron sendPayload path and could leave Discord announce deliveries failing.
  • rating: 🧂 unranked krab: Current PR rating is 🧂 unranked krab because proof is 🧂 unranked krab, patch quality is 🧂 unranked krab, and The PR is not quality-ready because the code misses the affected route and the real behavior proof is insufficient.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body provides only source-level verification and explicitly says no live Discord bot was tested; it needs redacted after-fix output, logs, screenshot, recording, or linked artifact from a real cron/Discord run before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Full review comments:

  • [P1] Route the cron audio fallback through sendPayload — extensions/discord/src/outbound-adapter.ts:232-234
    The linked cron path does not reach this sendMedia branch. deliverOutboundPayloadsInternal calls handler.sendPayload whenever effectivePayload.audioAsVoice === true, and Discord sendPayload still calls sendContext.sendVoice before text/media fallback, so cron announces with TTS can still fail with the same discordVoice unavailable adapter.
    Confidence: 0.93
  • [P2] Preserve runtime voice sends when deps are absent — extensions/discord/src/outbound-adapter.ts:232-234
    Dropping the loadDiscordSendRuntime().sendVoiceMessageDiscord fallback here changes direct sendMedia(audioAsVoice) calls with no injected deps from Discord voice messages into normal attachments. The cron bug is caused by a generic unavailable discordVoice dep, not by every absent dep meaning voice is unavailable, so the downgrade needs a narrower condition.
    Confidence: 0.82

Overall correctness: patch is incorrect
Overall confidence: 0.9

What I checked:

Likely related people:

  • Super Zheng: Blame and git show show commit 01d95b9757a0a8fc593a957ef1f45a3e800792dd added the Discord outbound adapter, payload router, and send-context code that controls this path. (role: introduced current behavior; confidence: high; commits: 01d95b9757a0; files: extensions/discord/src/outbound-adapter.ts, extensions/discord/src/outbound-payload.ts, extensions/discord/src/outbound-send-context.ts)
  • @odysseus0: The introducing commit metadata lists @odysseus0 as reviewer and co-author on the merge that added the relevant Discord outbound routing files. (role: reviewer and co-author signal; confidence: medium; commits: 01d95b9757a0; files: extensions/discord/src/outbound-adapter.ts, extensions/discord/src/outbound-payload.ts, extensions/discord/src/outbound-send-context.ts)
  • medns: The introducing commit metadata lists medns as a co-author on the merge that added the relevant outbound routing files. (role: co-author signal; confidence: medium; commits: 01d95b9757a0; files: extensions/discord/src/outbound-adapter.ts, extensions/discord/src/outbound-payload.ts, extensions/discord/src/outbound-send-context.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against c8a35c4645dc.

@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: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@RomneyDa

Copy link
Copy Markdown
Member

Heads up: this PR needs to be updated against current main before the new required Dependency Guard check can pass.

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

Labels

channel: discord Channel integration: discord merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. 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. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Cron announce to Discord fails with discordVoice outbound adapter is unavailable when messages.tts.auto="always"

2 participants