refactor(chatbot): drop static server-stats context, go fully tool-based
The chatbot already had an agentic tool loop (get_server_stats, get_top_channels, get_recent_activity, get_top_flagged), but processMessage still baked a serverInsights snapshot into the system prompt and told the model to "answer from that data". That defeats the tools: the model answered from a stale snapshot instead of living numbers, and the guild/channel scope the frontend sends was never forwarded to the tools. Changes (services/backend/src/modules/chatbot): - Remove getServerInsights() + ServerInsights (dead after this change). - buildSystemPrompt(): drop the hardcoded stats block; instruct the model it has NO memorized server numbers and MUST call a tool for any server-data question, answering only from tool results. - processMessage(): stop fetching insights; pass the request guildId/channelId scope through to callLLM. - callLLM(): accept scope; auto-fill empty guildId/channelId on tool calls from the request scope so the model never has to guess IDs and tools always query the right server. Behavior: answers now come from live DB data via tools, scoped to the server the user is chatting in. tsc + biome + 36 backend tests green. Co-Authored-By: Claude Opus 5 (Nous Research)
This commit is contained in:
co-authored by
Claude Opus 5 (Nous Research)
parent
a3e5a8c1b9
commit
30828a5534
@@ -31,13 +31,6 @@ export interface ChatbotHistoryRow {
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface ServerInsights {
|
||||
total_messages: number;
|
||||
active_users: number;
|
||||
flagged: number;
|
||||
warned: number;
|
||||
}
|
||||
|
||||
export class ChatbotRepository {
|
||||
async saveConversation(input: SaveConversationInput): Promise<void> {
|
||||
const db = getDatabase();
|
||||
@@ -83,56 +76,6 @@ export class ChatbotRepository {
|
||||
"Chat history cleared",
|
||||
);
|
||||
}
|
||||
|
||||
async getServerInsights(
|
||||
guildId?: string,
|
||||
channelId?: string,
|
||||
): Promise<ServerInsights> {
|
||||
try {
|
||||
const db = getDatabase();
|
||||
const conditions: SQL[] = [];
|
||||
|
||||
if (guildId) {
|
||||
conditions.push(eq(pgMessagesTable.guild_id, guildId));
|
||||
}
|
||||
if (channelId) {
|
||||
conditions.push(eq(pgMessagesTable.channel_id, channelId));
|
||||
}
|
||||
|
||||
const where = conditions.length > 0 ? and(...conditions) : undefined;
|
||||
|
||||
const [result] = await db
|
||||
.select({
|
||||
total_messages: sql<number>`COUNT(*)::int`,
|
||||
active_users: sql<number>`COUNT(DISTINCT ${pgMessagesTable.user_id})::int`,
|
||||
flagged: sql<number>`COUNT(*) FILTER (WHERE ${pgMessagesTable.ai_status} = 'flagged')::int`,
|
||||
warned: sql<number>`COUNT(*) FILTER (WHERE ${pgMessagesTable.ai_status} = 'warn')::int`,
|
||||
})
|
||||
.from(pgMessagesTable)
|
||||
.where(where);
|
||||
|
||||
const insights = result ?? {
|
||||
total_messages: 0,
|
||||
active_users: 0,
|
||||
flagged: 0,
|
||||
warned: 0,
|
||||
};
|
||||
|
||||
logger.debug({ guildId, channelId, insights }, "Server insights fetched");
|
||||
return insights;
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
{ error, guildId, channelId },
|
||||
"Failed to load server insights",
|
||||
);
|
||||
return {
|
||||
total_messages: 0,
|
||||
active_users: 0,
|
||||
flagged: 0,
|
||||
warned: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const chatbotRepository = new ChatbotRepository();
|
||||
|
||||
Reference in New Issue
Block a user