Files
clawdbot/src/twilio/heartbeat.ts
2025-12-03 00:43:28 +00:00

94 lines
2.5 KiB
TypeScript

import { getReplyFromConfig } from "../auto-reply/reply.js";
import { danger, success } from "../globals.js";
import { logInfo } from "../logger.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { HEARTBEAT_PROMPT, stripHeartbeatToken } from "../web/auto-reply.js";
import { sendMessage } from "./send.js";
type ReplyResolver = typeof getReplyFromConfig;
export async function runTwilioHeartbeatOnce(opts: {
to: string;
verbose?: boolean;
runtime?: RuntimeEnv;
replyResolver?: ReplyResolver;
overrideBody?: string;
dryRun?: boolean;
}) {
const {
to,
verbose: _verbose = false,
runtime = defaultRuntime,
overrideBody,
dryRun = false,
} = opts;
const replyResolver = opts.replyResolver ?? getReplyFromConfig;
if (overrideBody && overrideBody.trim().length === 0) {
throw new Error("Override body must be non-empty when provided.");
}
try {
if (overrideBody) {
if (dryRun) {
logInfo(
`[dry-run] twilio send -> ${to}: ${overrideBody.trim()} (manual message)`,
runtime,
);
return;
}
await sendMessage(to, overrideBody, undefined, runtime);
logInfo(success(`sent manual message to ${to} (twilio)`), runtime);
return;
}
const replyResult = await replyResolver(
{
Body: HEARTBEAT_PROMPT,
From: to,
To: to,
MessageSid: undefined,
},
{ isHeartbeat: true },
);
const replyPayload = Array.isArray(replyResult)
? replyResult[0]
: replyResult;
if (
!replyPayload ||
(!replyPayload.text &&
!replyPayload.mediaUrl &&
!replyPayload.mediaUrls?.length)
) {
logInfo("heartbeat skipped: empty reply", runtime);
return;
}
const hasMedia = Boolean(
replyPayload.mediaUrl || (replyPayload.mediaUrls?.length ?? 0) > 0,
);
const stripped = stripHeartbeatToken(replyPayload.text);
if (stripped.shouldSkip && !hasMedia) {
logInfo(success("heartbeat: ok (HEARTBEAT_OK)"), runtime);
return;
}
const finalText = stripped.text || replyPayload.text || "";
if (dryRun) {
logInfo(
`[dry-run] heartbeat -> ${to}: ${finalText.slice(0, 200)}`,
runtime,
);
return;
}
await sendMessage(to, finalText, undefined, runtime);
logInfo(success(`heartbeat sent to ${to} (twilio)`), runtime);
} catch (err) {
runtime.error(danger(`Heartbeat failed: ${String(err)}`));
throw err;
}
}