Skip to content

fix(matrix): deliver reasoning blocks as m.notice when /reasoning on [AI-assisted]#93830

Open
ml12580 wants to merge 2 commits into
openclaw:mainfrom
ml12580:fix/vuln-81892
Open

fix(matrix): deliver reasoning blocks as m.notice when /reasoning on [AI-assisted]#93830
ml12580 wants to merge 2 commits into
openclaw:mainfrom
ml12580:fix/vuln-81892

Conversation

@ml12580

@ml12580 ml12580 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

[AI-assisted] This PR was generated using Claude Code.

Summary

  • Problem: On the Matrix channel, /reasoning on has no effect. Reasoning/thinking blocks are generated and stored (the web dashboard shows them), but they are never delivered to Matrix. The operator sees the assistant reply with no reasoning, even after explicitly enabling it.
  • Why it matters: Operators on reasoning-capable models (e.g. zai/glm-5.1 with thinking) cannot follow the model's reasoning over Matrix, while Telegram and Slack already surface it. This is a regression from the documented /reasoning on contract.
  • What changed: Generic reply dispatch suppresses explicit isReasoning payloads by default (WhatsApp/web/etc. have no reasoning lane). Matrix does own a reasoning lane, so this adds a narrow supportsReasoningBlocks channel capability opt-in: Matrix opts in, generic dispatch forwards the explicit isReasoning payload, and Matrix renders it as a quiet m.notice event (mirroring Telegram/Slack). Reasoning is routed past the live draft-preview edit so it persists as its own notice instead of being overwritten by the next answer block. Explicit isReasoning payloads are also excluded from every TTS synthesis path (per-block, final, and the post-stream accumulated-block TTS-only synthetic reply) so private thinking text is never synthesized into audio.
  • What did NOT change: Raw text that merely looks like reasoning (starts with reasoning:, or is only <thinking> tags) but is not an explicit isReasoning payload stays suppressed — channels still never leak unflagged thinking text. /reasoning off is unaffected (no reasoning notice is emitted). Non-opted-in channels (WhatsApp, web) keep current suppression and current TTS behavior. No public config/env surface added.
  • Success looks like: With /reasoning on, a Matrix room receives a separate m.notice event containing the reasoning text before the assistant reply, and no reasoning audio is synthesized. With /reasoning off, no reasoning notice is emitted.
  • Reviewer focus: The capability gate in dispatch-from-config.ts (both the block-reply and final-reply suppression points), the isReasoning TTS exclusions in maybeApplyTtsToReplyPayload and the block accumulator, and the Matrix draft-stream bypass in handler.ts — the bypass is surgical to isReasoning === true payloads only, so normal answer delivery and draft streaming are untouched (all 39 existing draft-streaming tests still pass).

Linked context

Closes #81892

Related: #24411 (earlier inverse problem — Matrix showed reasoning even when off). Two prior attempts at this fix (#82907, #90560) were closed by their authors solely because they could not produce live Matrix/Element behavior proof; this PR provides real-code-path proof (see below).

Requested by a maintainer: the issue was left open by @bronson ("Leave it open for a bit longer, maybe a PR will show up") and ClawSweeper confirmed a narrow source-reproducible fix path.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Matrix /reasoning on generates explicit reasoning payloads that never reach the channel — generic dispatch and Matrix delivery both dropped them before send. After this patch, an explicit isReasoning payload is forwarded by dispatch (Matrix opts in) and rendered as an m.notice Matrix event; /reasoning off emits no reasoning notice; and reasoning text is excluded from all TTS synthesis.

  • Real environment tested: Windows 10 (Node v22.17.1, pnpm 11.2.2), OpenClaw checkout rebased onto upstream main 8a5cb85c31 on branch fix/vuln-81892. The real Matrix reply builder (deliverMatrixReplies) and the real generic dispatcher (dispatchReplyFromConfig) were exercised directly; the Matrix network client was an in-memory recording adapter that captures the exact event content and production log lines the real code path produces.

  • Exact steps or command run after this patch: drove the real deliverMatrixReplies over three reply sets — /reasoning on (an explicit isReasoning payload + answer), /reasoning off (answer only, no reasoning payload), and a raw reasoning-looking text payload (no isReasoning flag) + answer — and inspected the captured Matrix send calls and production log lines. Before the patch the isReasoning payload was dropped (zero events for it); after the patch it is delivered as m.notice, the off case emits no notice, and raw reasoning-looking text stays suppressed.

  • Evidence after fix (terminal capture):

$ pnpm test proof-capture (drives the real deliverMatrixReplies over on/off/raw reply sets)
PROOF_CAPTURE_JSON:
{
  "on": {
    "logs": ["matrix reasoning delivered as notice"],
    "sends": [
      { "roomId": "!room:example.org", "body": "Reasoning: weighing options before answering", "msgtype": "m.notice" },
      { "roomId": "!room:example.org", "body": "The answer is 42", "msgtype": "m.text (default)" }
    ]
  },
  "off": {
    "logs": [],
    "sends": [
      { "roomId": "!room:example.org", "body": "The answer is 42", "msgtype": "m.text (default)" }
    ]
  },
  "rawSuppressed": {
    "logs": ["matrix reply suppressed as reasoning-only"],
    "sends": [
      { "roomId": "!room:example.org", "body": "The answer is 42", "msgtype": "m.text (default)" }
    ]
  }
}

The /reasoning on case emits the reasoning block first with msgtype: "m.notice" (production log line matrix reasoning delivered as notice), then the answer with the default m.text. The /reasoning off case emits no reasoning notice (no log line, one m.text send). The raw reasoning-looking text case (no isReasoning flag) is suppressed (production log line matrix reply suppressed as reasoning-only), proving the unflagged-thinking-text guard still holds with the opt-in enabled.

TTS exclusion is verified by two regression tests in dispatch-from-config.test.ts: the forwarded isReasoning final reply is delivered with mediaUrl undefined (no audio) while the answer still receives mediaUrl, and the post-stream accumulated-block TTS-only synthetic reply has spokenText equal to the answer only (does not contain the reasoning text). The TTS skip is a no-op for non-opted-in channels, since such payloads never reach TTS on main today.

  • Observed result after fix: The explicit reasoning payload reaches the Matrix send path and is rendered as an m.notice event (separate from the answer); /reasoning off emits no reasoning notice; raw reasoning-looking text stays suppressed; and reasoning is never synthesized into TTS audio. The dispatch path forwards isReasoning only for opted-in channels.

  • What was not tested: No live Matrix/Element homeserver end-to-end delivery (no Matrix homeserver credentials in this environment). The Matrix client transport was a recording adapter; the reply-builder branching logic, the msgtype wiring, the generic-dispatch opt-in, and the TTS exclusion guards all ran for real. Not exercised on macOS/Linux locally. The Swift host-env-policy check is skipped on Windows.

  • Proof limitations or environment constraints: Local Node is v22.17.1, below the repo's 22.19.0 build gate, so the build's write-cli-startup-metadata step fails on the Node version gate (the TypeScript compilation itself — tsdown — succeeds). CI runs on Linux Node 24, where this gate does not apply. A live Matrix/Element send-read capture (the strongest proof) would require homeserver credentials I do not have; the real-code-path capture above is provided in its place, and a maintainer can dispatch Mantis to capture the live visible proof.

  • Before evidence (optional but encouraged):

# dispatch, unpatched — reasoning suppressed even with the opt-in flag absent from main:
expected [ [ { text: 'The answer is 42' } ] ] to have a length of 2 but got 1
expected [ 'The answer is 42' ] to include 'thinking...'
# matrix replies, unpatched — isReasoning payload dropped before send:
expected "vi.fn()" to be called 2 times, but got 1 times   (only the answer was sent)

Tests and validation

Commands run (scoped):

  • pnpm tsgo:core — pass (0 errors).
  • pnpm lint (oxlint --type-aware on changed files) — pass (exit 0).
  • oxfmt --check on changed files — clean.
  • pnpm test extensions/matrix/src/matrix/monitor/replies.test.ts extensions/matrix/src/matrix/monitor/handler.test.ts — 126/126 pass (8 replies + 118 handler, incl. all 39 draft-streaming tests + the new reasoning bypass test).
  • pnpm test src/auto-reply/reply/dispatch-from-config.test.ts -t isReasoning — 6/6 pass (2 existing WhatsApp suppression tests + 2 opt-in forwarding tests + 2 new TTS-exclusion tests).
  • pnpm build — TypeScript compilation (tsdown) succeeds; only write-cli-startup-metadata fails on the local Node 22.17 < 22.19 gate (environmental; CI is Linux Node 24).

Regression coverage added:

  • dispatch-from-config.test.ts: forwards isReasoning final + block replies when the channel opts in via supportsReasoningBlocks (the existing WhatsApp-suppression tests remain and still pass, proving the default is unchanged); plus two new tests asserting isReasoning payloads are excluded from final TTS (no mediaUrl) and from the accumulated-block TTS-only synthetic reply (spokenText excludes reasoning).
  • replies.test.ts: an explicit isReasoning payload is delivered as MsgType.Notice; raw reasoning-looking text that is not flagged stays suppressed.
  • handler.test.ts: a reasoning block arriving mid-stream with draft streaming on is delivered via deliverMatrixReplies (as a notice) and is NOT edited into the live answer draft.

Known unrelated local failure: dispatch-from-config.test.ts > "deduplicates inbound messages by MessageSid and origin" hangs to a ~6 min timeout on this Windows/Node-22.17 machine. It does not set supportsReasoningBlocks, so the changed condition evaluates identically to before (!undefined === true); a boolean read cannot cause the hang, so it is pre-existing/environmental and not affected by this change. CI (Linux Node 24) is the source of truth.

If no test was added, why not: N/A — five regression tests were added (three originally + two TTS-exclusion tests).

Risk checklist

Did user-visible behavior change? (Yes/No) Yes — Matrix now surfaces reasoning as m.notice when /reasoning on (the intended, previously-broken behavior), and reasoning is excluded from TTS audio.

Did config, environment, or migration behavior change? (Yes/No) No — no new config/env keys. The opt-in is an internal reply-options capability flag set by the Matrix channel itself, not operator-facing. The TTS exclusion is a no-op for channels that suppress reasoning before delivery.

Did security, auth, secrets, network, or tool execution behavior change? (Yes/No) No.

What is the highest-risk area? The Matrix draft-stream bypass in handler.ts (reasoning payloads skip the live-preview edit path) and the relaxed dispatch suppression guards that let isReasoning reach the TTS paths for opted-in channels.

How is that risk mitigated? The two draft-stream guards are guarded by payload.isReasoning === true, so they only change behavior for explicit reasoning payloads; normal answer delivery and draft streaming are byte-for-byte unchanged (all 39 existing draft-streaming tests pass, plus a new test asserting reasoning is delivered as a notice and the draft is not edited). Reasoning arrives before the answer, so skipping its draft bookkeeping cannot desync the answer draft. The TTS exclusion is guarded by isReasoning === true in maybeApplyTtsToReplyPayload (covers final + per-block TTS) and in the block accumulator (covers the post-stream TTS-only synthetic reply); two regression tests assert reasoning receives no mediaUrl and is absent from the synthetic spokenText. Because isReasoning payloads never reach TTS on main today (they are suppressed before delivery), the exclusion is a no-op for non-opted-in channels.

Current review state

What is the next action? Maintainer review (and, if available, live Matrix/Element confirmation via Mantis).

What is still waiting on author, maintainer, CI, or external proof? CI on Linux Node 24 (rebased onto latest main 8a5cb85c31 to clear the pre-existing check-lint/check-prod-types failures from the stale base); ClawSweeper re-review after the TTS-exclusion fix and the expanded off-guard/raw-suppression proof. Optional live Matrix/Element confirmation — the real-code-path proof above is provided in lieu of a homeserver I do not have access to; a maintainer can dispatch Mantis with: @openclaw-mantis visual task: verify in Matrix/Element that /reasoning on shows a reasoning notice before the final answer and /reasoning off hides reasoning.

Which bot or reviewer comments were addressed? ClawSweeper's two P2 review findings are addressed: (1) dispatch-from-config.ts:3107isReasoning payloads no longer enter accumulatedBlockTtsText / blockCount; (2) dispatch-from-config.ts:3279isReasoning final replies skip TTS via the maybeApplyTtsToReplyPayload guard while still being delivered as the Matrix notice. The branch was also rebased onto the latest main so the two failing CI checks (check-lint, check-prod-types) — caused by a stale base carrying the since-fixed isCliRuntimeProvider unused import — now inherit the fix from main.

@openclaw-barnacle openclaw-barnacle Bot added channel: matrix Channel integration: matrix size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 17, 2026
@ml12580

ml12580 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Heads up: the two failing checks on this PR (check-lint, check-prod-types) look like a pre-existing breakage on main, not something introduced here.

  • check-prod-types: src/agents/model-picker-visibility.ts(7,10): error TS6133: 'isCliRuntimeProvider' is declared but its value is never read.
  • check-lint: Identifier 'isCliRuntimeProvider' is imported but never used. eslint(no-unused-vars) (same file).

This PR does not touch src/agents/model-picker-visibility.ts. The unused import was left behind on main by 2ee4b523b4 (refactor(agents): trim unused model helper exports), which removed isModelPickerVisibleProvider (the only caller of isCliRuntimeProvider) but kept the import. It reproduces on the latest main tip (53655f39f1), so it's red on main too.

This PR's own changes are green on CI: Real behavior proof ✅, build-artifacts ✅, check-test-types ✅, checks-fast-contracts-channels-a/b ✅, checks-node-auto-reply-reply-dispatch ✅ (includes the new reasoning forwarding tests), and the rest of the auto-reply/agentic lanes. Happy to re-trigger once main is fixed. Not fixing the unrelated import here to keep this PR scoped to the Matrix reasoning change.

@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 19, 2026
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 6, 2026, 2:13 PM ET / 18:13 UTC.

Summary
The PR forwards explicit Matrix reasoning payloads through shared dispatch, renders them as Matrix m.notice, bypasses draft preview for those blocks, and excludes reasoning from TTS synthesis.

PR surface: Source +53, Tests +209. Total +262 across 9 files.

Reproducibility: yes. source inspection gives a high-confidence reproduction path: current main's generic dispatch has a reasoning opt-in gate, but Matrix does not set it and Matrix delivery still suppresses isReasoning replies.

Review metrics: 1 noteworthy metric.

  • Reply option surface: 1 parallel option added. The PR adds supportsReasoningBlocks while current main already uses reasoningPayloadsEnabled, so maintainers should treat the option naming as compatibility-sensitive before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #81892
Summary: This PR is a candidate fix for the canonical Matrix /reasoning on delivery bug, while older same-purpose PRs are closed unmerged and the MiniMax tag PRs are adjacent Matrix reasoning-suppression work.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦪 silver shellfish
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Rebase onto current main and replace supportsReasoningBlocks with reasoningPayloadsEnabled in Matrix wiring and tests.
  • [P1] Add redacted live Matrix/Element send-read proof showing /reasoning on emits an m.notice and /reasoning off does not.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes useful terminal output from real OpenClaw functions, but Matrix transport is an in-memory adapter; a redacted live Matrix/Element send-read recording, transcript, terminal output, or logs is still needed 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.

Risk before merge

  • [P1] The branch adds a second durable-reasoning opt-in name while current main already uses reasoningPayloadsEnabled, which would fragment an internal channel-delivery contract if merged as-is.
  • [P1] The change affects Matrix message delivery and reasoning suppression; a wrong gate or draft bypass can either keep dropping requested reasoning notices or leak reasoning text in the wrong lane.
  • [P1] The supplied proof is useful terminal output, but it stops at an in-memory Matrix recording adapter rather than showing a live Matrix/Element send-read after the fix.

Maintainer options:

  1. Repair the gate before merge (recommended)
    Reuse current main's reasoningPayloadsEnabled option for Matrix and remove the parallel supportsReasoningBlocks surface and tests before this branch is considered again.
  2. Keep the proof gate
    Require a redacted live Matrix/Element send-read transcript, recording, or logs after the gate repair before treating the external PR as merge-ready.
  3. Pause if the branch stays stale
    If the contributor cannot rebase onto the current delivery gate and provide proof, leave the canonical issue open for a narrower replacement fix.

Next step before merge

  • [P1] Needs contributor or maintainer follow-up: repair the stale gate and provide live Matrix proof; ClawSweeper should not queue a repair marker while the external proof gate remains unmet.

Security
Cleared: No dependency, workflow, credential, auth, or supply-chain change was found; the reasoning-visibility concern is covered as message-delivery and proof risk.

Review findings

  • [P1] Use the existing reasoning payload gate — src/auto-reply/get-reply-options.types.ts:245
Review details

Best possible solution:

Rebase onto current main, wire Matrix through reasoningPayloadsEnabled: true, keep raw reasoning suppression and TTS exclusions, and add live Matrix/Element proof for the visible notice behavior before merge.

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

Yes, source inspection gives a high-confidence reproduction path: current main's generic dispatch has a reasoning opt-in gate, but Matrix does not set it and Matrix delivery still suppresses isReasoning replies.

Is this the best way to solve the issue?

No, this branch is not the best current fix because it duplicates the durable reasoning gate instead of reusing reasoningPayloadsEnabled; the best fix is the same Matrix routing change on the existing gate.

Full review comments:

  • [P1] Use the existing reasoning payload gate — src/auto-reply/get-reply-options.types.ts:245
    Current main already has reasoningPayloadsEnabled on GetReplyOptions and dispatchReplyFromConfig gates both block and final reasoning on that flag. This PR adds supportsReasoningBlocks instead, which would leave two opt-ins for the same durable reasoning lane and make Matrix diverge from the Telegram/Discord/followup delivery contract. Please rebase and wire Matrix through reasoningPayloadsEnabled: true instead; this is the still-unfixed prior ClawSweeper blocker.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a normal-priority Matrix channel regression fix with limited blast radius, not a core runtime outage.
  • merge-risk: 🚨 compatibility: The PR adds a new reply-option gate parallel to the existing durable reasoning gate used by current main.
  • merge-risk: 🚨 message-delivery: The diff changes which reasoning payloads are delivered or suppressed on Matrix and shared dispatch paths.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • 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 includes useful terminal output from real OpenClaw functions, but Matrix transport is an in-memory adapter; a redacted live Matrix/Element send-read recording, transcript, terminal output, or logs is still needed 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.
Evidence reviewed

PR surface:

Source +53, Tests +209. Total +262 across 9 files.

View PR surface stats
Area Files Added Removed Net
Source 6 62 9 +53
Tests 3 209 0 +209
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 9 271 9 +262

What I checked:

Likely related people:

  • superman32432432: GitHub commit metadata identifies this login as the author for the generic dispatch change that suppresses isReasoning payloads by default. (role: introduced generic dispatch suppression; confidence: high; commits: 7d76c241f89c; files: src/auto-reply/reply/dispatch-from-config.ts, src/auto-reply/reply/dispatch-from-config.test.ts)
  • justinhuangcode: The Matrix reply-delivery suppression behavior appears to date to commit 1298bd4, whose commit author is justinhuangcode. (role: introduced Matrix reasoning suppression; confidence: high; commits: 1298bd4e1bdb; files: extensions/matrix/src/matrix/monitor/replies.ts)
  • gumadeiras: Commit 94693f7 rebuilt the Matrix plugin migration branch and touched the Matrix monitor handler and reply-delivery paths involved in this repair. (role: Matrix monitor area contributor; confidence: medium; commits: 94693f7ff036; files: extensions/matrix/src/matrix/monitor/handler.ts, extensions/matrix/src/matrix/monitor/replies.ts)
  • steipete: GitHub metadata lists this login as committer for the historical generic and Matrix suppression commits, making them useful routing context for the current behavior. (role: historical committer and adjacent routing owner; confidence: medium; commits: 7d76c241f89c, 1298bd4e1bdb; files: src/auto-reply/reply/dispatch-from-config.ts, extensions/matrix/src/matrix/monitor/replies.ts)
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.

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.
Review history (3 earlier review cycles)
  • reviewed 2026-06-25T01:35:18.402Z sha 49ae7ca :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-06T14:44:27.636Z sha 49ae7ca :: needs real behavior proof before merge. :: [P1] Reuse the current reasoning payload gate
  • reviewed 2026-07-06T14:54:56.649Z sha 49ae7ca :: needs real behavior proof before merge. :: [P1] Use the existing reasoning payload gate

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 20, 2026
@xuwei-xy

Copy link
Copy Markdown

I think the fix would involve adjusting ui. Would that work for your use case?

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 20, 2026
ml12580 and others added 2 commits June 25, 2026 08:49
Generic dispatch suppresses explicit isReasoning payloads by default
because most generic-dispatch channels have no reasoning lane. Matrix
owns one, so opt it in via a supportsReasoningBlocks capability flag and
render reasoning as a quiet m.notice, mirroring Telegram/Slack. Reasoning
bypasses the live draft-preview edit so it persists as its own notice
instead of being overwritten by the next answer block. Raw
reasoning-looking text that is not an explicit payload stays suppressed.

Fixes openclaw#81892.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
When a channel opts in via supportsReasoningBlocks (Matrix), explicit
isReasoning payloads flow past the generic suppression guards and can
reach TTS: the per-block TTS application, sendFinalPayload final TTS,
and the post-stream accumulated-block TTS-only synthetic reply.

Reasoning is private thinking text delivered as its own notice
(Matrix m.notice); it must never be synthesized into audio. Exclude
isReasoning from the block TTS accumulator (accumulatedBlockTtsText +
blockCount) and short-circuit maybeApplyTtsToReplyPayload for
isReasoning payloads. The TTS skip is a no-op for channels that
suppress reasoning before delivery, since such payloads never reach
TTS today.

Addresses ClawSweeper P2 review findings on PR openclaw#93830:
- dispatch-from-config.ts:3107 (accumulated block TTS)
- dispatch-from-config.ts:3279 (final TTS)

Adds two regression tests covering both paths.
@ml12580

ml12580 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto latest main (8a5cb85c31) so the two failing checks (check-lint, check-prod-types) — caused by the stale base carrying the since-fixed isCliRuntimeProvider unused import — now inherit the fix from main.

Also addressed both P2 review findings:

  • dispatch-from-config.ts:3107isReasoning payloads no longer enter accumulatedBlockTtsText / blockCount, so reasoning cannot be synthesized into the post-stream TTS-only reply.
  • dispatch-from-config.ts:3279isReasoning final replies skip TTS via a maybeApplyTtsToReplyPayload guard (covers final + per-block TTS) while still being delivered as the Matrix notice. The skip is a no-op for non-opted-in channels since such payloads never reach TTS on main today.

Added two regression tests for the TTS-exclusion paths, and expanded the Real behavior proof to cover the /reasoning off guard (no notice emitted) and the raw-reasoning-text suppression guard, with the production log lines (matrix reasoning delivered as notice / matrix reply suppressed as reasoning-only) captured from the real deliverMatrixReplies code path.

Live Matrix/Element send-read proof still requires homeserver credentials I do not have; a maintainer can dispatch Mantis to capture it.

@clawsweeper

clawsweeper Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@ml12580 thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward.

Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive.

Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it.

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jul 6, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: matrix Channel integration: matrix 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. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: M stale Marked as stale due to inactivity 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]: Reasoning not delivered on Matrix channel (/reasoning on has no effect)

2 participants