UNPKG

@paroicms/site-generator-plugin

Version:

ParoiCMS Site Generator Plugin

98 lines (97 loc) 3.39 kB
import { type } from "arktype"; import { insertIssueEvent } from "../../db/db-write.queries.js"; import { invokeClaude } from "../lib/calling-llm-anthropic.js"; import { createPromptTemplate } from "../lib/create-prompt.js"; import { debugLlmOutput } from "../lib/debug-utils.js"; import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js"; const guardPrompt = await createPromptTemplate({ filename: "message-guard.md", }); const MessageGuardReportAT = type({ "language?": "string|undefined", valid: "boolean", "causes?": '("rude"|"malicious"|"outOfScope"|"technicalLimits"|"noSense")[]|undefined', "explanation?": "string|undefined", "+": "reject", }); export async function invokeMessageGuard(ctx, input, { skipOutOfScopeCheck = false } = {}) { const llmTaskName = "guard"; const llmInput = { message: input.prompt, }; const debug = await debugLlmOutput(ctx, llmTaskName, ctx.anthropicModelName, undefined, { message: llmInput.message, }); let llmOutput = debug.stored; if (!llmOutput) { const { messageContent, report } = await invokeClaude(ctx, { llmTaskName, prompt: guardPrompt(llmInput), maxTokens: 200, temperature: 0.2, systemInstruction: "beFast", }); llmOutput = await debug.getMessageContent(messageContent, report); } const rawReport = parseLlmResponseAsProperties(llmOutput.output, [ { tagName: "guard_json", key: "guard", format: "json", }, ]); const report = MessageGuardReportAT.assert(rawReport.guard); if (report.causes && skipOutOfScopeCheck) { report.causes = report.causes.filter((cause) => cause !== "outOfScope"); if (report.causes.length === 0) { report.valid = true; } } if (report.valid) return { detectedLanguage: report.language }; await insertIssueEvent(ctx, { eventType: "blockedByGuard", llmTaskName: "guard", issueMessage: report.explanation, }); return { success: false, language: report.language, userMessage: report.explanation ?? toUserMessage(report.causes, report.language), }; } function toUserMessage(causes, language) { if (!causes || causes.length === 0) return "Invalid message"; return causes.map((cause) => getCauseLabel(cause, language)).join(", "); } function getCauseLabel(cause, language) { if (language === "fr") { switch (cause) { case "rude": case "malicious": return "Nous ne pouvons pas répondre à cette demande"; case "outOfScope": return "Hors sujet"; case "technicalLimits": return "Limites techniques"; case "noSense": return "Nous ne comprenons pas la demande"; default: return cause; } } switch (cause) { case "rude": case "malicious": return "We cannot answer to this request"; case "outOfScope": return "Out of scope"; case "technicalLimits": return "Technical limits"; case "noSense": return "We do not understand the request"; default: return cause; } }