UNPKG

agent-contracts-runtime

Version:

Runtime bridge for executing agent-contracts workflows on Agent SDKs

321 lines (319 loc) 9.85 kB
// src/lib/plugin.ts var PluginRegistry = class { plugins = []; register(plugin) { if (this.plugins.some((p) => p.id === plugin.id)) { throw new Error(`Plugin "${plugin.id}" is already registered`); } this.plugins.push(plugin); } getAll() { return this.plugins; } async runBeforeTask(taskId, context) { let ctx = context; for (const plugin of this.plugins) { if (!plugin.beforeTask || ctx === null) continue; ctx = await plugin.beforeTask(taskId, ctx); } return ctx; } async runAfterTask(taskId, outcome) { let result = outcome; for (const plugin of this.plugins) { if (!plugin.afterTask) continue; result = await plugin.afterTask(taskId, result); } return result; } applyContextEnhancers(taskId, context) { let ctx = context; for (const plugin of this.plugins) { if (!plugin.contextEnhancer) continue; ctx = plugin.contextEnhancer(taskId, ctx); } return ctx; } /** * Try plugin promptBuilder hooks. Returns custom prompt if any plugin provides one, * or null to use the default buildTaskPrompt. */ applyPromptBuilder(args) { for (const plugin of this.plugins) { if (!plugin.promptBuilder) continue; const result = plugin.promptBuilder(args); if (result !== null) return result; } return null; } applyPromptEnhancers(taskId, prompt, context) { let enhanced = prompt; for (const plugin of this.plugins) { if (!plugin.promptEnhancer) continue; enhanced = plugin.promptEnhancer(taskId, enhanced, context); } return enhanced; } evaluateCommandGuardrails(command) { const results = []; for (const plugin of this.plugins) { if (!plugin.customGuardrails?.evaluateCommand) continue; results.push(...plugin.customGuardrails.evaluateCommand(command)); } return results; } evaluateFilePathGuardrails(filePath) { const results = []; for (const plugin of this.plugins) { if (!plugin.customGuardrails?.evaluateFilePath) continue; results.push(...plugin.customGuardrails.evaluateFilePath(filePath)); } return results; } evaluateFileContentGuardrails(filePath, content) { const results = []; for (const plugin of this.plugins) { if (!plugin.customGuardrails?.evaluateFileContent) continue; results.push(...plugin.customGuardrails.evaluateFileContent(filePath, content)); } return results; } async runBeforeWorkflow(workflowId, userRequest) { for (const plugin of this.plugins) { if (!plugin.beforeWorkflow) continue; await plugin.beforeWorkflow(workflowId, userRequest); } } async runAfterWorkflow(workflowId, result) { for (const plugin of this.plugins) { if (!plugin.afterWorkflow) continue; await plugin.afterWorkflow(workflowId, result); } } }; var pluginRegistry = new PluginRegistry(); // src/lib/guardrail-hooks.ts function globFragmentToRegex(fragment) { let out = ""; for (const ch of fragment) { if (ch === "*") out += "[^/]*"; else if (ch === "?") out += "[^/]"; else if (".+^$|()[]\\".includes(ch)) out += "\\" + ch; else out += ch; } return out; } function matchGlob(pattern, path) { let regex = ""; let i = 0; while (i < pattern.length) { if (pattern[i] === "*" && pattern[i + 1] === "*" && pattern[i + 2] === "/") { regex += "(?:.+/)?"; i += 3; } else if (pattern[i] === "*" && pattern[i + 1] === "*") { regex += ".*"; i += 2; } else if (pattern[i] === "*") { regex += "[^/]*"; i += 1; } else if (pattern[i] === "?") { regex += "[^/]"; i += 1; } else if (pattern[i] === "{") { const end = pattern.indexOf("}", i); if (end !== -1) { const alts = pattern.slice(i + 1, end).split(",").map(globFragmentToRegex); regex += "(?:" + alts.join("|") + ")"; i = end + 1; } else { regex += "\\{"; i += 1; } } else if (".+^$|()[]\\".includes(pattern[i])) { regex += "\\" + pattern[i]; i += 1; } else { regex += pattern[i]; i += 1; } } return new RegExp("^" + regex + "$").test(path); } function getBlockingViolations(results) { return results.filter((r) => !r.passed && r.action === "block"); } function getWarnings(results) { return results.filter((r) => !r.passed && r.action === "warn"); } function hasBlockingViolation(results) { return results.some((r) => !r.passed && r.action === "block"); } function pluginResultToCheckResult(r) { return { guardrail_id: r.guardrail_id, passed: !r.matched, action: r.action, message: r.matched ? r.message : "" }; } function createGuardrailHooks(checks) { function runChecks(ctx) { const results = []; if (ctx.command) { results.push(...checks.checkCommand(ctx.command)); results.push( ...pluginRegistry.evaluateCommandGuardrails(ctx.command).map(pluginResultToCheckResult) ); } if (ctx.filePath) { results.push(...checks.checkFilePath(ctx.filePath)); results.push( ...pluginRegistry.evaluateFilePathGuardrails(ctx.filePath).map(pluginResultToCheckResult) ); } if (ctx.filePath && ctx.content) { results.push(...checks.checkContent(ctx.filePath, ctx.content)); results.push( ...pluginRegistry.evaluateFileContentGuardrails(ctx.filePath, ctx.content).map(pluginResultToCheckResult) ); } return results; } function beforeShellExecution(input) { const command = input.command ?? ""; if (!command) return {}; const results = runChecks({ command }); const blocks = getBlockingViolations(results); const warns = getWarnings(results); if (blocks.length > 0) { const msg = blocks.map((r) => `[${r.guardrail_id}] ${r.message}`).join("\n"); return { permission: "deny", user_message: msg, agent_message: msg }; } if (warns.length > 0) { return { additionalContext: warns.map((r) => `[${r.guardrail_id}] ${r.message}`).join("\n") }; } return {}; } function preToolUse(input) { const filePath = input.tool_input?.file_path ?? input.tool_input?.path ?? ""; if (!filePath) return {}; const results = runChecks({ filePath }); const blocks = getBlockingViolations(results); if (blocks.length > 0) { const msg = blocks.map((r) => `[${r.guardrail_id}] ${r.message}`).join("\n"); return { permission: "deny", user_message: msg, agent_message: msg }; } return {}; } function afterFileEdit(input) { const filePath = input.file_path ?? ""; const content = input.content ?? ""; if (!filePath) return {}; const results = runChecks({ filePath, content }); const blocks = getBlockingViolations(results); if (blocks.length > 0) { const msg = blocks.map((r) => `[${r.guardrail_id}] ${r.message}`).join("\n"); return { permission: "deny", user_message: msg, agent_message: msg }; } return {}; } return { beforeShellExecution, preToolUse, afterFileEdit, runChecks }; } function createGuardrailHooksForAgent(agentId, perAgent) { const rules = perAgent.get(agentId); if (!rules) { return createGuardrailHooks({ checkCommand: () => [], checkFilePath: () => [], checkContent: () => [] }); } const hooks = createGuardrailHooksFromRules(rules); const baseRunChecks = hooks.runChecks; return { ...hooks, runChecks(ctx) { return baseRunChecks({ ...ctx, agentId }); } }; } function createGuardrailHooksFromRules(rules) { const commandChecks = rules.commandRules.map((rule) => ({ guardrail_id: rule.guardrail_id, pattern: new RegExp(rule.pattern), action: rule.action, message: rule.message })); const fileChecks = rules.fileRules; const contentChecks = rules.contentRules.map((rule) => ({ guardrail_id: rule.guardrail_id, pattern: new RegExp(rule.pattern), action: rule.action, message: rule.message, file_glob: rule.file_glob, exclude_glob: rule.exclude_glob })); return createGuardrailHooks({ checkCommand(command) { const results = []; for (const check of commandChecks) { const passed = !check.pattern.test(command); results.push({ guardrail_id: check.guardrail_id, passed, action: check.action, message: passed ? "" : check.message }); } return results; }, checkFilePath(filePath) { const results = []; for (const check of fileChecks) { if (check.exclude_glob && matchGlob(check.exclude_glob, filePath)) { continue; } const matched = matchGlob(check.pattern, filePath); results.push({ guardrail_id: check.guardrail_id, passed: !matched, action: check.action, message: matched ? check.message : "" }); } return results; }, checkContent(filePath, content) { const results = []; for (const check of contentChecks) { if (check.file_glob && !matchGlob(check.file_glob, filePath)) { continue; } if (check.exclude_glob && matchGlob(check.exclude_glob, filePath)) { continue; } const matched = check.pattern.test(content); results.push({ guardrail_id: check.guardrail_id, passed: !matched, action: check.action, message: matched ? check.message : "" }); } return results; } }); } export { PluginRegistry, pluginRegistry, getBlockingViolations, getWarnings, hasBlockingViolation, createGuardrailHooks, createGuardrailHooksForAgent, createGuardrailHooksFromRules }; //# sourceMappingURL=chunk-MGRZBGQL.js.map