Files
clawdbot/src/auto-reply/reply/normalize-reply.ts
2026-01-09 13:55:27 +01:00

50 lines
1.4 KiB
TypeScript

import { stripHeartbeatToken } from "../heartbeat.js";
import { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "../tokens.js";
import type { ReplyPayload } from "../types.js";
export type NormalizeReplyOptions = {
responsePrefix?: string;
onHeartbeatStrip?: () => void;
stripHeartbeat?: boolean;
silentToken?: string;
};
export function normalizeReplyPayload(
payload: ReplyPayload,
opts: NormalizeReplyOptions = {},
): ReplyPayload | null {
const hasMedia = Boolean(
payload.mediaUrl || (payload.mediaUrls?.length ?? 0) > 0,
);
const trimmed = payload.text?.trim() ?? "";
if (!trimmed && !hasMedia) return null;
const silentToken = opts.silentToken ?? SILENT_REPLY_TOKEN;
if (trimmed === silentToken && !hasMedia) return null;
let text = payload.text ?? undefined;
if (text && !trimmed) {
// Keep empty text when media exists so media-only replies still send.
text = "";
}
const shouldStripHeartbeat = opts.stripHeartbeat ?? true;
if (shouldStripHeartbeat && text?.includes(HEARTBEAT_TOKEN)) {
const stripped = stripHeartbeatToken(text, { mode: "message" });
if (stripped.didStrip) opts.onHeartbeatStrip?.();
if (stripped.shouldSkip && !hasMedia) return null;
text = stripped.text;
}
if (
opts.responsePrefix &&
text &&
text.trim() !== HEARTBEAT_TOKEN &&
!text.startsWith(opts.responsePrefix)
) {
text = `${opts.responsePrefix} ${text}`;
}
return { ...payload, text };
}