@neuroverseos/governance 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.well-known/ai-plugin.json +26 -0
- package/.well-known/mcp.json +68 -0
- package/AGENTS.md +219 -0
- package/README.md +84 -4
- package/dist/adapters/autoresearch.cjs +196 -0
- package/dist/adapters/autoresearch.d.cts +103 -0
- package/dist/adapters/autoresearch.d.ts +103 -0
- package/dist/adapters/autoresearch.js +7 -0
- package/dist/adapters/deep-agents.cjs +1472 -0
- package/dist/adapters/deep-agents.d.cts +181 -0
- package/dist/adapters/deep-agents.d.ts +181 -0
- package/dist/adapters/deep-agents.js +17 -0
- package/dist/adapters/express.cjs +103 -21
- package/dist/adapters/express.d.cts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +3 -3
- package/dist/adapters/index.cjs +649 -109
- package/dist/adapters/index.d.cts +4 -1
- package/dist/adapters/index.d.ts +4 -1
- package/dist/adapters/index.js +39 -13
- package/dist/adapters/langchain.cjs +152 -48
- package/dist/adapters/langchain.d.cts +5 -5
- package/dist/adapters/langchain.d.ts +5 -5
- package/dist/adapters/langchain.js +4 -3
- package/dist/adapters/openai.cjs +154 -50
- package/dist/adapters/openai.d.cts +5 -5
- package/dist/adapters/openai.d.ts +5 -5
- package/dist/adapters/openai.js +4 -3
- package/dist/adapters/openclaw.cjs +152 -48
- package/dist/adapters/openclaw.d.cts +5 -5
- package/dist/adapters/openclaw.d.ts +5 -5
- package/dist/adapters/openclaw.js +4 -3
- package/dist/{build-P42YFKQV.js → build-X5MZY4IA.js} +2 -2
- package/dist/{chunk-2NICNKOM.js → chunk-4L6OPKMQ.js} +1 -1
- package/dist/chunk-5U2MQO5P.js +57 -0
- package/dist/{chunk-SKU3GAPD.js → chunk-6BB55YJI.js} +16 -34
- package/dist/{chunk-KEST3MWO.js → chunk-AF2VX4AL.js} +47 -8
- package/dist/chunk-BQZMOEML.js +43 -0
- package/dist/chunk-D2UCV5AK.js +326 -0
- package/dist/{chunk-RWXVAH6P.js → chunk-EVDJUSZ2.js} +16 -34
- package/dist/{chunk-4JRYGIO7.js → chunk-IZSO75NZ.js} +72 -7
- package/dist/chunk-JCKSW2PZ.js +304 -0
- package/dist/{chunk-PDOZHZWL.js → chunk-KTFTTLTP.js} +25 -4
- package/dist/{chunk-MWDQ4MJB.js → chunk-MH7BT4VH.js} +5 -1
- package/dist/{chunk-4QXB6PEO.js → chunk-QLPTHTVB.js} +37 -16
- package/dist/{chunk-QPASI2BR.js → chunk-REXY4LUL.js} +49 -10
- package/dist/chunk-T5EUJQE5.js +172 -0
- package/dist/{chunk-DPVS43ZT.js → chunk-TTBKTF3P.js} +5 -5
- package/dist/{chunk-OHAC6HJE.js → chunk-ZIVQNSZU.js} +16 -36
- package/dist/{chunk-BUWWN2NX.js → chunk-ZJTDUCC2.js} +9 -7
- package/dist/cli/neuroverse.cjs +2582 -493
- package/dist/cli/neuroverse.js +39 -15
- package/dist/cli/plan.cjs +119 -32
- package/dist/cli/plan.js +5 -13
- package/dist/cli/run.cjs +223 -24
- package/dist/cli/run.js +2 -2
- package/dist/decision-flow-LETV5NWY.js +61 -0
- package/dist/{derive-TLIV4OOU.js → derive-7365SUFU.js} +2 -2
- package/dist/{doctor-QV6HELS5.js → doctor-QYISMKEL.js} +5 -2
- package/dist/equity-penalties-63FGB3I2.js +244 -0
- package/dist/{explain-IDCRWMPX.js → explain-A2EWI2OL.js} +4 -23
- package/dist/{guard-GFLQZY6U.js → guard-3BWL3IGH.js} +6 -10
- package/dist/{guard-contract-Cm91Kp4j.d.ts → guard-contract-C9_zKbzd.d.cts} +117 -5
- package/dist/{guard-contract-Cm91Kp4j.d.cts → guard-contract-C9_zKbzd.d.ts} +117 -5
- package/dist/{guard-engine-JLTUARGU.js → guard-engine-QFMIBWJY.js} +2 -2
- package/dist/{impact-XPECYRLH.js → impact-UB6DXKSX.js} +4 -4
- package/dist/{improve-GPUBKTEA.js → improve-XZA57GER.js} +5 -24
- package/dist/index.cjs +592 -44
- package/dist/index.d.cts +218 -5
- package/dist/index.d.ts +218 -5
- package/dist/index.js +92 -41
- package/dist/infer-world-7GVZWFX4.js +543 -0
- package/dist/init-world-VWMQZQC7.js +223 -0
- package/dist/{mcp-server-LZVJHBT5.js → mcp-server-XWQZXNW7.js} +3 -3
- package/dist/{playground-FGOMASHN.js → playground-ADWZORNV.js} +2 -2
- package/dist/{redteam-SK7AMIG3.js → redteam-JRQ7FD2F.js} +2 -2
- package/dist/{session-VISISNWJ.js → session-MMYX5YCF.js} +4 -3
- package/dist/shared--Q8wPBVN.d.ts +60 -0
- package/dist/shared-HpAG90PX.d.cts +60 -0
- package/dist/shared-U2QFV7JH.js +16 -0
- package/dist/{simulate-VDOYQFRO.js → simulate-GMIFFXYV.js} +5 -30
- package/dist/{test-75AVHC3R.js → test-JBBZ65X4.js} +2 -2
- package/dist/{trace-JVF67VR3.js → trace-3MYWIDEF.js} +3 -3
- package/dist/worlds/autoresearch.nv-world.md +230 -0
- package/dist/worlds/coding-agent.nv-world.md +211 -0
- package/llms.txt +79 -0
- package/openapi.yaml +230 -0
- package/package.json +26 -4
- package/dist/{chunk-GR6DGCZ2.js → chunk-BMOXICAB.js} +3 -3
- package/dist/{chunk-NF5POFCI.js → chunk-ORJ3NOE6.js} +3 -3
- package/dist/{world-LAXO6DOX.js → world-BFJCIQSH.js} +3 -3
package/dist/adapters/index.cjs
CHANGED
|
@@ -30,12 +30,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/adapters/index.ts
|
|
31
31
|
var adapters_exports = {};
|
|
32
32
|
__export(adapters_exports, {
|
|
33
|
+
AutoresearchGovernor: () => AutoresearchGovernor,
|
|
34
|
+
DeepAgentsGovernanceBlockedError: () => GovernanceBlockedError5,
|
|
35
|
+
DeepAgentsGuard: () => DeepAgentsGuard,
|
|
36
|
+
GovernanceBlockedError: () => GovernanceBlockedError,
|
|
33
37
|
GovernedToolExecutor: () => GovernedToolExecutor,
|
|
34
|
-
LangChainGovernanceBlockedError: () =>
|
|
38
|
+
LangChainGovernanceBlockedError: () => GovernanceBlockedError2,
|
|
35
39
|
NeuroVerseCallbackHandler: () => NeuroVerseCallbackHandler,
|
|
36
40
|
NeuroVersePlugin: () => NeuroVersePlugin,
|
|
37
|
-
OpenAIGovernanceBlockedError: () =>
|
|
38
|
-
OpenClawGovernanceBlockedError: () =>
|
|
41
|
+
OpenAIGovernanceBlockedError: () => GovernanceBlockedError3,
|
|
42
|
+
OpenClawGovernanceBlockedError: () => GovernanceBlockedError4,
|
|
43
|
+
buildEngineOptions: () => buildEngineOptions,
|
|
44
|
+
createDeepAgentsGuard: () => createDeepAgentsGuard,
|
|
45
|
+
createDeepAgentsGuardFromWorld: () => createDeepAgentsGuardFromWorld,
|
|
39
46
|
createGovernanceMiddleware: () => createGovernanceMiddleware,
|
|
40
47
|
createGovernanceMiddlewareFromWorld: () => createGovernanceMiddlewareFromWorld,
|
|
41
48
|
createGovernedToolExecutor: () => createGovernedToolExecutor,
|
|
@@ -43,21 +50,34 @@ __export(adapters_exports, {
|
|
|
43
50
|
createNeuroVerseCallbackHandler: () => createNeuroVerseCallbackHandler,
|
|
44
51
|
createNeuroVerseCallbackHandlerFromWorld: () => createNeuroVerseCallbackHandlerFromWorld,
|
|
45
52
|
createNeuroVersePlugin: () => createNeuroVersePlugin,
|
|
46
|
-
createNeuroVersePluginFromWorld: () => createNeuroVersePluginFromWorld
|
|
53
|
+
createNeuroVersePluginFromWorld: () => createNeuroVersePluginFromWorld,
|
|
54
|
+
defaultBlockMessage: () => defaultBlockMessage,
|
|
55
|
+
extractScope: () => extractScope,
|
|
56
|
+
trackPlanProgress: () => trackPlanProgress
|
|
47
57
|
});
|
|
48
58
|
module.exports = __toCommonJS(adapters_exports);
|
|
49
59
|
|
|
50
|
-
// src/engine/
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
// src/engine/text-utils.ts
|
|
61
|
+
function normalizeEventText(event) {
|
|
62
|
+
return [
|
|
63
|
+
event.intent,
|
|
64
|
+
event.tool ?? "",
|
|
65
|
+
event.scope ?? ""
|
|
56
66
|
].join(" ").toLowerCase();
|
|
57
|
-
|
|
67
|
+
}
|
|
68
|
+
function extractKeywords(text, minLength = 3) {
|
|
69
|
+
return text.toLowerCase().split(/\s+/).filter((w) => w.length > minLength);
|
|
70
|
+
}
|
|
71
|
+
function matchesAllKeywords(eventText, ruleText) {
|
|
72
|
+
const keywords = extractKeywords(ruleText);
|
|
73
|
+
if (keywords.length === 0) return false;
|
|
74
|
+
return keywords.every((kw) => eventText.includes(kw));
|
|
75
|
+
}
|
|
76
|
+
function matchesKeywordThreshold(eventText, ruleText, threshold = 0.5) {
|
|
77
|
+
const keywords = extractKeywords(ruleText);
|
|
58
78
|
if (keywords.length === 0) return false;
|
|
59
79
|
const matched = keywords.filter((kw) => eventText.includes(kw));
|
|
60
|
-
return matched.length >= Math.ceil(keywords.length *
|
|
80
|
+
return matched.length >= Math.ceil(keywords.length * threshold);
|
|
61
81
|
}
|
|
62
82
|
function tokenSimilarity(a, b) {
|
|
63
83
|
const tokensA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
|
|
@@ -70,6 +90,19 @@ function tokenSimilarity(a, b) {
|
|
|
70
90
|
const union = (/* @__PURE__ */ new Set([...tokensA, ...tokensB])).size;
|
|
71
91
|
return union > 0 ? intersection / union : 0;
|
|
72
92
|
}
|
|
93
|
+
|
|
94
|
+
// src/engine/plan-engine.ts
|
|
95
|
+
function keywordMatch(eventText, step) {
|
|
96
|
+
const stepText = [
|
|
97
|
+
step.label,
|
|
98
|
+
step.description ?? "",
|
|
99
|
+
...step.tags ?? []
|
|
100
|
+
].join(" ");
|
|
101
|
+
return matchesKeywordThreshold(eventText, stepText, 0.5);
|
|
102
|
+
}
|
|
103
|
+
function tokenSimilarity2(a, b) {
|
|
104
|
+
return tokenSimilarity(a, b);
|
|
105
|
+
}
|
|
73
106
|
function findMatchingStep(eventText, event, steps) {
|
|
74
107
|
const pendingOrActive = steps.filter((s) => s.status === "pending" || s.status === "active");
|
|
75
108
|
if (pendingOrActive.length === 0) {
|
|
@@ -88,7 +121,7 @@ function findMatchingStep(eventText, event, steps) {
|
|
|
88
121
|
let bestScore = 0;
|
|
89
122
|
for (const step of pendingOrActive) {
|
|
90
123
|
const stepText = [step.label, step.description ?? "", ...step.tags ?? []].join(" ");
|
|
91
|
-
const score =
|
|
124
|
+
const score = tokenSimilarity2(intentText, stepText);
|
|
92
125
|
if (score > bestScore) {
|
|
93
126
|
bestScore = score;
|
|
94
127
|
bestStep = step;
|
|
@@ -129,7 +162,7 @@ function checkConstraints(event, eventText, constraints) {
|
|
|
129
162
|
continue;
|
|
130
163
|
}
|
|
131
164
|
if (constraint.type === "scope" && constraint.trigger) {
|
|
132
|
-
const keywords = constraint.trigger
|
|
165
|
+
const keywords = extractKeywords(constraint.trigger);
|
|
133
166
|
const violated = keywords.length > 0 && keywords.every((kw) => eventText.includes(kw));
|
|
134
167
|
checks.push({
|
|
135
168
|
constraintId: constraint.id,
|
|
@@ -210,11 +243,7 @@ function evaluatePlan(event, plan) {
|
|
|
210
243
|
progress
|
|
211
244
|
};
|
|
212
245
|
}
|
|
213
|
-
const eventText =
|
|
214
|
-
event.intent,
|
|
215
|
-
event.tool ?? "",
|
|
216
|
-
event.scope ?? ""
|
|
217
|
-
].join(" ").toLowerCase();
|
|
246
|
+
const eventText = normalizeEventText(event);
|
|
218
247
|
const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
|
|
219
248
|
if (!matched) {
|
|
220
249
|
return {
|
|
@@ -255,7 +284,7 @@ function evaluatePlan(event, plan) {
|
|
|
255
284
|
};
|
|
256
285
|
}
|
|
257
286
|
function buildPlanCheck(event, plan, verdict) {
|
|
258
|
-
const eventText =
|
|
287
|
+
const eventText = normalizeEventText(event);
|
|
259
288
|
const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
|
|
260
289
|
const { checks: constraintChecks } = checkConstraints(event, eventText, plan.constraints);
|
|
261
290
|
const progress = getPlanProgress(plan);
|
|
@@ -273,6 +302,50 @@ function buildPlanCheck(event, plan, verdict) {
|
|
|
273
302
|
};
|
|
274
303
|
}
|
|
275
304
|
|
|
305
|
+
// src/adapters/shared.ts
|
|
306
|
+
var GovernanceBlockedError = class extends Error {
|
|
307
|
+
verdict;
|
|
308
|
+
constructor(verdict, message) {
|
|
309
|
+
super(message ?? `[NeuroVerse] BLOCKED: ${verdict.reason ?? verdict.ruleId ?? "governance rule"}`);
|
|
310
|
+
this.name = "GovernanceBlockedError";
|
|
311
|
+
this.verdict = verdict;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
function trackPlanProgress(event, state, callbacks) {
|
|
315
|
+
if (!state.activePlan) return;
|
|
316
|
+
const planVerdict = evaluatePlan(event, state.activePlan);
|
|
317
|
+
if (planVerdict.matchedStep) {
|
|
318
|
+
const advResult = advancePlan(state.activePlan, planVerdict.matchedStep);
|
|
319
|
+
if (advResult.success && advResult.plan) {
|
|
320
|
+
state.activePlan = advResult.plan;
|
|
321
|
+
state.engineOptions.plan = state.activePlan;
|
|
322
|
+
}
|
|
323
|
+
const progress = getPlanProgress(state.activePlan);
|
|
324
|
+
callbacks.onPlanProgress?.(progress);
|
|
325
|
+
if (progress.completed === progress.total) {
|
|
326
|
+
callbacks.onPlanComplete?.();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function extractScope(args) {
|
|
331
|
+
if (typeof args.path === "string") return args.path;
|
|
332
|
+
if (typeof args.file_path === "string") return args.file_path;
|
|
333
|
+
if (typeof args.filename === "string") return args.filename;
|
|
334
|
+
if (typeof args.url === "string") return args.url;
|
|
335
|
+
if (typeof args.command === "string") return args.command;
|
|
336
|
+
return void 0;
|
|
337
|
+
}
|
|
338
|
+
function buildEngineOptions(options, plan) {
|
|
339
|
+
return {
|
|
340
|
+
trace: options.trace ?? false,
|
|
341
|
+
level: options.level,
|
|
342
|
+
plan: plan ?? options.plan
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function defaultBlockMessage(verdict) {
|
|
346
|
+
return `Action blocked by governance policy: ${verdict.reason ?? "rule violation"}. Rule: ${verdict.ruleId ?? "unknown"}.`;
|
|
347
|
+
}
|
|
348
|
+
|
|
276
349
|
// src/engine/guard-engine.ts
|
|
277
350
|
var PROMPT_INJECTION_PATTERNS = [
|
|
278
351
|
// Instruction override
|
|
@@ -361,7 +434,7 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
361
434
|
const startTime = performance.now();
|
|
362
435
|
const level = options.level ?? "standard";
|
|
363
436
|
const includeTrace = options.trace ?? false;
|
|
364
|
-
const eventText = (event
|
|
437
|
+
const eventText = normalizeEventText(event);
|
|
365
438
|
const invariantChecks = [];
|
|
366
439
|
const safetyChecks = [];
|
|
367
440
|
let planCheckResult;
|
|
@@ -374,6 +447,43 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
374
447
|
const guardsMatched = [];
|
|
375
448
|
const rulesMatched = [];
|
|
376
449
|
checkInvariantCoverage(world, invariantChecks);
|
|
450
|
+
if (event.roleId && options.agentStates) {
|
|
451
|
+
const agentState = options.agentStates.get(event.roleId);
|
|
452
|
+
if (agentState && agentState.cooldownRemaining > 0) {
|
|
453
|
+
decidingLayer = "safety";
|
|
454
|
+
decidingId = `penalize-cooldown-${event.roleId}`;
|
|
455
|
+
const verdict = buildVerdict(
|
|
456
|
+
"PENALIZE",
|
|
457
|
+
`Agent "${event.roleId}" is frozen for ${agentState.cooldownRemaining} more round(s) due to prior penalty.`,
|
|
458
|
+
`penalize-cooldown-${event.roleId}`,
|
|
459
|
+
void 0,
|
|
460
|
+
world,
|
|
461
|
+
level,
|
|
462
|
+
invariantChecks,
|
|
463
|
+
guardsMatched,
|
|
464
|
+
rulesMatched,
|
|
465
|
+
includeTrace ? buildTrace(
|
|
466
|
+
invariantChecks,
|
|
467
|
+
safetyChecks,
|
|
468
|
+
planCheckResult,
|
|
469
|
+
roleChecks,
|
|
470
|
+
guardChecks,
|
|
471
|
+
kernelRuleChecks,
|
|
472
|
+
levelChecks,
|
|
473
|
+
decidingLayer,
|
|
474
|
+
decidingId,
|
|
475
|
+
startTime
|
|
476
|
+
) : void 0
|
|
477
|
+
);
|
|
478
|
+
verdict.intentRecord = {
|
|
479
|
+
originalIntent: event.intent,
|
|
480
|
+
finalAction: "blocked (agent frozen)",
|
|
481
|
+
enforcement: "PENALIZE",
|
|
482
|
+
consequence: { type: "freeze", rounds: agentState.cooldownRemaining, description: "Agent still in cooldown from prior penalty" }
|
|
483
|
+
};
|
|
484
|
+
return verdict;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
377
487
|
if (options.sessionAllowlist) {
|
|
378
488
|
const key = eventToAllowlistKey(event);
|
|
379
489
|
if (options.sessionAllowlist.has(key)) {
|
|
@@ -501,7 +611,16 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
501
611
|
if (guardVerdict.status !== "ALLOW") {
|
|
502
612
|
decidingLayer = "guard";
|
|
503
613
|
decidingId = guardVerdict.ruleId;
|
|
504
|
-
|
|
614
|
+
const intentRecord = {
|
|
615
|
+
originalIntent: event.intent,
|
|
616
|
+
finalAction: guardVerdict.status === "MODIFY" ? guardVerdict.modifiedTo ?? "modified" : guardVerdict.status === "PENALIZE" ? "blocked + penalized" : guardVerdict.status === "REWARD" ? event.intent : guardVerdict.status === "NEUTRAL" ? event.intent : guardVerdict.status === "BLOCK" ? "blocked" : "paused",
|
|
617
|
+
ruleApplied: guardVerdict.ruleId,
|
|
618
|
+
enforcement: guardVerdict.status,
|
|
619
|
+
modifiedTo: guardVerdict.modifiedTo,
|
|
620
|
+
consequence: guardVerdict.consequence,
|
|
621
|
+
reward: guardVerdict.reward
|
|
622
|
+
};
|
|
623
|
+
const verdict = buildVerdict(
|
|
505
624
|
guardVerdict.status,
|
|
506
625
|
guardVerdict.reason,
|
|
507
626
|
guardVerdict.ruleId,
|
|
@@ -524,6 +643,10 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
524
643
|
startTime
|
|
525
644
|
) : void 0
|
|
526
645
|
);
|
|
646
|
+
verdict.intentRecord = intentRecord;
|
|
647
|
+
if (guardVerdict.consequence) verdict.consequence = guardVerdict.consequence;
|
|
648
|
+
if (guardVerdict.reward) verdict.reward = guardVerdict.reward;
|
|
649
|
+
return verdict;
|
|
527
650
|
}
|
|
528
651
|
}
|
|
529
652
|
const kernelVerdict = checkKernelRules(eventText, world, kernelRuleChecks, rulesMatched);
|
|
@@ -818,6 +941,21 @@ function checkGuards(event, eventText, world, checks, guardsMatched) {
|
|
|
818
941
|
if (actionMode === "pause") {
|
|
819
942
|
return { status: "PAUSE", reason, ruleId: `guard-${guard.id}` };
|
|
820
943
|
}
|
|
944
|
+
if (actionMode === "penalize") {
|
|
945
|
+
const consequence = guard.consequence ? { ...guard.consequence } : { type: "freeze", rounds: 1, description: `Penalized for violating: ${guard.label}` };
|
|
946
|
+
return { status: "PENALIZE", reason, ruleId: `guard-${guard.id}`, consequence };
|
|
947
|
+
}
|
|
948
|
+
if (actionMode === "reward") {
|
|
949
|
+
const reward = guard.reward ? { ...guard.reward } : { type: "boost_influence", magnitude: 0.1, description: `Rewarded for: ${guard.label}` };
|
|
950
|
+
return { status: "REWARD", reason, ruleId: `guard-${guard.id}`, reward };
|
|
951
|
+
}
|
|
952
|
+
if (actionMode === "modify") {
|
|
953
|
+
const modifiedTo = guard.modify_to ?? guard.redirect ?? "hold";
|
|
954
|
+
return { status: "MODIFY", reason: `${reason} \u2192 Modified to: ${modifiedTo}`, ruleId: `guard-${guard.id}`, modifiedTo };
|
|
955
|
+
}
|
|
956
|
+
if (actionMode === "neutral") {
|
|
957
|
+
return { status: "NEUTRAL", reason, ruleId: `guard-${guard.id}` };
|
|
958
|
+
}
|
|
821
959
|
if (actionMode === "warn" && !warnResult) {
|
|
822
960
|
warnResult = { status: "ALLOW", warning: reason, ruleId: `guard-${guard.id}` };
|
|
823
961
|
}
|
|
@@ -927,9 +1065,7 @@ function checkLevelConstraints(event, level, checks) {
|
|
|
927
1065
|
return null;
|
|
928
1066
|
}
|
|
929
1067
|
function matchesKeywords(eventText, ruleText) {
|
|
930
|
-
|
|
931
|
-
if (keywords.length === 0) return false;
|
|
932
|
-
return keywords.every((kw) => eventText.includes(kw));
|
|
1068
|
+
return matchesAllKeywords(eventText, ruleText);
|
|
933
1069
|
}
|
|
934
1070
|
function eventToAllowlistKey(event) {
|
|
935
1071
|
return `${(event.tool ?? "*").toLowerCase()}::${event.intent.toLowerCase().trim()}`;
|
|
@@ -1067,13 +1203,10 @@ async function loadWorld(worldPath) {
|
|
|
1067
1203
|
}
|
|
1068
1204
|
|
|
1069
1205
|
// src/adapters/langchain.ts
|
|
1070
|
-
var
|
|
1071
|
-
verdict;
|
|
1206
|
+
var GovernanceBlockedError2 = class extends GovernanceBlockedError {
|
|
1072
1207
|
event;
|
|
1073
1208
|
constructor(verdict, event) {
|
|
1074
|
-
super(
|
|
1075
|
-
this.name = "GovernanceBlockedError";
|
|
1076
|
-
this.verdict = verdict;
|
|
1209
|
+
super(verdict);
|
|
1077
1210
|
this.event = event;
|
|
1078
1211
|
}
|
|
1079
1212
|
};
|
|
@@ -1081,7 +1214,7 @@ function defaultMapToolCall(toolName, toolInput) {
|
|
|
1081
1214
|
return {
|
|
1082
1215
|
intent: toolName,
|
|
1083
1216
|
tool: toolName,
|
|
1084
|
-
scope:
|
|
1217
|
+
scope: extractScope(toolInput),
|
|
1085
1218
|
args: toolInput,
|
|
1086
1219
|
direction: "input"
|
|
1087
1220
|
};
|
|
@@ -1097,11 +1230,7 @@ var NeuroVerseCallbackHandler = class {
|
|
|
1097
1230
|
this.world = world;
|
|
1098
1231
|
this.options = options;
|
|
1099
1232
|
this.activePlan = options.plan;
|
|
1100
|
-
this.engineOptions =
|
|
1101
|
-
trace: options.trace ?? false,
|
|
1102
|
-
level: options.level,
|
|
1103
|
-
plan: this.activePlan
|
|
1104
|
-
};
|
|
1233
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1105
1234
|
this.mapToolCall = options.mapToolCall ?? defaultMapToolCall;
|
|
1106
1235
|
}
|
|
1107
1236
|
/**
|
|
@@ -1124,28 +1253,16 @@ var NeuroVerseCallbackHandler = class {
|
|
|
1124
1253
|
this.options.onEvaluate?.(verdict, event);
|
|
1125
1254
|
if (verdict.status === "BLOCK") {
|
|
1126
1255
|
this.options.onBlock?.(verdict, event);
|
|
1127
|
-
throw new
|
|
1256
|
+
throw new GovernanceBlockedError2(verdict, event);
|
|
1128
1257
|
}
|
|
1129
1258
|
if (verdict.status === "PAUSE") {
|
|
1130
1259
|
const approved = await this.options.onPause?.(verdict, event);
|
|
1131
1260
|
if (!approved) {
|
|
1132
|
-
throw new
|
|
1261
|
+
throw new GovernanceBlockedError2(verdict, event);
|
|
1133
1262
|
}
|
|
1134
1263
|
}
|
|
1135
|
-
if (verdict.status === "ALLOW"
|
|
1136
|
-
|
|
1137
|
-
if (planVerdict.matchedStep) {
|
|
1138
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1139
|
-
if (advResult.success && advResult.plan) {
|
|
1140
|
-
this.activePlan = advResult.plan;
|
|
1141
|
-
this.engineOptions.plan = this.activePlan;
|
|
1142
|
-
}
|
|
1143
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1144
|
-
this.options.onPlanProgress?.(progress);
|
|
1145
|
-
if (progress.completed === progress.total) {
|
|
1146
|
-
this.options.onPlanComplete?.();
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1264
|
+
if (verdict.status === "ALLOW") {
|
|
1265
|
+
trackPlanProgress(event, this, this.options);
|
|
1149
1266
|
}
|
|
1150
1267
|
}
|
|
1151
1268
|
};
|
|
@@ -1158,13 +1275,10 @@ function createNeuroVerseCallbackHandlerFromWorld(world, options) {
|
|
|
1158
1275
|
}
|
|
1159
1276
|
|
|
1160
1277
|
// src/adapters/openai.ts
|
|
1161
|
-
var
|
|
1162
|
-
verdict;
|
|
1278
|
+
var GovernanceBlockedError3 = class extends GovernanceBlockedError {
|
|
1163
1279
|
toolCallId;
|
|
1164
1280
|
constructor(verdict, toolCallId) {
|
|
1165
|
-
super(
|
|
1166
|
-
this.name = "GovernanceBlockedError";
|
|
1167
|
-
this.verdict = verdict;
|
|
1281
|
+
super(verdict);
|
|
1168
1282
|
this.toolCallId = toolCallId;
|
|
1169
1283
|
}
|
|
1170
1284
|
};
|
|
@@ -1172,14 +1286,11 @@ function defaultMapFunctionCall(name, args) {
|
|
|
1172
1286
|
return {
|
|
1173
1287
|
intent: name,
|
|
1174
1288
|
tool: name,
|
|
1175
|
-
scope:
|
|
1289
|
+
scope: extractScope(args),
|
|
1176
1290
|
args,
|
|
1177
1291
|
direction: "input"
|
|
1178
1292
|
};
|
|
1179
1293
|
}
|
|
1180
|
-
function defaultBlockMessage(verdict) {
|
|
1181
|
-
return `Action blocked by governance policy: ${verdict.reason ?? "rule violation"}. Rule: ${verdict.ruleId ?? "unknown"}.`;
|
|
1182
|
-
}
|
|
1183
1294
|
var GovernedToolExecutor = class {
|
|
1184
1295
|
world;
|
|
1185
1296
|
options;
|
|
@@ -1191,11 +1302,7 @@ var GovernedToolExecutor = class {
|
|
|
1191
1302
|
this.world = world;
|
|
1192
1303
|
this.options = options;
|
|
1193
1304
|
this.activePlan = options.plan;
|
|
1194
|
-
this.engineOptions =
|
|
1195
|
-
trace: options.trace ?? false,
|
|
1196
|
-
level: options.level,
|
|
1197
|
-
plan: this.activePlan
|
|
1198
|
-
};
|
|
1305
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1199
1306
|
this.mapFn = options.mapFunctionCall ?? defaultMapFunctionCall;
|
|
1200
1307
|
this.blockMsg = options.blockMessage ?? defaultBlockMessage;
|
|
1201
1308
|
}
|
|
@@ -1214,20 +1321,8 @@ var GovernedToolExecutor = class {
|
|
|
1214
1321
|
this.engineOptions.plan = this.activePlan;
|
|
1215
1322
|
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
1216
1323
|
this.options.onEvaluate?.(verdict, event);
|
|
1217
|
-
if (verdict.status === "ALLOW"
|
|
1218
|
-
|
|
1219
|
-
if (planVerdict.matchedStep) {
|
|
1220
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1221
|
-
if (advResult.success && advResult.plan) {
|
|
1222
|
-
this.activePlan = advResult.plan;
|
|
1223
|
-
this.engineOptions.plan = this.activePlan;
|
|
1224
|
-
}
|
|
1225
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1226
|
-
this.options.onPlanProgress?.(progress);
|
|
1227
|
-
if (progress.completed === progress.total) {
|
|
1228
|
-
this.options.onPlanComplete?.();
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1324
|
+
if (verdict.status === "ALLOW") {
|
|
1325
|
+
trackPlanProgress(event, this, this.options);
|
|
1231
1326
|
}
|
|
1232
1327
|
return verdict;
|
|
1233
1328
|
}
|
|
@@ -1253,7 +1348,7 @@ var GovernedToolExecutor = class {
|
|
|
1253
1348
|
};
|
|
1254
1349
|
}
|
|
1255
1350
|
if (verdict.status === "PAUSE") {
|
|
1256
|
-
throw new
|
|
1351
|
+
throw new GovernanceBlockedError3(verdict, toolCall.id);
|
|
1257
1352
|
}
|
|
1258
1353
|
let args;
|
|
1259
1354
|
try {
|
|
@@ -1279,13 +1374,10 @@ function createGovernedToolExecutorFromWorld(world, options) {
|
|
|
1279
1374
|
}
|
|
1280
1375
|
|
|
1281
1376
|
// src/adapters/openclaw.ts
|
|
1282
|
-
var
|
|
1283
|
-
verdict;
|
|
1377
|
+
var GovernanceBlockedError4 = class extends GovernanceBlockedError {
|
|
1284
1378
|
action;
|
|
1285
1379
|
constructor(verdict, action) {
|
|
1286
|
-
super(
|
|
1287
|
-
this.name = "GovernanceBlockedError";
|
|
1288
|
-
this.verdict = verdict;
|
|
1380
|
+
super(verdict);
|
|
1289
1381
|
this.action = action;
|
|
1290
1382
|
}
|
|
1291
1383
|
};
|
|
@@ -1295,7 +1387,7 @@ function defaultMapAction(action, direction) {
|
|
|
1295
1387
|
tool: action.tool ?? action.type,
|
|
1296
1388
|
args: action.input,
|
|
1297
1389
|
direction,
|
|
1298
|
-
scope:
|
|
1390
|
+
scope: action.input ? extractScope(action.input) : void 0
|
|
1299
1391
|
};
|
|
1300
1392
|
}
|
|
1301
1393
|
var NeuroVersePlugin = class {
|
|
@@ -1309,11 +1401,7 @@ var NeuroVersePlugin = class {
|
|
|
1309
1401
|
this.world = world;
|
|
1310
1402
|
this.options = options;
|
|
1311
1403
|
this.activePlan = options.plan;
|
|
1312
|
-
this.engineOptions =
|
|
1313
|
-
trace: options.trace ?? false,
|
|
1314
|
-
level: options.level,
|
|
1315
|
-
plan: this.activePlan
|
|
1316
|
-
};
|
|
1404
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1317
1405
|
this.mapAction = options.mapAction ?? defaultMapAction;
|
|
1318
1406
|
}
|
|
1319
1407
|
/**
|
|
@@ -1333,22 +1421,10 @@ var NeuroVersePlugin = class {
|
|
|
1333
1421
|
};
|
|
1334
1422
|
this.options.onEvaluate?.(result);
|
|
1335
1423
|
if (verdict.status === "BLOCK") {
|
|
1336
|
-
throw new
|
|
1424
|
+
throw new GovernanceBlockedError4(verdict, action);
|
|
1337
1425
|
}
|
|
1338
|
-
if (verdict.status === "ALLOW"
|
|
1339
|
-
|
|
1340
|
-
if (planVerdict.matchedStep) {
|
|
1341
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1342
|
-
if (advResult.success && advResult.plan) {
|
|
1343
|
-
this.activePlan = advResult.plan;
|
|
1344
|
-
this.engineOptions.plan = this.activePlan;
|
|
1345
|
-
}
|
|
1346
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1347
|
-
this.options.onPlanProgress?.(progress);
|
|
1348
|
-
if (progress.completed === progress.total) {
|
|
1349
|
-
this.options.onPlanComplete?.();
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1426
|
+
if (verdict.status === "ALLOW") {
|
|
1427
|
+
trackPlanProgress(event, this, this.options);
|
|
1352
1428
|
}
|
|
1353
1429
|
return result;
|
|
1354
1430
|
}
|
|
@@ -1369,7 +1445,7 @@ var NeuroVersePlugin = class {
|
|
|
1369
1445
|
};
|
|
1370
1446
|
this.options.onEvaluate?.(result);
|
|
1371
1447
|
if (verdict.status === "BLOCK") {
|
|
1372
|
-
throw new
|
|
1448
|
+
throw new GovernanceBlockedError4(verdict, action);
|
|
1373
1449
|
}
|
|
1374
1450
|
return result;
|
|
1375
1451
|
}
|
|
@@ -1479,14 +1555,475 @@ function createGovernanceMiddlewareFromWorld(world, options = {}) {
|
|
|
1479
1555
|
}
|
|
1480
1556
|
};
|
|
1481
1557
|
}
|
|
1558
|
+
|
|
1559
|
+
// src/adapters/autoresearch.ts
|
|
1560
|
+
var AutoresearchGovernor = class {
|
|
1561
|
+
config;
|
|
1562
|
+
state;
|
|
1563
|
+
constructor(config) {
|
|
1564
|
+
this.config = config;
|
|
1565
|
+
this.state = {
|
|
1566
|
+
experiments_run: 0,
|
|
1567
|
+
best_result: null,
|
|
1568
|
+
architectures_tested: [],
|
|
1569
|
+
experiment_log: [],
|
|
1570
|
+
total_compute_minutes: 0,
|
|
1571
|
+
keep_count: 0
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Convert an experiment proposal into a GuardEvent for governance evaluation.
|
|
1576
|
+
*/
|
|
1577
|
+
proposalToGuardEvent(proposal) {
|
|
1578
|
+
return {
|
|
1579
|
+
intent: `run experiment: ${proposal.description}`,
|
|
1580
|
+
tool: "experiment_runner",
|
|
1581
|
+
scope: "experiment",
|
|
1582
|
+
roleId: "experiment_runner",
|
|
1583
|
+
direction: "output",
|
|
1584
|
+
actionCategory: "shell",
|
|
1585
|
+
args: {
|
|
1586
|
+
experiment_id: String(proposal.experiment_id),
|
|
1587
|
+
architecture: proposal.architecture,
|
|
1588
|
+
estimated_minutes: String(proposal.estimated_minutes || 5)
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Evaluate an experiment proposal against governance rules.
|
|
1594
|
+
* Returns a simplified verdict without requiring the full guard engine.
|
|
1595
|
+
*/
|
|
1596
|
+
evaluateProposal(proposal) {
|
|
1597
|
+
const warnings = [];
|
|
1598
|
+
const estimatedMinutes = proposal.estimated_minutes || 5;
|
|
1599
|
+
if (this.state.total_compute_minutes + estimatedMinutes > this.config.computeBudgetMinutes) {
|
|
1600
|
+
return {
|
|
1601
|
+
allowed: false,
|
|
1602
|
+
reason: `Compute budget exhausted: ${this.state.total_compute_minutes}/${this.config.computeBudgetMinutes} minutes used`,
|
|
1603
|
+
warnings
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
if (this.config.constraints) {
|
|
1607
|
+
for (const constraint of this.config.constraints) {
|
|
1608
|
+
const lower = constraint.toLowerCase();
|
|
1609
|
+
const archLower = proposal.architecture.toLowerCase();
|
|
1610
|
+
const descLower = proposal.description.toLowerCase();
|
|
1611
|
+
if (lower.startsWith("no ")) {
|
|
1612
|
+
const forbidden = lower.slice(3).trim();
|
|
1613
|
+
if (archLower.includes(forbidden) || descLower.includes(forbidden)) {
|
|
1614
|
+
return {
|
|
1615
|
+
allowed: false,
|
|
1616
|
+
reason: `Architecture constraint violated: ${constraint}`,
|
|
1617
|
+
warnings
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
const failureCount = this.state.experiment_log.filter((e) => !e.success).length;
|
|
1624
|
+
if (failureCount > 5) {
|
|
1625
|
+
warnings.push(`High failure rate: ${failureCount} failed experiments. Consider investigating root cause.`);
|
|
1626
|
+
}
|
|
1627
|
+
const recentArchitectures = this.state.experiment_log.slice(-5).map((e) => e.architecture);
|
|
1628
|
+
const uniqueRecent = new Set(recentArchitectures).size;
|
|
1629
|
+
if (recentArchitectures.length >= 5 && uniqueRecent === 1) {
|
|
1630
|
+
warnings.push("Research may be stuck: last 5 experiments used the same architecture.");
|
|
1631
|
+
}
|
|
1632
|
+
return { allowed: true, reason: "Experiment approved", warnings };
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Record an experiment result and update research state.
|
|
1636
|
+
*/
|
|
1637
|
+
recordResult(result) {
|
|
1638
|
+
this.state.experiments_run++;
|
|
1639
|
+
this.state.total_compute_minutes += result.wall_clock_minutes;
|
|
1640
|
+
this.state.experiment_log.push(result);
|
|
1641
|
+
if (!this.state.architectures_tested.includes(result.architecture)) {
|
|
1642
|
+
this.state.architectures_tested.push(result.architecture);
|
|
1643
|
+
}
|
|
1644
|
+
if (!result.success) {
|
|
1645
|
+
return { kept: false, improvement: null, state: { ...this.state } };
|
|
1646
|
+
}
|
|
1647
|
+
let kept = false;
|
|
1648
|
+
let improvement = null;
|
|
1649
|
+
if (this.state.best_result === null) {
|
|
1650
|
+
kept = true;
|
|
1651
|
+
this.state.best_result = result;
|
|
1652
|
+
this.state.keep_count++;
|
|
1653
|
+
} else {
|
|
1654
|
+
const prev = this.state.best_result.metric_value;
|
|
1655
|
+
const curr = result.metric_value;
|
|
1656
|
+
if (this.config.optimize === "minimize") {
|
|
1657
|
+
kept = curr < prev;
|
|
1658
|
+
improvement = kept ? prev - curr : null;
|
|
1659
|
+
} else {
|
|
1660
|
+
kept = curr > prev;
|
|
1661
|
+
improvement = kept ? curr - prev : null;
|
|
1662
|
+
}
|
|
1663
|
+
if (kept) {
|
|
1664
|
+
this.state.best_result = result;
|
|
1665
|
+
this.state.keep_count++;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
return { kept, improvement, state: { ...this.state } };
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Export current state as a state snapshot compatible with the world file.
|
|
1672
|
+
*/
|
|
1673
|
+
toWorldState() {
|
|
1674
|
+
const successfulExperiments = this.state.experiment_log.filter((e) => e.success);
|
|
1675
|
+
const failedCount = this.state.experiment_log.filter((e) => !e.success).length;
|
|
1676
|
+
const keepRate = this.state.experiments_run > 0 ? Math.round(this.state.keep_count / this.state.experiments_run * 100) : 0;
|
|
1677
|
+
let improvementRate = 0;
|
|
1678
|
+
if (successfulExperiments.length >= 2) {
|
|
1679
|
+
const recent = successfulExperiments.slice(-10);
|
|
1680
|
+
let improvements = 0;
|
|
1681
|
+
for (let i = 1; i < recent.length; i++) {
|
|
1682
|
+
const prev = recent[i - 1].metric_value;
|
|
1683
|
+
const curr = recent[i].metric_value;
|
|
1684
|
+
if (this.config.optimize === "minimize" ? curr < prev : curr > prev) {
|
|
1685
|
+
improvements++;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
improvementRate = Math.round(improvements / (recent.length - 1) * 100);
|
|
1689
|
+
}
|
|
1690
|
+
return {
|
|
1691
|
+
experiments_run: this.state.experiments_run,
|
|
1692
|
+
best_metric_value: this.state.best_result?.metric_value ?? (this.config.optimize === "minimize" ? 100 : -1e3),
|
|
1693
|
+
keep_rate: keepRate,
|
|
1694
|
+
compute_used_minutes: Math.round(this.state.total_compute_minutes),
|
|
1695
|
+
compute_budget_minutes: this.config.computeBudgetMinutes,
|
|
1696
|
+
failed_experiments: failedCount,
|
|
1697
|
+
metric_improvement_rate: improvementRate,
|
|
1698
|
+
research_context_drift: 0
|
|
1699
|
+
// would need NLP to compute properly
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Get a summary of the current research state.
|
|
1704
|
+
*/
|
|
1705
|
+
getSummary() {
|
|
1706
|
+
return {
|
|
1707
|
+
experiments_run: this.state.experiments_run,
|
|
1708
|
+
best_result: this.state.best_result,
|
|
1709
|
+
keep_rate: this.state.experiments_run > 0 ? Math.round(this.state.keep_count / this.state.experiments_run * 100) : 0,
|
|
1710
|
+
compute_remaining_minutes: this.config.computeBudgetMinutes - this.state.total_compute_minutes,
|
|
1711
|
+
architectures_tested: [...this.state.architectures_tested]
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Load state from a persisted research context file.
|
|
1716
|
+
*/
|
|
1717
|
+
loadState(state) {
|
|
1718
|
+
this.state = { ...state };
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Export state for persistence.
|
|
1722
|
+
*/
|
|
1723
|
+
exportState() {
|
|
1724
|
+
return { ...this.state };
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
// src/engine/tool-classifier.ts
|
|
1729
|
+
var TOOL_CATEGORY_MAP = {
|
|
1730
|
+
// File operations
|
|
1731
|
+
read_file: "file_read",
|
|
1732
|
+
read: "file_read",
|
|
1733
|
+
glob: "file_read",
|
|
1734
|
+
grep: "file_read",
|
|
1735
|
+
list_files: "file_read",
|
|
1736
|
+
write_file: "file_write",
|
|
1737
|
+
write: "file_write",
|
|
1738
|
+
create_file: "file_write",
|
|
1739
|
+
edit_file: "file_write",
|
|
1740
|
+
edit: "file_write",
|
|
1741
|
+
patch: "file_write",
|
|
1742
|
+
delete_file: "file_delete",
|
|
1743
|
+
remove_file: "file_delete",
|
|
1744
|
+
// Shell
|
|
1745
|
+
shell: "shell",
|
|
1746
|
+
bash: "shell",
|
|
1747
|
+
execute: "shell",
|
|
1748
|
+
run_command: "shell",
|
|
1749
|
+
terminal: "shell",
|
|
1750
|
+
// Git
|
|
1751
|
+
git: "git",
|
|
1752
|
+
git_commit: "git",
|
|
1753
|
+
git_push: "git",
|
|
1754
|
+
git_checkout: "git",
|
|
1755
|
+
// Network
|
|
1756
|
+
http: "network",
|
|
1757
|
+
fetch: "network",
|
|
1758
|
+
curl: "network",
|
|
1759
|
+
web_search: "network",
|
|
1760
|
+
// Sub-agents
|
|
1761
|
+
sub_agent: "sub_agent",
|
|
1762
|
+
spawn_agent: "sub_agent",
|
|
1763
|
+
delegate: "sub_agent",
|
|
1764
|
+
// Context management
|
|
1765
|
+
summarize: "context",
|
|
1766
|
+
compress_context: "context"
|
|
1767
|
+
};
|
|
1768
|
+
function classifyTool(toolName) {
|
|
1769
|
+
const normalized = toolName.toLowerCase().replace(/[-\s]/g, "_");
|
|
1770
|
+
return TOOL_CATEGORY_MAP[normalized] ?? "unknown";
|
|
1771
|
+
}
|
|
1772
|
+
var DANGEROUS_SHELL_PATTERNS = [
|
|
1773
|
+
{ pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*-rf\s+|.*--force)/, label: "force-delete" },
|
|
1774
|
+
{ pattern: /rm\s+-[a-zA-Z]*r/, label: "recursive-delete" },
|
|
1775
|
+
{ pattern: />\s*\/dev\/sd/, label: "disk-overwrite" },
|
|
1776
|
+
{ pattern: /mkfs\./, label: "format-disk" },
|
|
1777
|
+
{ pattern: /dd\s+if=/, label: "disk-dump" },
|
|
1778
|
+
{ pattern: /chmod\s+(-R\s+)?777/, label: "world-writable" },
|
|
1779
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
1780
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
1781
|
+
{ pattern: /:(){ :\|:& };:/, label: "fork-bomb" },
|
|
1782
|
+
{ pattern: />\s*\/etc\//, label: "system-config-overwrite" },
|
|
1783
|
+
{ pattern: /shutdown|reboot|halt|poweroff/, label: "system-shutdown" },
|
|
1784
|
+
{ pattern: /kill\s+-9\s+1\b/, label: "kill-init" }
|
|
1785
|
+
];
|
|
1786
|
+
var DANGEROUS_GIT_PATTERNS = [
|
|
1787
|
+
{ pattern: /push\s+.*--force/, label: "force-push" },
|
|
1788
|
+
{ pattern: /push\s+.*-f\b/, label: "force-push" },
|
|
1789
|
+
{ pattern: /push\s+(origin\s+)?main\b/, label: "push-main" },
|
|
1790
|
+
{ pattern: /push\s+(origin\s+)?master\b/, label: "push-master" },
|
|
1791
|
+
{ pattern: /reset\s+--hard/, label: "hard-reset" },
|
|
1792
|
+
{ pattern: /clean\s+-fd/, label: "clean-force" },
|
|
1793
|
+
{ pattern: /branch\s+-D/, label: "force-delete-branch" }
|
|
1794
|
+
];
|
|
1795
|
+
function isDangerousCommand(command) {
|
|
1796
|
+
const matched = DANGEROUS_SHELL_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
1797
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
1798
|
+
}
|
|
1799
|
+
function isDangerousGitCommand(command) {
|
|
1800
|
+
const matched = DANGEROUS_GIT_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
1801
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
1802
|
+
}
|
|
1803
|
+
function assessRiskLevel(category) {
|
|
1804
|
+
if (category === "file_read" || category === "context") return "low";
|
|
1805
|
+
if (category === "file_write" || category === "sub_agent") return "medium";
|
|
1806
|
+
if (category === "shell" || category === "file_delete" || category === "git" || category === "network") return "high";
|
|
1807
|
+
return void 0;
|
|
1808
|
+
}
|
|
1809
|
+
function categoryToActionCategory(category) {
|
|
1810
|
+
if (category === "file_read" || category === "context") return "read";
|
|
1811
|
+
if (category === "file_write") return "write";
|
|
1812
|
+
if (category === "file_delete") return "delete";
|
|
1813
|
+
if (category === "shell") return "shell";
|
|
1814
|
+
if (category === "network") return "network";
|
|
1815
|
+
return "other";
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// src/adapters/deep-agents.ts
|
|
1819
|
+
var GovernanceBlockedError5 = class extends GovernanceBlockedError {
|
|
1820
|
+
toolCall;
|
|
1821
|
+
category;
|
|
1822
|
+
constructor(verdict, toolCall, category) {
|
|
1823
|
+
super(verdict);
|
|
1824
|
+
this.toolCall = toolCall;
|
|
1825
|
+
this.category = category;
|
|
1826
|
+
}
|
|
1827
|
+
};
|
|
1828
|
+
function defaultMapToolCall2(toolCall) {
|
|
1829
|
+
const category = classifyTool(toolCall.tool);
|
|
1830
|
+
const args = toolCall.args;
|
|
1831
|
+
const scope = extractScope(args);
|
|
1832
|
+
let intent = toolCall.tool;
|
|
1833
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
1834
|
+
intent = `shell: ${args.command}`;
|
|
1835
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
1836
|
+
intent = `git ${args.command}`;
|
|
1837
|
+
} else if (category === "file_write" && scope) {
|
|
1838
|
+
intent = `write ${scope}`;
|
|
1839
|
+
} else if (category === "file_delete" && scope) {
|
|
1840
|
+
intent = `delete ${scope}`;
|
|
1841
|
+
}
|
|
1842
|
+
const riskLevel = assessRiskLevel(category);
|
|
1843
|
+
let irreversible = false;
|
|
1844
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
1845
|
+
irreversible = DANGEROUS_SHELL_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
1846
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
1847
|
+
irreversible = DANGEROUS_GIT_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
1848
|
+
} else if (category === "file_delete") {
|
|
1849
|
+
irreversible = true;
|
|
1850
|
+
}
|
|
1851
|
+
return {
|
|
1852
|
+
intent,
|
|
1853
|
+
tool: toolCall.tool,
|
|
1854
|
+
scope,
|
|
1855
|
+
args,
|
|
1856
|
+
direction: "input",
|
|
1857
|
+
actionCategory: categoryToActionCategory(category),
|
|
1858
|
+
riskLevel,
|
|
1859
|
+
irreversible
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
var DeepAgentsGuard = class {
|
|
1863
|
+
name = "neuroverse-deep-agents-guard";
|
|
1864
|
+
world;
|
|
1865
|
+
options;
|
|
1866
|
+
engineOptions;
|
|
1867
|
+
mapToolCall;
|
|
1868
|
+
activePlan;
|
|
1869
|
+
constructor(world, options = {}) {
|
|
1870
|
+
this.world = world;
|
|
1871
|
+
this.options = options;
|
|
1872
|
+
this.activePlan = options.plan;
|
|
1873
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1874
|
+
this.mapToolCall = options.mapToolCall ?? defaultMapToolCall2;
|
|
1875
|
+
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Evaluate a tool call against governance rules.
|
|
1878
|
+
* Returns the result without side effects.
|
|
1879
|
+
*/
|
|
1880
|
+
evaluate(toolCall) {
|
|
1881
|
+
const event = this.mapToolCall(toolCall);
|
|
1882
|
+
this.engineOptions.plan = this.activePlan;
|
|
1883
|
+
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
1884
|
+
const category = classifyTool(toolCall.tool);
|
|
1885
|
+
const result = {
|
|
1886
|
+
allowed: verdict.status === "ALLOW",
|
|
1887
|
+
verdict,
|
|
1888
|
+
toolCall,
|
|
1889
|
+
category
|
|
1890
|
+
};
|
|
1891
|
+
this.options.onEvaluate?.(result);
|
|
1892
|
+
if (verdict.status === "ALLOW" && this.activePlan) {
|
|
1893
|
+
this.trackPlanProgressInternal(event);
|
|
1894
|
+
}
|
|
1895
|
+
return result;
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Evaluate and enforce governance on a tool call.
|
|
1899
|
+
*
|
|
1900
|
+
* @throws GovernanceBlockedError if BLOCKED
|
|
1901
|
+
* @throws GovernanceBlockedError if PAUSED and onPause returns false
|
|
1902
|
+
* @returns DeepAgentsGuardResult on ALLOW
|
|
1903
|
+
*/
|
|
1904
|
+
async enforce(toolCall) {
|
|
1905
|
+
const result = this.evaluate(toolCall);
|
|
1906
|
+
if (result.verdict.status === "BLOCK") {
|
|
1907
|
+
this.options.onBlock?.(result);
|
|
1908
|
+
throw new GovernanceBlockedError5(result.verdict, toolCall, result.category);
|
|
1909
|
+
}
|
|
1910
|
+
if (result.verdict.status === "PAUSE") {
|
|
1911
|
+
const approved = await this.options.onPause?.(result);
|
|
1912
|
+
if (!approved) {
|
|
1913
|
+
throw new GovernanceBlockedError5(result.verdict, toolCall, result.category);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
return result;
|
|
1917
|
+
}
|
|
1918
|
+
/**
|
|
1919
|
+
* Evaluate and execute a tool call with governance enforcement.
|
|
1920
|
+
*
|
|
1921
|
+
* If ALLOW: runs the executor and returns its result.
|
|
1922
|
+
* If BLOCK: returns a governance-blocked message.
|
|
1923
|
+
* If PAUSE: calls onPause; blocks if not approved.
|
|
1924
|
+
*
|
|
1925
|
+
* @param toolCall - The Deep Agents tool call to evaluate
|
|
1926
|
+
* @param executor - The actual tool execution function
|
|
1927
|
+
* @returns The tool execution result or a blocked message
|
|
1928
|
+
*/
|
|
1929
|
+
async execute(toolCall, executor) {
|
|
1930
|
+
const guardResult = this.evaluate(toolCall);
|
|
1931
|
+
if (guardResult.verdict.status === "BLOCK") {
|
|
1932
|
+
this.options.onBlock?.(guardResult);
|
|
1933
|
+
return {
|
|
1934
|
+
blocked: true,
|
|
1935
|
+
verdict: guardResult.verdict,
|
|
1936
|
+
reason: guardResult.verdict.reason ?? "Action blocked by governance policy."
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
if (guardResult.verdict.status === "PAUSE") {
|
|
1940
|
+
const approved = await this.options.onPause?.(guardResult);
|
|
1941
|
+
if (!approved) {
|
|
1942
|
+
return {
|
|
1943
|
+
blocked: true,
|
|
1944
|
+
verdict: guardResult.verdict,
|
|
1945
|
+
reason: guardResult.verdict.reason ?? "Action requires approval."
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
const result = await executor(toolCall);
|
|
1950
|
+
return { result, verdict: guardResult.verdict };
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* Returns a middleware function compatible with Deep Agents' tool pipeline.
|
|
1954
|
+
*
|
|
1955
|
+
* The middleware intercepts tool calls before execution:
|
|
1956
|
+
* agent.use(guard.middleware());
|
|
1957
|
+
*/
|
|
1958
|
+
middleware() {
|
|
1959
|
+
return async (toolCall, next) => {
|
|
1960
|
+
await this.enforce(toolCall);
|
|
1961
|
+
return next();
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Returns a callback-handler-style object for LangChain integration.
|
|
1966
|
+
* Compatible with Deep Agents' callback system.
|
|
1967
|
+
*/
|
|
1968
|
+
callbacks() {
|
|
1969
|
+
return {
|
|
1970
|
+
handleToolStart: async (tool, input) => {
|
|
1971
|
+
let parsedInput;
|
|
1972
|
+
try {
|
|
1973
|
+
parsedInput = typeof input === "string" ? JSON.parse(input) : input;
|
|
1974
|
+
} catch {
|
|
1975
|
+
parsedInput = { raw: input };
|
|
1976
|
+
}
|
|
1977
|
+
await this.enforce({ tool: tool.name, args: parsedInput });
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Check if a shell command contains dangerous patterns.
|
|
1983
|
+
* Useful for pre-screening before full governance evaluation.
|
|
1984
|
+
*/
|
|
1985
|
+
static isDangerousCommand(command) {
|
|
1986
|
+
return isDangerousCommand(command);
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Check if a git command contains dangerous patterns.
|
|
1990
|
+
*/
|
|
1991
|
+
static isDangerousGitCommand(command) {
|
|
1992
|
+
return isDangerousGitCommand(command);
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* Classify a tool name into a category.
|
|
1996
|
+
*/
|
|
1997
|
+
static classifyTool(toolName) {
|
|
1998
|
+
return classifyTool(toolName);
|
|
1999
|
+
}
|
|
2000
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
2001
|
+
trackPlanProgressInternal(event) {
|
|
2002
|
+
trackPlanProgress(event, this, this.options);
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
async function createDeepAgentsGuard(worldPath, options) {
|
|
2006
|
+
const world = await loadWorld(worldPath);
|
|
2007
|
+
return new DeepAgentsGuard(world, options);
|
|
2008
|
+
}
|
|
2009
|
+
function createDeepAgentsGuardFromWorld(world, options) {
|
|
2010
|
+
return new DeepAgentsGuard(world, options);
|
|
2011
|
+
}
|
|
1482
2012
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1483
2013
|
0 && (module.exports = {
|
|
2014
|
+
AutoresearchGovernor,
|
|
2015
|
+
DeepAgentsGovernanceBlockedError,
|
|
2016
|
+
DeepAgentsGuard,
|
|
2017
|
+
GovernanceBlockedError,
|
|
1484
2018
|
GovernedToolExecutor,
|
|
1485
2019
|
LangChainGovernanceBlockedError,
|
|
1486
2020
|
NeuroVerseCallbackHandler,
|
|
1487
2021
|
NeuroVersePlugin,
|
|
1488
2022
|
OpenAIGovernanceBlockedError,
|
|
1489
2023
|
OpenClawGovernanceBlockedError,
|
|
2024
|
+
buildEngineOptions,
|
|
2025
|
+
createDeepAgentsGuard,
|
|
2026
|
+
createDeepAgentsGuardFromWorld,
|
|
1490
2027
|
createGovernanceMiddleware,
|
|
1491
2028
|
createGovernanceMiddlewareFromWorld,
|
|
1492
2029
|
createGovernedToolExecutor,
|
|
@@ -1494,5 +2031,8 @@ function createGovernanceMiddlewareFromWorld(world, options = {}) {
|
|
|
1494
2031
|
createNeuroVerseCallbackHandler,
|
|
1495
2032
|
createNeuroVerseCallbackHandlerFromWorld,
|
|
1496
2033
|
createNeuroVersePlugin,
|
|
1497
|
-
createNeuroVersePluginFromWorld
|
|
2034
|
+
createNeuroVersePluginFromWorld,
|
|
2035
|
+
defaultBlockMessage,
|
|
2036
|
+
extractScope,
|
|
2037
|
+
trackPlanProgress
|
|
1498
2038
|
});
|