refactor: restructure PrismFacet per OpenClaw plugin spec
- plugin/ directory structure: hooks/, tools/, core/
- export default { id, name, register } entry format
- globalThis state management with lifecycle protection
- WeakSet dedup on before_prompt_build hook
- Tool uses inputSchema + execute (not parameters + handler)
- additionalProperties: false in config schema
- Core logic in plugin/core/ (no plugin-sdk dependency)
- Install/uninstall script (scripts/install.mjs)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
106
plugin/tools/prompt-rules.ts
Normal file
106
plugin/tools/prompt-rules.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
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).",
|
||||
inputSchema: {
|
||||
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 { result: "Error: add requires router, key, and file" };
|
||||
}
|
||||
addRule(router, key, file);
|
||||
return { result: `Rule added: ${router}:${key} → ${file}` };
|
||||
}
|
||||
case "remove": {
|
||||
if (!router || !key) {
|
||||
return { result: "Error: remove requires router and key" };
|
||||
}
|
||||
const removed = removeRule(router, key);
|
||||
return {
|
||||
result: removed
|
||||
? `Rule removed: ${router}:${key}`
|
||||
: `Rule not found: ${router}:${key}`,
|
||||
};
|
||||
}
|
||||
case "list": {
|
||||
const rules = listRules();
|
||||
const entries = Object.entries(rules);
|
||||
if (entries.length === 0) return { result: "No rules registered." };
|
||||
return { result: entries.map(([k, v]) => `${k} → ${v}`).join("\n") };
|
||||
}
|
||||
case "test": {
|
||||
if (!agent) return { result: "Error: test requires agent" };
|
||||
const result = await resolveInjection({ agentId: agent }, api.logger);
|
||||
if (!result.appendSystemContext) {
|
||||
return { result: `No prompts matched for agent: ${agent}` };
|
||||
}
|
||||
return { result: `Matched prompts for ${agent}:\n\n${result.appendSystemContext}` };
|
||||
}
|
||||
case "reload-routers": {
|
||||
await loadRouters(routersDir, api.logger);
|
||||
const names = getRouterNames();
|
||||
return { result: `Routers reloaded: ${names.join(", ") || "(none)"}` };
|
||||
}
|
||||
case "list-routers": {
|
||||
const names = getRouterNames();
|
||||
return {
|
||||
result: names.length > 0
|
||||
? `Loaded routers: ${names.join(", ")}`
|
||||
: "No routers loaded.",
|
||||
};
|
||||
}
|
||||
default:
|
||||
return { result: `Unknown action: ${action}` };
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user