






















@@ -1,4 +1,5 @@
11import { deliverInboundReplyWithMessageSendContext } from "openclaw/plugin-sdk/channel-message";
2+import { DEFAULT_TIMING, type StatusReactionController } from "openclaw/plugin-sdk/channel-feedback";
23import { hasVisibleInboundReplyDispatch } from "openclaw/plugin-sdk/inbound-reply-dispatch";
34import type { FinalizedMsgContext } from "openclaw/plugin-sdk/reply-runtime";
45import {
@@ -399,7 +400,14 @@ export async function dispatchWhatsAppBufferedReply(params: {
399400replyResolver: typeof getReplyFromConfig;
400401route: ReturnType<typeof resolveAgentRoute>;
401402shouldClearGroupHistory: boolean;
403+statusReactionController?: StatusReactionController | null;
402404}) {
405+const statusReactionController = params.statusReactionController ?? null;
406+const statusReactionTiming = {
407+ ...DEFAULT_TIMING,
408+ ...params.cfg.messages?.statusReactions?.timing,
409+};
410+const removeAckAfterReply = params.cfg.messages?.removeAckAfterReply ?? false;
403411const textLimit = params.maxMediaTextChunkLimit ?? resolveTextChunkLimit(params.cfg, "whatsapp");
404412const chunkMode = resolveChunkMode(params.cfg, "whatsapp", params.route.accountId);
405413const tableMode = resolveMarkdownTableMode({
@@ -484,6 +492,10 @@ export async function dispatchWhatsAppBufferedReply(params: {
484492},
485493});
486494495+if (statusReactionController) {
496+void statusReactionController.setThinking();
497+}
498+487499const { queuedFinal, counts } = await dispatchReplyWithBufferedBlockDispatcher({
488500ctx: params.context,
489501cfg: params.cfg,
@@ -563,6 +575,17 @@ export async function dispatchWhatsAppBufferedReply(params: {
563575await deliverNormalizedPayload(normalizedDeliveryPayload, info);
564576},
565577onReplyStart: params.msg.sendComposing,
578+ ...(statusReactionController
579+ ? {
580+onCompactionStart: async () => {
581+await statusReactionController.setCompacting();
582+},
583+onCompactionEnd: async () => {
584+statusReactionController.cancelPending();
585+await statusReactionController.setThinking();
586+},
587+}
588+ : {}),
566589onError: (err, info) => {
567590logWhatsAppReplyDeliveryError({
568591 err,
@@ -578,22 +601,84 @@ export async function dispatchWhatsAppBufferedReply(params: {
578601 disableBlockStreaming,
579602 ...(sourceReplyDeliveryMode ? { sourceReplyDeliveryMode } : {}),
580603onModelSelected: params.onModelSelected,
604+ ...(statusReactionController
605+ ? {
606+onToolStart: async (payload: { name?: string }) => {
607+const toolName = payload.name?.trim();
608+if (toolName) {
609+await statusReactionController.setTool(toolName);
610+}
611+},
612+}
613+ : {}),
581614},
582615});
583616logWhatsAppMediaOnlyFlushResult(await mediaOnlyCoalescer.flushAll());
584617585618const didQueueVisibleReply = hasVisibleInboundReplyDispatch({ queuedFinal, counts });
586619if (!didQueueVisibleReply) {
620+if (statusReactionController) {
621+void finalizeWhatsAppStatusReaction({
622+controller: statusReactionController,
623+outcome: "error",
624+hasFinalResponse: false,
625+ removeAckAfterReply,
626+timing: statusReactionTiming,
627+});
628+}
587629if (params.shouldClearGroupHistory) {
588630params.groupHistories.set(params.groupHistoryKey, []);
589631}
590632logVerbose("Skipping auto-reply: silent token or no text/media returned from resolver");
591633return false;
592634}
593635636+if (statusReactionController) {
637+void finalizeWhatsAppStatusReaction({
638+controller: statusReactionController,
639+outcome: didSendReply ? "done" : "error",
640+hasFinalResponse: didSendReply,
641+ removeAckAfterReply,
642+timing: statusReactionTiming,
643+});
644+}
645+594646if (params.shouldClearGroupHistory) {
595647params.groupHistories.set(params.groupHistoryKey, []);
596648}
597649598650return didSendReply;
599651}
652+653+async function finalizeWhatsAppStatusReaction(params: {
654+controller: StatusReactionController;
655+outcome: "done" | "error";
656+hasFinalResponse: boolean;
657+removeAckAfterReply: boolean;
658+timing: typeof DEFAULT_TIMING;
659+}): Promise<void> {
660+if (params.outcome === "done") {
661+await params.controller.setDone();
662+if (params.removeAckAfterReply) {
663+await new Promise<void>((resolve) => setTimeout(resolve, params.timing.doneHoldMs));
664+await params.controller.clear();
665+} else {
666+await params.controller.restoreInitial();
667+}
668+return;
669+}
670+await params.controller.setError();
671+if (params.hasFinalResponse) {
672+if (params.removeAckAfterReply) {
673+await new Promise<void>((resolve) => setTimeout(resolve, params.timing.errorHoldMs));
674+await params.controller.clear();
675+} else {
676+await params.controller.restoreInitial();
677+}
678+return;
679+}
680+if (params.removeAckAfterReply) {
681+await new Promise<void>((resolve) => setTimeout(resolve, params.timing.errorHoldMs));
682+}
683+await params.controller.restoreInitial();
684+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。