@agent-e/core 1.6.5 → 1.6.7
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/dist/index.d.mts +784 -0
- package/dist/index.d.ts +784 -0
- package/dist/index.js +115 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -60,7 +60,9 @@ var DEFAULT_THRESHOLDS = {
|
|
|
60
60
|
relativePriceConvergenceTarget: 0.85,
|
|
61
61
|
priceDiscoveryWindowTicks: 20,
|
|
62
62
|
giftTradeFilterRatio: 0.15,
|
|
63
|
-
disposalTradeWeightDiscount: 0.5
|
|
63
|
+
disposalTradeWeightDiscount: 0.5,
|
|
64
|
+
// Structural dominance (P8)
|
|
65
|
+
dominantRoles: []
|
|
64
66
|
};
|
|
65
67
|
var PERSONA_HEALTHY_RANGES = {
|
|
66
68
|
Active: { min: 0.2, max: 0.4 },
|
|
@@ -92,7 +94,7 @@ var Observer = class {
|
|
|
92
94
|
registerCustomMetric(name, fn) {
|
|
93
95
|
this.customMetricFns[name] = fn;
|
|
94
96
|
}
|
|
95
|
-
compute(state, recentEvents) {
|
|
97
|
+
compute(state, recentEvents, personaDistribution) {
|
|
96
98
|
if (!state.currencies || state.currencies.length === 0) {
|
|
97
99
|
console.warn("[AgentE] Warning: state.currencies is empty. Metrics will be zeroed.");
|
|
98
100
|
}
|
|
@@ -245,6 +247,16 @@ var Observer = class {
|
|
|
245
247
|
for (const [role, count] of Object.entries(populationByRole)) {
|
|
246
248
|
roleShares[role] = count / Math.max(1, totalAgents);
|
|
247
249
|
}
|
|
250
|
+
const uniqueRoles = new Set(Object.values(state.agentRoles));
|
|
251
|
+
const rolesEmpty = uniqueRoles.size <= 1;
|
|
252
|
+
if (rolesEmpty && personaDistribution && Object.keys(personaDistribution).length > 0) {
|
|
253
|
+
for (const [persona, fraction] of Object.entries(personaDistribution)) {
|
|
254
|
+
populationByRole[persona] = Math.round(fraction * totalAgents);
|
|
255
|
+
}
|
|
256
|
+
for (const [role, count] of Object.entries(populationByRole)) {
|
|
257
|
+
roleShares[role] = count / Math.max(1, totalAgents);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
248
260
|
const churnByRole = {};
|
|
249
261
|
for (const e of roleChangeEvents) {
|
|
250
262
|
const role = e.role ?? "unknown";
|
|
@@ -734,25 +746,45 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
734
746
|
category: "supply_chain",
|
|
735
747
|
description: "Input delivery rate must exceed or match production cooldown rate. If producers produce every 5 ticks but only receive raw materials every 10 ticks, they starve regardless of supply levels.",
|
|
736
748
|
check(metrics, _thresholds) {
|
|
737
|
-
const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
|
|
749
|
+
const { supplyByResource, populationByRole, velocity, velocityByCurrency, totalAgents } = metrics;
|
|
738
750
|
const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
739
751
|
const avgSupplyPerAgent = totalAgents > 0 ? totalSupply / totalAgents : 0;
|
|
740
752
|
const roleEntries = Object.entries(populationByRole);
|
|
741
753
|
const totalRoles = roleEntries.length;
|
|
742
|
-
if (totalRoles >= 2 &&
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
754
|
+
if (totalRoles >= 2 && avgSupplyPerAgent < 0.5) {
|
|
755
|
+
for (const [currency, currVelocity] of Object.entries(velocityByCurrency)) {
|
|
756
|
+
if (currVelocity < 5) {
|
|
757
|
+
return {
|
|
758
|
+
violated: true,
|
|
759
|
+
severity: 5,
|
|
760
|
+
evidence: { currency, currVelocity, avgSupplyPerAgent, totalRoles },
|
|
761
|
+
suggestedAction: {
|
|
762
|
+
parameterType: "yield",
|
|
763
|
+
scope: { currency },
|
|
764
|
+
direction: "increase",
|
|
765
|
+
magnitude: 0.15,
|
|
766
|
+
reasoning: `${currency} velocity is ${currVelocity.toFixed(1)} \u2014 materials not flowing. Increase yield to compensate.`
|
|
767
|
+
},
|
|
768
|
+
confidence: 0.7,
|
|
769
|
+
estimatedLag: 8
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (Object.keys(velocityByCurrency).length === 0 && velocity < 5) {
|
|
774
|
+
return {
|
|
775
|
+
violated: true,
|
|
776
|
+
severity: 5,
|
|
777
|
+
evidence: { avgSupplyPerAgent, velocity, totalRoles },
|
|
778
|
+
suggestedAction: {
|
|
779
|
+
parameterType: "yield",
|
|
780
|
+
direction: "increase",
|
|
781
|
+
magnitude: 0.15,
|
|
782
|
+
reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
|
|
783
|
+
},
|
|
784
|
+
confidence: 0.65,
|
|
785
|
+
estimatedLag: 8
|
|
786
|
+
};
|
|
787
|
+
}
|
|
756
788
|
}
|
|
757
789
|
if (avgSupplyPerAgent > 2) {
|
|
758
790
|
return {
|
|
@@ -911,28 +943,42 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
911
943
|
id: "P8",
|
|
912
944
|
name: "Regulator Cannot Fight the Design",
|
|
913
945
|
category: "incentive",
|
|
914
|
-
description: "If
|
|
915
|
-
check(metrics,
|
|
946
|
+
description: "If a role dominates above 30%, classify as structural (in dominantRoles config) or pathological. Structural dominance gets no intervention. Pathological dominance gets crowding pressure.",
|
|
947
|
+
check(metrics, thresholds) {
|
|
916
948
|
const { roleShares, avgSatisfaction } = metrics;
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
}
|
|
933
|
-
|
|
949
|
+
const dominant = Object.entries(roleShares).sort((a, b) => b[1] - a[1])[0];
|
|
950
|
+
if (!dominant) return { violated: false };
|
|
951
|
+
const [dominantRole, dominantShare] = dominant;
|
|
952
|
+
if (dominantShare <= 0.3) return { violated: false };
|
|
953
|
+
const isStructural = thresholds.dominantRoles?.includes(dominantRole) ?? false;
|
|
954
|
+
if (isStructural) {
|
|
955
|
+
return {
|
|
956
|
+
violated: true,
|
|
957
|
+
severity: 3,
|
|
958
|
+
evidence: { role: dominantRole, share: dominantShare, classification: "structural" },
|
|
959
|
+
suggestedAction: {
|
|
960
|
+
parameterType: "rate",
|
|
961
|
+
direction: "set",
|
|
962
|
+
magnitude: 0,
|
|
963
|
+
reasoning: `${dominantRole} dominance (${(dominantShare * 100).toFixed(0)}%) is by design. No intervention.`
|
|
964
|
+
},
|
|
965
|
+
confidence: 0.85
|
|
966
|
+
};
|
|
934
967
|
}
|
|
935
|
-
return {
|
|
968
|
+
return {
|
|
969
|
+
violated: true,
|
|
970
|
+
severity: 7,
|
|
971
|
+
evidence: { role: dominantRole, share: dominantShare, classification: "pathological", avgSatisfaction },
|
|
972
|
+
suggestedAction: {
|
|
973
|
+
parameterType: "reward",
|
|
974
|
+
scope: { tags: [dominantRole] },
|
|
975
|
+
direction: "decrease",
|
|
976
|
+
magnitude: 0.1,
|
|
977
|
+
reasoning: `${dominantRole} at ${(dominantShare * 100).toFixed(0)}% is not a designed majority \u2014 apply crowding pressure.`
|
|
978
|
+
},
|
|
979
|
+
confidence: 0.7,
|
|
980
|
+
estimatedLag: 12
|
|
981
|
+
};
|
|
936
982
|
}
|
|
937
983
|
};
|
|
938
984
|
var INCENTIVE_PRINCIPLES = [
|
|
@@ -1198,7 +1244,7 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1198
1244
|
id: "P15",
|
|
1199
1245
|
name: "Pools Need Cap + Decay",
|
|
1200
1246
|
category: "currency",
|
|
1201
|
-
description: "Any pool (bank, reward pool) without a cap accumulates infinitely. A pool at 42% of total supply means 42% of the economy is frozen. Cap
|
|
1247
|
+
description: "Any pool (bank, reward pool) without a cap accumulates infinitely. A pool at 42% of total supply means 42% of the economy is frozen. Cap configurable (default 10%). Violation fires at 2\xD7 cap share of total supply.",
|
|
1202
1248
|
check(metrics, thresholds) {
|
|
1203
1249
|
const { poolCapPercent } = thresholds;
|
|
1204
1250
|
for (const [pool, currencyAmounts] of Object.entries(metrics.poolSizesByCurrency)) {
|
|
@@ -1231,7 +1277,7 @@ var P16_WithdrawalPenaltyScales = {
|
|
|
1231
1277
|
id: "P16",
|
|
1232
1278
|
name: "Withdrawal Penalty Scales with Lock Duration",
|
|
1233
1279
|
category: "currency",
|
|
1234
|
-
description: "
|
|
1280
|
+
description: "Depleted pool with estimated high staking signals early-withdrawal abuse. Symptom detector \u2014 penalty formula is developer responsibility.",
|
|
1235
1281
|
check(metrics, _thresholds) {
|
|
1236
1282
|
for (const [poolName, currencyAmounts] of Object.entries(metrics.poolSizesByCurrency)) {
|
|
1237
1283
|
for (const curr of metrics.currencies) {
|
|
@@ -1347,7 +1393,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1347
1393
|
id: "P17",
|
|
1348
1394
|
name: "Grace Period Before Intervention",
|
|
1349
1395
|
category: "bootstrap",
|
|
1350
|
-
description: "Any intervention before tick
|
|
1396
|
+
description: "Any intervention before tick 30 is premature. The economy needs time to bootstrap with designed distributions. Early intervention against designed dominance can kill the economy instantly.",
|
|
1351
1397
|
check(metrics, _thresholds) {
|
|
1352
1398
|
if (metrics.tick < 30 && metrics.avgSatisfaction < 40) {
|
|
1353
1399
|
return {
|
|
@@ -1668,7 +1714,7 @@ var P27_AdjustmentsNeedCooldowns = {
|
|
|
1668
1714
|
id: "P27",
|
|
1669
1715
|
name: "Adjustments Need Cooldowns",
|
|
1670
1716
|
category: "regulator",
|
|
1671
|
-
description: "
|
|
1717
|
+
description: "High churn + low satisfaction may indicate oscillation from rapid adjustments. Cooldown enforcement is structural (Planner). This is a symptom detector.",
|
|
1672
1718
|
check(metrics, _thresholds) {
|
|
1673
1719
|
const { churnRate, avgSatisfaction } = metrics;
|
|
1674
1720
|
if (churnRate > 0.08 && avgSatisfaction < 50) {
|
|
@@ -1725,7 +1771,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1725
1771
|
id: "P38",
|
|
1726
1772
|
name: "Communication Prevents Revolt",
|
|
1727
1773
|
category: "regulator",
|
|
1728
|
-
description: "
|
|
1774
|
+
description: "High churn may indicate unexplained changes. Logging enforcement is structural (DecisionLog). Flags high churn as signal to review recent decisions.",
|
|
1729
1775
|
check(metrics, _thresholds) {
|
|
1730
1776
|
const { churnRate } = metrics;
|
|
1731
1777
|
if (churnRate > 0.1) {
|
|
@@ -1750,7 +1796,7 @@ var REGULATOR_PRINCIPLES = [
|
|
|
1750
1796
|
P25_CorrectLeversForCorrectProblems,
|
|
1751
1797
|
P26_ContinuousPressureBeatsThresholdCuts,
|
|
1752
1798
|
P27_AdjustmentsNeedCooldowns,
|
|
1753
|
-
|
|
1799
|
+
// P28 merged into P8 (v1.6.7)
|
|
1754
1800
|
P38_CommunicationPreventsRevolt
|
|
1755
1801
|
];
|
|
1756
1802
|
|
|
@@ -2059,7 +2105,7 @@ var P43_SimulationMinimum = {
|
|
|
2059
2105
|
id: "P43",
|
|
2060
2106
|
name: "Simulation Minimum (100 Iterations)",
|
|
2061
2107
|
category: "statistical",
|
|
2062
|
-
description: "
|
|
2108
|
+
description: "Wild inflation swings (>30%) may indicate insufficient simulation data. Minimum iteration enforcement is structural (Simulator config). Symptom detector.",
|
|
2063
2109
|
check(metrics, thresholds) {
|
|
2064
2110
|
const { inflationRate } = metrics;
|
|
2065
2111
|
if (Math.abs(inflationRate) > 0.3) {
|
|
@@ -2226,7 +2272,7 @@ var P49_IdleAssetTax = {
|
|
|
2226
2272
|
id: "P49",
|
|
2227
2273
|
name: "Idle Asset Tax",
|
|
2228
2274
|
category: "resource",
|
|
2229
|
-
description:
|
|
2275
|
+
description: "Concentrated idle wealth (Gini >0.55, top 10% >60%, velocity <5). Raises transaction fees as proxy holding tax. Decay/storage/expiry requires developer implementation.",
|
|
2230
2276
|
check(metrics, _thresholds) {
|
|
2231
2277
|
const { giniCoefficient, top10PctShare, velocity } = metrics;
|
|
2232
2278
|
if (giniCoefficient > 0.55 && top10PctShare > 0.6 && velocity < 5) {
|
|
@@ -2259,7 +2305,7 @@ var P33_FairNotEqual = {
|
|
|
2259
2305
|
id: "P33",
|
|
2260
2306
|
name: "Fair \u2260 Equal",
|
|
2261
2307
|
category: "participant_experience",
|
|
2262
|
-
description: "Gini = 0 is boring \u2014 everyone has the same and there is nothing to strive for. Healthy inequality from skill/effort is fine. Inequality from money (pay-to-win) is toxic.
|
|
2308
|
+
description: "Gini = 0 is boring \u2014 everyone has the same and there is nothing to strive for. Healthy inequality from skill/effort is fine. Inequality from money (pay-to-win) is toxic. Below 0.10 Gini = too flat; above configurable thresholds = oligarchy.",
|
|
2263
2309
|
check(metrics, thresholds) {
|
|
2264
2310
|
for (const curr of metrics.currencies) {
|
|
2265
2311
|
const giniCoefficient = metrics.giniCoefficientByCurrency[curr] ?? 0;
|
|
@@ -2369,7 +2415,7 @@ var P45_TimeBudget = {
|
|
|
2369
2415
|
id: "P45",
|
|
2370
2416
|
name: "Time Budget",
|
|
2371
2417
|
category: "participant_experience",
|
|
2372
|
-
description: "
|
|
2418
|
+
description: "timeToValue > 30 with satisfaction < 55 suggests excessive time demand. Proxy metric \u2014 does not measure individual available time.",
|
|
2373
2419
|
check(metrics, thresholds) {
|
|
2374
2420
|
const { timeToValue, avgSatisfaction } = metrics;
|
|
2375
2421
|
const timePressure = timeToValue > 30;
|
|
@@ -2607,7 +2653,7 @@ var P52_EndowmentEffect = {
|
|
|
2607
2653
|
id: "P52",
|
|
2608
2654
|
name: "Endowment Effect",
|
|
2609
2655
|
category: "operations",
|
|
2610
|
-
description: "
|
|
2656
|
+
description: "High completion (>90%) + low satisfaction (<60) suggests activities not creating perceived value. May indicate missing endowment effect.",
|
|
2611
2657
|
check(metrics, _thresholds) {
|
|
2612
2658
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2613
2659
|
const { eventCompletionRate } = metrics;
|
|
@@ -2680,7 +2726,7 @@ var P54_OperationalCadence = {
|
|
|
2680
2726
|
id: "P54",
|
|
2681
2727
|
name: "Operational Cadence",
|
|
2682
2728
|
category: "operations",
|
|
2683
|
-
description: "
|
|
2729
|
+
description: "Low velocity (<2) + low satisfaction after tick 100 = supply stagnation. Advisory signal for developer to audit content freshness.",
|
|
2684
2730
|
check(metrics, _thresholds) {
|
|
2685
2731
|
const { velocity, avgSatisfaction } = metrics;
|
|
2686
2732
|
if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
|
|
@@ -3530,11 +3576,14 @@ var DEFAULT_PERSONA_CONFIG = {
|
|
|
3530
3576
|
dormantWindow: 20,
|
|
3531
3577
|
atRiskDropThreshold: 0.5,
|
|
3532
3578
|
powerUserMinSystems: 3,
|
|
3533
|
-
historyWindow: 50
|
|
3579
|
+
historyWindow: 50,
|
|
3580
|
+
reclassifyInterval: 10
|
|
3534
3581
|
};
|
|
3535
3582
|
var PersonaTracker = class {
|
|
3536
3583
|
constructor(config) {
|
|
3537
3584
|
this.agents = /* @__PURE__ */ new Map();
|
|
3585
|
+
this.cachedDistribution = {};
|
|
3586
|
+
this.lastClassifiedTick = -Infinity;
|
|
3538
3587
|
this.config = { ...DEFAULT_PERSONA_CONFIG, ...config };
|
|
3539
3588
|
}
|
|
3540
3589
|
/**
|
|
@@ -3542,6 +3591,7 @@ var PersonaTracker = class {
|
|
|
3542
3591
|
* Call this once per tick BEFORE getDistribution().
|
|
3543
3592
|
*/
|
|
3544
3593
|
update(state, events) {
|
|
3594
|
+
if (!state.agentBalances) return;
|
|
3545
3595
|
const tick = state.tick;
|
|
3546
3596
|
const txByAgent = /* @__PURE__ */ new Map();
|
|
3547
3597
|
if (events) {
|
|
@@ -3597,8 +3647,18 @@ var PersonaTracker = class {
|
|
|
3597
3647
|
/**
|
|
3598
3648
|
* Classify all tracked agents and return the population distribution.
|
|
3599
3649
|
* Returns { Whale: 0.05, ActiveTrader: 0.18, Passive: 0.42, ... }
|
|
3650
|
+
* Caches results and only reclassifies at `reclassifyInterval` boundaries.
|
|
3600
3651
|
*/
|
|
3601
|
-
getDistribution() {
|
|
3652
|
+
getDistribution(currentTick) {
|
|
3653
|
+
const tick = currentTick ?? 0;
|
|
3654
|
+
if (tick - this.lastClassifiedTick < this.config.reclassifyInterval && Object.keys(this.cachedDistribution).length > 0) {
|
|
3655
|
+
return this.cachedDistribution;
|
|
3656
|
+
}
|
|
3657
|
+
this.lastClassifiedTick = tick;
|
|
3658
|
+
this.cachedDistribution = this._classify();
|
|
3659
|
+
return this.cachedDistribution;
|
|
3660
|
+
}
|
|
3661
|
+
_classify() {
|
|
3602
3662
|
const agentIds = [...this.agents.keys()];
|
|
3603
3663
|
const total = agentIds.length;
|
|
3604
3664
|
if (total === 0) return {};
|
|
@@ -3904,16 +3964,17 @@ var AgentE = class {
|
|
|
3904
3964
|
this.currentTick = currentState.tick;
|
|
3905
3965
|
const events = this.eventBuffer;
|
|
3906
3966
|
this.eventBuffer = [];
|
|
3967
|
+
this.personaTracker.update(currentState, events);
|
|
3968
|
+
const personaDist = this.personaTracker.getDistribution(currentState.tick);
|
|
3907
3969
|
let metrics;
|
|
3908
3970
|
try {
|
|
3909
|
-
metrics = this.observer.compute(currentState, events);
|
|
3971
|
+
metrics = this.observer.compute(currentState, events, personaDist);
|
|
3910
3972
|
} catch (err) {
|
|
3911
3973
|
console.error(`[AgentE] Observer.compute() failed at tick ${currentState.tick}:`, err);
|
|
3912
3974
|
return;
|
|
3913
3975
|
}
|
|
3914
3976
|
this.store.record(metrics);
|
|
3915
|
-
|
|
3916
|
-
metrics.personaDistribution = this.personaTracker.getDistribution();
|
|
3977
|
+
metrics.personaDistribution = personaDist;
|
|
3917
3978
|
const { rolledBack, settled } = await this.executor.checkRollbacks(metrics, this.adapter);
|
|
3918
3979
|
for (const plan2 of rolledBack) {
|
|
3919
3980
|
this.planner.recordRolledBack(plan2);
|