import type { InteractiveReply } from "../interactive/payload.js"; export type ReplyPayload = { text?: string; mediaUrl?: string; mediaUrls?: string[]; interactive?: InteractiveReply; btw?: { question: string; }; replyToId?: string; replyToTag?: boolean; /** True when [[reply_to_current]] was present but not yet mapped to a message id. */ replyToCurrent?: boolean; /** Send audio as voice message (bubble) instead of audio file. Defaults to false. */ audioAsVoice?: boolean; isError?: boolean; /** Marks this payload as a reasoning/thinking block. Channels that do not * have a dedicated reasoning lane (e.g. WhatsApp, web) should suppress it. */ isReasoning?: boolean; /** Marks this payload as a compaction status notice (start/end). * Should be excluded from TTS transcript accumulation so compaction * status lines are not synthesised into the spoken assistant reply. */ isCompactionNotice?: boolean; /** Channel-specific payload data (per-channel envelope). */ channelData?: Record; }; export type ReplyPayloadMetadata = { assistantMessageIndex?: number; }; const replyPayloadMetadata = new WeakMap(); export function setReplyPayloadMetadata( payload: T, metadata: ReplyPayloadMetadata, ): T { const previous = replyPayloadMetadata.get(payload); replyPayloadMetadata.set(payload, { ...previous, ...metadata }); return payload; } export function getReplyPayloadMetadata(payload: object): ReplyPayloadMetadata | undefined { return replyPayloadMetadata.get(payload); }