feat: add channel/topic overrides for skills + auto-reply

This commit is contained in:
Peter Steinberger
2026-01-07 11:23:04 +01:00
parent 61f720b945
commit 43c6bb7595
8 changed files with 706 additions and 86 deletions

View File

@@ -26,6 +26,56 @@ function normalizeSlackSlug(raw?: string | null) {
return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
}
function parseTelegramGroupId(value?: string | null) {
const raw = value?.trim() ?? "";
if (!raw) return { chatId: undefined, topicId: undefined };
const parts = raw.split(":").filter(Boolean);
if (
parts.length >= 3 &&
parts[1] === "topic" &&
/^-?\d+$/.test(parts[0]) &&
/^\d+$/.test(parts[2])
) {
return { chatId: parts[0], topicId: parts[2] };
}
if (parts.length >= 2 && /^-?\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
return { chatId: parts[0], topicId: parts[1] };
}
return { chatId: raw, topicId: undefined };
}
function hasOwn(obj: unknown, key: string): boolean {
return Boolean(obj && typeof obj === "object" && Object.hasOwn(obj, key));
}
function resolveTelegramAutoReply(params: {
cfg: ClawdbotConfig;
chatId?: string;
topicId?: string;
}): boolean | undefined {
const { cfg, chatId, topicId } = params;
if (!chatId) return undefined;
const groupConfig = cfg.telegram?.groups?.[chatId];
const groupDefault = cfg.telegram?.groups?.["*"];
const topicConfig =
topicId && groupConfig?.topics ? groupConfig.topics[topicId] : undefined;
const defaultTopicConfig =
topicId && groupDefault?.topics ? groupDefault.topics[topicId] : undefined;
if (hasOwn(topicConfig, "autoReply")) {
return (topicConfig as { autoReply?: boolean }).autoReply;
}
if (hasOwn(defaultTopicConfig, "autoReply")) {
return (defaultTopicConfig as { autoReply?: boolean }).autoReply;
}
if (hasOwn(groupConfig, "autoReply")) {
return (groupConfig as { autoReply?: boolean }).autoReply;
}
if (hasOwn(groupDefault, "autoReply")) {
return (groupDefault as { autoReply?: boolean }).autoReply;
}
return undefined;
}
function resolveDiscordGuildEntry(
guilds: NonNullable<ClawdbotConfig["discord"]>["guilds"],
groupSpace?: string,
@@ -55,11 +105,17 @@ export function resolveGroupRequireMention(params: {
const groupId = groupResolution?.id ?? ctx.From?.replace(/^group:/, "");
const groupRoom = ctx.GroupRoom?.trim() ?? ctx.GroupSubject?.trim();
const groupSpace = ctx.GroupSpace?.trim();
if (
provider === "telegram" ||
provider === "whatsapp" ||
provider === "imessage"
) {
if (provider === "telegram") {
const { chatId, topicId } = parseTelegramGroupId(groupId);
const autoReply = resolveTelegramAutoReply({ cfg, chatId, topicId });
if (typeof autoReply === "boolean") return !autoReply;
return resolveProviderGroupRequireMention({
cfg,
provider,
groupId: chatId ?? groupId,
});
}
if (provider === "whatsapp" || provider === "imessage") {
return resolveProviderGroupRequireMention({
cfg,
provider,
@@ -82,6 +138,9 @@ export function resolveGroupRequireMention(params: {
(groupRoom
? channelEntries[normalizeDiscordSlug(groupRoom)]
: undefined);
if (entry && typeof entry.autoReply === "boolean") {
return !entry.autoReply;
}
if (entry && typeof entry.requireMention === "boolean") {
return entry.requireMention;
}
@@ -104,7 +163,7 @@ export function resolveGroupRequireMention(params: {
channelName ?? "",
normalizedName,
].filter(Boolean);
let matched: { requireMention?: boolean } | undefined;
let matched: { requireMention?: boolean; autoReply?: boolean } | undefined;
for (const candidate of candidates) {
if (candidate && channels[candidate]) {
matched = channels[candidate];
@@ -113,6 +172,9 @@ export function resolveGroupRequireMention(params: {
}
const fallback = channels["*"];
const resolved = matched ?? fallback;
if (typeof resolved?.autoReply === "boolean") {
return !resolved.autoReply;
}
if (typeof resolved?.requireMention === "boolean") {
return resolved.requireMention;
}