@neuroverseos/governance 0.3.0 → 0.3.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 +34 -9
- package/AGENTS.md +72 -24
- package/README.md +352 -237
- package/dist/adapters/autoresearch.cjs +1152 -3
- package/dist/adapters/autoresearch.d.cts +11 -3
- package/dist/adapters/autoresearch.d.ts +11 -3
- package/dist/adapters/autoresearch.js +9 -4
- package/dist/adapters/deep-agents.cjs +1528 -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 +171 -32
- package/dist/adapters/express.d.cts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +5 -5
- package/dist/adapters/index.cjs +564 -121
- package/dist/adapters/index.d.cts +3 -1
- package/dist/adapters/index.d.ts +3 -1
- package/dist/adapters/index.js +38 -16
- package/dist/adapters/langchain.cjs +217 -57
- package/dist/adapters/langchain.d.cts +5 -5
- package/dist/adapters/langchain.d.ts +5 -5
- package/dist/adapters/langchain.js +6 -5
- package/dist/adapters/openai.cjs +219 -59
- package/dist/adapters/openai.d.cts +5 -5
- package/dist/adapters/openai.d.ts +5 -5
- package/dist/adapters/openai.js +6 -5
- package/dist/adapters/openclaw.cjs +217 -57
- package/dist/adapters/openclaw.d.cts +6 -6
- package/dist/adapters/openclaw.d.ts +6 -6
- package/dist/adapters/openclaw.js +6 -5
- package/dist/add-ROOZLU62.js +314 -0
- package/dist/behavioral-MJO34S6Q.js +118 -0
- package/dist/{bootstrap-GXVDZNF7.js → bootstrap-CQRZVOXK.js} +6 -4
- package/dist/bootstrap-emitter-Q7UIJZ2O.js +7 -0
- package/dist/bootstrap-parser-EEF36XDU.js +7 -0
- package/dist/browser.global.js +941 -0
- package/dist/{build-P42YFKQV.js → build-QKOBBC23.js} +7 -5
- package/dist/{chunk-COT5XS4V.js → chunk-3WQLXYTP.js} +17 -35
- package/dist/{chunk-ER62HNGF.js → chunk-4FLICVVA.js} +17 -37
- package/dist/chunk-5TPFNWRU.js +215 -0
- package/dist/chunk-5U2MQO5P.js +57 -0
- package/dist/{chunk-NF5POFCI.js → chunk-6S5CFQXY.js} +6 -4
- package/dist/{chunk-QPASI2BR.js → chunk-A7GKPPU7.js} +49 -10
- package/dist/{chunk-OGL7QXZS.js → chunk-B6OXJLJ5.js} +17 -3
- package/dist/{chunk-2PQU3VAN.js → chunk-BNKJPUPQ.js} +17 -35
- package/dist/chunk-BQZMOEML.js +43 -0
- package/dist/chunk-CNSO6XW5.js +207 -0
- package/dist/{chunk-JZPQGIKR.js → chunk-CTZHONLA.js} +65 -9
- package/dist/chunk-D2UCV5AK.js +326 -0
- package/dist/{chunk-XPDMYECO.js → chunk-EMQDLDAF.js} +1 -185
- package/dist/{chunk-GR6DGCZ2.js → chunk-F66BVUYB.js} +3 -3
- package/dist/{chunk-2NICNKOM.js → chunk-G7DJ6VOD.js} +5 -4
- package/dist/{chunk-4A7LISES.js → chunk-IS4WUH6Y.js} +45 -6
- package/dist/{chunk-MWDQ4MJB.js → chunk-MH7BT4VH.js} +5 -1
- package/dist/chunk-O5ABKEA7.js +304 -0
- package/dist/chunk-PVTQQS3Y.js +186 -0
- package/dist/{chunk-4QXB6PEO.js → chunk-QLPTHTVB.js} +37 -16
- package/dist/chunk-QWGCMQQD.js +16 -0
- package/dist/{chunk-T5EUJQE5.js → chunk-QXBFT7NI.js} +31 -2
- package/dist/{chunk-PDOZHZWL.js → chunk-TG6SEF24.js} +25 -4
- package/dist/chunk-U6U7EJZL.js +177 -0
- package/dist/{chunk-4JRYGIO7.js → chunk-W7LLXRGY.js} +110 -7
- package/dist/{chunk-BUWWN2NX.js → chunk-ZJTDUCC2.js} +9 -7
- package/dist/{chunk-FYS2CBUW.js → chunk-ZWI3NIXK.js} +10 -0
- package/dist/cli/neuroverse.cjs +5091 -2348
- package/dist/cli/neuroverse.js +52 -21
- package/dist/cli/plan.cjs +881 -41
- package/dist/cli/plan.js +7 -15
- package/dist/cli/run.cjs +289 -34
- package/dist/cli/run.js +4 -4
- package/dist/{configure-ai-TK67ZWZL.js → configure-ai-6TZ3MCSI.js} +1 -1
- package/dist/decision-flow-M63D47LO.js +61 -0
- package/dist/demo-G43RLCPK.js +469 -0
- package/dist/{derive-TLIV4OOU.js → derive-FJZVIPUZ.js} +5 -4
- package/dist/{doctor-XPDLEYXN.js → doctor-6BC6X2VO.js} +6 -4
- package/dist/equity-penalties-SG5IZQ7I.js +244 -0
- package/dist/{explain-IDCRWMPX.js → explain-RHBU2GBR.js} +6 -25
- package/dist/{guard-RV65TT4L.js → guard-AJCCGZMF.js} +8 -12
- package/dist/{guard-contract-WZx__PmU.d.cts → guard-contract-DqFcTScd.d.cts} +117 -5
- package/dist/{guard-contract-WZx__PmU.d.ts → guard-contract-DqFcTScd.d.ts} +117 -5
- package/dist/{guard-engine-JLTUARGU.js → guard-engine-PNR6MHCM.js} +3 -3
- package/dist/{impact-XPECYRLH.js → impact-3XVDSCBU.js} +5 -5
- package/dist/{improve-GPUBKTEA.js → improve-TQP4ECSY.js} +7 -26
- package/dist/index.cjs +5597 -4279
- package/dist/index.d.cts +597 -18
- package/dist/index.d.ts +597 -18
- package/dist/index.js +134 -41
- package/dist/{infer-world-7GVZWFX4.js → infer-world-IFXCACJ5.js} +1 -1
- package/dist/{init-PKPIYHYE.js → init-FYPV4SST.js} +1 -1
- package/dist/{init-world-VWMQZQC7.js → init-world-TI7ARHBT.js} +1 -1
- package/dist/mcp-server-5Y3ZM7TV.js +13 -0
- package/dist/{model-adapter-BB7G4MFI.js → model-adapter-VXEKB4LS.js} +1 -1
- package/dist/{playground-E664U4T6.js → playground-VZBNPPBO.js} +29 -19
- package/dist/{redteam-Z7WREJ44.js → redteam-MZPZD3EF.js} +4 -4
- package/dist/session-JYOARW54.js +15 -0
- package/dist/shared-7RLUHNMU.js +16 -0
- package/dist/shared-B8dvUUD8.d.cts +60 -0
- package/dist/shared-Dr5Wiay8.d.ts +60 -0
- package/dist/{simulate-VDOYQFRO.js → simulate-LJXYBC6M.js} +8 -33
- package/dist/{test-OGXJK4QU.js → test-BOOR4A5F.js} +4 -4
- package/dist/{trace-JVF67VR3.js → trace-PKV4KX56.js} +4 -4
- package/dist/{validate-LLBWVPGV.js → validate-RALX7CZS.js} +2 -2
- package/dist/{validate-engine-UIABSIHD.js → validate-engine-7ZXFVGF2.js} +1 -1
- package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
- package/dist/viz/index.html +23 -0
- package/dist/{world-LAXO6DOX.js → world-BIP4GZBZ.js} +9 -11
- package/dist/world-loader-Y6HMQH2D.js +13 -0
- package/dist/worlds/coding-agent.nv-world.md +211 -0
- package/dist/worlds/research-agent.nv-world.md +169 -0
- package/dist/worlds/social-media.nv-world.md +198 -0
- package/dist/worlds/trading-agent.nv-world.md +218 -0
- package/examples/social-media-sim/bridge.py +209 -0
- package/examples/social-media-sim/simulation.py +927 -0
- package/package.json +30 -4
- package/policies/content-moderation-rules.txt +8 -0
- package/policies/marketing-rules.txt +8 -0
- package/policies/science-research-rules.txt +11 -0
- package/policies/social-media-rules.txt +7 -0
- package/policies/strict-rules.txt +8 -0
- package/policies/trading-rules.txt +8 -0
- package/simulate.html +1567 -0
- package/dist/chunk-YZFATT7X.js +0 -9
- package/dist/mcp-server-FPVSU32Z.js +0 -13
- package/dist/session-EKTRSR7C.js +0 -14
- package/dist/world-loader-HMPTOEA2.js +0 -9
package/dist/adapters/index.cjs
CHANGED
|
@@ -31,12 +31,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var adapters_exports = {};
|
|
32
32
|
__export(adapters_exports, {
|
|
33
33
|
AutoresearchGovernor: () => AutoresearchGovernor,
|
|
34
|
+
DeepAgentsGovernanceBlockedError: () => GovernanceBlockedError5,
|
|
35
|
+
DeepAgentsGuard: () => DeepAgentsGuard,
|
|
36
|
+
GovernanceBlockedError: () => GovernanceBlockedError,
|
|
34
37
|
GovernedToolExecutor: () => GovernedToolExecutor,
|
|
35
|
-
LangChainGovernanceBlockedError: () =>
|
|
38
|
+
LangChainGovernanceBlockedError: () => GovernanceBlockedError2,
|
|
36
39
|
NeuroVerseCallbackHandler: () => NeuroVerseCallbackHandler,
|
|
37
40
|
NeuroVersePlugin: () => NeuroVersePlugin,
|
|
38
|
-
OpenAIGovernanceBlockedError: () =>
|
|
39
|
-
OpenClawGovernanceBlockedError: () =>
|
|
41
|
+
OpenAIGovernanceBlockedError: () => GovernanceBlockedError3,
|
|
42
|
+
OpenClawGovernanceBlockedError: () => GovernanceBlockedError4,
|
|
43
|
+
buildEngineOptions: () => buildEngineOptions,
|
|
44
|
+
createDeepAgentsGuard: () => createDeepAgentsGuard,
|
|
45
|
+
createDeepAgentsGuardFromWorld: () => createDeepAgentsGuardFromWorld,
|
|
40
46
|
createGovernanceMiddleware: () => createGovernanceMiddleware,
|
|
41
47
|
createGovernanceMiddlewareFromWorld: () => createGovernanceMiddlewareFromWorld,
|
|
42
48
|
createGovernedToolExecutor: () => createGovernedToolExecutor,
|
|
@@ -44,21 +50,34 @@ __export(adapters_exports, {
|
|
|
44
50
|
createNeuroVerseCallbackHandler: () => createNeuroVerseCallbackHandler,
|
|
45
51
|
createNeuroVerseCallbackHandlerFromWorld: () => createNeuroVerseCallbackHandlerFromWorld,
|
|
46
52
|
createNeuroVersePlugin: () => createNeuroVersePlugin,
|
|
47
|
-
createNeuroVersePluginFromWorld: () => createNeuroVersePluginFromWorld
|
|
53
|
+
createNeuroVersePluginFromWorld: () => createNeuroVersePluginFromWorld,
|
|
54
|
+
defaultBlockMessage: () => defaultBlockMessage,
|
|
55
|
+
extractScope: () => extractScope,
|
|
56
|
+
trackPlanProgress: () => trackPlanProgress
|
|
48
57
|
});
|
|
49
58
|
module.exports = __toCommonJS(adapters_exports);
|
|
50
59
|
|
|
51
|
-
// src/engine/
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
// src/engine/text-utils.ts
|
|
61
|
+
function normalizeEventText(event) {
|
|
62
|
+
return [
|
|
63
|
+
event.intent,
|
|
64
|
+
event.tool ?? "",
|
|
65
|
+
event.scope ?? ""
|
|
57
66
|
].join(" ").toLowerCase();
|
|
58
|
-
|
|
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);
|
|
59
78
|
if (keywords.length === 0) return false;
|
|
60
79
|
const matched = keywords.filter((kw) => eventText.includes(kw));
|
|
61
|
-
return matched.length >= Math.ceil(keywords.length *
|
|
80
|
+
return matched.length >= Math.ceil(keywords.length * threshold);
|
|
62
81
|
}
|
|
63
82
|
function tokenSimilarity(a, b) {
|
|
64
83
|
const tokensA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
|
|
@@ -71,6 +90,19 @@ function tokenSimilarity(a, b) {
|
|
|
71
90
|
const union = (/* @__PURE__ */ new Set([...tokensA, ...tokensB])).size;
|
|
72
91
|
return union > 0 ? intersection / union : 0;
|
|
73
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
|
+
}
|
|
74
106
|
function findMatchingStep(eventText, event, steps) {
|
|
75
107
|
const pendingOrActive = steps.filter((s) => s.status === "pending" || s.status === "active");
|
|
76
108
|
if (pendingOrActive.length === 0) {
|
|
@@ -89,7 +121,7 @@ function findMatchingStep(eventText, event, steps) {
|
|
|
89
121
|
let bestScore = 0;
|
|
90
122
|
for (const step of pendingOrActive) {
|
|
91
123
|
const stepText = [step.label, step.description ?? "", ...step.tags ?? []].join(" ");
|
|
92
|
-
const score =
|
|
124
|
+
const score = tokenSimilarity2(intentText, stepText);
|
|
93
125
|
if (score > bestScore) {
|
|
94
126
|
bestScore = score;
|
|
95
127
|
bestStep = step;
|
|
@@ -130,7 +162,7 @@ function checkConstraints(event, eventText, constraints) {
|
|
|
130
162
|
continue;
|
|
131
163
|
}
|
|
132
164
|
if (constraint.type === "scope" && constraint.trigger) {
|
|
133
|
-
const keywords = constraint.trigger
|
|
165
|
+
const keywords = extractKeywords(constraint.trigger);
|
|
134
166
|
const violated = keywords.length > 0 && keywords.every((kw) => eventText.includes(kw));
|
|
135
167
|
checks.push({
|
|
136
168
|
constraintId: constraint.id,
|
|
@@ -211,11 +243,7 @@ function evaluatePlan(event, plan) {
|
|
|
211
243
|
progress
|
|
212
244
|
};
|
|
213
245
|
}
|
|
214
|
-
const eventText =
|
|
215
|
-
event.intent,
|
|
216
|
-
event.tool ?? "",
|
|
217
|
-
event.scope ?? ""
|
|
218
|
-
].join(" ").toLowerCase();
|
|
246
|
+
const eventText = normalizeEventText(event);
|
|
219
247
|
const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
|
|
220
248
|
if (!matched) {
|
|
221
249
|
return {
|
|
@@ -256,7 +284,7 @@ function evaluatePlan(event, plan) {
|
|
|
256
284
|
};
|
|
257
285
|
}
|
|
258
286
|
function buildPlanCheck(event, plan, verdict) {
|
|
259
|
-
const eventText =
|
|
287
|
+
const eventText = normalizeEventText(event);
|
|
260
288
|
const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
|
|
261
289
|
const { checks: constraintChecks } = checkConstraints(event, eventText, plan.constraints);
|
|
262
290
|
const progress = getPlanProgress(plan);
|
|
@@ -274,6 +302,50 @@ function buildPlanCheck(event, plan, verdict) {
|
|
|
274
302
|
};
|
|
275
303
|
}
|
|
276
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
|
+
|
|
277
349
|
// src/engine/guard-engine.ts
|
|
278
350
|
var PROMPT_INJECTION_PATTERNS = [
|
|
279
351
|
// Instruction override
|
|
@@ -358,11 +430,49 @@ function isExternalScope(scope) {
|
|
|
358
430
|
];
|
|
359
431
|
return !internalPatterns.some((p) => p.test(scope));
|
|
360
432
|
}
|
|
433
|
+
var MAX_INPUT_LENGTH = 1e5;
|
|
361
434
|
function evaluateGuard(event, world, options = {}) {
|
|
362
435
|
const startTime = performance.now();
|
|
363
436
|
const level = options.level ?? "standard";
|
|
364
437
|
const includeTrace = options.trace ?? false;
|
|
365
|
-
|
|
438
|
+
if (!event.intent || typeof event.intent !== "string") {
|
|
439
|
+
return {
|
|
440
|
+
status: "BLOCK",
|
|
441
|
+
reason: "GuardEvent.intent is required and must be a string",
|
|
442
|
+
ruleId: "safety-input-validation",
|
|
443
|
+
evidence: {
|
|
444
|
+
worldId: world.world?.world_id ?? "",
|
|
445
|
+
worldName: world.world?.name ?? "",
|
|
446
|
+
worldVersion: world.world?.version ?? "",
|
|
447
|
+
evaluatedAt: Date.now(),
|
|
448
|
+
invariantsSatisfied: 0,
|
|
449
|
+
invariantsTotal: 0,
|
|
450
|
+
guardsMatched: [],
|
|
451
|
+
rulesMatched: [],
|
|
452
|
+
enforcementLevel: level
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
const inputLength = event.intent.length + (event.tool?.length ?? 0) + (event.scope?.length ?? 0) + (event.payload ? JSON.stringify(event.payload).length : 0);
|
|
457
|
+
if (inputLength > MAX_INPUT_LENGTH) {
|
|
458
|
+
return {
|
|
459
|
+
status: "BLOCK",
|
|
460
|
+
reason: `Input exceeds maximum allowed length (${MAX_INPUT_LENGTH} characters)`,
|
|
461
|
+
ruleId: "safety-input-length",
|
|
462
|
+
evidence: {
|
|
463
|
+
worldId: world.world?.world_id ?? "",
|
|
464
|
+
worldName: world.world?.name ?? "",
|
|
465
|
+
worldVersion: world.world?.version ?? "",
|
|
466
|
+
evaluatedAt: Date.now(),
|
|
467
|
+
invariantsSatisfied: 0,
|
|
468
|
+
invariantsTotal: 0,
|
|
469
|
+
guardsMatched: [],
|
|
470
|
+
rulesMatched: [],
|
|
471
|
+
enforcementLevel: level
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
const eventText = normalizeEventText(event);
|
|
366
476
|
const invariantChecks = [];
|
|
367
477
|
const safetyChecks = [];
|
|
368
478
|
let planCheckResult;
|
|
@@ -375,6 +485,43 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
375
485
|
const guardsMatched = [];
|
|
376
486
|
const rulesMatched = [];
|
|
377
487
|
checkInvariantCoverage(world, invariantChecks);
|
|
488
|
+
if (event.roleId && options.agentStates) {
|
|
489
|
+
const agentState = options.agentStates.get(event.roleId);
|
|
490
|
+
if (agentState && agentState.cooldownRemaining > 0) {
|
|
491
|
+
decidingLayer = "safety";
|
|
492
|
+
decidingId = `penalize-cooldown-${event.roleId}`;
|
|
493
|
+
const verdict = buildVerdict(
|
|
494
|
+
"PENALIZE",
|
|
495
|
+
`Agent "${event.roleId}" is frozen for ${agentState.cooldownRemaining} more round(s) due to prior penalty.`,
|
|
496
|
+
`penalize-cooldown-${event.roleId}`,
|
|
497
|
+
void 0,
|
|
498
|
+
world,
|
|
499
|
+
level,
|
|
500
|
+
invariantChecks,
|
|
501
|
+
guardsMatched,
|
|
502
|
+
rulesMatched,
|
|
503
|
+
includeTrace ? buildTrace(
|
|
504
|
+
invariantChecks,
|
|
505
|
+
safetyChecks,
|
|
506
|
+
planCheckResult,
|
|
507
|
+
roleChecks,
|
|
508
|
+
guardChecks,
|
|
509
|
+
kernelRuleChecks,
|
|
510
|
+
levelChecks,
|
|
511
|
+
decidingLayer,
|
|
512
|
+
decidingId,
|
|
513
|
+
startTime
|
|
514
|
+
) : void 0
|
|
515
|
+
);
|
|
516
|
+
verdict.intentRecord = {
|
|
517
|
+
originalIntent: event.intent,
|
|
518
|
+
finalAction: "blocked (agent frozen)",
|
|
519
|
+
enforcement: "PENALIZE",
|
|
520
|
+
consequence: { type: "freeze", rounds: agentState.cooldownRemaining, description: "Agent still in cooldown from prior penalty" }
|
|
521
|
+
};
|
|
522
|
+
return verdict;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
378
525
|
if (options.sessionAllowlist) {
|
|
379
526
|
const key = eventToAllowlistKey(event);
|
|
380
527
|
if (options.sessionAllowlist.has(key)) {
|
|
@@ -502,7 +649,16 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
502
649
|
if (guardVerdict.status !== "ALLOW") {
|
|
503
650
|
decidingLayer = "guard";
|
|
504
651
|
decidingId = guardVerdict.ruleId;
|
|
505
|
-
|
|
652
|
+
const intentRecord = {
|
|
653
|
+
originalIntent: event.intent,
|
|
654
|
+
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",
|
|
655
|
+
ruleApplied: guardVerdict.ruleId,
|
|
656
|
+
enforcement: guardVerdict.status,
|
|
657
|
+
modifiedTo: guardVerdict.modifiedTo,
|
|
658
|
+
consequence: guardVerdict.consequence,
|
|
659
|
+
reward: guardVerdict.reward
|
|
660
|
+
};
|
|
661
|
+
const verdict = buildVerdict(
|
|
506
662
|
guardVerdict.status,
|
|
507
663
|
guardVerdict.reason,
|
|
508
664
|
guardVerdict.ruleId,
|
|
@@ -525,6 +681,10 @@ function evaluateGuard(event, world, options = {}) {
|
|
|
525
681
|
startTime
|
|
526
682
|
) : void 0
|
|
527
683
|
);
|
|
684
|
+
verdict.intentRecord = intentRecord;
|
|
685
|
+
if (guardVerdict.consequence) verdict.consequence = guardVerdict.consequence;
|
|
686
|
+
if (guardVerdict.reward) verdict.reward = guardVerdict.reward;
|
|
687
|
+
return verdict;
|
|
528
688
|
}
|
|
529
689
|
}
|
|
530
690
|
const kernelVerdict = checkKernelRules(eventText, world, kernelRuleChecks, rulesMatched);
|
|
@@ -819,6 +979,21 @@ function checkGuards(event, eventText, world, checks, guardsMatched) {
|
|
|
819
979
|
if (actionMode === "pause") {
|
|
820
980
|
return { status: "PAUSE", reason, ruleId: `guard-${guard.id}` };
|
|
821
981
|
}
|
|
982
|
+
if (actionMode === "penalize") {
|
|
983
|
+
const consequence = guard.consequence ? { ...guard.consequence } : { type: "freeze", rounds: 1, description: `Penalized for violating: ${guard.label}` };
|
|
984
|
+
return { status: "PENALIZE", reason, ruleId: `guard-${guard.id}`, consequence };
|
|
985
|
+
}
|
|
986
|
+
if (actionMode === "reward") {
|
|
987
|
+
const reward = guard.reward ? { ...guard.reward } : { type: "boost_influence", magnitude: 0.1, description: `Rewarded for: ${guard.label}` };
|
|
988
|
+
return { status: "REWARD", reason, ruleId: `guard-${guard.id}`, reward };
|
|
989
|
+
}
|
|
990
|
+
if (actionMode === "modify") {
|
|
991
|
+
const modifiedTo = guard.modify_to ?? guard.redirect ?? "hold";
|
|
992
|
+
return { status: "MODIFY", reason: `${reason} \u2192 Modified to: ${modifiedTo}`, ruleId: `guard-${guard.id}`, modifiedTo };
|
|
993
|
+
}
|
|
994
|
+
if (actionMode === "neutral") {
|
|
995
|
+
return { status: "NEUTRAL", reason, ruleId: `guard-${guard.id}` };
|
|
996
|
+
}
|
|
822
997
|
if (actionMode === "warn" && !warnResult) {
|
|
823
998
|
warnResult = { status: "ALLOW", warning: reason, ruleId: `guard-${guard.id}` };
|
|
824
999
|
}
|
|
@@ -928,9 +1103,7 @@ function checkLevelConstraints(event, level, checks) {
|
|
|
928
1103
|
return null;
|
|
929
1104
|
}
|
|
930
1105
|
function matchesKeywords(eventText, ruleText) {
|
|
931
|
-
|
|
932
|
-
if (keywords.length === 0) return false;
|
|
933
|
-
return keywords.every((kw) => eventText.includes(kw));
|
|
1106
|
+
return matchesAllKeywords(eventText, ruleText);
|
|
934
1107
|
}
|
|
935
1108
|
function eventToAllowlistKey(event) {
|
|
936
1109
|
return `${(event.tool ?? "*").toLowerCase()}::${event.intent.toLowerCase().trim()}`;
|
|
@@ -998,10 +1171,18 @@ async function loadWorldFromDirectory(dirPath) {
|
|
|
998
1171
|
const { join } = await import("path");
|
|
999
1172
|
const { readdirSync } = await import("fs");
|
|
1000
1173
|
async function readJson(filename) {
|
|
1174
|
+
const filePath = join(dirPath, filename);
|
|
1001
1175
|
try {
|
|
1002
|
-
const content = await readFile(
|
|
1176
|
+
const content = await readFile(filePath, "utf-8");
|
|
1003
1177
|
return JSON.parse(content);
|
|
1004
|
-
} catch {
|
|
1178
|
+
} catch (err) {
|
|
1179
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
1180
|
+
return void 0;
|
|
1181
|
+
}
|
|
1182
|
+
process.stderr.write(
|
|
1183
|
+
`[neuroverse] Warning: Failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}
|
|
1184
|
+
`
|
|
1185
|
+
);
|
|
1005
1186
|
return void 0;
|
|
1006
1187
|
}
|
|
1007
1188
|
}
|
|
@@ -1023,10 +1204,23 @@ async function loadWorldFromDirectory(dirPath) {
|
|
|
1023
1204
|
const rulesDir = join(dirPath, "rules");
|
|
1024
1205
|
const ruleFiles = readdirSync(rulesDir).filter((f) => f.endsWith(".json")).sort();
|
|
1025
1206
|
for (const file of ruleFiles) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1207
|
+
try {
|
|
1208
|
+
const content = await readFile(join(rulesDir, file), "utf-8");
|
|
1209
|
+
rules.push(JSON.parse(content));
|
|
1210
|
+
} catch (err) {
|
|
1211
|
+
process.stderr.write(
|
|
1212
|
+
`[neuroverse] Warning: Failed to parse rule ${file}: ${err instanceof Error ? err.message : String(err)}
|
|
1213
|
+
`
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
} catch (err) {
|
|
1218
|
+
if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) {
|
|
1219
|
+
process.stderr.write(
|
|
1220
|
+
`[neuroverse] Warning: Failed to read rules directory: ${err instanceof Error ? err.message : String(err)}
|
|
1221
|
+
`
|
|
1222
|
+
);
|
|
1028
1223
|
}
|
|
1029
|
-
} catch {
|
|
1030
1224
|
}
|
|
1031
1225
|
return {
|
|
1032
1226
|
world: worldJson,
|
|
@@ -1061,20 +1255,14 @@ async function loadWorld(worldPath) {
|
|
|
1061
1255
|
if (info.isDirectory()) {
|
|
1062
1256
|
return loadWorldFromDirectory(worldPath);
|
|
1063
1257
|
}
|
|
1064
|
-
|
|
1065
|
-
throw new Error(".nv-world.zip loading not yet implemented \u2014 use a world directory");
|
|
1066
|
-
}
|
|
1067
|
-
throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory or .nv-world.zip`);
|
|
1258
|
+
throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory`);
|
|
1068
1259
|
}
|
|
1069
1260
|
|
|
1070
1261
|
// src/adapters/langchain.ts
|
|
1071
|
-
var
|
|
1072
|
-
verdict;
|
|
1262
|
+
var GovernanceBlockedError2 = class extends GovernanceBlockedError {
|
|
1073
1263
|
event;
|
|
1074
1264
|
constructor(verdict, event) {
|
|
1075
|
-
super(
|
|
1076
|
-
this.name = "GovernanceBlockedError";
|
|
1077
|
-
this.verdict = verdict;
|
|
1265
|
+
super(verdict);
|
|
1078
1266
|
this.event = event;
|
|
1079
1267
|
}
|
|
1080
1268
|
};
|
|
@@ -1082,7 +1270,7 @@ function defaultMapToolCall(toolName, toolInput) {
|
|
|
1082
1270
|
return {
|
|
1083
1271
|
intent: toolName,
|
|
1084
1272
|
tool: toolName,
|
|
1085
|
-
scope:
|
|
1273
|
+
scope: extractScope(toolInput),
|
|
1086
1274
|
args: toolInput,
|
|
1087
1275
|
direction: "input"
|
|
1088
1276
|
};
|
|
@@ -1098,11 +1286,7 @@ var NeuroVerseCallbackHandler = class {
|
|
|
1098
1286
|
this.world = world;
|
|
1099
1287
|
this.options = options;
|
|
1100
1288
|
this.activePlan = options.plan;
|
|
1101
|
-
this.engineOptions =
|
|
1102
|
-
trace: options.trace ?? false,
|
|
1103
|
-
level: options.level,
|
|
1104
|
-
plan: this.activePlan
|
|
1105
|
-
};
|
|
1289
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1106
1290
|
this.mapToolCall = options.mapToolCall ?? defaultMapToolCall;
|
|
1107
1291
|
}
|
|
1108
1292
|
/**
|
|
@@ -1125,28 +1309,16 @@ var NeuroVerseCallbackHandler = class {
|
|
|
1125
1309
|
this.options.onEvaluate?.(verdict, event);
|
|
1126
1310
|
if (verdict.status === "BLOCK") {
|
|
1127
1311
|
this.options.onBlock?.(verdict, event);
|
|
1128
|
-
throw new
|
|
1312
|
+
throw new GovernanceBlockedError2(verdict, event);
|
|
1129
1313
|
}
|
|
1130
1314
|
if (verdict.status === "PAUSE") {
|
|
1131
1315
|
const approved = await this.options.onPause?.(verdict, event);
|
|
1132
1316
|
if (!approved) {
|
|
1133
|
-
throw new
|
|
1317
|
+
throw new GovernanceBlockedError2(verdict, event);
|
|
1134
1318
|
}
|
|
1135
1319
|
}
|
|
1136
|
-
if (verdict.status === "ALLOW"
|
|
1137
|
-
|
|
1138
|
-
if (planVerdict.matchedStep) {
|
|
1139
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1140
|
-
if (advResult.success && advResult.plan) {
|
|
1141
|
-
this.activePlan = advResult.plan;
|
|
1142
|
-
this.engineOptions.plan = this.activePlan;
|
|
1143
|
-
}
|
|
1144
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1145
|
-
this.options.onPlanProgress?.(progress);
|
|
1146
|
-
if (progress.completed === progress.total) {
|
|
1147
|
-
this.options.onPlanComplete?.();
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1320
|
+
if (verdict.status === "ALLOW") {
|
|
1321
|
+
trackPlanProgress(event, this, this.options);
|
|
1150
1322
|
}
|
|
1151
1323
|
}
|
|
1152
1324
|
};
|
|
@@ -1159,13 +1331,10 @@ function createNeuroVerseCallbackHandlerFromWorld(world, options) {
|
|
|
1159
1331
|
}
|
|
1160
1332
|
|
|
1161
1333
|
// src/adapters/openai.ts
|
|
1162
|
-
var
|
|
1163
|
-
verdict;
|
|
1334
|
+
var GovernanceBlockedError3 = class extends GovernanceBlockedError {
|
|
1164
1335
|
toolCallId;
|
|
1165
1336
|
constructor(verdict, toolCallId) {
|
|
1166
|
-
super(
|
|
1167
|
-
this.name = "GovernanceBlockedError";
|
|
1168
|
-
this.verdict = verdict;
|
|
1337
|
+
super(verdict);
|
|
1169
1338
|
this.toolCallId = toolCallId;
|
|
1170
1339
|
}
|
|
1171
1340
|
};
|
|
@@ -1173,14 +1342,11 @@ function defaultMapFunctionCall(name, args) {
|
|
|
1173
1342
|
return {
|
|
1174
1343
|
intent: name,
|
|
1175
1344
|
tool: name,
|
|
1176
|
-
scope:
|
|
1345
|
+
scope: extractScope(args),
|
|
1177
1346
|
args,
|
|
1178
1347
|
direction: "input"
|
|
1179
1348
|
};
|
|
1180
1349
|
}
|
|
1181
|
-
function defaultBlockMessage(verdict) {
|
|
1182
|
-
return `Action blocked by governance policy: ${verdict.reason ?? "rule violation"}. Rule: ${verdict.ruleId ?? "unknown"}.`;
|
|
1183
|
-
}
|
|
1184
1350
|
var GovernedToolExecutor = class {
|
|
1185
1351
|
world;
|
|
1186
1352
|
options;
|
|
@@ -1192,11 +1358,7 @@ var GovernedToolExecutor = class {
|
|
|
1192
1358
|
this.world = world;
|
|
1193
1359
|
this.options = options;
|
|
1194
1360
|
this.activePlan = options.plan;
|
|
1195
|
-
this.engineOptions =
|
|
1196
|
-
trace: options.trace ?? false,
|
|
1197
|
-
level: options.level,
|
|
1198
|
-
plan: this.activePlan
|
|
1199
|
-
};
|
|
1361
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1200
1362
|
this.mapFn = options.mapFunctionCall ?? defaultMapFunctionCall;
|
|
1201
1363
|
this.blockMsg = options.blockMessage ?? defaultBlockMessage;
|
|
1202
1364
|
}
|
|
@@ -1215,20 +1377,8 @@ var GovernedToolExecutor = class {
|
|
|
1215
1377
|
this.engineOptions.plan = this.activePlan;
|
|
1216
1378
|
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
1217
1379
|
this.options.onEvaluate?.(verdict, event);
|
|
1218
|
-
if (verdict.status === "ALLOW"
|
|
1219
|
-
|
|
1220
|
-
if (planVerdict.matchedStep) {
|
|
1221
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1222
|
-
if (advResult.success && advResult.plan) {
|
|
1223
|
-
this.activePlan = advResult.plan;
|
|
1224
|
-
this.engineOptions.plan = this.activePlan;
|
|
1225
|
-
}
|
|
1226
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1227
|
-
this.options.onPlanProgress?.(progress);
|
|
1228
|
-
if (progress.completed === progress.total) {
|
|
1229
|
-
this.options.onPlanComplete?.();
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1380
|
+
if (verdict.status === "ALLOW") {
|
|
1381
|
+
trackPlanProgress(event, this, this.options);
|
|
1232
1382
|
}
|
|
1233
1383
|
return verdict;
|
|
1234
1384
|
}
|
|
@@ -1254,7 +1404,7 @@ var GovernedToolExecutor = class {
|
|
|
1254
1404
|
};
|
|
1255
1405
|
}
|
|
1256
1406
|
if (verdict.status === "PAUSE") {
|
|
1257
|
-
throw new
|
|
1407
|
+
throw new GovernanceBlockedError3(verdict, toolCall.id);
|
|
1258
1408
|
}
|
|
1259
1409
|
let args;
|
|
1260
1410
|
try {
|
|
@@ -1280,13 +1430,10 @@ function createGovernedToolExecutorFromWorld(world, options) {
|
|
|
1280
1430
|
}
|
|
1281
1431
|
|
|
1282
1432
|
// src/adapters/openclaw.ts
|
|
1283
|
-
var
|
|
1284
|
-
verdict;
|
|
1433
|
+
var GovernanceBlockedError4 = class extends GovernanceBlockedError {
|
|
1285
1434
|
action;
|
|
1286
1435
|
constructor(verdict, action) {
|
|
1287
|
-
super(
|
|
1288
|
-
this.name = "GovernanceBlockedError";
|
|
1289
|
-
this.verdict = verdict;
|
|
1436
|
+
super(verdict);
|
|
1290
1437
|
this.action = action;
|
|
1291
1438
|
}
|
|
1292
1439
|
};
|
|
@@ -1296,7 +1443,7 @@ function defaultMapAction(action, direction) {
|
|
|
1296
1443
|
tool: action.tool ?? action.type,
|
|
1297
1444
|
args: action.input,
|
|
1298
1445
|
direction,
|
|
1299
|
-
scope:
|
|
1446
|
+
scope: action.input ? extractScope(action.input) : void 0
|
|
1300
1447
|
};
|
|
1301
1448
|
}
|
|
1302
1449
|
var NeuroVersePlugin = class {
|
|
@@ -1310,11 +1457,7 @@ var NeuroVersePlugin = class {
|
|
|
1310
1457
|
this.world = world;
|
|
1311
1458
|
this.options = options;
|
|
1312
1459
|
this.activePlan = options.plan;
|
|
1313
|
-
this.engineOptions =
|
|
1314
|
-
trace: options.trace ?? false,
|
|
1315
|
-
level: options.level,
|
|
1316
|
-
plan: this.activePlan
|
|
1317
|
-
};
|
|
1460
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1318
1461
|
this.mapAction = options.mapAction ?? defaultMapAction;
|
|
1319
1462
|
}
|
|
1320
1463
|
/**
|
|
@@ -1334,22 +1477,10 @@ var NeuroVersePlugin = class {
|
|
|
1334
1477
|
};
|
|
1335
1478
|
this.options.onEvaluate?.(result);
|
|
1336
1479
|
if (verdict.status === "BLOCK") {
|
|
1337
|
-
throw new
|
|
1480
|
+
throw new GovernanceBlockedError4(verdict, action);
|
|
1338
1481
|
}
|
|
1339
|
-
if (verdict.status === "ALLOW"
|
|
1340
|
-
|
|
1341
|
-
if (planVerdict.matchedStep) {
|
|
1342
|
-
const advResult = advancePlan(this.activePlan, planVerdict.matchedStep);
|
|
1343
|
-
if (advResult.success && advResult.plan) {
|
|
1344
|
-
this.activePlan = advResult.plan;
|
|
1345
|
-
this.engineOptions.plan = this.activePlan;
|
|
1346
|
-
}
|
|
1347
|
-
const progress = getPlanProgress(this.activePlan);
|
|
1348
|
-
this.options.onPlanProgress?.(progress);
|
|
1349
|
-
if (progress.completed === progress.total) {
|
|
1350
|
-
this.options.onPlanComplete?.();
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1482
|
+
if (verdict.status === "ALLOW") {
|
|
1483
|
+
trackPlanProgress(event, this, this.options);
|
|
1353
1484
|
}
|
|
1354
1485
|
return result;
|
|
1355
1486
|
}
|
|
@@ -1370,7 +1501,7 @@ var NeuroVersePlugin = class {
|
|
|
1370
1501
|
};
|
|
1371
1502
|
this.options.onEvaluate?.(result);
|
|
1372
1503
|
if (verdict.status === "BLOCK") {
|
|
1373
|
-
throw new
|
|
1504
|
+
throw new GovernanceBlockedError4(verdict, action);
|
|
1374
1505
|
}
|
|
1375
1506
|
return result;
|
|
1376
1507
|
}
|
|
@@ -1433,8 +1564,9 @@ function defaultOnBlock(verdict, _req, res, statusCode) {
|
|
|
1433
1564
|
ruleId: verdict.ruleId,
|
|
1434
1565
|
status: verdict.status
|
|
1435
1566
|
};
|
|
1436
|
-
if (res.status && res.json) {
|
|
1437
|
-
res.status(statusCode)
|
|
1567
|
+
if (typeof res.status === "function" && typeof res.json === "function") {
|
|
1568
|
+
const r = res.status(statusCode);
|
|
1569
|
+
r.json(body);
|
|
1438
1570
|
} else if (res.send) {
|
|
1439
1571
|
res.statusCode = statusCode;
|
|
1440
1572
|
res.send(JSON.stringify(body));
|
|
@@ -1485,8 +1617,12 @@ function createGovernanceMiddlewareFromWorld(world, options = {}) {
|
|
|
1485
1617
|
var AutoresearchGovernor = class {
|
|
1486
1618
|
config;
|
|
1487
1619
|
state;
|
|
1620
|
+
world;
|
|
1621
|
+
engineOptions;
|
|
1488
1622
|
constructor(config) {
|
|
1489
1623
|
this.config = config;
|
|
1624
|
+
this.world = config.world;
|
|
1625
|
+
this.engineOptions = { trace: true };
|
|
1490
1626
|
this.state = {
|
|
1491
1627
|
experiments_run: 0,
|
|
1492
1628
|
best_result: null,
|
|
@@ -1516,10 +1652,23 @@ var AutoresearchGovernor = class {
|
|
|
1516
1652
|
}
|
|
1517
1653
|
/**
|
|
1518
1654
|
* Evaluate an experiment proposal against governance rules.
|
|
1519
|
-
*
|
|
1655
|
+
* Routes through the guard engine when a world is loaded,
|
|
1656
|
+
* then layers on research-specific checks (budget, constraints, drift).
|
|
1520
1657
|
*/
|
|
1521
1658
|
evaluateProposal(proposal) {
|
|
1522
1659
|
const warnings = [];
|
|
1660
|
+
const event = this.proposalToGuardEvent(proposal);
|
|
1661
|
+
if (this.world) {
|
|
1662
|
+
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
1663
|
+
if (verdict.status === "BLOCK" || verdict.status === "PAUSE") {
|
|
1664
|
+
return {
|
|
1665
|
+
allowed: false,
|
|
1666
|
+
reason: verdict.reason ?? `Governance ${verdict.status}: ${verdict.ruleId ?? "unknown rule"}`,
|
|
1667
|
+
warnings,
|
|
1668
|
+
verdict
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1523
1672
|
const estimatedMinutes = proposal.estimated_minutes || 5;
|
|
1524
1673
|
if (this.state.total_compute_minutes + estimatedMinutes > this.config.computeBudgetMinutes) {
|
|
1525
1674
|
return {
|
|
@@ -1649,15 +1798,306 @@ var AutoresearchGovernor = class {
|
|
|
1649
1798
|
return { ...this.state };
|
|
1650
1799
|
}
|
|
1651
1800
|
};
|
|
1801
|
+
|
|
1802
|
+
// src/engine/tool-classifier.ts
|
|
1803
|
+
var TOOL_CATEGORY_MAP = {
|
|
1804
|
+
// File operations
|
|
1805
|
+
read_file: "file_read",
|
|
1806
|
+
read: "file_read",
|
|
1807
|
+
glob: "file_read",
|
|
1808
|
+
grep: "file_read",
|
|
1809
|
+
list_files: "file_read",
|
|
1810
|
+
write_file: "file_write",
|
|
1811
|
+
write: "file_write",
|
|
1812
|
+
create_file: "file_write",
|
|
1813
|
+
edit_file: "file_write",
|
|
1814
|
+
edit: "file_write",
|
|
1815
|
+
patch: "file_write",
|
|
1816
|
+
delete_file: "file_delete",
|
|
1817
|
+
remove_file: "file_delete",
|
|
1818
|
+
// Shell
|
|
1819
|
+
shell: "shell",
|
|
1820
|
+
bash: "shell",
|
|
1821
|
+
execute: "shell",
|
|
1822
|
+
run_command: "shell",
|
|
1823
|
+
terminal: "shell",
|
|
1824
|
+
// Git
|
|
1825
|
+
git: "git",
|
|
1826
|
+
git_commit: "git",
|
|
1827
|
+
git_push: "git",
|
|
1828
|
+
git_checkout: "git",
|
|
1829
|
+
// Network
|
|
1830
|
+
http: "network",
|
|
1831
|
+
fetch: "network",
|
|
1832
|
+
curl: "network",
|
|
1833
|
+
web_search: "network",
|
|
1834
|
+
// Sub-agents
|
|
1835
|
+
sub_agent: "sub_agent",
|
|
1836
|
+
spawn_agent: "sub_agent",
|
|
1837
|
+
delegate: "sub_agent",
|
|
1838
|
+
// Context management
|
|
1839
|
+
summarize: "context",
|
|
1840
|
+
compress_context: "context"
|
|
1841
|
+
};
|
|
1842
|
+
function classifyTool(toolName) {
|
|
1843
|
+
const normalized = toolName.toLowerCase().replace(/[-\s]/g, "_");
|
|
1844
|
+
return TOOL_CATEGORY_MAP[normalized] ?? "unknown";
|
|
1845
|
+
}
|
|
1846
|
+
var DANGEROUS_SHELL_PATTERNS = [
|
|
1847
|
+
{ pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*-rf\s+|.*--force)/, label: "force-delete" },
|
|
1848
|
+
{ pattern: /rm\s+-[a-zA-Z]*r/, label: "recursive-delete" },
|
|
1849
|
+
{ pattern: />\s*\/dev\/sd/, label: "disk-overwrite" },
|
|
1850
|
+
{ pattern: /mkfs\./, label: "format-disk" },
|
|
1851
|
+
{ pattern: /dd\s+if=/, label: "disk-dump" },
|
|
1852
|
+
{ pattern: /chmod\s+(-R\s+)?777/, label: "world-writable" },
|
|
1853
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
1854
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
1855
|
+
{ pattern: /:(){ :\|:& };:/, label: "fork-bomb" },
|
|
1856
|
+
{ pattern: />\s*\/etc\//, label: "system-config-overwrite" },
|
|
1857
|
+
{ pattern: /shutdown|reboot|halt|poweroff/, label: "system-shutdown" },
|
|
1858
|
+
{ pattern: /kill\s+-9\s+1\b/, label: "kill-init" }
|
|
1859
|
+
];
|
|
1860
|
+
var DANGEROUS_GIT_PATTERNS = [
|
|
1861
|
+
{ pattern: /push\s+.*--force/, label: "force-push" },
|
|
1862
|
+
{ pattern: /push\s+.*-f\b/, label: "force-push" },
|
|
1863
|
+
{ pattern: /push\s+(origin\s+)?main\b/, label: "push-main" },
|
|
1864
|
+
{ pattern: /push\s+(origin\s+)?master\b/, label: "push-master" },
|
|
1865
|
+
{ pattern: /reset\s+--hard/, label: "hard-reset" },
|
|
1866
|
+
{ pattern: /clean\s+-fd/, label: "clean-force" },
|
|
1867
|
+
{ pattern: /branch\s+-D/, label: "force-delete-branch" }
|
|
1868
|
+
];
|
|
1869
|
+
function isDangerousCommand(command) {
|
|
1870
|
+
const matched = DANGEROUS_SHELL_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
1871
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
1872
|
+
}
|
|
1873
|
+
function isDangerousGitCommand(command) {
|
|
1874
|
+
const matched = DANGEROUS_GIT_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
1875
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
1876
|
+
}
|
|
1877
|
+
function assessRiskLevel(category) {
|
|
1878
|
+
if (category === "file_read" || category === "context") return "low";
|
|
1879
|
+
if (category === "file_write" || category === "sub_agent") return "medium";
|
|
1880
|
+
if (category === "shell" || category === "file_delete" || category === "git" || category === "network") return "high";
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
function categoryToActionCategory(category) {
|
|
1884
|
+
if (category === "file_read" || category === "context") return "read";
|
|
1885
|
+
if (category === "file_write") return "write";
|
|
1886
|
+
if (category === "file_delete") return "delete";
|
|
1887
|
+
if (category === "shell") return "shell";
|
|
1888
|
+
if (category === "network") return "network";
|
|
1889
|
+
return "other";
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
// src/adapters/deep-agents.ts
|
|
1893
|
+
var GovernanceBlockedError5 = class extends GovernanceBlockedError {
|
|
1894
|
+
toolCall;
|
|
1895
|
+
category;
|
|
1896
|
+
constructor(verdict, toolCall, category) {
|
|
1897
|
+
super(verdict);
|
|
1898
|
+
this.toolCall = toolCall;
|
|
1899
|
+
this.category = category;
|
|
1900
|
+
}
|
|
1901
|
+
};
|
|
1902
|
+
function defaultMapToolCall2(toolCall) {
|
|
1903
|
+
const category = classifyTool(toolCall.tool);
|
|
1904
|
+
const args = toolCall.args;
|
|
1905
|
+
const scope = extractScope(args);
|
|
1906
|
+
let intent = toolCall.tool;
|
|
1907
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
1908
|
+
intent = `shell: ${args.command}`;
|
|
1909
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
1910
|
+
intent = `git ${args.command}`;
|
|
1911
|
+
} else if (category === "file_write" && scope) {
|
|
1912
|
+
intent = `write ${scope}`;
|
|
1913
|
+
} else if (category === "file_delete" && scope) {
|
|
1914
|
+
intent = `delete ${scope}`;
|
|
1915
|
+
}
|
|
1916
|
+
const riskLevel = assessRiskLevel(category);
|
|
1917
|
+
let irreversible = false;
|
|
1918
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
1919
|
+
irreversible = DANGEROUS_SHELL_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
1920
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
1921
|
+
irreversible = DANGEROUS_GIT_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
1922
|
+
} else if (category === "file_delete") {
|
|
1923
|
+
irreversible = true;
|
|
1924
|
+
}
|
|
1925
|
+
return {
|
|
1926
|
+
intent,
|
|
1927
|
+
tool: toolCall.tool,
|
|
1928
|
+
scope,
|
|
1929
|
+
args,
|
|
1930
|
+
direction: "input",
|
|
1931
|
+
actionCategory: categoryToActionCategory(category),
|
|
1932
|
+
riskLevel,
|
|
1933
|
+
irreversible
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
var DeepAgentsGuard = class {
|
|
1937
|
+
name = "neuroverse-deep-agents-guard";
|
|
1938
|
+
world;
|
|
1939
|
+
options;
|
|
1940
|
+
engineOptions;
|
|
1941
|
+
mapToolCall;
|
|
1942
|
+
activePlan;
|
|
1943
|
+
constructor(world, options = {}) {
|
|
1944
|
+
this.world = world;
|
|
1945
|
+
this.options = options;
|
|
1946
|
+
this.activePlan = options.plan;
|
|
1947
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
1948
|
+
this.mapToolCall = options.mapToolCall ?? defaultMapToolCall2;
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Evaluate a tool call against governance rules.
|
|
1952
|
+
* Returns the result without side effects.
|
|
1953
|
+
*/
|
|
1954
|
+
evaluate(toolCall) {
|
|
1955
|
+
const event = this.mapToolCall(toolCall);
|
|
1956
|
+
this.engineOptions.plan = this.activePlan;
|
|
1957
|
+
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
1958
|
+
const category = classifyTool(toolCall.tool);
|
|
1959
|
+
const result = {
|
|
1960
|
+
allowed: verdict.status === "ALLOW",
|
|
1961
|
+
verdict,
|
|
1962
|
+
toolCall,
|
|
1963
|
+
category
|
|
1964
|
+
};
|
|
1965
|
+
this.options.onEvaluate?.(result);
|
|
1966
|
+
if (verdict.status === "ALLOW" && this.activePlan) {
|
|
1967
|
+
this.trackPlanProgressInternal(event);
|
|
1968
|
+
}
|
|
1969
|
+
return result;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Evaluate and enforce governance on a tool call.
|
|
1973
|
+
*
|
|
1974
|
+
* @throws GovernanceBlockedError if BLOCKED
|
|
1975
|
+
* @throws GovernanceBlockedError if PAUSED and onPause returns false
|
|
1976
|
+
* @returns DeepAgentsGuardResult on ALLOW
|
|
1977
|
+
*/
|
|
1978
|
+
async enforce(toolCall) {
|
|
1979
|
+
const result = this.evaluate(toolCall);
|
|
1980
|
+
if (result.verdict.status === "BLOCK") {
|
|
1981
|
+
this.options.onBlock?.(result);
|
|
1982
|
+
throw new GovernanceBlockedError5(result.verdict, toolCall, result.category);
|
|
1983
|
+
}
|
|
1984
|
+
if (result.verdict.status === "PAUSE") {
|
|
1985
|
+
const approved = await this.options.onPause?.(result);
|
|
1986
|
+
if (!approved) {
|
|
1987
|
+
throw new GovernanceBlockedError5(result.verdict, toolCall, result.category);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
return result;
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Evaluate and execute a tool call with governance enforcement.
|
|
1994
|
+
*
|
|
1995
|
+
* If ALLOW: runs the executor and returns its result.
|
|
1996
|
+
* If BLOCK: returns a governance-blocked message.
|
|
1997
|
+
* If PAUSE: calls onPause; blocks if not approved.
|
|
1998
|
+
*
|
|
1999
|
+
* @param toolCall - The Deep Agents tool call to evaluate
|
|
2000
|
+
* @param executor - The actual tool execution function
|
|
2001
|
+
* @returns The tool execution result or a blocked message
|
|
2002
|
+
*/
|
|
2003
|
+
async execute(toolCall, executor) {
|
|
2004
|
+
const guardResult = this.evaluate(toolCall);
|
|
2005
|
+
if (guardResult.verdict.status === "BLOCK") {
|
|
2006
|
+
this.options.onBlock?.(guardResult);
|
|
2007
|
+
return {
|
|
2008
|
+
blocked: true,
|
|
2009
|
+
verdict: guardResult.verdict,
|
|
2010
|
+
reason: guardResult.verdict.reason ?? "Action blocked by governance policy."
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
if (guardResult.verdict.status === "PAUSE") {
|
|
2014
|
+
const approved = await this.options.onPause?.(guardResult);
|
|
2015
|
+
if (!approved) {
|
|
2016
|
+
return {
|
|
2017
|
+
blocked: true,
|
|
2018
|
+
verdict: guardResult.verdict,
|
|
2019
|
+
reason: guardResult.verdict.reason ?? "Action requires approval."
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
const result = await executor(toolCall);
|
|
2024
|
+
return { result, verdict: guardResult.verdict };
|
|
2025
|
+
}
|
|
2026
|
+
/**
|
|
2027
|
+
* Returns a middleware function compatible with Deep Agents' tool pipeline.
|
|
2028
|
+
*
|
|
2029
|
+
* The middleware intercepts tool calls before execution:
|
|
2030
|
+
* agent.use(guard.middleware());
|
|
2031
|
+
*/
|
|
2032
|
+
middleware() {
|
|
2033
|
+
return async (toolCall, next) => {
|
|
2034
|
+
await this.enforce(toolCall);
|
|
2035
|
+
return next();
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* Returns a callback-handler-style object for LangChain integration.
|
|
2040
|
+
* Compatible with Deep Agents' callback system.
|
|
2041
|
+
*/
|
|
2042
|
+
callbacks() {
|
|
2043
|
+
return {
|
|
2044
|
+
handleToolStart: async (tool, input) => {
|
|
2045
|
+
let parsedInput;
|
|
2046
|
+
try {
|
|
2047
|
+
parsedInput = typeof input === "string" ? JSON.parse(input) : input;
|
|
2048
|
+
} catch {
|
|
2049
|
+
parsedInput = { raw: input };
|
|
2050
|
+
}
|
|
2051
|
+
await this.enforce({ tool: tool.name, args: parsedInput });
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Check if a shell command contains dangerous patterns.
|
|
2057
|
+
* Useful for pre-screening before full governance evaluation.
|
|
2058
|
+
*/
|
|
2059
|
+
static isDangerousCommand(command) {
|
|
2060
|
+
return isDangerousCommand(command);
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Check if a git command contains dangerous patterns.
|
|
2064
|
+
*/
|
|
2065
|
+
static isDangerousGitCommand(command) {
|
|
2066
|
+
return isDangerousGitCommand(command);
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Classify a tool name into a category.
|
|
2070
|
+
*/
|
|
2071
|
+
static classifyTool(toolName) {
|
|
2072
|
+
return classifyTool(toolName);
|
|
2073
|
+
}
|
|
2074
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
2075
|
+
trackPlanProgressInternal(event) {
|
|
2076
|
+
trackPlanProgress(event, this, this.options);
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
async function createDeepAgentsGuard(worldPath, options) {
|
|
2080
|
+
const world = await loadWorld(worldPath);
|
|
2081
|
+
return new DeepAgentsGuard(world, options);
|
|
2082
|
+
}
|
|
2083
|
+
function createDeepAgentsGuardFromWorld(world, options) {
|
|
2084
|
+
return new DeepAgentsGuard(world, options);
|
|
2085
|
+
}
|
|
1652
2086
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1653
2087
|
0 && (module.exports = {
|
|
1654
2088
|
AutoresearchGovernor,
|
|
2089
|
+
DeepAgentsGovernanceBlockedError,
|
|
2090
|
+
DeepAgentsGuard,
|
|
2091
|
+
GovernanceBlockedError,
|
|
1655
2092
|
GovernedToolExecutor,
|
|
1656
2093
|
LangChainGovernanceBlockedError,
|
|
1657
2094
|
NeuroVerseCallbackHandler,
|
|
1658
2095
|
NeuroVersePlugin,
|
|
1659
2096
|
OpenAIGovernanceBlockedError,
|
|
1660
2097
|
OpenClawGovernanceBlockedError,
|
|
2098
|
+
buildEngineOptions,
|
|
2099
|
+
createDeepAgentsGuard,
|
|
2100
|
+
createDeepAgentsGuardFromWorld,
|
|
1661
2101
|
createGovernanceMiddleware,
|
|
1662
2102
|
createGovernanceMiddlewareFromWorld,
|
|
1663
2103
|
createGovernedToolExecutor,
|
|
@@ -1665,5 +2105,8 @@ var AutoresearchGovernor = class {
|
|
|
1665
2105
|
createNeuroVerseCallbackHandler,
|
|
1666
2106
|
createNeuroVerseCallbackHandlerFromWorld,
|
|
1667
2107
|
createNeuroVersePlugin,
|
|
1668
|
-
createNeuroVersePluginFromWorld
|
|
2108
|
+
createNeuroVersePluginFromWorld,
|
|
2109
|
+
defaultBlockMessage,
|
|
2110
|
+
extractScope,
|
|
2111
|
+
trackPlanProgress
|
|
1669
2112
|
});
|