|
| 1 | +import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload"; |
| 2 | +import type { MessagingToolSend } from "../../agents/pi-embedded-runner.js"; |
| 3 | +import type { OpenClawConfig } from "../../config/config.js"; |
| 4 | +import { stripHeartbeatToken } from "../heartbeat.js"; |
| 5 | +import type { OriginatingChannelType } from "../templating.js"; |
| 6 | +import type { ReplyPayload } from "../types.js"; |
| 7 | +import { |
| 8 | + resolveOriginAccountId, |
| 9 | + resolveOriginMessageProvider, |
| 10 | + resolveOriginMessageTo, |
| 11 | +} from "./origin-routing.js"; |
| 12 | +import { |
| 13 | + applyReplyThreading, |
| 14 | + filterMessagingToolDuplicates, |
| 15 | + filterMessagingToolMediaDuplicates, |
| 16 | + shouldSuppressMessagingToolReplies, |
| 17 | +} from "./reply-payloads.js"; |
| 18 | +import { resolveReplyToMode } from "./reply-threading.js"; |
| 19 | + |
| 20 | +export function resolveFollowupDeliveryPayloads(params: { |
| 21 | + cfg: OpenClawConfig; |
| 22 | + payloads: ReplyPayload[]; |
| 23 | + messageProvider?: string; |
| 24 | + originatingAccountId?: string; |
| 25 | + originatingChannel?: string; |
| 26 | + originatingChatType?: string | null; |
| 27 | + originatingTo?: string; |
| 28 | + sentMediaUrls?: string[]; |
| 29 | + sentTargets?: MessagingToolSend[]; |
| 30 | + sentTexts?: string[]; |
| 31 | +}): ReplyPayload[] { |
| 32 | + const replyToChannel = resolveOriginMessageProvider({ |
| 33 | + originatingChannel: params.originatingChannel, |
| 34 | + provider: params.messageProvider, |
| 35 | + }) as OriginatingChannelType | undefined; |
| 36 | + const replyToMode = resolveReplyToMode( |
| 37 | + params.cfg, |
| 38 | + replyToChannel, |
| 39 | + params.originatingAccountId, |
| 40 | + params.originatingChatType, |
| 41 | + ); |
| 42 | + const sanitizedPayloads = params.payloads.flatMap((payload) => { |
| 43 | + const text = payload.text; |
| 44 | + if (!text || !text.includes("HEARTBEAT_OK")) { |
| 45 | + return [payload]; |
| 46 | + } |
| 47 | + const stripped = stripHeartbeatToken(text, { mode: "message" }); |
| 48 | + const hasMedia = resolveSendableOutboundReplyParts(payload).hasMedia; |
| 49 | + if (stripped.shouldSkip && !hasMedia) { |
| 50 | + return []; |
| 51 | + } |
| 52 | + return [{ ...payload, text: stripped.text }]; |
| 53 | + }); |
| 54 | + const replyTaggedPayloads = applyReplyThreading({ |
| 55 | + payloads: sanitizedPayloads, |
| 56 | + replyToMode, |
| 57 | + replyToChannel, |
| 58 | + }); |
| 59 | + const dedupedPayloads = filterMessagingToolDuplicates({ |
| 60 | + payloads: replyTaggedPayloads, |
| 61 | + sentTexts: params.sentTexts ?? [], |
| 62 | + }); |
| 63 | + const mediaFilteredPayloads = filterMessagingToolMediaDuplicates({ |
| 64 | + payloads: dedupedPayloads, |
| 65 | + sentMediaUrls: params.sentMediaUrls ?? [], |
| 66 | + }); |
| 67 | + const suppressMessagingToolReplies = shouldSuppressMessagingToolReplies({ |
| 68 | + messageProvider: replyToChannel, |
| 69 | + messagingToolSentTargets: params.sentTargets, |
| 70 | + originatingTo: resolveOriginMessageTo({ |
| 71 | + originatingTo: params.originatingTo, |
| 72 | + }), |
| 73 | + accountId: resolveOriginAccountId({ |
| 74 | + originatingAccountId: params.originatingAccountId, |
| 75 | + }), |
| 76 | + }); |
| 77 | + return suppressMessagingToolReplies ? [] : mediaFilteredPayloads; |
| 78 | +} |
0 commit comments