fix(feishu): suppress reasoning/thinking block payloads from delivery#31723
Conversation
… / data leak Pattern from PR openclaw#24969 The fix addresses the critical race condition by placing the 'block' filter check at the very top of the `deliver` function. This ensures that for internal 'block' reasoning chunks, the function returns immediately, preventing any text processing (lines 195-203) and, crucially, preventing the initialization of the streaming state for these payloads (lines 212-216). This ensures that the `streaming` object is not initialized with empty data, and subsequent 'final' payloads will correctly initialize and stream only the final content. The fix also addresses the 'incomplete' validation issue by using `info?.kind !== 'block'`. While the contract likely ensures `info` is present, this defensive approach ensures that if `info` is missing (and the payload is unrelated to internal blocking), the message is still delivered to the user, preventing a 'silent failure' bug. The validation logic at line 205 (`!hasText && !hasMedia`) ensures we do not send empty messages.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ee40c0991
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (info?.kind === 'block') { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Do not drop all block replies in Feishu delivery
Returning immediately for every info.kind === "block" suppresses normal user-facing streamed output, not just reasoning. The ACP projector emits visible assistant text as block events (src/auto-reply/reply/acp-projector.ts), and the non-ACP path explicitly supports runs where block streaming succeeds and no final text reply is sent (src/auto-reply/reply/dispatch-from-config.ts around the replies.length === 0 handling), so this guard can cause Feishu users to receive no text response at all in those configurations (especially when streaming previews are unavailable/disabled).
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes a privacy vulnerability where internal reasoning/thinking blocks were being sent to external Feishu users. The fix adds an early return guard to filter out The implementation also removes This fix aligns with the repository guideline (CLAUDE.md:205) that external messaging surfaces should only receive final replies, not partial/streaming/block content. The approach is consistent with how WhatsApp handles similar filtering (using Confidence Score: 5/5
Last reviewed commit: 5ee40c0 |
The deliver function is inside the createReplyDispatcherWithTyping call, so it should be indented at 2 levels (8 spaces), not 3 levels (12 spaces). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa9d787a30
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (info?.kind === 'block') { | ||
| return; |
There was a problem hiding this comment.
Preserve non-reasoning block replies in Feishu delivery
Returning early for every info.kind === "block" drops legitimate assistant output, not just reasoning. In the generic reply pipeline, reasoning is already filtered before dispatcher.sendBlockReply(...) (src/auto-reply/reply/dispatch-from-config.ts around shouldSuppressReasoningPayload), and ACP/live runs can complete with replies.length === 0 while relying on block deliveries as the only user-visible text (dispatch-from-config.ts TTS fallback path for block-only runs). In those configurations, this guard causes Feishu users to receive no response content at all.
Useful? React with 👍 / 👎.
|
PR #31723 - fix(feishu): suppress reasoning/thinking block payloads from delivery (#31723) Merged after verification.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ea2961b42
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (info?.kind === "block") { | ||
| return; |
There was a problem hiding this comment.
Preserve non-reasoning block replies in Feishu
This unconditional info?.kind === "block" return drops every block payload before text/media handling, so Feishu never delivers block-streamed assistant output that is not reasoning. The core pipeline already filters reasoning via payload.isReasoning (src/auto-reply/reply/reply-payloads.ts) and still emits user-visible block content through dispatcher.sendBlockReply(...) (src/auto-reply/reply/dispatch-acp-delivery.ts and src/auto-reply/reply/dispatch-from-config.ts), including runs where there is no final reply; in those flows this guard causes Feishu responses (and block-mode TTS media) to disappear entirely.
Useful? React with 👍 / 👎.
…openclaw#31723) * fix(extensions/feishu/src/reply-dispatcher.ts): missing privacy check / data leak Pattern from PR openclaw#24969 The fix addresses the critical race condition by placing the 'block' filter check at the very top of the `deliver` function. This ensures that for internal 'block' reasoning chunks, the function returns immediately, preventing any text processing (lines 195-203) and, crucially, preventing the initialization of the streaming state for these payloads (lines 212-216). This ensures that the `streaming` object is not initialized with empty data, and subsequent 'final' payloads will correctly initialize and stream only the final content. The fix also addresses the 'incomplete' validation issue by using `info?.kind !== 'block'`. While the contract likely ensures `info` is present, this defensive approach ensures that if `info` is missing (and the payload is unrelated to internal blocking), the message is still delivered to the user, preventing a 'silent failure' bug. The validation logic at line 205 (`!hasText && !hasMedia`) ensures we do not send empty messages. * Fix indentation: remove extra 4 spaces from deliver function body The deliver function is inside the createReplyDispatcherWithTyping call, so it should be indented at 2 levels (8 spaces), not 3 levels (12 spaces). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(feishu): cover block payload suppression in reply dispatcher --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…openclaw#31723) * fix(extensions/feishu/src/reply-dispatcher.ts): missing privacy check / data leak Pattern from PR openclaw#24969 The fix addresses the critical race condition by placing the 'block' filter check at the very top of the `deliver` function. This ensures that for internal 'block' reasoning chunks, the function returns immediately, preventing any text processing (lines 195-203) and, crucially, preventing the initialization of the streaming state for these payloads (lines 212-216). This ensures that the `streaming` object is not initialized with empty data, and subsequent 'final' payloads will correctly initialize and stream only the final content. The fix also addresses the 'incomplete' validation issue by using `info?.kind !== 'block'`. While the contract likely ensures `info` is present, this defensive approach ensures that if `info` is missing (and the payload is unrelated to internal blocking), the message is still delivered to the user, preventing a 'silent failure' bug. The validation logic at line 205 (`!hasText && !hasMedia`) ensures we do not send empty messages. * Fix indentation: remove extra 4 spaces from deliver function body The deliver function is inside the createReplyDispatcherWithTyping call, so it should be indented at 2 levels (8 spaces), not 3 levels (12 spaces). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(feishu): cover block payload suppression in reply dispatcher --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…openclaw#31723) * fix(extensions/feishu/src/reply-dispatcher.ts): missing privacy check / data leak Pattern from PR openclaw#24969 The fix addresses the critical race condition by placing the 'block' filter check at the very top of the `deliver` function. This ensures that for internal 'block' reasoning chunks, the function returns immediately, preventing any text processing (lines 195-203) and, crucially, preventing the initialization of the streaming state for these payloads (lines 212-216). This ensures that the `streaming` object is not initialized with empty data, and subsequent 'final' payloads will correctly initialize and stream only the final content. The fix also addresses the 'incomplete' validation issue by using `info?.kind !== 'block'`. While the contract likely ensures `info` is present, this defensive approach ensures that if `info` is missing (and the payload is unrelated to internal blocking), the message is still delivered to the user, preventing a 'silent failure' bug. The validation logic at line 205 (`!hasText && !hasMedia`) ensures we do not send empty messages. * Fix indentation: remove extra 4 spaces from deliver function body The deliver function is inside the createReplyDispatcherWithTyping call, so it should be indented at 2 levels (8 spaces), not 3 levels (12 spaces). * test(feishu): cover block payload suppression in reply dispatcher --------- Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
The delivery callback did not filter out payloads where info.kind === 'block', causing internal reasoning data to be sent to external users in partial stream mode. Also fixed a race condition in streaming initialization.
Changes:
Risk level: low