Lumi/plugins/lumi_ai/backend/commands.js
2026-06-12 11:54:46 +02:00

92 lines
3.7 KiB
JavaScript

const { roleOf } = require("./permissions");
const PLATFORM_DEFAULTS = {
discord: { markdown: true, html: false, reply_thread: true, max: 1900 },
twitch: { markdown: false, html: false, reply_thread: false, max: 450 },
youtube: { markdown: false, html: false, reply_thread: false, max: 1800 },
kick: { markdown: false, html: false, reply_thread: false, max: 450 },
webui: { markdown: false, html: true, reply_thread: false, max: 4000 },
other: { markdown: false, html: false, reply_thread: false, max: 1000 }
};
function buildOriginContext(ctx, command = "assistant") {
const platform = ctx.platform || "other";
const defaults = PLATFORM_DEFAULTS[platform] || PLATFORM_DEFAULTS.other;
const role = inferRole(ctx);
return {
origin: platform,
platform,
channel_id: ctx.meta?.message?.channelId || ctx.meta?.channel || ctx.meta?.liveChatId || null,
channel_name: ctx.meta?.message?.channel?.name || ctx.meta?.channel || null,
server_id: ctx.meta?.message?.guildId || null,
user_id: ctx.user?.id || null,
username: ctx.user?.username || ctx.platformUser?.username || null,
display_name: ctx.user?.displayName || ctx.platformUser?.displayName || null,
role,
is_admin: role === "admin",
is_mod: role === "mod",
message_id: ctx.meta?.message?.id || ctx.meta?.messageId || null,
reply_mode: defaults.reply_thread ? "thread" : "same_channel",
format_capabilities: { markdown: defaults.markdown, html: defaults.html },
max_message_length: defaults.max,
source_plugin: "lumi_ai",
source_command: command,
permission_context: {
identified_user: Boolean(ctx.user?.id),
webui_actions_allowed: false
}
};
}
function formatPlatformReply(text, links, origin) {
return formatPlatformReplyDetails(text, links, origin).text;
}
function formatPlatformReplyDetails(text, links, origin) {
let output = String(text || "").trim();
const safeLinks = Array.isArray(links)
? links.filter((link) => /^https?:\/\//i.test(link?.href || "") || link?.href?.startsWith("/"))
: [];
if (safeLinks.length) {
const paths = safeLinks.map((link) => origin.format_capabilities.markdown
? `[${link.label}](${link.href})`
: `${link.label}: ${link.href}`).join(" | ");
output = `${output} ${paths}`.trim();
}
if (!origin.format_capabilities.markdown) {
output = output.replace(/[*_`~]/g, "").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1: $2");
}
output = output.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
const originalLength = output.length;
const delivered = truncate(output, origin.max_message_length);
return {
text: delivered,
original_final_length: originalLength,
delivered_length: delivered.length
};
}
function inferRole(ctx) {
if (ctx.isAdmin || ctx.user?.isAdmin || hasPermission(ctx, ["Administrator", "ADMINISTRATOR"])) return "admin";
const tags = ctx.meta?.tags || {};
if (ctx.isMod || ctx.user?.isMod || hasPermission(ctx, ["ManageMessages", "MANAGE_MESSAGES"]) ||
tags.mod === "1" || tags.badges?.broadcaster === "1" || tags.badges?.moderator === "1") return "mod";
return roleOf(ctx.user);
}
function hasPermission(ctx, names) {
const permissions = ctx.meta?.message?.member?.permissions;
if (!permissions?.has) return false;
return names.some((name) => {
try { return Boolean(permissions.has(name)); } catch { return false; }
});
}
function truncate(value, max) {
if (value.length <= max) return value;
const suffix = " [reply truncated]";
return `${value.slice(0, Math.max(1, max - suffix.length)).trimEnd()}${suffix}`;
}
module.exports = { PLATFORM_DEFAULTS, buildOriginContext, formatPlatformReply, formatPlatformReplyDetails, inferRole };