From 74ed75f2e74def40db11f407893a8809a6e4e4ed Mon Sep 17 00:00:00 2001 From: Frank the Builder Date: Thu, 26 Mar 2026 03:34:55 +0000 Subject: [PATCH] fix: deliver verbose tool summaries in Telegram forum topics (#43236) (thanks @frankbuild) * fix(auto-reply): deliver verbose tool summaries in Telegram forum topics Forum topics have ChatType 'group' but are threaded conversations where verbose tool output should be delivered (same as DMs). The shouldSendToolSummaries gate now checks IsForum to allow tool summaries in forum topic sessions. Fixes #43206 * test: add sendToolResult count assertion per review feedback * fix: add changelog for forum topic verbose tool summaries (#43236) (thanks @frankbuild) --------- Co-authored-by: Ayaan Zaidi --- CHANGELOG.md | 1 + .../reply/dispatch-from-config.test.ts | 28 +++++++++++++++++++ src/auto-reply/reply/dispatch-from-config.ts | 5 +++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863fbc134b3..679f95dbac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Telegram: deliver verbose tool summaries inside forum topic sessions again, so threaded topic chats now match DM verbose behavior. (#43236) Thanks @frankbuild. - Agents/sandbox: honor `tools.sandbox.tools.alsoAllow`, let explicit sandbox re-allows remove matching built-in default-deny tools, and keep sandbox explain/error guidance aligned with the effective sandbox tool policy. (#54492) Thanks @ngutman. - Agents/sandbox: make blocked-tool guidance glob-aware again, redact/sanitize session-specific explain hints for safer copy-paste, and avoid leaking control-character session keys in those hints. (#54684) Thanks @ngutman. - Feishu: close WebSocket connections on monitor stop/abort so ghost connections no longer persist, preventing duplicate event processing and resource leaks across restart cycles. (#52844) Thanks @schumilin. diff --git a/src/auto-reply/reply/dispatch-from-config.test.ts b/src/auto-reply/reply/dispatch-from-config.test.ts index d93a46863b9..025d0f3ff03 100644 --- a/src/auto-reply/reply/dispatch-from-config.test.ts +++ b/src/auto-reply/reply/dispatch-from-config.test.ts @@ -755,6 +755,34 @@ describe("dispatchReplyFromConfig", () => { expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1); }); + it("delivers tool summaries in forum topic sessions (group + IsForum)", async () => { + setNoAbort(); + const cfg = emptyConfig; + const dispatcher = createDispatcher(); + const ctx = buildTestCtx({ + Provider: "telegram", + ChatType: "group", + IsForum: true, + MessageThreadId: 99, + }); + + const replyResolver = async ( + _ctx: MsgContext, + opts?: GetReplyOptions, + _cfg?: OpenClawConfig, + ) => { + await opts?.onToolResult?.({ text: "🔧 exec: ls" }); + return { text: "done" } satisfies ReplyPayload; + }; + + await dispatchReplyFromConfig({ ctx, cfg, dispatcher, replyResolver }); + expect(dispatcher.sendToolResult).toHaveBeenCalledWith( + expect.objectContaining({ text: "🔧 exec: ls" }), + ); + expect(dispatcher.sendToolResult).toHaveBeenCalledTimes(1); + expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1); + }); + it("delivers deterministic exec approval tool payloads in groups", async () => { setNoAbort(); const cfg = emptyConfig; diff --git a/src/auto-reply/reply/dispatch-from-config.ts b/src/auto-reply/reply/dispatch-from-config.ts index 8f68e4ab784..9d9f54f60e7 100644 --- a/src/auto-reply/reply/dispatch-from-config.ts +++ b/src/auto-reply/reply/dispatch-from-config.ts @@ -587,7 +587,10 @@ export async function dispatchReplyFromConfig(params: { } } - const shouldSendToolSummaries = ctx.ChatType !== "group" && ctx.CommandSource !== "native"; + // Forum topics are threaded conversations within a group — verbose tool + // summaries should be delivered into the topic thread, same as DMs. + const shouldSendToolSummaries = + (ctx.ChatType !== "group" || ctx.IsForum === true) && ctx.CommandSource !== "native"; const acpDispatch = await dispatchAcpRuntime.tryDispatchAcpReply({ ctx, cfg,