@neuroverseos/nv-sim 0.1.9 → 0.1.11

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.
Files changed (38) hide show
  1. package/README.md +187 -535
  2. package/connectors/nv_mirofish_wrapper.py +841 -0
  3. package/connectors/nv_scienceclaw_wrapper.py +453 -0
  4. package/dist/adapters/scienceclaw.js +52 -2
  5. package/dist/assets/index-CH_VswRM.css +1 -0
  6. package/dist/assets/index-sT4b_z7w.js +686 -0
  7. package/dist/assets/{reportEngine-D2ZrMny8.js → reportEngine-Bu8bB5Yq.js} +1 -1
  8. package/dist/connectors/nv-scienceclaw-post.js +363 -0
  9. package/dist/engine/aiProvider.js +82 -3
  10. package/dist/engine/analyzer.js +12 -24
  11. package/dist/engine/cli.js +89 -114
  12. package/dist/engine/dynamicsGovernance.js +4 -0
  13. package/dist/engine/fullGovernedLoop.js +16 -1
  14. package/dist/engine/goalEngine.js +3 -4
  15. package/dist/engine/governance.js +18 -0
  16. package/dist/engine/index.js +19 -28
  17. package/dist/engine/intentTranslator.js +281 -0
  18. package/dist/engine/liveAdapter.js +100 -18
  19. package/dist/engine/liveVisualizer.js +2071 -1023
  20. package/dist/engine/primeRadiant.js +2 -8
  21. package/dist/engine/reasoningEngine.js +2 -7
  22. package/dist/engine/scenarioCapsule.js +5 -5
  23. package/dist/engine/swarmSimulation.js +1 -9
  24. package/dist/engine/universalAdapter.js +371 -0
  25. package/dist/engine/worldBridge.js +22 -8
  26. package/dist/index.html +2 -2
  27. package/dist/lib/reasoningEngine.js +17 -1
  28. package/dist/lib/simulationAdapter.js +11 -11
  29. package/dist/lib/swarmParser.js +1 -1
  30. package/dist/runtime/govern.js +160 -7
  31. package/dist/runtime/index.js +1 -4
  32. package/dist/runtime/types.js +91 -0
  33. package/package.json +23 -6
  34. package/dist/adapters/mirofish.js +0 -461
  35. package/dist/assets/index-B64NuIXu.css +0 -1
  36. package/dist/assets/index-BMkPevVr.js +0 -532
  37. package/dist/assets/mirotir-logo-DUexumBH.svg +0 -185
  38. package/dist/engine/mirofish.js +0 -295
@@ -54,7 +54,7 @@ function seededRandom(seed) {
54
54
  * Parse simulation output into a SwarmResult.
55
55
  *
56
56
  * Uses the universal simulation adapter to normalize input from
57
- * MiroFish, NetLogo, Mesa, AnyLogic/CSV, generic JSON, or freeform text,
57
+ * Agent Swarm, NetLogo, Mesa, AnyLogic/CSV, generic JSON, or freeform text,
58
58
  * then generates structured reasoning overlay from the normalized data.
59
59
  *
60
60
  * Returns both the SwarmResult (for UI) and the detected format.
@@ -79,22 +79,78 @@ function createGovernor(config) {
79
79
  blocked: 0,
80
80
  modified: 0,
81
81
  paused: 0,
82
+ rewarded: 0,
83
+ penalized: 0,
82
84
  rulesFired: 0,
83
85
  };
86
+ // Per-agent behavior states for incentive tracking
87
+ const agentStates = new Map();
88
+ function getOrCreateAgentState(agentId) {
89
+ if (!agentStates.has(agentId)) {
90
+ agentStates.set(agentId, {
91
+ agentId,
92
+ cooldownRemaining: 0,
93
+ influence: 1.0,
94
+ rewardMultiplier: 1.0,
95
+ totalPenalties: 0,
96
+ totalRewards: 0,
97
+ });
98
+ }
99
+ return agentStates.get(agentId);
100
+ }
84
101
  function evaluate(action, worldState) {
85
102
  stats.totalEvaluations++;
103
+ const agentState = getOrCreateAgentState(action.agentId);
104
+ // ── Cooldown check: frozen agents are auto-penalized ──
105
+ if (agentState.cooldownRemaining > 0) {
106
+ agentState.cooldownRemaining--;
107
+ stats.penalized++;
108
+ return {
109
+ status: "PENALIZE",
110
+ action: null,
111
+ reason: `Agent frozen: ${agentState.cooldownRemaining + 1} round(s) remaining on cooldown`,
112
+ rulesFired: [],
113
+ confidence: 1,
114
+ timestamp: Date.now(),
115
+ consequence: { type: "cooldown", rounds: agentState.cooldownRemaining + 1, description: "Agent still in cooldown period" },
116
+ };
117
+ }
86
118
  const rulesFired = [];
87
119
  let currentMagnitude = action.magnitude;
88
120
  let wasModified = false;
121
+ let penalizeRule = null;
122
+ let rewardRule = null;
89
123
  // --- Evaluate action against each invariant ---
90
124
  for (const inv of world.invariants) {
91
125
  if (!inv.enforceable) {
92
- // Advisory: log but don't block
126
+ // Check for reward patterns — advisory rules that match positively
127
+ if (matchesRewardPattern(inv.description, action)) {
128
+ rewardRule = { inv, reward: { type: "boost_influence", magnitude: 0.1, description: inv.description } };
129
+ rulesFired.push({
130
+ id: inv.id,
131
+ description: inv.description,
132
+ effect: "rewarded",
133
+ impactReduction: 0,
134
+ });
135
+ }
136
+ else {
137
+ rulesFired.push({
138
+ id: inv.id,
139
+ description: inv.description,
140
+ effect: "monitored",
141
+ impactReduction: 0,
142
+ });
143
+ }
144
+ continue;
145
+ }
146
+ // Check for penalize patterns before standard evaluation
147
+ if (matchesPenalizePattern(inv.description, action)) {
148
+ penalizeRule = { inv, consequence: { type: "freeze", rounds: 1, magnitude: 0.5, description: inv.description } };
93
149
  rulesFired.push({
94
150
  id: inv.id,
95
151
  description: inv.description,
96
- effect: "monitored",
97
- impactReduction: 0,
152
+ effect: "penalized",
153
+ impactReduction: 1,
98
154
  });
99
155
  continue;
100
156
  }
@@ -114,6 +170,58 @@ function createGovernor(config) {
114
170
  wasModified = true;
115
171
  }
116
172
  }
173
+ // ── PENALIZE verdict ──
174
+ if (penalizeRule) {
175
+ stats.penalized++;
176
+ stats.rulesFired++;
177
+ const consequence = penalizeRule.consequence;
178
+ agentState.totalPenalties++;
179
+ agentState.cooldownRemaining = consequence.rounds ?? 1;
180
+ agentState.influence = Math.max(0, agentState.influence - (consequence.magnitude ?? 0.2));
181
+ const verdict = {
182
+ status: "PENALIZE",
183
+ action: null,
184
+ reason: buildReason("penalized", action, rulesFired),
185
+ rulesFired,
186
+ confidence: computeConfidence(rulesFired, 1),
187
+ timestamp: Date.now(),
188
+ consequence,
189
+ };
190
+ if (audit) {
191
+ audit.logVerdict({
192
+ agent: action.agentId, action: action.description, actionType: action.type,
193
+ verdict: "BLOCK", reason: verdict.reason, confidence: verdict.confidence,
194
+ rulesFired: rulesFired.map((r) => ({ id: r.id, description: r.description, effect: r.effect, impactReduction: r.impactReduction })),
195
+ });
196
+ }
197
+ return verdict;
198
+ }
199
+ // ── REWARD verdict (only when no rules blocked/modified the action) ──
200
+ if (rewardRule && !wasModified) {
201
+ stats.rewarded++;
202
+ stats.rulesFired++;
203
+ const reward = rewardRule.reward;
204
+ agentState.totalRewards++;
205
+ agentState.influence = Math.min(2.0, agentState.influence + (reward.magnitude ?? 0.1));
206
+ agentState.rewardMultiplier = Math.min(3.0, agentState.rewardMultiplier + 0.05);
207
+ const verdict = {
208
+ status: "REWARD",
209
+ action: action,
210
+ reason: buildReason("rewarded", action, rulesFired),
211
+ rulesFired,
212
+ confidence: computeConfidence(rulesFired, 0),
213
+ timestamp: Date.now(),
214
+ reward,
215
+ };
216
+ if (audit) {
217
+ audit.logVerdict({
218
+ agent: action.agentId, action: action.description, actionType: action.type,
219
+ verdict: "ALLOW", reason: verdict.reason, confidence: verdict.confidence,
220
+ rulesFired: rulesFired.map((r) => ({ id: r.id, description: r.description, effect: r.effect, impactReduction: r.impactReduction })),
221
+ });
222
+ }
223
+ return verdict;
224
+ }
117
225
  // --- Determine final verdict ---
118
226
  stats.rulesFired += rulesFired.filter((r) => r.effect !== "monitored").length;
119
227
  const totalReduction = 1 - (currentMagnitude / Math.max(action.magnitude, 0.001));
@@ -121,28 +229,24 @@ function createGovernor(config) {
121
229
  let reason;
122
230
  let outputAction;
123
231
  if (totalReduction > 0.85) {
124
- // Action is essentially killed
125
232
  status = "BLOCK";
126
233
  reason = buildReason("blocked", action, rulesFired);
127
234
  outputAction = null;
128
235
  stats.blocked++;
129
236
  }
130
237
  else if (totalReduction > 0.5) {
131
- // Action is significantly reduced — pause for review
132
238
  status = "PAUSE";
133
239
  reason = buildReason("paused", action, rulesFired);
134
240
  outputAction = { ...action, magnitude: Number(currentMagnitude.toFixed(3)) };
135
241
  stats.paused++;
136
242
  }
137
243
  else if (wasModified && totalReduction > 0.05) {
138
- // Action was modified but still largely allowed
139
244
  status = "MODIFY";
140
245
  reason = buildReason("modified", action, rulesFired);
141
246
  outputAction = { ...action, magnitude: Number(currentMagnitude.toFixed(3)) };
142
247
  stats.modified++;
143
248
  }
144
249
  else {
145
- // Clean pass
146
250
  status = "ALLOW";
147
251
  reason = rulesFired.length > 0
148
252
  ? `Allowed — ${rulesFired.filter((r) => r.effect === "monitored").length} advisory rule(s) noted`
@@ -185,10 +289,22 @@ function createGovernor(config) {
185
289
  health = (0, policyEngine_1.validatePolicy)(parsed);
186
290
  world = (0, policyEngine_1.policyToWorld)(parsed);
187
291
  }
292
+ /** Decrement cooldowns for all tracked agents — call once per round */
293
+ function tickCooldowns() {
294
+ for (const [, state] of agentStates) {
295
+ state.cooldownRemaining = Math.max(0, state.cooldownRemaining - 1);
296
+ }
297
+ }
298
+ /** Get all agent behavior states */
299
+ function getAgentStates() {
300
+ return agentStates;
301
+ }
188
302
  return {
189
303
  evaluate,
190
304
  evaluateBatch,
191
305
  updatePolicy,
306
+ tickCooldowns,
307
+ getAgentStates,
192
308
  get policy() {
193
309
  return {
194
310
  ruleCount: parsed.summary.total,
@@ -384,7 +500,44 @@ function buildReason(type, action, rulesFired) {
384
500
  return `Paused by "${primary.description}"${others} — action "${action.description}" requires review`;
385
501
  case "modified":
386
502
  return `Modified by "${primary.description}"${others} — magnitude reduced from ${action.magnitude.toFixed(2)} to stay within policy limits`;
503
+ case "penalized":
504
+ return `Penalized by "${primary.description}"${others} — agent "${action.agentId}" frozen for violating governance`;
505
+ case "rewarded":
506
+ return `Rewarded by "${primary.description}"${others} — agent "${action.agentId}" demonstrated compliant behavior`;
507
+ }
508
+ }
509
+ // ============================================
510
+ // INCENTIVE PATTERN MATCHING
511
+ // ============================================
512
+ /**
513
+ * Detects penalize patterns in rule descriptions.
514
+ * Rules that say "penalize", "freeze", "suspend", "cooldown" for matching actions.
515
+ */
516
+ function matchesPenalizePattern(ruleDesc, action) {
517
+ const desc = ruleDesc.toLowerCase();
518
+ const actionDesc = action.description.toLowerCase();
519
+ const actionType = action.type.toLowerCase();
520
+ // Must have penalize/freeze/suspend keyword
521
+ if (!matchesPattern(desc, ["penalize", "freeze", "suspend", "cooldown", "punish", "sanction"])) {
522
+ return false;
523
+ }
524
+ // Extract what should be penalized
525
+ const actionTerms = extractActionTerms(desc, ["penalize", "freeze", "suspend", "cooldown", "punish", "sanction"]);
526
+ return actionTerms.some((term) => actionDesc.includes(term) || actionType.includes(term));
527
+ }
528
+ /**
529
+ * Detects reward patterns in rule descriptions.
530
+ * Rules that say "reward", "boost", "incentivize", "encourage" for matching actions.
531
+ */
532
+ function matchesRewardPattern(ruleDesc, action) {
533
+ const desc = ruleDesc.toLowerCase();
534
+ const actionDesc = action.description.toLowerCase();
535
+ const actionType = action.type.toLowerCase();
536
+ if (!matchesPattern(desc, ["reward", "boost", "incentivize", "encourage", "promote", "prioritize"])) {
537
+ return false;
387
538
  }
539
+ const actionTerms = extractActionTerms(desc, ["reward", "boost", "incentivize", "encourage", "promote", "prioritize"]);
540
+ return actionTerms.some((term) => actionDesc.includes(term) || actionType.includes(term));
388
541
  }
389
542
  function capitalize(s) {
390
543
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -38,7 +38,7 @@
38
38
  * const decision = await radiant.compareOptions(options)
39
39
  */
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
- exports.createMiroFishWrapper = exports.generateDemoInvestigation = exports.createScienceClawAdapter = exports.interpretScienceState = exports.SCIENCE_INITIAL_STATE = exports.SCIENCE_POLICY_TEXT = exports.SCIENCE_METRICS = exports.PRIME_RADIANT_PRESETS = exports.createPrimeRadiant = exports.DEFAULT_METRICS = exports.runScenarioMatrix = exports.runFullGovernedSimulation = exports.createDynamicsGovernor = exports.governDynamics = exports.EXAMPLE_WORLD_STATES = exports.EXAMPLE_ACTIONS = exports.createGovernor = exports.govern = void 0;
41
+ exports.generateDemoInvestigation = exports.createScienceClawAdapter = exports.interpretScienceState = exports.SCIENCE_INITIAL_STATE = exports.SCIENCE_POLICY_TEXT = exports.SCIENCE_METRICS = exports.PRIME_RADIANT_PRESETS = exports.createPrimeRadiant = exports.DEFAULT_METRICS = exports.runScenarioMatrix = exports.runFullGovernedSimulation = exports.createDynamicsGovernor = exports.governDynamics = exports.EXAMPLE_WORLD_STATES = exports.EXAMPLE_ACTIONS = exports.createGovernor = exports.govern = void 0;
42
42
  // Core runtime — Layer A: action governance
43
43
  var govern_1 = require("./govern");
44
44
  Object.defineProperty(exports, "govern", { enumerable: true, get: function () { return govern_1.govern; } });
@@ -70,6 +70,3 @@ Object.defineProperty(exports, "interpretScienceState", { enumerable: true, get:
70
70
  var scienceclaw_1 = require("../adapters/scienceclaw");
71
71
  Object.defineProperty(exports, "createScienceClawAdapter", { enumerable: true, get: function () { return scienceclaw_1.createScienceClawAdapter; } });
72
72
  Object.defineProperty(exports, "generateDemoInvestigation", { enumerable: true, get: function () { return scienceclaw_1.generateDemoInvestigation; } });
73
- // MiroFish adapter — governance wrapper for external simulators
74
- var mirofish_1 = require("../adapters/mirofish");
75
- Object.defineProperty(exports, "createMiroFishWrapper", { enumerable: true, get: function () { return mirofish_1.createMiroFishWrapper; } });
@@ -9,3 +9,94 @@
9
9
  * import { type AgentAction, type GovernanceVerdict } from "@neuroverseos/runtime"
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.validateGovernableEvent = validateGovernableEvent;
13
+ exports.validateGovernableCycle = validateGovernableCycle;
14
+ exports.normalizeActionType = normalizeActionType;
15
+ /**
16
+ * Maps a raw JSON object to an NVGovernableEvent, or returns the reason it can't.
17
+ * This is the universal validation gate — used by all adapters.
18
+ */
19
+ function validateGovernableEvent(raw, source) {
20
+ const cycle = raw.cycle ?? raw.step ?? raw.round;
21
+ if (cycle == null)
22
+ return "missing_cycle";
23
+ const agentId = raw.agent_id ?? raw.agentId ?? raw.id ?? raw.agent;
24
+ if (!agentId || typeof agentId !== "string")
25
+ return "missing_agent";
26
+ const actionType = raw.type ?? raw.action ?? raw.action_type ?? raw.actionType;
27
+ if (!actionType || typeof actionType !== "string")
28
+ return "missing_action_type";
29
+ return {
30
+ schema: 1,
31
+ source,
32
+ cycle: typeof cycle === "number" ? cycle : parseInt(cycle, 10),
33
+ agentId: agentId,
34
+ actionType: normalizeActionType(actionType),
35
+ description: raw.description ?? `${actionType} action`,
36
+ confidence: typeof raw.confidence === "number" ? raw.confidence : 0.5,
37
+ magnitude: typeof raw.magnitude === "number" ? raw.magnitude : 0.5,
38
+ reproduced: raw.reproduced === true,
39
+ references: typeof raw.citations === "number" ? raw.citations
40
+ : typeof raw.references === "number" ? raw.references : 0,
41
+ metadata: raw.metadata,
42
+ };
43
+ }
44
+ /**
45
+ * Validates a cycle-level JSON object containing multiple events.
46
+ * Returns an NVGovernableCycle or the reason the cycle itself is ungovernable.
47
+ */
48
+ function validateGovernableCycle(raw, source) {
49
+ const cycle = raw.cycle ?? raw.step ?? raw.round;
50
+ if (cycle == null)
51
+ return "missing_cycle";
52
+ const rawEvents = raw.artifacts ?? raw.agents ?? raw.agent_actions ?? raw.events;
53
+ if (!Array.isArray(rawEvents))
54
+ return "missing_action_type";
55
+ const events = [];
56
+ for (const item of rawEvents) {
57
+ if (typeof item !== "object" || item == null)
58
+ continue;
59
+ const withCycle = { ...item, cycle };
60
+ const result = validateGovernableEvent(withCycle, source);
61
+ if (typeof result !== "string") {
62
+ events.push(result);
63
+ }
64
+ }
65
+ return {
66
+ schema: 1,
67
+ source,
68
+ cycle: typeof cycle === "number" ? cycle : parseInt(cycle, 10),
69
+ events,
70
+ systemSignals: raw.system_state,
71
+ };
72
+ }
73
+ /** Normalize free-form action types to the governed vocabulary. */
74
+ function normalizeActionType(raw) {
75
+ const lower = raw.toLowerCase();
76
+ const map = {
77
+ hypothesis: "hypothesis",
78
+ experiment: "experiment",
79
+ analysis: "analysis",
80
+ publication: "publication",
81
+ publish: "publication",
82
+ paper: "publication",
83
+ replication: "replication",
84
+ replicate: "replication",
85
+ review: "review",
86
+ trade: "trade",
87
+ buy: "trade",
88
+ sell: "trade",
89
+ decision: "decision",
90
+ communicate: "communication",
91
+ communication: "communication",
92
+ post: "communication",
93
+ message: "communication",
94
+ withdrawal: "withdrawal",
95
+ withdraw: "withdrawal",
96
+ vote: "vote",
97
+ coalition: "coalition",
98
+ dataset: "analysis",
99
+ model: "analysis",
100
+ };
101
+ return map[lower] ?? "custom";
102
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuroverseos/nv-sim",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "CLI for running governed vs baseline agent simulations to explore how world rules shape emergent system behavior.",
@@ -8,25 +8,41 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/NeuroverseOS/neuroverse-simulations"
10
10
  },
11
+ "keywords": [
12
+ "agent-incentives",
13
+ "governance",
14
+ "ai-agents",
15
+ "simulation",
16
+ "multi-agent",
17
+ "neuroverse",
18
+ "policy-enforcement",
19
+ "reward-penalize",
20
+ "agent-behavior",
21
+ "emergent-systems"
22
+ ],
11
23
  "homepage": "https://github.com/NeuroverseOS/neuroverse-simulations",
12
24
  "bugs": {
13
25
  "url": "https://github.com/NeuroverseOS/neuroverse-simulations/issues"
14
26
  },
15
27
  "bin": {
16
- "nv-sim": "dist/engine/cli.js"
28
+ "nv-sim": "dist/engine/cli.js",
29
+ "nv-scienceclaw-post": "dist/connectors/nv-scienceclaw-post.js"
17
30
  },
18
31
  "files": [
19
32
  "dist",
33
+ "connectors",
20
34
  "variants",
21
35
  "README.md",
22
36
  "LICENSE"
23
37
  ],
24
38
  "scripts": {
25
39
  "dev": "vite",
26
- "build": "vite build && tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js",
27
- "build:cli": "tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js",
40
+ "build": "vite build && tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js && (test -f dist/connectors/nv-scienceclaw-post.js && chmod +x dist/connectors/nv-scienceclaw-post.js || true)",
41
+ "build:cli": "tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js && (test -f dist/connectors/nv-scienceclaw-post.js && chmod +x dist/connectors/nv-scienceclaw-post.js || true)",
28
42
  "build:dev": "vite build --mode development",
29
- "build:all": "vite build && tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js",
43
+ "build:all": "vite build && tsc -p tsconfig.cli.json && echo '{\"type\":\"commonjs\"}' > dist/package.json && chmod +x dist/engine/cli.js && (test -f dist/connectors/nv-scienceclaw-post.js && chmod +x dist/connectors/nv-scienceclaw-post.js || true)",
44
+ "server": "tsx src/server/index.ts",
45
+ "dev:full": "tsx src/server/index.ts & vite",
30
46
  "lint": "eslint .",
31
47
  "preview": "vite preview",
32
48
  "test": "vitest run",
@@ -38,7 +54,7 @@
38
54
  },
39
55
  "dependencies": {
40
56
  "@hookform/resolvers": "^3.10.0",
41
- "@neuroverseos/governance": "^0.3.0",
57
+ "@neuroverseos/governance": "^0.2.3",
42
58
  "@radix-ui/react-accordion": "^1.2.11",
43
59
  "@radix-ui/react-alert-dialog": "^1.1.14",
44
60
  "@radix-ui/react-aspect-ratio": "^1.1.7",
@@ -109,6 +125,7 @@
109
125
  "typescript": "^5.8.3",
110
126
  "typescript-eslint": "^8.38.0",
111
127
  "vite": "^5.4.19",
128
+ "tsx": "^4.21.0",
112
129
  "vitest": "^3.2.4"
113
130
  }
114
131
  }