@neuroverseos/nv-sim 0.1.9 → 0.1.10

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 (37) hide show
  1. package/README.md +90 -3
  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-B43_0HyO.css +1 -0
  6. package/dist/assets/index-CdghpsS8.js +595 -0
  7. package/dist/assets/{reportEngine-D2ZrMny8.js → reportEngine-CYSZfooa.js} +1 -1
  8. package/dist/connectors/nv-scienceclaw-post.js +376 -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/worldBridge.js +22 -8
  25. package/dist/index.html +2 -2
  26. package/dist/lib/reasoningEngine.js +17 -1
  27. package/dist/lib/simulationAdapter.js +11 -11
  28. package/dist/lib/swarmParser.js +1 -1
  29. package/dist/runtime/govern.js +160 -7
  30. package/dist/runtime/index.js +1 -4
  31. package/dist/runtime/types.js +91 -0
  32. package/package.json +23 -6
  33. package/dist/adapters/mirofish.js +0 -461
  34. package/dist/assets/index-B64NuIXu.css +0 -1
  35. package/dist/assets/index-BMkPevVr.js +0 -532
  36. package/dist/assets/mirotir-logo-DUexumBH.svg +0 -185
  37. package/dist/engine/mirofish.js +0 -295
@@ -2,16 +2,10 @@
2
2
  /**
3
3
  * Prime Radiant — The Unified Governance Intelligence Platform
4
4
  *
5
- * "MiroFish simulates how narratives emerge from interacting agents.
6
- * NeuroverseOS intervenes at the action level to shape how those narratives evolve."
7
- *
8
- * Or sharper:
9
- * "They simulate society. We control how it behaves."
10
- *
11
5
  * The Prime Radiant operates in three modes:
12
6
  *
13
7
  * MODE 1: WORLD BUILDER
14
- * Merge knowledge graph (MiroFish) + policy constraints (NeuroverseOS)
8
+ * Merge knowledge graph + policy constraints (NeuroverseOS)
15
9
  * → Governed world file ready for simulation
16
10
  *
17
11
  * MODE 2: GOVERNED SIMULATION
@@ -299,7 +293,7 @@ function buildNarrative(governed, baseline, delta) {
299
293
  * Pre-built Prime Radiant configurations for common scenarios.
300
294
  */
301
295
  exports.PRIME_RADIANT_PRESETS = {
302
- /** University disciplinary crisis (inspired by MiroFish demo) */
296
+ /** University disciplinary crisis */
303
297
  university_crisis: {
304
298
  scenario: "A university's disciplinary decision sparks widespread backlash. " +
305
299
  "Students, media, alumni, and government stakeholders react across social platforms. " +
@@ -20,7 +20,7 @@
20
20
  */
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.processReasonRequest = processReasonRequest;
23
- const mirofish_1 = require("./mirofish");
23
+ const swarmSimulation_1 = require("./swarmSimulation");
24
24
  const governance_1 = require("./governance");
25
25
  const goalEngine_1 = require("./goalEngine");
26
26
  // ============================================
@@ -420,14 +420,9 @@ async function processReasonRequest(request) {
420
420
  missing_questions: identifyMissingQuestions(request, stakeholders),
421
421
  };
422
422
  // 9. Run swarm simulation (if requested)
423
- // Uses MiroFish when available, falls back to Echelon-native.
424
- // MiroFish shows WHAT happens. Echelon reasons about WHAT IT MEANS.
425
423
  let swarmResult = undefined;
426
- let simulationSource;
427
424
  if (request.swarm?.enabled && stakeholders.length > 0) {
428
- const unified = await (0, mirofish_1.runUnifiedSimulation)(request.scenario, stakeholders, paths, request.swarm);
429
- swarmResult = unified.result;
430
- simulationSource = unified.source;
425
+ swarmResult = await (0, swarmSimulation_1.runSwarmSimulation)(request.scenario, stakeholders, paths, request.swarm);
431
426
  }
432
427
  // 10. Goal-directed reasoning (if goal mode)
433
428
  // "How do I get here?" — works backward from desired outcome
@@ -11,7 +11,7 @@
11
11
  * - initial evidence signals
12
12
  *
13
13
  * Capsules can be:
14
- * 1. Encoded in a URL: mirotir.com/run#capsule=<encoded>
14
+ * 1. Encoded in a URL: neuroverse.dev/run#capsule=<encoded>
15
15
  * 2. Downloaded as JSON: scenario.capsule.json
16
16
  * 3. Generated via API: POST /api/v1/scenario → capsule
17
17
  * 4. Created by agents: autonomous agents generate decision worlds
@@ -81,7 +81,7 @@ function capsuleToReasonRequest(capsule) {
81
81
  // ============================================
82
82
  /**
83
83
  * Encode a capsule for URL embedding.
84
- * Result can be used as: mirotir.com/run#capsule=<encoded>
84
+ * Result can be used as: neuroverse.dev/run#capsule=<encoded>
85
85
  */
86
86
  function encodeCapsule(capsule) {
87
87
  const json = JSON.stringify(capsule);
@@ -123,7 +123,7 @@ function decodeCapsule(encoded) {
123
123
  /**
124
124
  * Build a shareable URL from a capsule.
125
125
  */
126
- function buildShareableUrl(capsule, baseUrl = "https://mirotir.com") {
126
+ function buildShareableUrl(capsule, baseUrl = "https://neuroverse.dev") {
127
127
  const encoded = encodeCapsule(capsule);
128
128
  return `${baseUrl}/run#capsule=${encoded}`;
129
129
  }
@@ -158,7 +158,7 @@ function computeCapsuleHash(data) {
158
158
  // PRESET SCENARIO TEMPLATES
159
159
  // ============================================
160
160
  /**
161
- * Built-in scenario templates that demonstrate Mirotir's capabilities.
161
+ * Built-in scenario templates that demonstrate NeuroVerse's capabilities.
162
162
  * These are the "instant insight" scenarios that make people share.
163
163
  */
164
164
  exports.SCENARIO_TEMPLATES = {
@@ -189,7 +189,7 @@ exports.SCENARIO_TEMPLATES = {
189
189
  depth: "full",
190
190
  perspective: "strategic_advisor",
191
191
  swarm: { enabled: true, rounds: 6, reaction_model: "mixed" },
192
- tags: ["social", "simulation", "agents", "mirofish", "opinion", "discourse"],
192
+ tags: ["social", "simulation", "agents", "opinion", "discourse"],
193
193
  world: {
194
194
  world_id: "social_simulation",
195
195
  name: "Multi-Agent Social Simulation",
@@ -4,18 +4,10 @@
4
4
  *
5
5
  * Lightweight stakeholder reaction simulation for POST /reason.
6
6
  *
7
- * IMPORTANT — MiroFish License Compliance:
8
- * This is NOT MiroFish. This is Echelon's own lightweight reaction model.
9
- * MiroFish is a separate product with its own license.
10
- * If/when MiroFish integration is desired, it would be called as an
11
- * external service via its REST API, respecting its license terms.
12
- *
13
7
  * This simulation layer uses:
14
8
  * - Echelon-native stakeholder modeling
15
9
  * - Simplified reaction dynamics (rational, emotional, mixed)
16
10
  * - Projected reactions based on scenario decomposition
17
- *
18
- * It does NOT use MiroFish internals, algorithms, or data structures.
19
11
  */
20
12
  Object.defineProperty(exports, "__esModule", { value: true });
21
13
  exports.runSwarmSimulation = runSwarmSimulation;
@@ -203,7 +195,7 @@ function findInflectionPoints(rounds) {
203
195
  /**
204
196
  * Run the swarm simulation.
205
197
  *
206
- * This is Echelon's native reaction model — NOT MiroFish.
198
+ * This is Echelon's native reaction model.
207
199
  * It simulates how stakeholders react to different reasoning paths
208
200
  * over multiple rounds, detecting emergent dynamics.
209
201
  *
@@ -59,18 +59,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
59
59
  exports.initNeuroverseModule = initNeuroverseModule;
60
60
  exports.buildWorldFromScenario = buildWorldFromScenario;
61
61
  exports.evaluateScenarioGuard = evaluateScenarioGuard;
62
+ exports.getIncentiveSystem = getIncentiveSystem;
62
63
  exports.runWorldSimulation = runWorldSimulation;
63
64
  exports.validateScenarioWorld = validateScenarioWorld;
64
65
  exports.verdictToConstitutionalChecks = verdictToConstitutionalChecks;
65
66
  exports.simulationToGovernanceSignals = simulationToGovernanceSignals;
66
67
  exports.validationToEnforcedConstraints = validationToEnforcedConstraints;
67
- // ============================================
68
- // LAZY MODULE LOADER
69
- // ============================================
70
- /**
71
- * Lazy-load @neuroverseos/governance at runtime.
72
- * Returns null in browser environments where Node modules aren't available.
73
- */
74
68
  let _nvModule;
75
69
  async function getNVModule() {
76
70
  if (_nvModule !== undefined)
@@ -81,6 +75,10 @@ async function getNVModule() {
81
75
  evaluateGuard: mod.evaluateGuard,
82
76
  simulateWorld: mod.simulateWorld,
83
77
  validateWorld: mod.validateWorld,
78
+ createAgentState: mod.createAgentState,
79
+ applyConsequence: mod.applyConsequence,
80
+ applyReward: mod.applyReward,
81
+ tickAgentStates: mod.tickAgentStates,
84
82
  };
85
83
  return _nvModule;
86
84
  }
@@ -314,10 +312,26 @@ function evaluateScenarioGuard(request, world, options) {
314
312
  has_goal: !!request.goal,
315
313
  },
316
314
  };
317
- return nv.evaluateGuard(event, world, {
315
+ const verdict = nv.evaluateGuard(event, world, {
318
316
  trace: options?.trace ?? true,
319
317
  level: options?.level ?? "standard",
320
318
  });
319
+ return verdict;
320
+ }
321
+ /**
322
+ * Get the incentive system functions from the loaded NeuroverseOS module.
323
+ * Returns null if the module isn't loaded or doesn't export incentive functions.
324
+ */
325
+ function getIncentiveSystem() {
326
+ const nv = getNVModuleSync();
327
+ if (!nv || !nv.createAgentState)
328
+ return null;
329
+ return {
330
+ createAgentState: nv.createAgentState,
331
+ applyConsequence: nv.applyConsequence,
332
+ applyReward: nv.applyReward,
333
+ tickAgentStates: nv.tickAgentStates,
334
+ };
321
335
  }
322
336
  // ============================================
323
337
  // SIMULATION — World state evolution
package/dist/index.html CHANGED
@@ -14,8 +14,8 @@
14
14
  <meta name="twitter:title" content="NV-SIM — NeuroVerse Simulation">
15
15
  <meta name="twitter:description" content="Governed agent simulation — compare emergent outcomes with and without governance constraints.">
16
16
  <link rel="icon" type="image/x-icon" href="/favicon.ico">
17
- <script type="module" crossorigin src="/assets/index-BMkPevVr.js"></script>
18
- <link rel="stylesheet" crossorigin href="/assets/index-B64NuIXu.css">
17
+ <script type="module" crossorigin src="/assets/index-CdghpsS8.js"></script>
18
+ <link rel="stylesheet" crossorigin href="/assets/index-B43_0HyO.css">
19
19
  </head>
20
20
  <body>
21
21
  <div id="root"></div>
@@ -276,7 +276,23 @@ async function generateReasoning(scenario, sliders, options) {
276
276
  mode: options?.mode,
277
277
  goal: options?.goal,
278
278
  };
279
- const response = await (0, index_1.processReasonRequest)(request);
279
+ // All governance evaluation goes through the server.
280
+ // The browser NEVER evaluates governance locally — the server runs
281
+ // @neuroverseos/governance with full Node.js access and real enforcement.
282
+ const apiUrl = `${window.location.protocol}//${window.location.hostname}:3456/api/v1/reason`;
283
+ let response;
284
+ try {
285
+ const res = await fetch(apiUrl, {
286
+ method: 'POST',
287
+ headers: { 'Content-Type': 'application/json' },
288
+ body: JSON.stringify(request),
289
+ });
290
+ response = await res.json();
291
+ }
292
+ catch (err) {
293
+ console.error('Failed to reach governance server:', err);
294
+ response = { status: 'error' };
295
+ }
280
296
  if (response.status === 'error') {
281
297
  return {
282
298
  paths: [],
@@ -5,7 +5,7 @@
5
5
  * Converts output from ANY simulation engine into a normalized schema
6
6
  * that Echelon can reason about. Supported formats:
7
7
  *
8
- * - MiroFish (JSON with agents + emergent_behaviors)
8
+ * - Agent Swarm (JSON with agents + emergent_behaviors)
9
9
  * - NetLogo (tick-based key:value output)
10
10
  * - Mesa (Python agent action logs)
11
11
  * - AnyLogic / CSV (time-series tabular data)
@@ -37,8 +37,8 @@ function detectFormat(input) {
37
37
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
38
38
  try {
39
39
  const data = JSON.parse(trimmed);
40
- if (looksLikeMiroFish(data))
41
- return "mirofish";
40
+ if (looksLikeAgentSwarm(data))
41
+ return "agent_swarm";
42
42
  return "generic_json";
43
43
  }
44
44
  catch {
@@ -56,7 +56,7 @@ function detectFormat(input) {
56
56
  return "mesa";
57
57
  return "freeform_text";
58
58
  }
59
- function looksLikeMiroFish(data) {
59
+ function looksLikeAgentSwarm(data) {
60
60
  if (typeof data !== "object" || data === null)
61
61
  return false;
62
62
  const d = data;
@@ -107,8 +107,8 @@ function looksLikeMesa(text) {
107
107
  function parseSimulation(input) {
108
108
  const format = detectFormat(input);
109
109
  switch (format) {
110
- case "mirofish":
111
- return parseMiroFish(input);
110
+ case "agent_swarm":
111
+ return parseAgentSwarm(input);
112
112
  case "netlogo":
113
113
  return parseNetLogo(input);
114
114
  case "mesa":
@@ -121,8 +121,8 @@ function parseSimulation(input) {
121
121
  return parseFreeformText(input);
122
122
  }
123
123
  }
124
- // ── MiroFish Parser ──────────────────────────────────
125
- function parseMiroFish(input) {
124
+ // ── Agent Swarm Parser ──────────────────────────────────
125
+ function parseAgentSwarm(input) {
126
126
  const data = JSON.parse(input.trim());
127
127
  const agents = [];
128
128
  const events = [];
@@ -172,7 +172,7 @@ function parseMiroFish(input) {
172
172
  }
173
173
  }
174
174
  }
175
- // Parse steps (MiroFish simulation output)
175
+ // Parse steps (simulation output)
176
176
  if (data.steps && Array.isArray(data.steps)) {
177
177
  for (const step of data.steps) {
178
178
  const t = step.step ?? step.round ?? timeline.length;
@@ -196,7 +196,7 @@ function parseMiroFish(input) {
196
196
  }
197
197
  }
198
198
  return {
199
- sourceFormat: "mirofish",
199
+ sourceFormat: "agent_swarm",
200
200
  agents,
201
201
  events,
202
202
  stateChanges,
@@ -677,7 +677,7 @@ function extractAttributes(obj, exclude) {
677
677
  // FORMAT LABELS (for UI)
678
678
  // ============================================
679
679
  exports.FORMAT_LABELS = {
680
- mirofish: "MiroFish",
680
+ agent_swarm: "Agent Swarm",
681
681
  netlogo: "NetLogo",
682
682
  mesa: "Mesa (Python)",
683
683
  anylogic_csv: "AnyLogic / CSV",
@@ -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
+ }