@agent-e/core 1.5.4 → 1.5.6

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 CHANGED
@@ -363,7 +363,7 @@ interface AgentEConfig {
363
363
  onAlert?: (diagnosis: Diagnosis) => void;
364
364
  onRollback?: (plan: ActionPlan, reason: string) => void;
365
365
  }
366
- type PersonaType = 'Active' | 'Trader' | 'Collector' | 'Speculator' | 'Earner' | 'Builder' | 'Social' | 'HighValue' | 'Influencer' | string;
366
+ type PersonaType = 'Whale' | 'ActiveTrader' | 'Accumulator' | 'Spender' | 'NewEntrant' | 'AtRisk' | 'Dormant' | 'PowerUser' | 'Passive' | string;
367
367
  interface PersonaProfile {
368
368
  type: PersonaType;
369
369
  share: number;
@@ -596,14 +596,36 @@ declare class Executor {
596
596
  getActivePlans(): ActionPlan[];
597
597
  }
598
598
 
599
+ interface PersonaConfig {
600
+ /** Top X% by holdings = Whale. Default: 0.05 (5%) */
601
+ whalePercentile: number;
602
+ /** Top X% by tx frequency = Active Trader. Default: 0.20 (20%) */
603
+ activeTraderPercentile: number;
604
+ /** Ticks to consider an agent "new." Default: 10 */
605
+ newEntrantWindow: number;
606
+ /** Ticks with zero activity = Dormant. Default: 20 */
607
+ dormantWindow: number;
608
+ /** Activity drop threshold for At-Risk. Default: 0.5 (50% drop) */
609
+ atRiskDropThreshold: number;
610
+ /** Min distinct systems for Power User. Default: 3 */
611
+ powerUserMinSystems: number;
612
+ /** Rolling history window size (ticks). Default: 50 */
613
+ historyWindow: number;
614
+ }
599
615
  declare class PersonaTracker {
600
- private agentHistory;
601
- private lastSeen;
602
- /** Ingest a state snapshot and update agent signal history */
603
- update(state: EconomyState): void;
604
- /** Classify all agents and return persona distribution */
616
+ private agents;
617
+ private config;
618
+ constructor(config?: Partial<PersonaConfig>);
619
+ /**
620
+ * Ingest a state snapshot + events and update per-agent signals.
621
+ * Call this once per tick BEFORE getDistribution().
622
+ */
623
+ update(state: EconomyState, events?: EconomicEvent[]): void;
624
+ /**
625
+ * Classify all tracked agents and return the population distribution.
626
+ * Returns { Whale: 0.05, ActiveTrader: 0.18, Passive: 0.42, ... }
627
+ */
605
628
  getDistribution(): Record<string, number>;
606
- private classify;
607
629
  }
608
630
 
609
631
  /**
@@ -736,4 +758,4 @@ declare const OPERATIONS_PRINCIPLES: Principle[];
736
758
  /** All 60 built-in principles in priority order (supply chain → operations) */
737
759
  declare const ALL_PRINCIPLES: Principle[];
738
760
 
739
- export { ALL_PRINCIPLES, type ActionPlan, AgentE, type AgentEConfig, type AgentEMode, BOOTSTRAP_PRINCIPLES, CURRENCY_FLOW_PRINCIPLES, DEFAULT_THRESHOLDS, type DecisionEntry, DecisionLog, type DecisionResult, Diagnoser, type Diagnosis, type EconomicEvent, type EconomicEventType, type EconomyAdapter, type EconomyMetrics, type EconomyState, type ExecutionResult, Executor, FEEDBACK_LOOP_PRINCIPLES, type FlowImpact, INCENTIVE_PRINCIPLES, MARKET_DYNAMICS_PRINCIPLES, MEASUREMENT_PRINCIPLES, type MetricQuery, type MetricQueryResult, type MetricResolution, MetricStore, OPEN_ECONOMY_PRINCIPLES, OPERATIONS_PRINCIPLES, Observer, P10_EntryWeightingUsesInversePopulation, P11_TwoTierPressure, P12_OnePrimaryFaucet, P13_PotsAreZeroSumAndSelfRegulate, P14_TrackActualInjection, P15_PoolsNeedCapAndDecay, P16_WithdrawalPenaltyScales, P17_GracePeriodBeforeIntervention, P18_FirstProducerNeedsStartingInventory, P19_StartingSupplyExceedsDemand, P1_ProductionMatchesConsumption, P20_DecayPreventsAccumulation, P21_PriceFromGlobalSupply, P22_MarketAwarenessPreventsSurplus, P23_ProfitabilityFactorsFeasibility, P24_BlockedAgentsDecayFaster, P25_CorrectLeversForCorrectProblems, P26_ContinuousPressureBeatsThresholdCuts, P27_AdjustmentsNeedCooldowns, P28_StructuralDominanceIsNotPathological, P29_BottleneckDetection, P2_ClosedLoopsNeedDirectHandoff, P30_DynamicBottleneckRotation, P31_AnchorValueTracking, P32_VelocityAboveSupply, P33_FairNotEqual, P34_ExtractionRatio, P35_DestructionCreatesValue, P36_MechanicFrictionDetector, P37_LatecommerProblem, P38_CommunicationPreventsRevolt, P39_TheLagPrinciple, P3_BootstrapCapitalCoversFirstTransaction, P40_ReplacementRate, P41_MultiResolutionMonitoring, P42_TheMedianPrinciple, P43_SimulationMinimum, P44_ComplexityBudget, P45_TimeBudget, P46_PersonaDiversity, P47_SmokeTest, P48_CurrencyInsulation, P49_IdleAssetTax, P4_MaterialsFlowFasterThanCooldown, P50_PayPowerRatio, P51_CyclicalEngagement, P52_EndowmentEffect, P53_EventCompletionRate, P54_OperationalCadence, P55_ArbitrageThermometer, P56_SupplyShockAbsorption, P57_CombinatorialPriceSpace, P58_NoNaturalNumeraire, P59_GiftEconomyNoise, P5_ProfitabilityIsRelative, P60_SurplusDisposalAsymmetry, P6_CrowdingMultiplierOnAllRoles, P7_NonSpecialistsSubsidiseSpecialists, P8_RegulatorCannotFightDesign, P9_RoleSwitchingNeedsFriction, PARTICIPANT_EXPERIENCE_PRINCIPLES, PERSONA_HEALTHY_RANGES, POPULATION_PRINCIPLES, ParameterRegistry, type ParameterScope, type ParameterType, type PersonaProfile, PersonaTracker, type PersonaType, type PinchPointStatus, Planner, type Principle, type PrincipleCategory, type PrincipleOk, type PrincipleResult, type PrincipleViolation, REGULATOR_PRINCIPLES, RESOURCE_MGMT_PRINCIPLES, type RegisteredParameter, type RegistryValidationResult, type RollbackCondition, STATISTICAL_PRINCIPLES, SUPPLY_CHAIN_PRINCIPLES, SYSTEM_DYNAMICS_PRINCIPLES, type SimulationConfig, type SimulationOutcome, type SimulationResult, Simulator, type SuggestedAction, type Thresholds, type TickConfig, type ValidationError, type ValidationResult, type ValidationWarning, emptyMetrics, findWorstSystem, validateEconomyState };
761
+ export { ALL_PRINCIPLES, type ActionPlan, AgentE, type AgentEConfig, type AgentEMode, BOOTSTRAP_PRINCIPLES, CURRENCY_FLOW_PRINCIPLES, DEFAULT_THRESHOLDS, type DecisionEntry, DecisionLog, type DecisionResult, Diagnoser, type Diagnosis, type EconomicEvent, type EconomicEventType, type EconomyAdapter, type EconomyMetrics, type EconomyState, type ExecutionResult, Executor, FEEDBACK_LOOP_PRINCIPLES, type FlowImpact, INCENTIVE_PRINCIPLES, MARKET_DYNAMICS_PRINCIPLES, MEASUREMENT_PRINCIPLES, type MetricQuery, type MetricQueryResult, type MetricResolution, MetricStore, OPEN_ECONOMY_PRINCIPLES, OPERATIONS_PRINCIPLES, Observer, P10_EntryWeightingUsesInversePopulation, P11_TwoTierPressure, P12_OnePrimaryFaucet, P13_PotsAreZeroSumAndSelfRegulate, P14_TrackActualInjection, P15_PoolsNeedCapAndDecay, P16_WithdrawalPenaltyScales, P17_GracePeriodBeforeIntervention, P18_FirstProducerNeedsStartingInventory, P19_StartingSupplyExceedsDemand, P1_ProductionMatchesConsumption, P20_DecayPreventsAccumulation, P21_PriceFromGlobalSupply, P22_MarketAwarenessPreventsSurplus, P23_ProfitabilityFactorsFeasibility, P24_BlockedAgentsDecayFaster, P25_CorrectLeversForCorrectProblems, P26_ContinuousPressureBeatsThresholdCuts, P27_AdjustmentsNeedCooldowns, P28_StructuralDominanceIsNotPathological, P29_BottleneckDetection, P2_ClosedLoopsNeedDirectHandoff, P30_DynamicBottleneckRotation, P31_AnchorValueTracking, P32_VelocityAboveSupply, P33_FairNotEqual, P34_ExtractionRatio, P35_DestructionCreatesValue, P36_MechanicFrictionDetector, P37_LatecommerProblem, P38_CommunicationPreventsRevolt, P39_TheLagPrinciple, P3_BootstrapCapitalCoversFirstTransaction, P40_ReplacementRate, P41_MultiResolutionMonitoring, P42_TheMedianPrinciple, P43_SimulationMinimum, P44_ComplexityBudget, P45_TimeBudget, P46_PersonaDiversity, P47_SmokeTest, P48_CurrencyInsulation, P49_IdleAssetTax, P4_MaterialsFlowFasterThanCooldown, P50_PayPowerRatio, P51_CyclicalEngagement, P52_EndowmentEffect, P53_EventCompletionRate, P54_OperationalCadence, P55_ArbitrageThermometer, P56_SupplyShockAbsorption, P57_CombinatorialPriceSpace, P58_NoNaturalNumeraire, P59_GiftEconomyNoise, P5_ProfitabilityIsRelative, P60_SurplusDisposalAsymmetry, P6_CrowdingMultiplierOnAllRoles, P7_NonSpecialistsSubsidiseSpecialists, P8_RegulatorCannotFightDesign, P9_RoleSwitchingNeedsFriction, PARTICIPANT_EXPERIENCE_PRINCIPLES, PERSONA_HEALTHY_RANGES, POPULATION_PRINCIPLES, ParameterRegistry, type ParameterScope, type ParameterType, type PersonaConfig, type PersonaProfile, PersonaTracker, type PersonaType, type PinchPointStatus, Planner, type Principle, type PrincipleCategory, type PrincipleOk, type PrincipleResult, type PrincipleViolation, REGULATOR_PRINCIPLES, RESOURCE_MGMT_PRINCIPLES, type RegisteredParameter, type RegistryValidationResult, type RollbackCondition, STATISTICAL_PRINCIPLES, SUPPLY_CHAIN_PRINCIPLES, SYSTEM_DYNAMICS_PRINCIPLES, type SimulationConfig, type SimulationOutcome, type SimulationResult, Simulator, type SuggestedAction, type Thresholds, type TickConfig, type ValidationError, type ValidationResult, type ValidationWarning, emptyMetrics, findWorstSystem, validateEconomyState };
package/dist/index.d.ts CHANGED
@@ -363,7 +363,7 @@ interface AgentEConfig {
363
363
  onAlert?: (diagnosis: Diagnosis) => void;
364
364
  onRollback?: (plan: ActionPlan, reason: string) => void;
365
365
  }
366
- type PersonaType = 'Active' | 'Trader' | 'Collector' | 'Speculator' | 'Earner' | 'Builder' | 'Social' | 'HighValue' | 'Influencer' | string;
366
+ type PersonaType = 'Whale' | 'ActiveTrader' | 'Accumulator' | 'Spender' | 'NewEntrant' | 'AtRisk' | 'Dormant' | 'PowerUser' | 'Passive' | string;
367
367
  interface PersonaProfile {
368
368
  type: PersonaType;
369
369
  share: number;
@@ -596,14 +596,36 @@ declare class Executor {
596
596
  getActivePlans(): ActionPlan[];
597
597
  }
598
598
 
599
+ interface PersonaConfig {
600
+ /** Top X% by holdings = Whale. Default: 0.05 (5%) */
601
+ whalePercentile: number;
602
+ /** Top X% by tx frequency = Active Trader. Default: 0.20 (20%) */
603
+ activeTraderPercentile: number;
604
+ /** Ticks to consider an agent "new." Default: 10 */
605
+ newEntrantWindow: number;
606
+ /** Ticks with zero activity = Dormant. Default: 20 */
607
+ dormantWindow: number;
608
+ /** Activity drop threshold for At-Risk. Default: 0.5 (50% drop) */
609
+ atRiskDropThreshold: number;
610
+ /** Min distinct systems for Power User. Default: 3 */
611
+ powerUserMinSystems: number;
612
+ /** Rolling history window size (ticks). Default: 50 */
613
+ historyWindow: number;
614
+ }
599
615
  declare class PersonaTracker {
600
- private agentHistory;
601
- private lastSeen;
602
- /** Ingest a state snapshot and update agent signal history */
603
- update(state: EconomyState): void;
604
- /** Classify all agents and return persona distribution */
616
+ private agents;
617
+ private config;
618
+ constructor(config?: Partial<PersonaConfig>);
619
+ /**
620
+ * Ingest a state snapshot + events and update per-agent signals.
621
+ * Call this once per tick BEFORE getDistribution().
622
+ */
623
+ update(state: EconomyState, events?: EconomicEvent[]): void;
624
+ /**
625
+ * Classify all tracked agents and return the population distribution.
626
+ * Returns { Whale: 0.05, ActiveTrader: 0.18, Passive: 0.42, ... }
627
+ */
605
628
  getDistribution(): Record<string, number>;
606
- private classify;
607
629
  }
608
630
 
609
631
  /**
@@ -736,4 +758,4 @@ declare const OPERATIONS_PRINCIPLES: Principle[];
736
758
  /** All 60 built-in principles in priority order (supply chain → operations) */
737
759
  declare const ALL_PRINCIPLES: Principle[];
738
760
 
739
- export { ALL_PRINCIPLES, type ActionPlan, AgentE, type AgentEConfig, type AgentEMode, BOOTSTRAP_PRINCIPLES, CURRENCY_FLOW_PRINCIPLES, DEFAULT_THRESHOLDS, type DecisionEntry, DecisionLog, type DecisionResult, Diagnoser, type Diagnosis, type EconomicEvent, type EconomicEventType, type EconomyAdapter, type EconomyMetrics, type EconomyState, type ExecutionResult, Executor, FEEDBACK_LOOP_PRINCIPLES, type FlowImpact, INCENTIVE_PRINCIPLES, MARKET_DYNAMICS_PRINCIPLES, MEASUREMENT_PRINCIPLES, type MetricQuery, type MetricQueryResult, type MetricResolution, MetricStore, OPEN_ECONOMY_PRINCIPLES, OPERATIONS_PRINCIPLES, Observer, P10_EntryWeightingUsesInversePopulation, P11_TwoTierPressure, P12_OnePrimaryFaucet, P13_PotsAreZeroSumAndSelfRegulate, P14_TrackActualInjection, P15_PoolsNeedCapAndDecay, P16_WithdrawalPenaltyScales, P17_GracePeriodBeforeIntervention, P18_FirstProducerNeedsStartingInventory, P19_StartingSupplyExceedsDemand, P1_ProductionMatchesConsumption, P20_DecayPreventsAccumulation, P21_PriceFromGlobalSupply, P22_MarketAwarenessPreventsSurplus, P23_ProfitabilityFactorsFeasibility, P24_BlockedAgentsDecayFaster, P25_CorrectLeversForCorrectProblems, P26_ContinuousPressureBeatsThresholdCuts, P27_AdjustmentsNeedCooldowns, P28_StructuralDominanceIsNotPathological, P29_BottleneckDetection, P2_ClosedLoopsNeedDirectHandoff, P30_DynamicBottleneckRotation, P31_AnchorValueTracking, P32_VelocityAboveSupply, P33_FairNotEqual, P34_ExtractionRatio, P35_DestructionCreatesValue, P36_MechanicFrictionDetector, P37_LatecommerProblem, P38_CommunicationPreventsRevolt, P39_TheLagPrinciple, P3_BootstrapCapitalCoversFirstTransaction, P40_ReplacementRate, P41_MultiResolutionMonitoring, P42_TheMedianPrinciple, P43_SimulationMinimum, P44_ComplexityBudget, P45_TimeBudget, P46_PersonaDiversity, P47_SmokeTest, P48_CurrencyInsulation, P49_IdleAssetTax, P4_MaterialsFlowFasterThanCooldown, P50_PayPowerRatio, P51_CyclicalEngagement, P52_EndowmentEffect, P53_EventCompletionRate, P54_OperationalCadence, P55_ArbitrageThermometer, P56_SupplyShockAbsorption, P57_CombinatorialPriceSpace, P58_NoNaturalNumeraire, P59_GiftEconomyNoise, P5_ProfitabilityIsRelative, P60_SurplusDisposalAsymmetry, P6_CrowdingMultiplierOnAllRoles, P7_NonSpecialistsSubsidiseSpecialists, P8_RegulatorCannotFightDesign, P9_RoleSwitchingNeedsFriction, PARTICIPANT_EXPERIENCE_PRINCIPLES, PERSONA_HEALTHY_RANGES, POPULATION_PRINCIPLES, ParameterRegistry, type ParameterScope, type ParameterType, type PersonaProfile, PersonaTracker, type PersonaType, type PinchPointStatus, Planner, type Principle, type PrincipleCategory, type PrincipleOk, type PrincipleResult, type PrincipleViolation, REGULATOR_PRINCIPLES, RESOURCE_MGMT_PRINCIPLES, type RegisteredParameter, type RegistryValidationResult, type RollbackCondition, STATISTICAL_PRINCIPLES, SUPPLY_CHAIN_PRINCIPLES, SYSTEM_DYNAMICS_PRINCIPLES, type SimulationConfig, type SimulationOutcome, type SimulationResult, Simulator, type SuggestedAction, type Thresholds, type TickConfig, type ValidationError, type ValidationResult, type ValidationWarning, emptyMetrics, findWorstSystem, validateEconomyState };
761
+ export { ALL_PRINCIPLES, type ActionPlan, AgentE, type AgentEConfig, type AgentEMode, BOOTSTRAP_PRINCIPLES, CURRENCY_FLOW_PRINCIPLES, DEFAULT_THRESHOLDS, type DecisionEntry, DecisionLog, type DecisionResult, Diagnoser, type Diagnosis, type EconomicEvent, type EconomicEventType, type EconomyAdapter, type EconomyMetrics, type EconomyState, type ExecutionResult, Executor, FEEDBACK_LOOP_PRINCIPLES, type FlowImpact, INCENTIVE_PRINCIPLES, MARKET_DYNAMICS_PRINCIPLES, MEASUREMENT_PRINCIPLES, type MetricQuery, type MetricQueryResult, type MetricResolution, MetricStore, OPEN_ECONOMY_PRINCIPLES, OPERATIONS_PRINCIPLES, Observer, P10_EntryWeightingUsesInversePopulation, P11_TwoTierPressure, P12_OnePrimaryFaucet, P13_PotsAreZeroSumAndSelfRegulate, P14_TrackActualInjection, P15_PoolsNeedCapAndDecay, P16_WithdrawalPenaltyScales, P17_GracePeriodBeforeIntervention, P18_FirstProducerNeedsStartingInventory, P19_StartingSupplyExceedsDemand, P1_ProductionMatchesConsumption, P20_DecayPreventsAccumulation, P21_PriceFromGlobalSupply, P22_MarketAwarenessPreventsSurplus, P23_ProfitabilityFactorsFeasibility, P24_BlockedAgentsDecayFaster, P25_CorrectLeversForCorrectProblems, P26_ContinuousPressureBeatsThresholdCuts, P27_AdjustmentsNeedCooldowns, P28_StructuralDominanceIsNotPathological, P29_BottleneckDetection, P2_ClosedLoopsNeedDirectHandoff, P30_DynamicBottleneckRotation, P31_AnchorValueTracking, P32_VelocityAboveSupply, P33_FairNotEqual, P34_ExtractionRatio, P35_DestructionCreatesValue, P36_MechanicFrictionDetector, P37_LatecommerProblem, P38_CommunicationPreventsRevolt, P39_TheLagPrinciple, P3_BootstrapCapitalCoversFirstTransaction, P40_ReplacementRate, P41_MultiResolutionMonitoring, P42_TheMedianPrinciple, P43_SimulationMinimum, P44_ComplexityBudget, P45_TimeBudget, P46_PersonaDiversity, P47_SmokeTest, P48_CurrencyInsulation, P49_IdleAssetTax, P4_MaterialsFlowFasterThanCooldown, P50_PayPowerRatio, P51_CyclicalEngagement, P52_EndowmentEffect, P53_EventCompletionRate, P54_OperationalCadence, P55_ArbitrageThermometer, P56_SupplyShockAbsorption, P57_CombinatorialPriceSpace, P58_NoNaturalNumeraire, P59_GiftEconomyNoise, P5_ProfitabilityIsRelative, P60_SurplusDisposalAsymmetry, P6_CrowdingMultiplierOnAllRoles, P7_NonSpecialistsSubsidiseSpecialists, P8_RegulatorCannotFightDesign, P9_RoleSwitchingNeedsFriction, PARTICIPANT_EXPERIENCE_PRINCIPLES, PERSONA_HEALTHY_RANGES, POPULATION_PRINCIPLES, ParameterRegistry, type ParameterScope, type ParameterType, type PersonaConfig, type PersonaProfile, PersonaTracker, type PersonaType, type PinchPointStatus, Planner, type Principle, type PrincipleCategory, type PrincipleOk, type PrincipleResult, type PrincipleViolation, REGULATOR_PRINCIPLES, RESOURCE_MGMT_PRINCIPLES, type RegisteredParameter, type RegistryValidationResult, type RollbackCondition, STATISTICAL_PRINCIPLES, SUPPLY_CHAIN_PRINCIPLES, SYSTEM_DYNAMICS_PRINCIPLES, type SimulationConfig, type SimulationOutcome, type SimulationResult, Simulator, type SuggestedAction, type Thresholds, type TickConfig, type ValidationError, type ValidationResult, type ValidationWarning, emptyMetrics, findWorstSystem, validateEconomyState };
package/dist/index.js CHANGED
@@ -3600,86 +3600,152 @@ var MetricStore = class {
3600
3600
  };
3601
3601
 
3602
3602
  // src/PersonaTracker.ts
3603
+ var DEFAULT_PERSONA_CONFIG = {
3604
+ whalePercentile: 0.05,
3605
+ activeTraderPercentile: 0.2,
3606
+ newEntrantWindow: 10,
3607
+ dormantWindow: 20,
3608
+ atRiskDropThreshold: 0.5,
3609
+ powerUserMinSystems: 3,
3610
+ historyWindow: 50
3611
+ };
3603
3612
  var PersonaTracker = class {
3604
- constructor() {
3605
- this.agentHistory = /* @__PURE__ */ new Map();
3606
- this.lastSeen = /* @__PURE__ */ new Map();
3613
+ constructor(config) {
3614
+ this.agents = /* @__PURE__ */ new Map();
3615
+ this.config = { ...DEFAULT_PERSONA_CONFIG, ...config };
3607
3616
  }
3608
- /** Ingest a state snapshot and update agent signal history */
3609
- update(state) {
3617
+ /**
3618
+ * Ingest a state snapshot + events and update per-agent signals.
3619
+ * Call this once per tick BEFORE getDistribution().
3620
+ */
3621
+ update(state, events) {
3610
3622
  const tick = state.tick;
3611
- for (const agentId of Object.keys(state.agentBalances)) {
3612
- this.lastSeen.set(agentId, tick);
3613
- const history = this.agentHistory.get(agentId) ?? [];
3614
- const inv = state.agentInventories[agentId] ?? {};
3615
- const uniqueItems = Object.values(inv).filter((q) => q > 0).length;
3616
- history.push({
3617
- transactionCount: 0,
3618
- // would be computed from events in full impl
3619
- netExtraction: 0,
3620
- // gold out vs in
3621
- uniqueItemsHeld: uniqueItems,
3622
- holdingDuration: 1,
3623
- spendAmount: 0,
3624
- sessionActivity: 1,
3625
- socialInteractions: 0
3626
- });
3627
- if (history.length > 50) history.shift();
3628
- this.agentHistory.set(agentId, history);
3629
- }
3630
- if (tick % 50 === 0) {
3631
- for (const [id, lastTick] of this.lastSeen) {
3632
- if (tick - lastTick > 100) {
3633
- this.agentHistory.delete(id);
3634
- this.lastSeen.delete(id);
3623
+ const txByAgent = /* @__PURE__ */ new Map();
3624
+ if (events) {
3625
+ for (const e of events) {
3626
+ const agents = [e.actor];
3627
+ if (e.from) agents.push(e.from);
3628
+ if (e.to) agents.push(e.to);
3629
+ for (const id of agents) {
3630
+ if (!id) continue;
3631
+ const entry = txByAgent.get(id) ?? { count: 0, volume: 0, systems: /* @__PURE__ */ new Set() };
3632
+ entry.count++;
3633
+ entry.volume += e.amount ?? 0;
3634
+ if (e.system) entry.systems.add(e.system);
3635
+ txByAgent.set(id, entry);
3636
+ }
3637
+ }
3638
+ }
3639
+ for (const [agentId, balances] of Object.entries(state.agentBalances)) {
3640
+ const totalHoldings = Object.values(balances).reduce((s, v) => s + v, 0);
3641
+ const tx = txByAgent.get(agentId);
3642
+ const record = this.agents.get(agentId) ?? {
3643
+ firstSeen: tick,
3644
+ lastActive: tick,
3645
+ snapshots: [],
3646
+ previousTxRate: 0
3647
+ };
3648
+ const snapshot = {
3649
+ totalHoldings,
3650
+ txCount: tx?.count ?? 0,
3651
+ txVolume: tx?.volume ?? 0,
3652
+ systems: tx?.systems ?? /* @__PURE__ */ new Set()
3653
+ };
3654
+ record.snapshots.push(snapshot);
3655
+ if (record.snapshots.length > this.config.historyWindow) {
3656
+ const oldHalf = record.snapshots.slice(0, Math.floor(record.snapshots.length / 2));
3657
+ record.previousTxRate = oldHalf.reduce((s, sn) => s + sn.txCount, 0) / Math.max(1, oldHalf.length);
3658
+ record.snapshots = record.snapshots.slice(-this.config.historyWindow);
3659
+ }
3660
+ if ((tx?.count ?? 0) > 0) {
3661
+ record.lastActive = tick;
3662
+ }
3663
+ this.agents.set(agentId, record);
3664
+ }
3665
+ const pruneThreshold = this.config.dormantWindow * 2;
3666
+ if (tick % this.config.dormantWindow === 0) {
3667
+ for (const [id, rec] of this.agents) {
3668
+ if (tick - rec.lastActive > pruneThreshold && !(id in state.agentBalances)) {
3669
+ this.agents.delete(id);
3635
3670
  }
3636
3671
  }
3637
3672
  }
3638
3673
  }
3639
- /** Classify all agents and return persona distribution */
3674
+ /**
3675
+ * Classify all tracked agents and return the population distribution.
3676
+ * Returns { Whale: 0.05, ActiveTrader: 0.18, Passive: 0.42, ... }
3677
+ */
3640
3678
  getDistribution() {
3641
- const counts = {
3642
- Active: 0,
3643
- Trader: 0,
3644
- Collector: 0,
3645
- Speculator: 0,
3646
- Earner: 0,
3647
- Builder: 0,
3648
- Social: 0,
3649
- HighValue: 0,
3650
- Influencer: 0
3651
- };
3652
- let total = 0;
3653
- for (const [, history] of this.agentHistory) {
3654
- const persona = this.classify(history);
3679
+ const agentIds = [...this.agents.keys()];
3680
+ const total = agentIds.length;
3681
+ if (total === 0) return {};
3682
+ const holdings = agentIds.map((id) => {
3683
+ const rec = this.agents.get(id);
3684
+ const latest = rec.snapshots[rec.snapshots.length - 1];
3685
+ return latest?.totalHoldings ?? 0;
3686
+ }).sort((a, b) => a - b);
3687
+ const whaleThreshold = percentile(holdings, 1 - this.config.whalePercentile);
3688
+ const txRates = agentIds.map((id) => {
3689
+ const rec = this.agents.get(id);
3690
+ return rec.snapshots.reduce((s, sn) => s + sn.txCount, 0) / Math.max(1, rec.snapshots.length);
3691
+ }).sort((a, b) => a - b);
3692
+ const activeTraderThreshold = percentile(txRates, 1 - this.config.activeTraderPercentile);
3693
+ const medianTxRate = percentile(txRates, 0.5);
3694
+ const counts = {};
3695
+ const currentTick = Math.max(...agentIds.map((id) => this.agents.get(id).lastActive), 0);
3696
+ for (let i = 0; i < agentIds.length; i++) {
3697
+ const id = agentIds[i];
3698
+ const rec = this.agents.get(id);
3699
+ const snaps = rec.snapshots;
3700
+ if (snaps.length === 0) continue;
3701
+ const latestHoldings = snaps[snaps.length - 1].totalHoldings;
3702
+ const agentTxRate = txRates[i];
3703
+ const ticksSinceFirst = currentTick - rec.firstSeen;
3704
+ const ticksSinceActive = currentTick - rec.lastActive;
3705
+ const halfIdx = Math.floor(snaps.length / 2);
3706
+ const earlyAvg = snaps.slice(0, Math.max(1, halfIdx)).reduce((s, sn) => s + sn.totalHoldings, 0) / Math.max(1, halfIdx);
3707
+ const lateAvg = snaps.slice(halfIdx).reduce((s, sn) => s + sn.totalHoldings, 0) / Math.max(1, snaps.length - halfIdx);
3708
+ const balanceDelta = lateAvg - earlyAvg;
3709
+ const allSystems = /* @__PURE__ */ new Set();
3710
+ for (const sn of snaps) {
3711
+ for (const sys of sn.systems) allSystems.add(sys);
3712
+ }
3713
+ const recentSnaps = snaps.slice(-Math.min(10, snaps.length));
3714
+ const recentTxRate = recentSnaps.reduce((s, sn) => s + sn.txCount, 0) / Math.max(1, recentSnaps.length);
3715
+ let persona;
3716
+ if (ticksSinceFirst <= this.config.newEntrantWindow) {
3717
+ persona = "NewEntrant";
3718
+ } else if (latestHoldings > 0 && ticksSinceActive > this.config.dormantWindow) {
3719
+ persona = "Dormant";
3720
+ } else if (rec.previousTxRate > 0 && recentTxRate < rec.previousTxRate * (1 - this.config.atRiskDropThreshold)) {
3721
+ persona = "AtRisk";
3722
+ } else if (latestHoldings >= whaleThreshold && whaleThreshold > 0) {
3723
+ persona = "Whale";
3724
+ } else if (allSystems.size >= this.config.powerUserMinSystems) {
3725
+ persona = "PowerUser";
3726
+ } else if (agentTxRate >= activeTraderThreshold && activeTraderThreshold > 0) {
3727
+ persona = "ActiveTrader";
3728
+ } else if (balanceDelta > 0 && agentTxRate < medianTxRate) {
3729
+ persona = "Accumulator";
3730
+ } else if (balanceDelta < 0 && agentTxRate >= medianTxRate) {
3731
+ persona = "Spender";
3732
+ } else {
3733
+ persona = "Passive";
3734
+ }
3655
3735
  counts[persona] = (counts[persona] ?? 0) + 1;
3656
- total++;
3657
3736
  }
3658
- if (total === 0) return {};
3659
3737
  const distribution = {};
3660
3738
  for (const [persona, count] of Object.entries(counts)) {
3661
3739
  distribution[persona] = count / total;
3662
3740
  }
3663
3741
  return distribution;
3664
3742
  }
3665
- classify(history) {
3666
- if (history.length === 0) return "Active";
3667
- const avg = (key) => {
3668
- const vals = history.map((h) => h[key]);
3669
- return vals.reduce((s, v) => s + v, 0) / vals.length;
3670
- };
3671
- const txRate = avg("transactionCount");
3672
- const extraction = avg("netExtraction");
3673
- const uniqueItems = avg("uniqueItemsHeld");
3674
- const spend = avg("spendAmount");
3675
- if (spend > 1e3) return "HighValue";
3676
- if (txRate > 10) return "Trader";
3677
- if (uniqueItems > 5 && extraction < 0) return "Collector";
3678
- if (extraction > 100) return "Earner";
3679
- if (extraction > 50) return "Speculator";
3680
- return "Active";
3681
- }
3682
3743
  };
3744
+ function percentile(sorted, p) {
3745
+ if (sorted.length === 0) return 0;
3746
+ const idx = Math.ceil(p * sorted.length) - 1;
3747
+ return sorted[Math.max(0, Math.min(idx, sorted.length - 1))];
3748
+ }
3683
3749
 
3684
3750
  // src/ParameterRegistry.ts
3685
3751
  var ParameterRegistry = class {
@@ -3922,7 +3988,7 @@ var AgentE = class {
3922
3988
  return;
3923
3989
  }
3924
3990
  this.store.record(metrics);
3925
- this.personaTracker.update(currentState);
3991
+ this.personaTracker.update(currentState, events);
3926
3992
  metrics.personaDistribution = this.personaTracker.getDistribution();
3927
3993
  const { rolledBack, settled } = await this.executor.checkRollbacks(metrics, this.adapter);
3928
3994
  for (const plan2 of rolledBack) {