From 78b804176a4afdcf4f30d25a2c26430c24ce5125 Mon Sep 17 00:00:00 2001 From: 1tzEmerald Date: Fri, 27 Mar 2026 16:25:59 +0000 Subject: [PATCH] 26.0 --- Configs/supportbot-ai.yml | 12 +++- Events/messageCreate.js | 67 ++++++++++++------ Structures/AIDatabase.js | 144 +++++++++++++++++++++++++++++++++++++- 3 files changed, 200 insertions(+), 23 deletions(-) diff --git a/Configs/supportbot-ai.yml b/Configs/supportbot-ai.yml index 5ebc8ba..ac6807c 100644 --- a/Configs/supportbot-ai.yml +++ b/Configs/supportbot-ai.yml @@ -10,7 +10,7 @@ Enabled: true General: Provider: "openai" Model: "gpt-5.4" - Model_API_Key: "MODEL_API_KEY" + Model_API_Key: "AI_API_KEY" # Providers Available: # "openai" - Use OpenAI's GPT models. Example: "gpt-5.4" "gpt-5-mini" # "groq" - Use Groq's GroqAI models. Example: "meta-llama/llama-4-scout-17b-16e-instruct" @@ -43,8 +43,18 @@ Embed: Memory: Enabled: true StoreFacts: true + # StoreFacts - Enables saving important facts the AI learns. + StoreSummaries: true + # StoreSummaries - Enables saving conversation summaries. + MaxRecentMessages: 15 + # MaxRecentMessages - Number of recent messages used for context. + + Scope: "guild" # channel | guild + # Available Scopes for Memory: + # "channel" - Memory is per channel only. + # "guild" - Memory is shared across the server. CustomInstructions: - "You are SupportBot AI made by Emerald Services" diff --git a/Events/messageCreate.js b/Events/messageCreate.js index 9302511..55a8d8c 100644 --- a/Events/messageCreate.js +++ b/Events/messageCreate.js @@ -113,10 +113,11 @@ function buildSystemPrompt(message) { return sections.join("\n- ").replace(/^/, "- "); } -function buildConversationFromMemory(channelId, currentMessage) { +function buildConversationFromMemory(currentMessage) { const memoryConfig = supportbotai.Memory || {}; const memoryEnabled = memoryConfig.Enabled !== false; const maxRecentMessages = memoryConfig.MaxRecentMessages || 15; + const memoryScope = String(memoryConfig.Scope || "guild").toLowerCase(); const conversation = [ { @@ -127,32 +128,61 @@ function buildConversationFromMemory(channelId, currentMessage) { if (!memoryEnabled) return conversation; - const recentMessages = AIDatabase.getRecentMessages( - channelId, - maxRecentMessages, - ); + const recentMessages = + typeof AIDatabase.getRecentMessagesByScope === "function" + ? AIDatabase.getRecentMessagesByScope({ + guildId: currentMessage.guild?.id || null, + channelId: currentMessage.channel?.id || null, + limit: maxRecentMessages, + scope: memoryScope, + }) + : AIDatabase.getRecentMessages( + currentMessage.channel?.id, + maxRecentMessages, + ); const latestSummary = memoryConfig.StoreSummaries !== false - ? AIDatabase.getLatestSummary(channelId) + ? typeof AIDatabase.getLatestSummaryByScope === "function" + ? AIDatabase.getLatestSummaryByScope({ + guildId: currentMessage.guild?.id || null, + channelId: currentMessage.channel?.id || null, + scope: memoryScope, + }) + : AIDatabase.getLatestSummary(currentMessage.channel?.id) : null; const facts = - memoryConfig.StoreFacts !== false ? AIDatabase.getFacts(channelId) : []; + memoryConfig.StoreFacts !== false + ? typeof AIDatabase.getFactsByScope === "function" + ? AIDatabase.getFactsByScope({ + guildId: currentMessage.guild?.id || null, + channelId: currentMessage.channel?.id || null, + scope: memoryScope, + }) + : AIDatabase.getFacts(currentMessage.channel?.id) + : []; const userFacts = memoryConfig.StoreFacts !== false && - typeof AIDatabase.getUserFacts === "function" - ? AIDatabase.getUserFacts( - currentMessage.guild?.id, - currentMessage.author?.id, - ) - : []; + typeof AIDatabase.getUserFactsByScope === "function" + ? AIDatabase.getUserFactsByScope({ + guildId: currentMessage.guild?.id || null, + userId: currentMessage.author?.id || null, + scope: memoryScope, + }) + : memoryConfig.StoreFacts !== false && + typeof AIDatabase.getUserFacts === "function" + ? AIDatabase.getUserFacts( + currentMessage.guild?.id, + currentMessage.author?.id, + ) + : []; if (latestSummary?.summary) { conversation.push({ role: "system", - content: `Conversation summary:\n${latestSummary.summary}`, + content: `Shared memory summary (${memoryScope} scope):\n${latestSummary.summary}`, }); } @@ -165,7 +195,7 @@ function buildConversationFromMemory(channelId, currentMessage) { conversation.push({ role: "system", - content: `Known facts in this chat:\n${factText}`, + content: `Known shared facts (${memoryScope} scope):\n${factText}`, }); } @@ -422,10 +452,7 @@ module.exports = new Event("messageCreate", async (client, message) => { const ticket = getTicketContextForMessage(message); - const conversation = buildConversationFromMemory( - message.channel.id, - message, - ); + const conversation = buildConversationFromMemory(message); if (ticket) { conversation.push({ @@ -532,4 +559,4 @@ module.exports = new Event("messageCreate", async (client, message) => { message.reply({ embeds: [embed] }).catch(() => {}); } -}); +}); \ No newline at end of file diff --git a/Structures/AIDatabase.js b/Structures/AIDatabase.js index 077c861..9d3dc0a 100644 --- a/Structures/AIDatabase.js +++ b/Structures/AIDatabase.js @@ -85,7 +85,6 @@ try { } module.exports = { - saveUserFact({ guildId, userId, factType, factKey, factValue }) { const existing = db .prepare( @@ -138,6 +137,32 @@ module.exports = { .all(guildId || null, userId || null); }, + getUserFactsByScope({ guildId = null, userId = null, scope = "guild" }) { + if (!userId) return []; + + if (scope === "global") { + return db + .prepare( + ` + SELECT * FROM ai_facts + WHERE user_id IS ? + ORDER BY updated_at DESC + `, + ) + .all(userId || null); + } + + return db + .prepare( + ` + SELECT * FROM ai_facts + WHERE guild_id IS ? AND user_id IS ? + ORDER BY updated_at DESC + `, + ) + .all(guildId || null, userId || null); + }, + addMessage({ guildId, channelId, userId, role, content }) { db.prepare( ` @@ -169,6 +194,47 @@ module.exports = { .reverse(); }, + getRecentMessagesByScope({ guildId = null, channelId = null, limit = 15, scope = "guild" }) { + if (scope === "channel") { + return db + .prepare( + ` + SELECT * FROM ai_conversations + WHERE channel_id = ? + ORDER BY created_at DESC + LIMIT ? + `, + ) + .all(channelId || null, limit) + .reverse(); + } + + if (scope === "global") { + return db + .prepare( + ` + SELECT * FROM ai_conversations + ORDER BY created_at DESC + LIMIT ? + `, + ) + .all(limit) + .reverse(); + } + + return db + .prepare( + ` + SELECT * FROM ai_conversations + WHERE guild_id IS ? + ORDER BY created_at DESC + LIMIT ? + `, + ) + .all(guildId || null, limit) + .reverse(); + }, + saveSummary({ guildId, channelId, summary }) { const existing = db .prepare( @@ -214,6 +280,44 @@ module.exports = { .get(channelId); }, + getLatestSummaryByScope({ guildId = null, channelId = null, scope = "guild" }) { + if (scope === "channel") { + return db + .prepare( + ` + SELECT * FROM ai_summaries + WHERE channel_id = ? + ORDER BY updated_at DESC + LIMIT 1 + `, + ) + .get(channelId || null); + } + + if (scope === "global") { + return db + .prepare( + ` + SELECT * FROM ai_summaries + ORDER BY updated_at DESC + LIMIT 1 + `, + ) + .get(); + } + + return db + .prepare( + ` + SELECT * FROM ai_summaries + WHERE guild_id IS ? + ORDER BY updated_at DESC + LIMIT 1 + `, + ) + .get(guildId || null); + }, + saveFact({ guildId, channelId, factType, factKey, factValue }) { const existing = db .prepare( @@ -265,6 +369,42 @@ module.exports = { .all(channelId); }, + getFactsByScope({ guildId = null, channelId = null, scope = "guild" }) { + if (scope === "channel") { + return db + .prepare( + ` + SELECT * FROM ai_facts + WHERE channel_id = ? AND user_id IS NULL + ORDER BY updated_at DESC + `, + ) + .all(channelId || null); + } + + if (scope === "global") { + return db + .prepare( + ` + SELECT * FROM ai_facts + WHERE user_id IS NULL + ORDER BY updated_at DESC + `, + ) + .all(); + } + + return db + .prepare( + ` + SELECT * FROM ai_facts + WHERE guild_id IS ? AND user_id IS NULL + ORDER BY updated_at DESC + `, + ) + .all(guildId || null); + }, + addKnowledge({ sourceType, sourceName, title, content }) { db.prepare( ` @@ -286,4 +426,4 @@ module.exports = { ) .all(limit); }, -}; +}; \ No newline at end of file