@neuroverseos/governance 0.3.1 → 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 +343 -248
- package/dist/adapters/autoresearch.cjs +1345 -0
- package/dist/adapters/autoresearch.d.cts +111 -0
- package/dist/adapters/autoresearch.d.ts +111 -0
- package/dist/adapters/autoresearch.js +12 -0
- 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 +1253 -0
- package/dist/adapters/express.d.cts +66 -0
- package/dist/adapters/express.d.ts +66 -0
- package/dist/adapters/express.js +12 -0
- package/dist/adapters/index.cjs +2112 -0
- package/dist/adapters/index.d.cts +8 -0
- package/dist/adapters/index.d.ts +8 -0
- package/dist/adapters/index.js +68 -0
- package/dist/adapters/langchain.cjs +1315 -0
- package/dist/adapters/langchain.d.cts +89 -0
- package/dist/adapters/langchain.d.ts +89 -0
- package/dist/adapters/langchain.js +17 -0
- package/dist/adapters/openai.cjs +1345 -0
- package/dist/adapters/openai.d.cts +99 -0
- package/dist/adapters/openai.d.ts +99 -0
- package/dist/adapters/openai.js +17 -0
- package/dist/adapters/openclaw.cjs +1337 -0
- package/dist/adapters/openclaw.d.cts +99 -0
- package/dist/adapters/openclaw.d.ts +99 -0
- package/dist/adapters/openclaw.js +17 -0
- package/dist/add-ROOZLU62.js +314 -0
- package/dist/behavioral-MJO34S6Q.js +118 -0
- package/dist/bootstrap-CQRZVOXK.js +116 -0
- 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-QKOBBC23.js +341 -0
- package/dist/chunk-3WQLXYTP.js +91 -0
- package/dist/chunk-4FLICVVA.js +119 -0
- package/dist/chunk-4NGDRRQH.js +10 -0
- package/dist/chunk-5TPFNWRU.js +215 -0
- package/dist/chunk-5U2MQO5P.js +57 -0
- package/dist/chunk-6CZSKEY5.js +164 -0
- package/dist/chunk-6S5CFQXY.js +624 -0
- package/dist/chunk-7P3S7MAY.js +1090 -0
- package/dist/chunk-A5W4GNQO.js +130 -0
- package/dist/chunk-A7GKPPU7.js +226 -0
- package/dist/chunk-AKW5YVCE.js +96 -0
- package/dist/chunk-B6OXJLJ5.js +622 -0
- package/dist/chunk-BNKJPUPQ.js +113 -0
- package/dist/chunk-BQZMOEML.js +43 -0
- package/dist/chunk-CNSO6XW5.js +207 -0
- package/dist/chunk-CTZHONLA.js +135 -0
- package/dist/chunk-D2UCV5AK.js +326 -0
- package/dist/chunk-EMQDLDAF.js +458 -0
- package/dist/chunk-F66BVUYB.js +340 -0
- package/dist/chunk-G7DJ6VOD.js +101 -0
- package/dist/chunk-I3RRAYK2.js +11 -0
- package/dist/chunk-IS4WUH6Y.js +363 -0
- package/dist/chunk-MH7BT4VH.js +15 -0
- package/dist/chunk-O5ABKEA7.js +304 -0
- package/dist/chunk-OT6PXH54.js +61 -0
- package/dist/chunk-PVTQQS3Y.js +186 -0
- package/dist/chunk-Q6O7ZLO2.js +62 -0
- package/dist/chunk-QLPTHTVB.js +253 -0
- package/dist/chunk-QWGCMQQD.js +16 -0
- package/dist/chunk-QXBFT7NI.js +201 -0
- package/dist/chunk-TG6SEF24.js +246 -0
- package/dist/chunk-U6U7EJZL.js +177 -0
- package/dist/chunk-W7LLXRGY.js +830 -0
- package/dist/chunk-ZJTDUCC2.js +194 -0
- package/dist/chunk-ZWI3NIXK.js +314 -0
- package/dist/cli/neuroverse.cjs +14191 -0
- package/dist/cli/neuroverse.d.cts +1 -0
- package/dist/cli/neuroverse.d.ts +1 -0
- package/dist/cli/neuroverse.js +227 -0
- package/dist/cli/plan.cjs +2439 -0
- package/dist/cli/plan.d.cts +20 -0
- package/dist/cli/plan.d.ts +20 -0
- package/dist/cli/plan.js +353 -0
- package/dist/cli/run.cjs +2001 -0
- package/dist/cli/run.d.cts +20 -0
- package/dist/cli/run.d.ts +20 -0
- package/dist/cli/run.js +143 -0
- package/dist/configure-ai-6TZ3MCSI.js +132 -0
- package/dist/decision-flow-M63D47LO.js +61 -0
- package/dist/demo-G43RLCPK.js +469 -0
- package/dist/derive-FJZVIPUZ.js +153 -0
- package/dist/doctor-6BC6X2VO.js +173 -0
- package/dist/equity-penalties-SG5IZQ7I.js +244 -0
- package/dist/explain-RHBU2GBR.js +51 -0
- package/dist/guard-AJCCGZMF.js +92 -0
- package/dist/guard-contract-DqFcTScd.d.cts +821 -0
- package/dist/guard-contract-DqFcTScd.d.ts +821 -0
- package/dist/guard-engine-PNR6MHCM.js +10 -0
- package/dist/impact-3XVDSCBU.js +59 -0
- package/dist/improve-TQP4ECSY.js +66 -0
- package/dist/index.cjs +7591 -0
- package/dist/index.d.cts +2195 -0
- package/dist/index.d.ts +2195 -0
- package/dist/index.js +472 -0
- package/dist/infer-world-IFXCACJ5.js +543 -0
- package/dist/init-FYPV4SST.js +144 -0
- package/dist/init-world-TI7ARHBT.js +223 -0
- package/dist/mcp-server-5Y3ZM7TV.js +13 -0
- package/dist/model-adapter-VXEKB4LS.js +11 -0
- package/dist/playground-VZBNPPBO.js +560 -0
- package/dist/redteam-MZPZD3EF.js +357 -0
- 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-LJXYBC6M.js +83 -0
- package/dist/test-BOOR4A5F.js +217 -0
- package/dist/trace-PKV4KX56.js +166 -0
- package/dist/validate-RALX7CZS.js +81 -0
- package/dist/validate-engine-7ZXFVGF2.js +7 -0
- package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
- package/dist/viz/index.html +23 -0
- package/dist/world-BIP4GZBZ.js +376 -0
- package/dist/world-loader-Y6HMQH2D.js +13 -0
- package/dist/worlds/autoresearch.nv-world.md +230 -0
- package/dist/worlds/coding-agent.nv-world.md +211 -0
- package/dist/worlds/derivation-world.nv-world.md +278 -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 +16 -3
- package/simulate.html +4 -336
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyConsequence,
|
|
3
|
+
applyReward,
|
|
4
|
+
createAgentState,
|
|
5
|
+
tickAgentStates
|
|
6
|
+
} from "./chunk-D2UCV5AK.js";
|
|
7
|
+
import {
|
|
8
|
+
evaluateGuard
|
|
9
|
+
} from "./chunk-W7LLXRGY.js";
|
|
10
|
+
import {
|
|
11
|
+
advancePlan,
|
|
12
|
+
evaluatePlan,
|
|
13
|
+
getPlanProgress
|
|
14
|
+
} from "./chunk-QLPTHTVB.js";
|
|
15
|
+
import {
|
|
16
|
+
loadWorld
|
|
17
|
+
} from "./chunk-CTZHONLA.js";
|
|
18
|
+
|
|
19
|
+
// src/runtime/session.ts
|
|
20
|
+
async function defaultToolExecutor(name, args) {
|
|
21
|
+
return `Tool "${name}" executed successfully with args: ${JSON.stringify(args)}`;
|
|
22
|
+
}
|
|
23
|
+
var SessionManager = class {
|
|
24
|
+
config;
|
|
25
|
+
state;
|
|
26
|
+
engineOptions;
|
|
27
|
+
executor;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.executor = config.toolExecutor ?? defaultToolExecutor;
|
|
31
|
+
this.engineOptions = {
|
|
32
|
+
trace: config.trace ?? false,
|
|
33
|
+
level: config.level,
|
|
34
|
+
plan: config.plan
|
|
35
|
+
};
|
|
36
|
+
this.state = {
|
|
37
|
+
active: false,
|
|
38
|
+
world: config.world,
|
|
39
|
+
plan: config.plan,
|
|
40
|
+
progress: config.plan ? getPlanProgress(config.plan) : void 0,
|
|
41
|
+
actionsEvaluated: 0,
|
|
42
|
+
actionsAllowed: 0,
|
|
43
|
+
actionsBlocked: 0,
|
|
44
|
+
actionsPaused: 0,
|
|
45
|
+
actionsModified: 0,
|
|
46
|
+
actionsPenalized: 0,
|
|
47
|
+
actionsRewarded: 0,
|
|
48
|
+
agentStates: /* @__PURE__ */ new Map()
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Initialize the session — load world from disk if needed.
|
|
53
|
+
*/
|
|
54
|
+
async start() {
|
|
55
|
+
if (this.config.worldPath && !this.config.world) {
|
|
56
|
+
this.state.world = await loadWorld(this.config.worldPath);
|
|
57
|
+
}
|
|
58
|
+
if (!this.state.world) {
|
|
59
|
+
throw new Error("No world provided. Use --world or pass a world definition.");
|
|
60
|
+
}
|
|
61
|
+
this.state.active = true;
|
|
62
|
+
return this.getState();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Evaluate a single event against governance.
|
|
66
|
+
* Returns the verdict without executing anything.
|
|
67
|
+
*/
|
|
68
|
+
evaluate(event) {
|
|
69
|
+
this.engineOptions.plan = this.state.plan;
|
|
70
|
+
this.engineOptions.agentStates = this.state.agentStates;
|
|
71
|
+
const verdict = evaluateGuard(event, this.state.world, this.engineOptions);
|
|
72
|
+
this.state.actionsEvaluated++;
|
|
73
|
+
if (verdict.status === "ALLOW") this.state.actionsAllowed++;
|
|
74
|
+
if (verdict.status === "BLOCK") this.state.actionsBlocked++;
|
|
75
|
+
if (verdict.status === "PAUSE") this.state.actionsPaused++;
|
|
76
|
+
if (verdict.status === "MODIFY") this.state.actionsModified++;
|
|
77
|
+
if (verdict.status === "PENALIZE") this.state.actionsPenalized++;
|
|
78
|
+
if (verdict.status === "REWARD") this.state.actionsRewarded++;
|
|
79
|
+
if (event.roleId) {
|
|
80
|
+
let agentState = this.state.agentStates.get(event.roleId) ?? createAgentState(event.roleId);
|
|
81
|
+
if (verdict.status === "PENALIZE" && verdict.consequence) {
|
|
82
|
+
agentState = applyConsequence(agentState, verdict.consequence, verdict.ruleId ?? "unknown");
|
|
83
|
+
}
|
|
84
|
+
if (verdict.status === "REWARD" && verdict.reward) {
|
|
85
|
+
agentState = applyReward(agentState, verdict.reward, verdict.ruleId ?? "unknown");
|
|
86
|
+
}
|
|
87
|
+
this.state.agentStates.set(event.roleId, agentState);
|
|
88
|
+
}
|
|
89
|
+
this.config.onVerdict?.(verdict, event);
|
|
90
|
+
return verdict;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Advance all agent states by one round.
|
|
94
|
+
* Call this at the end of each simulation round to decrement cooldowns.
|
|
95
|
+
*/
|
|
96
|
+
tickRound() {
|
|
97
|
+
this.state.agentStates = tickAgentStates(this.state.agentStates);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the behavior state for a specific agent.
|
|
101
|
+
*/
|
|
102
|
+
getAgentState(agentId) {
|
|
103
|
+
return this.state.agentStates.get(agentId);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Evaluate and execute a tool call.
|
|
107
|
+
* Returns the execution result or block reason.
|
|
108
|
+
*/
|
|
109
|
+
async executeToolCall(toolCall) {
|
|
110
|
+
let args;
|
|
111
|
+
try {
|
|
112
|
+
args = JSON.parse(toolCall.function.arguments);
|
|
113
|
+
} catch {
|
|
114
|
+
args = { raw: toolCall.function.arguments };
|
|
115
|
+
}
|
|
116
|
+
const event = {
|
|
117
|
+
intent: toolCall.function.name,
|
|
118
|
+
tool: toolCall.function.name,
|
|
119
|
+
args,
|
|
120
|
+
direction: "input"
|
|
121
|
+
};
|
|
122
|
+
const verdict = this.evaluate(event);
|
|
123
|
+
if (verdict.status === "BLOCK" || verdict.status === "PENALIZE") {
|
|
124
|
+
return { allowed: false, verdict };
|
|
125
|
+
}
|
|
126
|
+
if (verdict.status === "PAUSE") {
|
|
127
|
+
return { allowed: false, verdict };
|
|
128
|
+
}
|
|
129
|
+
const result = await this.executor(toolCall.function.name, args);
|
|
130
|
+
this.config.onToolResult?.(toolCall.function.name, result);
|
|
131
|
+
if (this.state.plan) {
|
|
132
|
+
const planVerdict = evaluatePlan(event, this.state.plan);
|
|
133
|
+
if (planVerdict.matchedStep) {
|
|
134
|
+
const advResult = advancePlan(this.state.plan, planVerdict.matchedStep);
|
|
135
|
+
if (advResult.success && advResult.plan) {
|
|
136
|
+
this.state.plan = advResult.plan;
|
|
137
|
+
this.engineOptions.plan = this.state.plan;
|
|
138
|
+
}
|
|
139
|
+
this.state.progress = getPlanProgress(this.state.plan);
|
|
140
|
+
this.config.onPlanProgress?.(this.state.progress);
|
|
141
|
+
if (this.state.progress.completed === this.state.progress.total) {
|
|
142
|
+
this.config.onPlanComplete?.();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { allowed: true, verdict, result };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Process a model response — evaluate and execute all tool calls.
|
|
150
|
+
* Returns results for each tool call.
|
|
151
|
+
*/
|
|
152
|
+
async processModelResponse(response, model) {
|
|
153
|
+
if (response.toolCalls.length === 0) {
|
|
154
|
+
return response;
|
|
155
|
+
}
|
|
156
|
+
for (const toolCall of response.toolCalls) {
|
|
157
|
+
const { allowed, verdict, result } = await this.executeToolCall(toolCall);
|
|
158
|
+
if (allowed && result) {
|
|
159
|
+
const nextResponse = await model.sendToolResult(toolCall.id, result);
|
|
160
|
+
if (nextResponse.toolCalls.length > 0) {
|
|
161
|
+
return this.processModelResponse(nextResponse, model);
|
|
162
|
+
}
|
|
163
|
+
return nextResponse;
|
|
164
|
+
} else {
|
|
165
|
+
const reason = verdict.reason ?? "Action blocked by governance.";
|
|
166
|
+
const nextResponse = await model.sendBlockedResult(toolCall.id, reason);
|
|
167
|
+
if (nextResponse.toolCalls.length > 0) {
|
|
168
|
+
return this.processModelResponse(nextResponse, model);
|
|
169
|
+
}
|
|
170
|
+
return nextResponse;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return response;
|
|
174
|
+
}
|
|
175
|
+
/** Get current session state. */
|
|
176
|
+
getState() {
|
|
177
|
+
return { ...this.state };
|
|
178
|
+
}
|
|
179
|
+
/** Stop the session. */
|
|
180
|
+
stop() {
|
|
181
|
+
this.state.active = false;
|
|
182
|
+
return this.getState();
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
async function runPipeMode(config) {
|
|
186
|
+
const session = new SessionManager(config);
|
|
187
|
+
await session.start();
|
|
188
|
+
const state = session.getState();
|
|
189
|
+
process.stderr.write(`[neuroverse] Pipe mode active
|
|
190
|
+
`);
|
|
191
|
+
process.stderr.write(`[neuroverse] World: ${state.world.world.name}
|
|
192
|
+
`);
|
|
193
|
+
if (state.plan) {
|
|
194
|
+
process.stderr.write(`[neuroverse] Plan: ${state.plan.plan_id} (${state.plan.objective})
|
|
195
|
+
`);
|
|
196
|
+
}
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
let buffer = "";
|
|
199
|
+
process.stdin.setEncoding("utf-8");
|
|
200
|
+
process.stdin.on("data", (chunk) => {
|
|
201
|
+
buffer += chunk;
|
|
202
|
+
const lines = buffer.split("\n");
|
|
203
|
+
buffer = lines.pop() ?? "";
|
|
204
|
+
for (const line of lines) {
|
|
205
|
+
const trimmed = line.trim();
|
|
206
|
+
if (!trimmed) continue;
|
|
207
|
+
try {
|
|
208
|
+
const event = JSON.parse(trimmed);
|
|
209
|
+
if (!event.intent) {
|
|
210
|
+
process.stderr.write(`[neuroverse] Warning: event missing "intent" field
|
|
211
|
+
`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const verdict = session.evaluate(event);
|
|
215
|
+
process.stdout.write(JSON.stringify(verdict) + "\n");
|
|
216
|
+
} catch (err) {
|
|
217
|
+
process.stderr.write(`[neuroverse] Error parsing line: ${err}
|
|
218
|
+
`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
process.stdin.on("end", () => {
|
|
223
|
+
if (buffer.trim()) {
|
|
224
|
+
try {
|
|
225
|
+
const event = JSON.parse(buffer.trim());
|
|
226
|
+
if (event.intent) {
|
|
227
|
+
const verdict = session.evaluate(event);
|
|
228
|
+
process.stdout.write(JSON.stringify(verdict) + "\n");
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const finalState = session.stop();
|
|
234
|
+
process.stderr.write(
|
|
235
|
+
`[neuroverse] Session complete: ${finalState.actionsEvaluated} evaluated, ${finalState.actionsAllowed} allowed, ${finalState.actionsBlocked} blocked, ${finalState.actionsPaused} paused
|
|
236
|
+
`
|
|
237
|
+
);
|
|
238
|
+
resolve();
|
|
239
|
+
});
|
|
240
|
+
process.stdin.on("error", reject);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function runInteractiveMode(config, model) {
|
|
244
|
+
const session = new SessionManager(config);
|
|
245
|
+
await session.start();
|
|
246
|
+
const state = session.getState();
|
|
247
|
+
process.stdout.write("\n");
|
|
248
|
+
process.stdout.write(` World: ${state.world.world.name}
|
|
249
|
+
`);
|
|
250
|
+
if (state.plan) {
|
|
251
|
+
process.stdout.write(` Plan: ${state.plan.plan_id}
|
|
252
|
+
`);
|
|
253
|
+
process.stdout.write(` Goal: ${state.plan.objective}
|
|
254
|
+
`);
|
|
255
|
+
process.stdout.write(` Steps: ${state.progress?.total ?? 0}
|
|
256
|
+
`);
|
|
257
|
+
}
|
|
258
|
+
process.stdout.write(` Type "exit" to end session.
|
|
259
|
+
`);
|
|
260
|
+
process.stdout.write("\n");
|
|
261
|
+
const readline = await import("readline");
|
|
262
|
+
const rl = readline.createInterface({
|
|
263
|
+
input: process.stdin,
|
|
264
|
+
output: process.stdout,
|
|
265
|
+
prompt: "> "
|
|
266
|
+
});
|
|
267
|
+
const printProgress = () => {
|
|
268
|
+
const s = session.getState();
|
|
269
|
+
if (s.progress) {
|
|
270
|
+
process.stdout.write(
|
|
271
|
+
` [plan: ${s.progress.completed}/${s.progress.total} (${s.progress.percentage}%)]
|
|
272
|
+
`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
rl.prompt();
|
|
277
|
+
rl.on("line", async (input) => {
|
|
278
|
+
const trimmed = input.trim();
|
|
279
|
+
if (!trimmed) {
|
|
280
|
+
rl.prompt();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
284
|
+
const finalState = session.stop();
|
|
285
|
+
process.stdout.write("\n");
|
|
286
|
+
process.stdout.write(` Session complete.
|
|
287
|
+
`);
|
|
288
|
+
process.stdout.write(` Actions: ${finalState.actionsEvaluated} evaluated`);
|
|
289
|
+
process.stdout.write(`, ${finalState.actionsAllowed} allowed`);
|
|
290
|
+
process.stdout.write(`, ${finalState.actionsBlocked} blocked
|
|
291
|
+
`);
|
|
292
|
+
if (finalState.progress) {
|
|
293
|
+
process.stdout.write(
|
|
294
|
+
` Plan: ${finalState.progress.completed}/${finalState.progress.total} steps completed
|
|
295
|
+
`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
process.stdout.write("\n");
|
|
299
|
+
rl.close();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (trimmed === "status") {
|
|
303
|
+
const s = session.getState();
|
|
304
|
+
process.stdout.write(`
|
|
305
|
+
World: ${s.world.world.name}
|
|
306
|
+
`);
|
|
307
|
+
process.stdout.write(` Actions: ${s.actionsEvaluated} evaluated
|
|
308
|
+
`);
|
|
309
|
+
process.stdout.write(` Allowed: ${s.actionsAllowed} | Blocked: ${s.actionsBlocked} | Modified: ${s.actionsModified} | Paused: ${s.actionsPaused}
|
|
310
|
+
`);
|
|
311
|
+
process.stdout.write(` Penalized: ${s.actionsPenalized} | Rewarded: ${s.actionsRewarded}
|
|
312
|
+
`);
|
|
313
|
+
if (s.progress && s.plan) {
|
|
314
|
+
process.stdout.write(` Plan: ${s.plan.plan_id} \u2014 ${s.progress.completed}/${s.progress.total} (${s.progress.percentage}%)
|
|
315
|
+
`);
|
|
316
|
+
for (const step of s.plan.steps) {
|
|
317
|
+
const icon = step.status === "completed" ? "[x]" : "[ ]";
|
|
318
|
+
process.stdout.write(` ${icon} ${step.label}
|
|
319
|
+
`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
process.stdout.write("\n");
|
|
323
|
+
rl.prompt();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const response = await model.chat(trimmed);
|
|
328
|
+
if (response.toolCalls.length > 0) {
|
|
329
|
+
const finalResponse = await session.processModelResponse(response, model);
|
|
330
|
+
if (finalResponse.content) {
|
|
331
|
+
process.stdout.write(`
|
|
332
|
+
${finalResponse.content}
|
|
333
|
+
|
|
334
|
+
`);
|
|
335
|
+
}
|
|
336
|
+
printProgress();
|
|
337
|
+
} else if (response.content) {
|
|
338
|
+
process.stdout.write(`
|
|
339
|
+
${response.content}
|
|
340
|
+
|
|
341
|
+
`);
|
|
342
|
+
}
|
|
343
|
+
} catch (err) {
|
|
344
|
+
process.stderr.write(`
|
|
345
|
+
Error: ${err}
|
|
346
|
+
|
|
347
|
+
`);
|
|
348
|
+
}
|
|
349
|
+
rl.prompt();
|
|
350
|
+
});
|
|
351
|
+
rl.on("close", () => {
|
|
352
|
+
session.stop();
|
|
353
|
+
});
|
|
354
|
+
return new Promise((resolve) => {
|
|
355
|
+
rl.on("close", resolve);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export {
|
|
360
|
+
SessionManager,
|
|
361
|
+
runPipeMode,
|
|
362
|
+
runInteractiveMode
|
|
363
|
+
};
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GovernanceBlockedError,
|
|
3
|
+
buildEngineOptions,
|
|
4
|
+
extractScope,
|
|
5
|
+
trackPlanProgress
|
|
6
|
+
} from "./chunk-5U2MQO5P.js";
|
|
7
|
+
import {
|
|
8
|
+
evaluateGuard
|
|
9
|
+
} from "./chunk-W7LLXRGY.js";
|
|
10
|
+
import {
|
|
11
|
+
loadWorld
|
|
12
|
+
} from "./chunk-CTZHONLA.js";
|
|
13
|
+
|
|
14
|
+
// src/engine/tool-classifier.ts
|
|
15
|
+
var TOOL_CATEGORY_MAP = {
|
|
16
|
+
// File operations
|
|
17
|
+
read_file: "file_read",
|
|
18
|
+
read: "file_read",
|
|
19
|
+
glob: "file_read",
|
|
20
|
+
grep: "file_read",
|
|
21
|
+
list_files: "file_read",
|
|
22
|
+
write_file: "file_write",
|
|
23
|
+
write: "file_write",
|
|
24
|
+
create_file: "file_write",
|
|
25
|
+
edit_file: "file_write",
|
|
26
|
+
edit: "file_write",
|
|
27
|
+
patch: "file_write",
|
|
28
|
+
delete_file: "file_delete",
|
|
29
|
+
remove_file: "file_delete",
|
|
30
|
+
// Shell
|
|
31
|
+
shell: "shell",
|
|
32
|
+
bash: "shell",
|
|
33
|
+
execute: "shell",
|
|
34
|
+
run_command: "shell",
|
|
35
|
+
terminal: "shell",
|
|
36
|
+
// Git
|
|
37
|
+
git: "git",
|
|
38
|
+
git_commit: "git",
|
|
39
|
+
git_push: "git",
|
|
40
|
+
git_checkout: "git",
|
|
41
|
+
// Network
|
|
42
|
+
http: "network",
|
|
43
|
+
fetch: "network",
|
|
44
|
+
curl: "network",
|
|
45
|
+
web_search: "network",
|
|
46
|
+
// Sub-agents
|
|
47
|
+
sub_agent: "sub_agent",
|
|
48
|
+
spawn_agent: "sub_agent",
|
|
49
|
+
delegate: "sub_agent",
|
|
50
|
+
// Context management
|
|
51
|
+
summarize: "context",
|
|
52
|
+
compress_context: "context"
|
|
53
|
+
};
|
|
54
|
+
function classifyTool(toolName) {
|
|
55
|
+
const normalized = toolName.toLowerCase().replace(/[-\s]/g, "_");
|
|
56
|
+
return TOOL_CATEGORY_MAP[normalized] ?? "unknown";
|
|
57
|
+
}
|
|
58
|
+
var DANGEROUS_SHELL_PATTERNS = [
|
|
59
|
+
{ pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*-rf\s+|.*--force)/, label: "force-delete" },
|
|
60
|
+
{ pattern: /rm\s+-[a-zA-Z]*r/, label: "recursive-delete" },
|
|
61
|
+
{ pattern: />\s*\/dev\/sd/, label: "disk-overwrite" },
|
|
62
|
+
{ pattern: /mkfs\./, label: "format-disk" },
|
|
63
|
+
{ pattern: /dd\s+if=/, label: "disk-dump" },
|
|
64
|
+
{ pattern: /chmod\s+(-R\s+)?777/, label: "world-writable" },
|
|
65
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
66
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh|zsh)/, label: "pipe-to-shell" },
|
|
67
|
+
{ pattern: /:(){ :\|:& };:/, label: "fork-bomb" },
|
|
68
|
+
{ pattern: />\s*\/etc\//, label: "system-config-overwrite" },
|
|
69
|
+
{ pattern: /shutdown|reboot|halt|poweroff/, label: "system-shutdown" },
|
|
70
|
+
{ pattern: /kill\s+-9\s+1\b/, label: "kill-init" }
|
|
71
|
+
];
|
|
72
|
+
var DANGEROUS_GIT_PATTERNS = [
|
|
73
|
+
{ pattern: /push\s+.*--force/, label: "force-push" },
|
|
74
|
+
{ pattern: /push\s+.*-f\b/, label: "force-push" },
|
|
75
|
+
{ pattern: /push\s+(origin\s+)?main\b/, label: "push-main" },
|
|
76
|
+
{ pattern: /push\s+(origin\s+)?master\b/, label: "push-master" },
|
|
77
|
+
{ pattern: /reset\s+--hard/, label: "hard-reset" },
|
|
78
|
+
{ pattern: /clean\s+-fd/, label: "clean-force" },
|
|
79
|
+
{ pattern: /branch\s+-D/, label: "force-delete-branch" }
|
|
80
|
+
];
|
|
81
|
+
function isDangerousCommand(command) {
|
|
82
|
+
const matched = DANGEROUS_SHELL_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
83
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
84
|
+
}
|
|
85
|
+
function isDangerousGitCommand(command) {
|
|
86
|
+
const matched = DANGEROUS_GIT_PATTERNS.filter((p) => p.pattern.test(command)).map((p) => p.label);
|
|
87
|
+
return { dangerous: matched.length > 0, labels: matched };
|
|
88
|
+
}
|
|
89
|
+
function assessRiskLevel(category) {
|
|
90
|
+
if (category === "file_read" || category === "context") return "low";
|
|
91
|
+
if (category === "file_write" || category === "sub_agent") return "medium";
|
|
92
|
+
if (category === "shell" || category === "file_delete" || category === "git" || category === "network") return "high";
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
function categoryToActionCategory(category) {
|
|
96
|
+
if (category === "file_read" || category === "context") return "read";
|
|
97
|
+
if (category === "file_write") return "write";
|
|
98
|
+
if (category === "file_delete") return "delete";
|
|
99
|
+
if (category === "shell") return "shell";
|
|
100
|
+
if (category === "network") return "network";
|
|
101
|
+
return "other";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/adapters/deep-agents.ts
|
|
105
|
+
var GovernanceBlockedError2 = class extends GovernanceBlockedError {
|
|
106
|
+
toolCall;
|
|
107
|
+
category;
|
|
108
|
+
constructor(verdict, toolCall, category) {
|
|
109
|
+
super(verdict);
|
|
110
|
+
this.toolCall = toolCall;
|
|
111
|
+
this.category = category;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
function defaultMapToolCall(toolCall) {
|
|
115
|
+
const category = classifyTool(toolCall.tool);
|
|
116
|
+
const args = toolCall.args;
|
|
117
|
+
const scope = extractScope(args);
|
|
118
|
+
let intent = toolCall.tool;
|
|
119
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
120
|
+
intent = `shell: ${args.command}`;
|
|
121
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
122
|
+
intent = `git ${args.command}`;
|
|
123
|
+
} else if (category === "file_write" && scope) {
|
|
124
|
+
intent = `write ${scope}`;
|
|
125
|
+
} else if (category === "file_delete" && scope) {
|
|
126
|
+
intent = `delete ${scope}`;
|
|
127
|
+
}
|
|
128
|
+
const riskLevel = assessRiskLevel(category);
|
|
129
|
+
let irreversible = false;
|
|
130
|
+
if (category === "shell" && typeof args.command === "string") {
|
|
131
|
+
irreversible = DANGEROUS_SHELL_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
132
|
+
} else if (category === "git" && typeof args.command === "string") {
|
|
133
|
+
irreversible = DANGEROUS_GIT_PATTERNS.some((p) => p.pattern.test(args.command));
|
|
134
|
+
} else if (category === "file_delete") {
|
|
135
|
+
irreversible = true;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
intent,
|
|
139
|
+
tool: toolCall.tool,
|
|
140
|
+
scope,
|
|
141
|
+
args,
|
|
142
|
+
direction: "input",
|
|
143
|
+
actionCategory: categoryToActionCategory(category),
|
|
144
|
+
riskLevel,
|
|
145
|
+
irreversible
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
var DeepAgentsGuard = class {
|
|
149
|
+
name = "neuroverse-deep-agents-guard";
|
|
150
|
+
world;
|
|
151
|
+
options;
|
|
152
|
+
engineOptions;
|
|
153
|
+
mapToolCall;
|
|
154
|
+
activePlan;
|
|
155
|
+
constructor(world, options = {}) {
|
|
156
|
+
this.world = world;
|
|
157
|
+
this.options = options;
|
|
158
|
+
this.activePlan = options.plan;
|
|
159
|
+
this.engineOptions = buildEngineOptions(options, this.activePlan);
|
|
160
|
+
this.mapToolCall = options.mapToolCall ?? defaultMapToolCall;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Evaluate a tool call against governance rules.
|
|
164
|
+
* Returns the result without side effects.
|
|
165
|
+
*/
|
|
166
|
+
evaluate(toolCall) {
|
|
167
|
+
const event = this.mapToolCall(toolCall);
|
|
168
|
+
this.engineOptions.plan = this.activePlan;
|
|
169
|
+
const verdict = evaluateGuard(event, this.world, this.engineOptions);
|
|
170
|
+
const category = classifyTool(toolCall.tool);
|
|
171
|
+
const result = {
|
|
172
|
+
allowed: verdict.status === "ALLOW",
|
|
173
|
+
verdict,
|
|
174
|
+
toolCall,
|
|
175
|
+
category
|
|
176
|
+
};
|
|
177
|
+
this.options.onEvaluate?.(result);
|
|
178
|
+
if (verdict.status === "ALLOW" && this.activePlan) {
|
|
179
|
+
this.trackPlanProgressInternal(event);
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Evaluate and enforce governance on a tool call.
|
|
185
|
+
*
|
|
186
|
+
* @throws GovernanceBlockedError if BLOCKED
|
|
187
|
+
* @throws GovernanceBlockedError if PAUSED and onPause returns false
|
|
188
|
+
* @returns DeepAgentsGuardResult on ALLOW
|
|
189
|
+
*/
|
|
190
|
+
async enforce(toolCall) {
|
|
191
|
+
const result = this.evaluate(toolCall);
|
|
192
|
+
if (result.verdict.status === "BLOCK") {
|
|
193
|
+
this.options.onBlock?.(result);
|
|
194
|
+
throw new GovernanceBlockedError2(result.verdict, toolCall, result.category);
|
|
195
|
+
}
|
|
196
|
+
if (result.verdict.status === "PAUSE") {
|
|
197
|
+
const approved = await this.options.onPause?.(result);
|
|
198
|
+
if (!approved) {
|
|
199
|
+
throw new GovernanceBlockedError2(result.verdict, toolCall, result.category);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Evaluate and execute a tool call with governance enforcement.
|
|
206
|
+
*
|
|
207
|
+
* If ALLOW: runs the executor and returns its result.
|
|
208
|
+
* If BLOCK: returns a governance-blocked message.
|
|
209
|
+
* If PAUSE: calls onPause; blocks if not approved.
|
|
210
|
+
*
|
|
211
|
+
* @param toolCall - The Deep Agents tool call to evaluate
|
|
212
|
+
* @param executor - The actual tool execution function
|
|
213
|
+
* @returns The tool execution result or a blocked message
|
|
214
|
+
*/
|
|
215
|
+
async execute(toolCall, executor) {
|
|
216
|
+
const guardResult = this.evaluate(toolCall);
|
|
217
|
+
if (guardResult.verdict.status === "BLOCK") {
|
|
218
|
+
this.options.onBlock?.(guardResult);
|
|
219
|
+
return {
|
|
220
|
+
blocked: true,
|
|
221
|
+
verdict: guardResult.verdict,
|
|
222
|
+
reason: guardResult.verdict.reason ?? "Action blocked by governance policy."
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (guardResult.verdict.status === "PAUSE") {
|
|
226
|
+
const approved = await this.options.onPause?.(guardResult);
|
|
227
|
+
if (!approved) {
|
|
228
|
+
return {
|
|
229
|
+
blocked: true,
|
|
230
|
+
verdict: guardResult.verdict,
|
|
231
|
+
reason: guardResult.verdict.reason ?? "Action requires approval."
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const result = await executor(toolCall);
|
|
236
|
+
return { result, verdict: guardResult.verdict };
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Returns a middleware function compatible with Deep Agents' tool pipeline.
|
|
240
|
+
*
|
|
241
|
+
* The middleware intercepts tool calls before execution:
|
|
242
|
+
* agent.use(guard.middleware());
|
|
243
|
+
*/
|
|
244
|
+
middleware() {
|
|
245
|
+
return async (toolCall, next) => {
|
|
246
|
+
await this.enforce(toolCall);
|
|
247
|
+
return next();
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Returns a callback-handler-style object for LangChain integration.
|
|
252
|
+
* Compatible with Deep Agents' callback system.
|
|
253
|
+
*/
|
|
254
|
+
callbacks() {
|
|
255
|
+
return {
|
|
256
|
+
handleToolStart: async (tool, input) => {
|
|
257
|
+
let parsedInput;
|
|
258
|
+
try {
|
|
259
|
+
parsedInput = typeof input === "string" ? JSON.parse(input) : input;
|
|
260
|
+
} catch {
|
|
261
|
+
parsedInput = { raw: input };
|
|
262
|
+
}
|
|
263
|
+
await this.enforce({ tool: tool.name, args: parsedInput });
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Check if a shell command contains dangerous patterns.
|
|
269
|
+
* Useful for pre-screening before full governance evaluation.
|
|
270
|
+
*/
|
|
271
|
+
static isDangerousCommand(command) {
|
|
272
|
+
return isDangerousCommand(command);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Check if a git command contains dangerous patterns.
|
|
276
|
+
*/
|
|
277
|
+
static isDangerousGitCommand(command) {
|
|
278
|
+
return isDangerousGitCommand(command);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Classify a tool name into a category.
|
|
282
|
+
*/
|
|
283
|
+
static classifyTool(toolName) {
|
|
284
|
+
return classifyTool(toolName);
|
|
285
|
+
}
|
|
286
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
287
|
+
trackPlanProgressInternal(event) {
|
|
288
|
+
trackPlanProgress(event, this, this.options);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
async function createDeepAgentsGuard(worldPath, options) {
|
|
292
|
+
const world = await loadWorld(worldPath);
|
|
293
|
+
return new DeepAgentsGuard(world, options);
|
|
294
|
+
}
|
|
295
|
+
function createDeepAgentsGuardFromWorld(world, options) {
|
|
296
|
+
return new DeepAgentsGuard(world, options);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export {
|
|
300
|
+
GovernanceBlockedError2 as GovernanceBlockedError,
|
|
301
|
+
DeepAgentsGuard,
|
|
302
|
+
createDeepAgentsGuard,
|
|
303
|
+
createDeepAgentsGuardFromWorld
|
|
304
|
+
};
|