@agent-e/core 1.1.0 → 1.1.2
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/README.md +136 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +42 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -5
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# @agent-e/core
|
|
2
|
+
|
|
3
|
+
Autonomous economic balancer SDK. 60 built-in principles, 5-stage pipeline, zero dependencies.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @agent-e/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { AgentE } from '@agent-e/core';
|
|
15
|
+
|
|
16
|
+
const agent = new AgentE({
|
|
17
|
+
adapter: {
|
|
18
|
+
getState: () => ({
|
|
19
|
+
tick: currentTick,
|
|
20
|
+
agentBalances: { /* id → gold */ },
|
|
21
|
+
agentRoles: { /* id → role */ },
|
|
22
|
+
agentInventories: { /* id → { resource → qty } */ },
|
|
23
|
+
marketPrices: { /* resource → price */ },
|
|
24
|
+
agentSatisfaction: { /* id → 0-100 */ },
|
|
25
|
+
poolSizes: { /* pool → amount */ },
|
|
26
|
+
}),
|
|
27
|
+
setParam: async (param, value) => {
|
|
28
|
+
// Apply parameter change to your economy
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
mode: 'advisor', // or 'autonomous'
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
agent.connect(agent.adapter).start();
|
|
35
|
+
|
|
36
|
+
// Call once per tick in your loop:
|
|
37
|
+
await agent.tick();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## The 5-Stage Pipeline
|
|
41
|
+
|
|
42
|
+
1. **Observer** — Translates raw state into 40+ metrics at 3 resolutions (fine/medium/coarse)
|
|
43
|
+
2. **Diagnoser** — Runs 60 principles, returns violations sorted by severity
|
|
44
|
+
3. **Simulator** — Monte Carlo forward projection (≥100 iterations) before any action
|
|
45
|
+
4. **Planner** — Lag-aware, cooldown-aware planning with rollback conditions
|
|
46
|
+
5. **Executor** — Applies actions and monitors for rollback triggers
|
|
47
|
+
|
|
48
|
+
## Modes
|
|
49
|
+
|
|
50
|
+
| Mode | Behavior |
|
|
51
|
+
|------|----------|
|
|
52
|
+
| `autonomous` | Full pipeline — executes parameter changes automatically |
|
|
53
|
+
| `advisor` | Full pipeline but stops before execution — emits recommendations via `onDecision` |
|
|
54
|
+
|
|
55
|
+
## 60 Principles
|
|
56
|
+
|
|
57
|
+
Organized across 15 categories: supply chain, incentives, population, currency flow, bootstrap, feedback loops, regulator, market dynamics, measurement, statistical, system dynamics, resource management, player experience, open economy, and liveops.
|
|
58
|
+
|
|
59
|
+
Each principle has a `check(metrics, thresholds)` function that returns either `{ violated: false }` or a violation with severity, evidence, suggested action, confidence, and estimated lag.
|
|
60
|
+
|
|
61
|
+
## Developer API
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// Lock a parameter from automated adjustment
|
|
65
|
+
agent.lock('craftingCost');
|
|
66
|
+
agent.unlock('craftingCost');
|
|
67
|
+
|
|
68
|
+
// Constrain a parameter to a range
|
|
69
|
+
agent.constrain('auctionFee', { min: 0.01, max: 0.50 });
|
|
70
|
+
|
|
71
|
+
// Add a custom principle
|
|
72
|
+
agent.addPrinciple(myPrinciple);
|
|
73
|
+
|
|
74
|
+
// Register a custom metric
|
|
75
|
+
agent.registerCustomMetric('myMetric', (state) => compute(state));
|
|
76
|
+
|
|
77
|
+
// Veto actions
|
|
78
|
+
agent.on('beforeAction', (plan) => {
|
|
79
|
+
if (plan.targetValue > 2.0) return false;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Query decision history
|
|
83
|
+
const decisions = agent.getDecisions({ outcome: 'applied' });
|
|
84
|
+
|
|
85
|
+
// Health score (0-100)
|
|
86
|
+
const health = agent.getHealth();
|
|
87
|
+
|
|
88
|
+
// Metric time-series
|
|
89
|
+
const latest = agent.metrics.latest('fine');
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Custom Principles
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import type { Principle } from '@agent-e/core';
|
|
96
|
+
|
|
97
|
+
const myRule: Principle = {
|
|
98
|
+
id: 'MY_01',
|
|
99
|
+
name: 'Healer Population Floor',
|
|
100
|
+
category: 'population',
|
|
101
|
+
description: 'Healer share below 5% is a crisis',
|
|
102
|
+
check(metrics, thresholds) {
|
|
103
|
+
const share = metrics.roleShares['Healer'] ?? 0;
|
|
104
|
+
if (share < 0.05) {
|
|
105
|
+
return {
|
|
106
|
+
violated: true,
|
|
107
|
+
severity: 8,
|
|
108
|
+
evidence: { share },
|
|
109
|
+
suggestedAction: {
|
|
110
|
+
parameter: 'healerReward',
|
|
111
|
+
direction: 'increase',
|
|
112
|
+
magnitude: 0.25,
|
|
113
|
+
reasoning: 'Healer population critically low.',
|
|
114
|
+
},
|
|
115
|
+
confidence: 0.90,
|
|
116
|
+
estimatedLag: 10,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return { violated: false };
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
agent.addPrinciple(myRule);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Performance
|
|
127
|
+
|
|
128
|
+
- **O(N) event classification** — single-pass instead of 6 separate filters
|
|
129
|
+
- **Cached diagnosis** — no redundant principle checks within the same tick
|
|
130
|
+
- **Numerical stability** — clamped inputs to prevent NaN edge cases
|
|
131
|
+
|
|
132
|
+
Typical for 1,000 agents, 100 events/tick: ~60ms end-to-end.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -360,6 +360,7 @@ declare class Observer {
|
|
|
360
360
|
|
|
361
361
|
declare class Simulator {
|
|
362
362
|
private diagnoser;
|
|
363
|
+
private beforeViolationsCache;
|
|
363
364
|
/**
|
|
364
365
|
* Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
|
|
365
366
|
* Runs `iterations` Monte Carlo trials and returns the outcome distribution.
|
package/dist/index.d.ts
CHANGED
|
@@ -360,6 +360,7 @@ declare class Observer {
|
|
|
360
360
|
|
|
361
361
|
declare class Simulator {
|
|
362
362
|
private diagnoser;
|
|
363
|
+
private beforeViolationsCache;
|
|
363
364
|
/**
|
|
364
365
|
* Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
|
|
365
366
|
* Runs `iterations` Monte Carlo trials and returns the outcome distribution.
|
package/dist/index.js
CHANGED
|
@@ -203,14 +203,38 @@ var Observer = class {
|
|
|
203
203
|
const balances = Object.values(state.agentBalances);
|
|
204
204
|
const roles = Object.values(state.agentRoles);
|
|
205
205
|
const totalAgents = balances.length;
|
|
206
|
+
let faucetVolume = 0;
|
|
207
|
+
let sinkVolume = 0;
|
|
208
|
+
const tradeEvents = [];
|
|
209
|
+
const roleChangeEvents = [];
|
|
210
|
+
let churnCount = 0;
|
|
211
|
+
for (const e of recentEvents) {
|
|
212
|
+
switch (e.type) {
|
|
213
|
+
case "mint":
|
|
214
|
+
case "spawn":
|
|
215
|
+
faucetVolume += e.amount ?? 0;
|
|
216
|
+
break;
|
|
217
|
+
case "burn":
|
|
218
|
+
case "consume":
|
|
219
|
+
sinkVolume += e.amount ?? 0;
|
|
220
|
+
break;
|
|
221
|
+
case "trade":
|
|
222
|
+
tradeEvents.push(e);
|
|
223
|
+
break;
|
|
224
|
+
case "churn":
|
|
225
|
+
churnCount++;
|
|
226
|
+
roleChangeEvents.push(e);
|
|
227
|
+
break;
|
|
228
|
+
case "role_change":
|
|
229
|
+
roleChangeEvents.push(e);
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
206
233
|
const totalSupply = balances.reduce((s, b) => s + b, 0);
|
|
207
|
-
const faucetVolume = recentEvents.filter((e) => e.type === "mint" || e.type === "spawn").reduce((s, e) => s + (e.amount ?? 0), 0);
|
|
208
|
-
const sinkVolume = recentEvents.filter((e) => e.type === "burn" || e.type === "consume").reduce((s, e) => s + (e.amount ?? 0), 0);
|
|
209
234
|
const netFlow = faucetVolume - sinkVolume;
|
|
210
235
|
const tapSinkRatio = sinkVolume > 0 ? faucetVolume / sinkVolume : faucetVolume > 0 ? Infinity : 1;
|
|
211
236
|
const prevSupply = this.previousMetrics?.totalSupply ?? totalSupply;
|
|
212
237
|
const inflationRate = prevSupply > 0 ? (totalSupply - prevSupply) / prevSupply : 0;
|
|
213
|
-
const tradeEvents = recentEvents.filter((e) => e.type === "trade");
|
|
214
238
|
const velocity = totalSupply > 0 ? tradeEvents.length / totalSupply : 0;
|
|
215
239
|
const sortedBalances = [...balances].sort((a, b) => a - b);
|
|
216
240
|
const meanBalance = totalAgents > 0 ? totalSupply / totalAgents : 0;
|
|
@@ -229,12 +253,10 @@ var Observer = class {
|
|
|
229
253
|
roleShares[role] = count / Math.max(1, totalAgents);
|
|
230
254
|
}
|
|
231
255
|
const churnByRole = {};
|
|
232
|
-
|
|
233
|
-
for (const e of roleChanges) {
|
|
256
|
+
for (const e of roleChangeEvents) {
|
|
234
257
|
const role = e.role ?? "unknown";
|
|
235
258
|
churnByRole[role] = (churnByRole[role] ?? 0) + 1;
|
|
236
259
|
}
|
|
237
|
-
const churnCount = recentEvents.filter((e) => e.type === "churn").length;
|
|
238
260
|
const churnRate = churnCount / Math.max(1, totalAgents);
|
|
239
261
|
const prices = { ...state.marketPrices };
|
|
240
262
|
const priceVolatility = {};
|
|
@@ -297,7 +319,8 @@ var Observer = class {
|
|
|
297
319
|
for (let j = i + 1; j < priceKeys.length; j++) {
|
|
298
320
|
const pA = prices[priceKeys[i]];
|
|
299
321
|
const pB = prices[priceKeys[j]];
|
|
300
|
-
|
|
322
|
+
let ratio = pA / pB;
|
|
323
|
+
ratio = Math.max(1e-3, Math.min(1e3, ratio));
|
|
301
324
|
totalDivergence += Math.abs(Math.log(ratio));
|
|
302
325
|
pairCount++;
|
|
303
326
|
}
|
|
@@ -1666,7 +1689,7 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1666
1689
|
magnitude: 0.1,
|
|
1667
1690
|
reasoning: `Only ${(convergenceRate * 100).toFixed(0)}% of ${relativePriceCount} relative prices have converged (target: ${(thresholds.relativePriceConvergenceTarget * 100).toFixed(0)}%). Price space too complex for distributed discovery. Lower friction to help.`
|
|
1668
1691
|
},
|
|
1669
|
-
confidence: 0.
|
|
1692
|
+
confidence: 0.55,
|
|
1670
1693
|
estimatedLag: thresholds.priceDiscoveryWindowTicks
|
|
1671
1694
|
};
|
|
1672
1695
|
}
|
|
@@ -1752,7 +1775,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1752
1775
|
magnitude: 0.15,
|
|
1753
1776
|
reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} exceeds critical threshold (${thresholds.arbitrageIndexCritical}). Relative prices are diverging \u2014 economy destabilizing. Lower trading friction to accelerate price convergence.`
|
|
1754
1777
|
},
|
|
1755
|
-
confidence: 0.
|
|
1778
|
+
confidence: 0.75,
|
|
1756
1779
|
estimatedLag: 8
|
|
1757
1780
|
};
|
|
1758
1781
|
}
|
|
@@ -2499,7 +2522,7 @@ var P56_ContentDropShock = {
|
|
|
2499
2522
|
magnitude: 0.1,
|
|
2500
2523
|
reasoning: `Content drop ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-drop max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
|
|
2501
2524
|
},
|
|
2502
|
-
confidence: 0.
|
|
2525
|
+
confidence: 0.6,
|
|
2503
2526
|
estimatedLag: 5
|
|
2504
2527
|
};
|
|
2505
2528
|
}
|
|
@@ -2553,6 +2576,7 @@ var ALL_PRINCIPLES = [
|
|
|
2553
2576
|
var Simulator = class {
|
|
2554
2577
|
constructor() {
|
|
2555
2578
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
2579
|
+
this.beforeViolationsCache = /* @__PURE__ */ new Map();
|
|
2556
2580
|
}
|
|
2557
2581
|
/**
|
|
2558
2582
|
* Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
|
|
@@ -2575,9 +2599,14 @@ var Simulator = class {
|
|
|
2575
2599
|
const p90 = sorted[Math.floor(actualIterations * 0.9)] ?? emptyMetrics();
|
|
2576
2600
|
const mean = this.averageMetrics(outcomes);
|
|
2577
2601
|
const netImprovement = this.checkImprovement(currentMetrics, p50, action);
|
|
2578
|
-
const
|
|
2579
|
-
|
|
2580
|
-
)
|
|
2602
|
+
const tick = currentMetrics.tick;
|
|
2603
|
+
let beforeViolations = this.beforeViolationsCache.get(tick);
|
|
2604
|
+
if (!beforeViolations) {
|
|
2605
|
+
beforeViolations = new Set(
|
|
2606
|
+
this.diagnoser.diagnose(currentMetrics, thresholds).map((d) => d.principle.id)
|
|
2607
|
+
);
|
|
2608
|
+
this.beforeViolationsCache.set(tick, beforeViolations);
|
|
2609
|
+
}
|
|
2581
2610
|
const afterViolations = new Set(
|
|
2582
2611
|
this.diagnoser.diagnose(p50, thresholds).map((d) => d.principle.id)
|
|
2583
2612
|
);
|