Files
PrismFacet/plugin/tools/prompt-rules.ts
zhi 6a70a68c7e fix: use parameters + content[] format per OpenClaw plugin spec
- inputSchema → parameters
- { result: text } → { content: [{ type: "text", text }] }

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 12:04:41 +00:00

101 lines
4.0 KiB
TypeScript

import { addRule, removeRule, listRules } from "../core/rule-store.js";
import { loadRouters, getRouterNames } from "../core/router-loader.js";
import { resolveInjection } from "../core/prompt-injector.js";
export function registerPromptRulesTool(
api: {
registerTool(def: any): void;
logger: { info(msg: string): void; warn(msg: string): void };
},
routersDir: string
): void {
api.registerTool({
name: "prompt_rules",
description:
"Manage PrismFacet prompt injection rules. " +
"Actions: add (register a rule mapping router:key to a prompt file), " +
"remove (delete a rule), list (show all rules), " +
"test (preview which prompts would be injected for an agent), " +
"reload-routers (hot-reload all router functions), " +
"list-routers (show loaded routers).",
parameters: {
type: "object",
properties: {
action: {
type: "string",
enum: ["add", "remove", "list", "test", "reload-routers", "list-routers"],
description: "The action to perform",
},
router: {
type: "string",
description: "Router name (for add/remove)",
},
key: {
type: "string",
description: "Rule key (for add/remove)",
},
file: {
type: "string",
description: "Absolute path to prompt file (for add)",
},
agent: {
type: "string",
description: "Agent ID to test (for test)",
},
},
required: ["action"],
},
execute: async (_toolCallId: string, params: Record<string, unknown>) => {
const action = params.action as string;
const router = params.router as string | undefined;
const key = params.key as string | undefined;
const file = params.file as string | undefined;
const agent = params.agent as string | undefined;
switch (action) {
case "add": {
if (!router || !key || !file) {
return { content: [{ type: "text", text: "Error: add requires router, key, and file" }] };
}
addRule(router, key, file);
return { content: [{ type: "text", text: `Rule added: ${router}:${key}${file}` }] };
}
case "remove": {
if (!router || !key) {
return { content: [{ type: "text", text: "Error: remove requires router and key" }] };
}
const removed = removeRule(router, key);
const msg = removed ? `Rule removed: ${router}:${key}` : `Rule not found: ${router}:${key}`;
return { content: [{ type: "text", text: msg }] };
}
case "list": {
const rules = listRules();
const entries = Object.entries(rules);
if (entries.length === 0) return { content: [{ type: "text", text: "No rules registered." }] };
return { content: [{ type: "text", text: entries.map(([k, v]) => `${k}${v}`).join("\n") }] };
}
case "test": {
if (!agent) return { content: [{ type: "text", text: "Error: test requires agent" }] };
const result = await resolveInjection({ agentId: agent }, api.logger);
if (!result.appendSystemContext) {
return { content: [{ type: "text", text: `No prompts matched for agent: ${agent}` }] };
}
return { content: [{ type: "text", text: `Matched prompts for ${agent}:\n\n${result.appendSystemContext}` }] };
}
case "reload-routers": {
await loadRouters(routersDir, api.logger);
const names = getRouterNames();
return { content: [{ type: "text", text: `Routers reloaded: ${names.join(", ") || "(none)"}` }] };
}
case "list-routers": {
const names = getRouterNames();
const msg = names.length > 0 ? `Loaded routers: ${names.join(", ")}` : "No routers loaded.";
return { content: [{ type: "text", text: msg }] };
}
default:
return { content: [{ type: "text", text: `Unknown action: ${action}` }] };
}
},
});
}