fix(chatbot): proper system role, tool catalog prompt, more rounds/history, tool failure observability

- Send system prompt as role:system instead of merging into the user message
  (models treat system messages as authoritative -> better tool selection)
- Add full 14-tool catalog + multi-hop instruction to the system prompt
- Raise MAX_TOOL_ROUNDS 4->6 so multi-hop queries complete
- Raise conversation history 3->8 exchanges (less repeat questioning)
- Append guild/channel scope hint to each user turn
- Add saturating toolErrors counter + structured warn log per tool failure
  so chatbot tool failures are observable instead of silently absorbed
This commit is contained in:
asepharyana authored and asepharyana committed 2026-09-04 13:36:51 +07:00
1 parent c5219ee866
commit 9682abef82
2 files changed
+60 -25

No files matched your search

@@ -1,4 +1,5 @@
import { and, desc, eq, like, sql } from "drizzle-orm";
import { createChildLogger } from "@/shared/logger/index";
import { getDatabase } from "../../shared/database/index.js";
import {
pgChannelCulturesTable,
@@ -19,6 +20,20 @@ import {
*/
export type ToolResult = string;
const logger = createChildLogger("chatbot.tools");
/** Saturating counter of chatbot tool execution errors (for observability). */
export let toolErrors = 0;
const TOOL_ERROR_CAP = 1000;
function toolExecError(err: unknown, name: string): string {
if (toolErrors < TOOL_ERROR_CAP) toolErrors++;
const detail = (err as Error)?.message ?? "unknown";
logger.warn({ tool: name, error: detail }, "Chatbot tool execution failed");
return `Tool ${name} gagal: ${detail}`;
}
/** Executes a tool call against the real DB and returns a readable result. */
export async function executeTool(
name: string,
@@ -90,7 +105,7 @@ export async function executeTool(
}
} catch (error) {
// Best-effort: if a tool fails, return readable error instead of crashing
return `Terjadi kesalahan saat ambil data: ${(error as Error).message ?? "unknown"}`;
return toolExecError(error, name);
}
}