Skip to content

Commit 477de54

Browse files
Maple778claudeTakhoffman
authored
fix(feishu): suppress reasoning/thinking block payloads from delivery (#31723)
* fix(extensions/feishu/src/reply-dispatcher.ts): missing privacy check / data leak Pattern from PR #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 <[email protected]> * test(feishu): cover block payload suppression in reply dispatcher --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]> Co-authored-by: Tak Hoffman <[email protected]>
1 parent bd4a082 commit 477de54

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

extensions/feishu/src/reply-dispatcher.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,23 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
185185
expect(sendMarkdownCardFeishuMock).not.toHaveBeenCalled();
186186
});
187187

188+
it("suppresses internal block payload delivery", async () => {
189+
createFeishuReplyDispatcher({
190+
cfg: {} as never,
191+
agentId: "agent",
192+
runtime: {} as never,
193+
chatId: "oc_chat",
194+
});
195+
196+
const options = createReplyDispatcherWithTypingMock.mock.calls[0]?.[0];
197+
await options.deliver({ text: "internal reasoning chunk" }, { kind: "block" });
198+
199+
expect(streamingInstances).toHaveLength(0);
200+
expect(sendMessageFeishuMock).not.toHaveBeenCalled();
201+
expect(sendMarkdownCardFeishuMock).not.toHaveBeenCalled();
202+
expect(sendMediaFeishuMock).not.toHaveBeenCalled();
203+
});
204+
188205
it("uses streaming session for auto mode markdown payloads", async () => {
189206
createFeishuReplyDispatcher({
190207
cfg: {} as never,

extensions/feishu/src/reply-dispatcher.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
192192
void typingCallbacks.onReplyStart?.();
193193
},
194194
deliver: async (payload: ReplyPayload, info) => {
195+
// FIX: Filter out internal 'block' reasoning chunks immediately to prevent
196+
// data leak and race conditions with streaming state initialization.
197+
if (info?.kind === "block") {
198+
return;
199+
}
200+
195201
const text = payload.text ?? "";
196202
const mediaList =
197203
payload.mediaUrls && payload.mediaUrls.length > 0
@@ -209,7 +215,7 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
209215
if (hasText) {
210216
const useCard = renderMode === "card" || (renderMode === "auto" && shouldUseCard(text));
211217

212-
if ((info?.kind === "block" || info?.kind === "final") && streamingEnabled && useCard) {
218+
if (info?.kind === "final" && streamingEnabled && useCard) {
213219
startStreaming();
214220
if (streamingStartPromise) {
215221
await streamingStartPromise;

0 commit comments

Comments
 (0)