openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
158 lines (157 loc) • 7.21 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { t as normalizeChatType } from "./chat-type-CxEvM45e.js";
import { a as resolveUserTimezone } from "./date-time-CcWivhrg.js";
import { n as formatZonedTimestamp, r as resolveTimezone, t as formatUtcTimestamp } from "./format-datetime-DO2rqkXr.js";
import { n as formatTimeAgo } from "./format-relative-Bjc3l98W.js";
//#region src/channels/sender-label.ts
function normalizeSenderLabelParams(params) {
return {
name: normalizeOptionalString(params.name),
username: normalizeOptionalString(params.username),
tag: normalizeOptionalString(params.tag),
e164: normalizeOptionalString(params.e164),
id: normalizeOptionalString(params.id)
};
}
/** Resolves the best one-line sender label from available identity fields. */
function resolveSenderLabel(params) {
const { name, username, tag, e164, id } = normalizeSenderLabelParams(params);
const display = name ?? username ?? tag ?? "";
const idPart = e164 ?? id ?? "";
if (display && idPart && display !== idPart) return `${display} (${idPart})`;
return display || idPart || null;
}
//#endregion
//#region src/auto-reply/envelope.ts
/** Formats inbound message envelopes with sender, timing, and channel metadata for agent prompts. */
function sanitizeEnvelopeHeaderPart(value) {
return value.replace(/\r\n|\r|\n/g, " ").replaceAll("[", "(").replaceAll("]", ")").replace(/\s+/g, " ").trim();
}
/** Resolves envelope formatting defaults from agent config. */
function resolveEnvelopeFormatOptions(cfg) {
const defaults = cfg?.agents?.defaults;
return {
timezone: defaults?.envelopeTimezone,
includeTimestamp: defaults?.envelopeTimestamp !== "off",
includeElapsed: defaults?.envelopeElapsed !== "off",
userTimezone: defaults?.userTimezone
};
}
function normalizeEnvelopeOptions(options) {
const includeTimestamp = options?.includeTimestamp !== false;
const includeElapsed = options?.includeElapsed !== false;
return {
timezone: normalizeOptionalString(options?.timezone) || "local",
includeTimestamp,
includeElapsed,
userTimezone: options?.userTimezone
};
}
function resolveEnvelopeTimezone(options) {
const trimmed = options.timezone?.trim();
if (!trimmed) return { mode: "local" };
const lowered = normalizeLowercaseStringOrEmpty(trimmed);
if (lowered === "utc" || lowered === "gmt") return { mode: "utc" };
if (lowered === "local" || lowered === "host") return { mode: "local" };
if (lowered === "user") return {
mode: "iana",
timeZone: resolveUserTimezone(options.userTimezone)
};
const explicit = resolveTimezone(trimmed);
return explicit ? {
mode: "iana",
timeZone: explicit
} : { mode: "utc" };
}
/** Formats an envelope timestamp using local, UTC, user, or explicit IANA timezone rules. */
function formatEnvelopeTimestamp(ts, options) {
if (!ts) return;
const resolved = normalizeEnvelopeOptions(options);
if (!resolved.includeTimestamp) return;
const date = ts instanceof Date ? ts : new Date(ts);
if (Number.isNaN(date.getTime())) return;
const zone = resolveEnvelopeTimezone(resolved);
const weekday = (() => {
try {
if (zone.mode === "utc") return new Intl.DateTimeFormat("en-US", {
timeZone: "UTC",
weekday: "short"
}).format(date);
if (zone.mode === "local") return new Intl.DateTimeFormat("en-US", { weekday: "short" }).format(date);
return new Intl.DateTimeFormat("en-US", {
timeZone: zone.timeZone,
weekday: "short"
}).format(date);
} catch {
return;
}
})();
const formatted = zone.mode === "utc" ? formatUtcTimestamp(date, { displaySeconds: true }) : zone.mode === "local" ? formatZonedTimestamp(date, { displaySeconds: true }) : formatZonedTimestamp(date, {
timeZone: zone.timeZone,
displaySeconds: true
});
if (!formatted) return;
return weekday ? `${weekday} ${formatted}` : formatted;
}
function resolveDirectEnvelopeBodyLabel(from) {
const label = sanitizeEnvelopeHeaderPart(from || "");
const idMarkerIndex = label.search(/\s+id:/i);
if (idMarkerIndex > 0) {
const displayLabel = label.slice(0, idMarkerIndex).trim();
return displayLabel.includes(":") ? "(sender)" : displayLabel;
}
return label.includes(":") ? "(sender)" : label;
}
/** Formats the generic bracketed envelope prepended to agent-visible messages. */
function formatAgentEnvelope(params) {
const parts = [sanitizeEnvelopeHeaderPart(normalizeOptionalString(params.channel) || "Channel")];
const resolved = normalizeEnvelopeOptions(params.envelope);
let elapsed;
if (resolved.includeElapsed && params.timestamp && params.previousTimestamp) {
const elapsedMs = (params.timestamp instanceof Date ? params.timestamp.getTime() : params.timestamp) - (params.previousTimestamp instanceof Date ? params.previousTimestamp.getTime() : params.previousTimestamp);
elapsed = Number.isFinite(elapsedMs) && elapsedMs >= 0 ? formatTimeAgo(elapsedMs, { suffix: false }) : void 0;
}
const from = normalizeOptionalString(params.from);
if (from) {
const fromLabel = sanitizeEnvelopeHeaderPart(from);
parts.push(elapsed ? `${fromLabel} +${elapsed}` : fromLabel);
} else if (elapsed) parts.push(`+${elapsed}`);
const host = normalizeOptionalString(params.host);
if (host) parts.push(sanitizeEnvelopeHeaderPart(host));
const ip = normalizeOptionalString(params.ip);
if (ip) parts.push(sanitizeEnvelopeHeaderPart(ip));
const ts = formatEnvelopeTimestamp(params.timestamp, resolved);
if (ts) parts.push(ts);
return `${`[${parts.join(" ")}]`} ${params.body}`;
}
/** Formats an inbound message body with sender attribution appropriate for direct/group chats. */
function formatInboundEnvelope(params) {
const chatType = normalizeChatType(params.chatType);
const isDirect = !chatType || chatType === "direct";
const resolvedSenderRaw = normalizeOptionalString(params.senderLabel) || resolveSenderLabel(params.sender ?? {});
const resolvedSender = resolvedSenderRaw ? sanitizeEnvelopeHeaderPart(resolvedSenderRaw) : "";
const directSender = resolveDirectEnvelopeBodyLabel(normalizeOptionalString(params.from));
const body = isDirect && params.fromMe ? `(self): ${params.body}` : isDirect && directSender ? `${directSender}: ${params.body}` : !isDirect && resolvedSender ? `${resolvedSender}: ${params.body}` : params.body;
return formatAgentEnvelope({
channel: params.channel,
from: params.from,
timestamp: params.timestamp,
previousTimestamp: params.previousTimestamp,
envelope: params.envelope,
body
});
}
/** Builds the compact `from` label used in inbound envelope headers. */
function formatInboundFromLabel(params) {
if (params.isGroup) {
const label = normalizeOptionalString(params.groupLabel) || params.groupFallback || "Group";
const id = params.groupId?.trim();
return id ? `${label} id:${id}` : label;
}
const directLabel = params.directLabel.trim();
const directId = params.directId?.trim();
if (!directId || directId === directLabel) return directLabel;
return `${directLabel} id:${directId}`;
}
//#endregion
export { resolveEnvelopeFormatOptions as a, formatInboundFromLabel as i, formatEnvelopeTimestamp as n, resolveSenderLabel as o, formatInboundEnvelope as r, formatAgentEnvelope as t };