export type WhisperGateConfig = { enabled?: boolean; discordOnly?: boolean; bypassUserIds?: string[]; endSymbols?: string[]; noReplyProvider: string; noReplyModel: string; }; export type Decision = { shouldUseNoReply: boolean; reason: string; }; function getLastChar(input: string): string { const t = input.trim(); return t.length ? t[t.length - 1] : ""; } export function evaluateDecision(params: { config: WhisperGateConfig; channel?: string; senderId?: string; content?: string; }): Decision { const { config } = params; if (config.enabled === false) { return { shouldUseNoReply: false, reason: "disabled" }; } const channel = (params.channel || "").toLowerCase(); if (config.discordOnly !== false && channel !== "discord") { return { shouldUseNoReply: false, reason: "non_discord" }; } if (params.senderId && (config.bypassUserIds || []).includes(params.senderId)) { return { shouldUseNoReply: false, reason: "bypass_sender" }; } const lastChar = getLastChar(params.content || ""); if (lastChar && (config.endSymbols || []).includes(lastChar)) { return { shouldUseNoReply: false, reason: `end_symbol:${lastChar}` }; } return { shouldUseNoReply: true, reason: "rule_match_no_end_symbol" }; }