@hazeljs/organism 2.0.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/README.md +205 -0
- package/dist/__tests__/organism.embedding.test.d.ts +2 -0
- package/dist/__tests__/organism.embedding.test.d.ts.map +1 -0
- package/dist/__tests__/organism.embedding.test.js +166 -0
- package/dist/__tests__/organism.embedding.test.js.map +1 -0
- package/dist/__tests__/organism.phase1.test.d.ts +2 -0
- package/dist/__tests__/organism.phase1.test.d.ts.map +1 -0
- package/dist/__tests__/organism.phase1.test.js +375 -0
- package/dist/__tests__/organism.phase1.test.js.map +1 -0
- package/dist/__tests__/organism.phase2-3.test.d.ts +2 -0
- package/dist/__tests__/organism.phase2-3.test.d.ts.map +1 -0
- package/dist/__tests__/organism.phase2-3.test.js +320 -0
- package/dist/__tests__/organism.phase2-3.test.js.map +1 -0
- package/dist/__tests__/organism.phase4.test.d.ts +2 -0
- package/dist/__tests__/organism.phase4.test.d.ts.map +1 -0
- package/dist/__tests__/organism.phase4.test.js +217 -0
- package/dist/__tests__/organism.phase4.test.js.map +1 -0
- package/dist/bridge/signal-bridge.d.ts +46 -0
- package/dist/bridge/signal-bridge.d.ts.map +1 -0
- package/dist/bridge/signal-bridge.js +75 -0
- package/dist/bridge/signal-bridge.js.map +1 -0
- package/dist/core/capability-registry.d.ts +16 -0
- package/dist/core/capability-registry.d.ts.map +1 -0
- package/dist/core/capability-registry.js +71 -0
- package/dist/core/capability-registry.js.map +1 -0
- package/dist/core/clock.d.ts +17 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/clock.js +63 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/mission.d.ts +4 -0
- package/dist/core/mission.d.ts.map +1 -0
- package/dist/core/mission.js +74 -0
- package/dist/core/mission.js.map +1 -0
- package/dist/core/organism-context.d.ts +139 -0
- package/dist/core/organism-context.d.ts.map +1 -0
- package/dist/core/organism-context.js +62 -0
- package/dist/core/organism-context.js.map +1 -0
- package/dist/core/organism-runtime.d.ts +199 -0
- package/dist/core/organism-runtime.d.ts.map +1 -0
- package/dist/core/organism-runtime.js +1016 -0
- package/dist/core/organism-runtime.js.map +1 -0
- package/dist/decorators/index.d.ts +39 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +165 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/economy/market-engine.d.ts +57 -0
- package/dist/economy/market-engine.d.ts.map +1 -0
- package/dist/economy/market-engine.js +258 -0
- package/dist/economy/market-engine.js.map +1 -0
- package/dist/economy/resource-allocator.d.ts +39 -0
- package/dist/economy/resource-allocator.d.ts.map +1 -0
- package/dist/economy/resource-allocator.js +153 -0
- package/dist/economy/resource-allocator.js.map +1 -0
- package/dist/economy/utility-engine.d.ts +16 -0
- package/dist/economy/utility-engine.d.ts.map +1 -0
- package/dist/economy/utility-engine.js +80 -0
- package/dist/economy/utility-engine.js.map +1 -0
- package/dist/economy/utility-forecaster.d.ts +24 -0
- package/dist/economy/utility-forecaster.d.ts.map +1 -0
- package/dist/economy/utility-forecaster.js +60 -0
- package/dist/economy/utility-forecaster.js.map +1 -0
- package/dist/errors/organism.errors.d.ts +23 -0
- package/dist/errors/organism.errors.d.ts.map +1 -0
- package/dist/errors/organism.errors.js +50 -0
- package/dist/errors/organism.errors.js.map +1 -0
- package/dist/events/organism-events.d.ts +61 -0
- package/dist/events/organism-events.d.ts.map +1 -0
- package/dist/events/organism-events.js +95 -0
- package/dist/events/organism-events.js.map +1 -0
- package/dist/evolution/evolution-engine.d.ts +41 -0
- package/dist/evolution/evolution-engine.d.ts.map +1 -0
- package/dist/evolution/evolution-engine.js +135 -0
- package/dist/evolution/evolution-engine.js.map +1 -0
- package/dist/evolution/mutation-engine.d.ts +21 -0
- package/dist/evolution/mutation-engine.d.ts.map +1 -0
- package/dist/evolution/mutation-engine.js +84 -0
- package/dist/evolution/mutation-engine.js.map +1 -0
- package/dist/genealogy/genealogy-manager.d.ts +18 -0
- package/dist/genealogy/genealogy-manager.d.ts.map +1 -0
- package/dist/genealogy/genealogy-manager.js +64 -0
- package/dist/genealogy/genealogy-manager.js.map +1 -0
- package/dist/governance/constitution.d.ts +20 -0
- package/dist/governance/constitution.d.ts.map +1 -0
- package/dist/governance/constitution.js +109 -0
- package/dist/governance/constitution.js.map +1 -0
- package/dist/host/organism-host-registry.d.ts +24 -0
- package/dist/host/organism-host-registry.d.ts.map +1 -0
- package/dist/host/organism-host-registry.js +65 -0
- package/dist/host/organism-host-registry.js.map +1 -0
- package/dist/host/organism-host.d.ts +32 -0
- package/dist/host/organism-host.d.ts.map +1 -0
- package/dist/host/organism-host.js +64 -0
- package/dist/host/organism-host.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/integration/create-ops-organism.d.ts +34 -0
- package/dist/integration/create-ops-organism.d.ts.map +1 -0
- package/dist/integration/create-ops-organism.js +43 -0
- package/dist/integration/create-ops-organism.js.map +1 -0
- package/dist/lifecycle/birth-engine.d.ts +41 -0
- package/dist/lifecycle/birth-engine.d.ts.map +1 -0
- package/dist/lifecycle/birth-engine.js +182 -0
- package/dist/lifecycle/birth-engine.js.map +1 -0
- package/dist/lifecycle/decision-engine.d.ts +19 -0
- package/dist/lifecycle/decision-engine.d.ts.map +1 -0
- package/dist/lifecycle/decision-engine.js +137 -0
- package/dist/lifecycle/decision-engine.js.map +1 -0
- package/dist/lifecycle/reproduction-engine.d.ts +58 -0
- package/dist/lifecycle/reproduction-engine.d.ts.map +1 -0
- package/dist/lifecycle/reproduction-engine.js +207 -0
- package/dist/lifecycle/reproduction-engine.js.map +1 -0
- package/dist/lifecycle/survival-engine.d.ts +17 -0
- package/dist/lifecycle/survival-engine.d.ts.map +1 -0
- package/dist/lifecycle/survival-engine.js +83 -0
- package/dist/lifecycle/survival-engine.js.map +1 -0
- package/dist/observability/metrics.d.ts +37 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +80 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/perception/perception-engine.d.ts +40 -0
- package/dist/perception/perception-engine.d.ts.map +1 -0
- package/dist/perception/perception-engine.js +126 -0
- package/dist/perception/perception-engine.js.map +1 -0
- package/dist/persistence/in-memory-organism-repository.d.ts +2 -0
- package/dist/persistence/in-memory-organism-repository.d.ts.map +1 -0
- package/dist/persistence/in-memory-organism-repository.js +18 -0
- package/dist/persistence/in-memory-organism-repository.js.map +1 -0
- package/dist/persistence/organism-repository.d.ts +42 -0
- package/dist/persistence/organism-repository.d.ts.map +1 -0
- package/dist/persistence/organism-repository.js +105 -0
- package/dist/persistence/organism-repository.js.map +1 -0
- package/dist/types/organism.types.d.ts +482 -0
- package/dist/types/organism.types.d.ts.map +1 -0
- package/dist/types/organism.types.js +45 -0
- package/dist/types/organism.types.js.map +1 -0
- package/examples/ecommerce-organism/run.ts +245 -0
- package/package.json +73 -0
- package/src/bridge/signal-bridge.ts +116 -0
- package/src/core/capability-registry.ts +72 -0
- package/src/core/clock.ts +58 -0
- package/src/core/mission.ts +83 -0
- package/src/core/organism-context.ts +176 -0
- package/src/core/organism-runtime.ts +1369 -0
- package/src/decorators/index.ts +180 -0
- package/src/economy/market-engine.ts +324 -0
- package/src/economy/resource-allocator.ts +188 -0
- package/src/economy/utility-engine.ts +103 -0
- package/src/economy/utility-forecaster.ts +88 -0
- package/src/errors/organism.errors.ts +47 -0
- package/src/events/organism-events.ts +122 -0
- package/src/evolution/evolution-engine.ts +167 -0
- package/src/evolution/mutation-engine.ts +110 -0
- package/src/genealogy/genealogy-manager.ts +70 -0
- package/src/governance/constitution.ts +120 -0
- package/src/host/organism-host-registry.ts +72 -0
- package/src/host/organism-host.ts +103 -0
- package/src/index.ts +78 -0
- package/src/integration/create-ops-organism.ts +80 -0
- package/src/lifecycle/birth-engine.ts +225 -0
- package/src/lifecycle/decision-engine.ts +158 -0
- package/src/lifecycle/reproduction-engine.ts +289 -0
- package/src/lifecycle/survival-engine.ts +95 -0
- package/src/observability/metrics.ts +120 -0
- package/src/perception/perception-engine.ts +140 -0
- package/src/persistence/in-memory-organism-repository.ts +1 -0
- package/src/persistence/organism-repository.ts +134 -0
- package/src/types/organism.types.ts +591 -0
- package/tsconfig.jest.json +8 -0
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OrganismRuntime — mission-defined self-organizing agent society control plane.
|
|
4
|
+
* Composes AgentRuntime; does not replace the Agent OS kernel.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.OrganismRuntime = void 0;
|
|
41
|
+
exports.createOrganism = createOrganism;
|
|
42
|
+
const agent_1 = require("@hazeljs/agent");
|
|
43
|
+
const organism_types_1 = require("../types/organism.types");
|
|
44
|
+
const organism_errors_1 = require("../errors/organism.errors");
|
|
45
|
+
const organism_events_1 = require("../events/organism-events");
|
|
46
|
+
const organism_repository_1 = require("../persistence/organism-repository");
|
|
47
|
+
const decorators_1 = require("../decorators");
|
|
48
|
+
const constitution_1 = require("../governance/constitution");
|
|
49
|
+
const resource_allocator_1 = require("../economy/resource-allocator");
|
|
50
|
+
const utility_engine_1 = require("../economy/utility-engine");
|
|
51
|
+
const utility_forecaster_1 = require("../economy/utility-forecaster");
|
|
52
|
+
const market_engine_1 = require("../economy/market-engine");
|
|
53
|
+
const capability_registry_1 = require("./capability-registry");
|
|
54
|
+
const perception_engine_1 = require("../perception/perception-engine");
|
|
55
|
+
const decision_engine_1 = require("../lifecycle/decision-engine");
|
|
56
|
+
const birth_engine_1 = require("../lifecycle/birth-engine");
|
|
57
|
+
const survival_engine_1 = require("../lifecycle/survival-engine");
|
|
58
|
+
const reproduction_engine_1 = require("../lifecycle/reproduction-engine");
|
|
59
|
+
const genealogy_manager_1 = require("../genealogy/genealogy-manager");
|
|
60
|
+
const mutation_engine_1 = require("../evolution/mutation-engine");
|
|
61
|
+
const evolution_engine_1 = require("../evolution/evolution-engine");
|
|
62
|
+
const mission_1 = require("./mission");
|
|
63
|
+
const organism_context_1 = require("./organism-context");
|
|
64
|
+
const clock_1 = require("./clock");
|
|
65
|
+
const metrics_1 = require("../observability/metrics");
|
|
66
|
+
class OrganismRuntime {
|
|
67
|
+
constructor(options) {
|
|
68
|
+
this.metrics = new metrics_1.OrganismMetrics();
|
|
69
|
+
this.capabilities = new capability_registry_1.CapabilityRegistry();
|
|
70
|
+
this.clock = new clock_1.OrganismClock();
|
|
71
|
+
this.cycleTimers = [];
|
|
72
|
+
this.pendingApprovals = new Map();
|
|
73
|
+
this.agentCache = new Map();
|
|
74
|
+
this.reproductionConfig = reproduction_engine_1.DEFAULT_REPRODUCTION_CONFIG;
|
|
75
|
+
this.id = options.id ?? `org_${Date.now().toString(36)}`;
|
|
76
|
+
this.events = new organism_events_1.OrganismEventEmitter();
|
|
77
|
+
this.repo = options.repository ?? new organism_repository_1.InMemoryOrganismRepository();
|
|
78
|
+
this.debug = options.debug ?? false;
|
|
79
|
+
this.log = (line) => {
|
|
80
|
+
if (this.debug || options.simulation) {
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.log(line);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
this.perception = new perception_engine_1.PerceptionEngine(options.relevanceThreshold ?? 0.3);
|
|
86
|
+
this.needDetector = new perception_engine_1.NeedDetector(options.signalNeedMappings ?? []);
|
|
87
|
+
this.decisionEngine = new decision_engine_1.DecisionEngine(this.capabilities);
|
|
88
|
+
this.allocator = new resource_allocator_1.ResourceAllocator(this.events, this.id, () => this.clock.now());
|
|
89
|
+
this.forecaster = new utility_forecaster_1.UtilityForecaster(this.events, this.id);
|
|
90
|
+
this.utilityEngine = new utility_engine_1.UtilityEngine(this.events, this.id, {
|
|
91
|
+
...organism_types_1.DEFAULT_UTILITY_WEIGHTS,
|
|
92
|
+
...options.utilityWeights,
|
|
93
|
+
});
|
|
94
|
+
this.reputationEngine = new utility_engine_1.ReputationEngine(this.events, this.id);
|
|
95
|
+
this.survivalEngine = new survival_engine_1.SurvivalEngine({ ...organism_types_1.DEFAULT_SURVIVAL_CONFIG, ...options.survival }, () => this.clock.now());
|
|
96
|
+
this.reproductionConfig = {
|
|
97
|
+
...reproduction_engine_1.DEFAULT_REPRODUCTION_CONFIG,
|
|
98
|
+
...options.reproduction,
|
|
99
|
+
};
|
|
100
|
+
this.marketEngine = new market_engine_1.MarketEngine(this.events, this.allocator, this.forecaster, this.id, () => this.clock.now(), options.market);
|
|
101
|
+
this.agentRuntime =
|
|
102
|
+
options.agentRuntime ??
|
|
103
|
+
new agent_1.AgentRuntime({
|
|
104
|
+
llmProvider: options.llmProvider ?? (0, agent_1.createMockLlmProvider)(),
|
|
105
|
+
enableMetrics: true,
|
|
106
|
+
enableRetry: false,
|
|
107
|
+
enableCircuitBreaker: false,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
static async create(options) {
|
|
111
|
+
const runtime = new OrganismRuntime(options);
|
|
112
|
+
await runtime.initialize(options);
|
|
113
|
+
return runtime;
|
|
114
|
+
}
|
|
115
|
+
/** Resolve decorator-decorated organism class into create options. */
|
|
116
|
+
static async fromClass(target, overrides = {}) {
|
|
117
|
+
const meta = (await Promise.resolve().then(() => __importStar(require('../decorators')))).getOrganismMetadata(target);
|
|
118
|
+
if (!meta) {
|
|
119
|
+
throw new organism_errors_1.OrganismStateError(`Class ${target.name} is not decorated with @Organism`);
|
|
120
|
+
}
|
|
121
|
+
const opts = OrganismRuntime.mergeDecoratorOptions(meta, overrides);
|
|
122
|
+
return OrganismRuntime.create(opts);
|
|
123
|
+
}
|
|
124
|
+
static mergeDecoratorOptions(meta, overrides) {
|
|
125
|
+
if (!meta.mission && !overrides.mission) {
|
|
126
|
+
throw new organism_errors_1.OrganismStateError('@Organism requires a mission');
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
mission: overrides.mission ?? meta.mission,
|
|
130
|
+
genes: overrides.genes ?? meta.genes,
|
|
131
|
+
environment: overrides.environment ?? meta.environment,
|
|
132
|
+
constitution: overrides.constitution ?? meta.constitution,
|
|
133
|
+
resources: overrides.resources ?? meta.resources,
|
|
134
|
+
id: overrides.id ?? meta.id,
|
|
135
|
+
...overrides,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async initialize(options) {
|
|
139
|
+
const existing = options.id ? await this.repo.getOrganism(this.id) : undefined;
|
|
140
|
+
if (existing) {
|
|
141
|
+
this.record = normalizeOrganismRecord(existing);
|
|
142
|
+
this.wireEngines(this.record.constitution, options);
|
|
143
|
+
await this.hydrateAgentsFromRepository();
|
|
144
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_RESTORED, this.id, {
|
|
145
|
+
missionId: this.record.mission.id,
|
|
146
|
+
objective: this.record.mission.objective,
|
|
147
|
+
agentCount: this.agentCache.size,
|
|
148
|
+
});
|
|
149
|
+
this.log(`[ORGANISM] Restored ${this.id} with ${this.agentCache.size} agents`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const mission = (0, decorators_1.resolveMission)(options.mission);
|
|
153
|
+
const genes = (options.genes ?? []).map(decorators_1.resolveGene);
|
|
154
|
+
const environment = options.environment ? (0, decorators_1.resolveEnvironment)(options.environment) : undefined;
|
|
155
|
+
const constitution = options.constitution
|
|
156
|
+
? (0, decorators_1.resolveConstitution)(options.constitution)
|
|
157
|
+
: undefined;
|
|
158
|
+
const resources = options.resources
|
|
159
|
+
? (0, decorators_1.resolveResource)(options.resources)
|
|
160
|
+
: {
|
|
161
|
+
tokenBudget: 5000000,
|
|
162
|
+
monthlyBudget: { amount: 1000, currency: 'USD' },
|
|
163
|
+
};
|
|
164
|
+
const limits = { ...organism_types_1.DEFAULT_ORGANISM_LIMITS, ...options.limits };
|
|
165
|
+
const now = this.clock.now();
|
|
166
|
+
this.record = {
|
|
167
|
+
id: this.id,
|
|
168
|
+
status: 'created',
|
|
169
|
+
mission,
|
|
170
|
+
constitution,
|
|
171
|
+
environment,
|
|
172
|
+
genes,
|
|
173
|
+
resources,
|
|
174
|
+
limits,
|
|
175
|
+
cycles: options.cycles ?? {
|
|
176
|
+
perception: '5s',
|
|
177
|
+
evaluation: '1m',
|
|
178
|
+
survival: '10m',
|
|
179
|
+
missionEvaluation: '1m',
|
|
180
|
+
},
|
|
181
|
+
missionProgress: (0, mission_1.createMissionProgress)(mission),
|
|
182
|
+
pool: {
|
|
183
|
+
tokensRemaining: resources.tokenBudget ?? 5000000,
|
|
184
|
+
moneyRemaining: {
|
|
185
|
+
amount: resources.monthlyBudget?.amount ?? 1000,
|
|
186
|
+
currency: resources.monthlyBudget?.currency ?? 'USD',
|
|
187
|
+
},
|
|
188
|
+
costSpentThisHour: 0,
|
|
189
|
+
},
|
|
190
|
+
debug: this.debug,
|
|
191
|
+
simulation: options.simulation ?? false,
|
|
192
|
+
createdAt: now,
|
|
193
|
+
updatedAt: now,
|
|
194
|
+
emergencyStopped: false,
|
|
195
|
+
};
|
|
196
|
+
this.wireEngines(constitution, options);
|
|
197
|
+
await this.repo.saveOrganism(this.record);
|
|
198
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_CREATED, this.id, {
|
|
199
|
+
missionId: mission.id,
|
|
200
|
+
objective: mission.objective,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
wireEngines(constitution, options) {
|
|
204
|
+
this.constitutionEnforcer = new constitution_1.ConstitutionEnforcer(constitution, this.events, this.id);
|
|
205
|
+
const policyRules = this.constitutionEnforcer.toPolicyRules();
|
|
206
|
+
if (policyRules.length) {
|
|
207
|
+
this.agentRuntime = new agent_1.AgentRuntime({
|
|
208
|
+
llmProvider: options.llmProvider ?? (0, agent_1.createMockLlmProvider)(),
|
|
209
|
+
enableMetrics: true,
|
|
210
|
+
enableRetry: false,
|
|
211
|
+
enableCircuitBreaker: false,
|
|
212
|
+
policyEngine: new agent_1.PolicyEngine(policyRules),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
this.birthEngine = new birth_engine_1.BirthEngine(this.events, this.repo, this.capabilities, this.id, this.agentRuntime);
|
|
216
|
+
this.terminationEngine = new birth_engine_1.TerminationEngine(this.events, this.repo, this.capabilities, this.id, (agent) => this.allocator.release(this.record, agent));
|
|
217
|
+
this.genealogyManager = new genealogy_manager_1.GenealogyManager(this.repo, this.id);
|
|
218
|
+
this.reproductionEngine = new reproduction_engine_1.ReproductionEngine(this.events, this.repo, this.birthEngine, this.genealogyManager, this.constitutionEnforcer, this.id, () => this.clock.now(), this.reproductionConfig);
|
|
219
|
+
this.mutationEngine = new mutation_engine_1.MutationEngine(this.events, this.repo, this.id, () => this.clock.now());
|
|
220
|
+
this.generationManager = new evolution_engine_1.GenerationManager();
|
|
221
|
+
this.evolutionEngine = new evolution_engine_1.EvolutionEngine(this.events, this.repo, this.generationManager, this.mutationEngine, this.id, { ...organism_types_1.DEFAULT_UTILITY_WEIGHTS }, () => this.clock.now());
|
|
222
|
+
}
|
|
223
|
+
/** Rebuild agent cache + capability index from durable repository (multi-replica hydrate). */
|
|
224
|
+
async hydrateAgentsFromRepository() {
|
|
225
|
+
const agents = await this.repo.listAgents(this.id);
|
|
226
|
+
for (const raw of agents) {
|
|
227
|
+
const agent = normalizeAgentRecord(raw);
|
|
228
|
+
this.agentCache.set(agent.id, agent);
|
|
229
|
+
this.capabilities.register(agent.id, agent.capabilities);
|
|
230
|
+
this.reregisterAgentDna(agent);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
reregisterAgentDna(agent) {
|
|
234
|
+
if (!this.agentRuntime || !agent.dnaAgentName)
|
|
235
|
+
return;
|
|
236
|
+
try {
|
|
237
|
+
const dna = (0, agent_1.exportAgentDna)({
|
|
238
|
+
name: agent.dnaAgentName,
|
|
239
|
+
description: agent.objective,
|
|
240
|
+
systemPrompt: agent.systemPrompt ??
|
|
241
|
+
`You are ${agent.dnaAgentName}. Objective: ${agent.objective}. Capabilities: ${agent.capabilities.join(', ')}.`,
|
|
242
|
+
tools: [],
|
|
243
|
+
mission: { goal: agent.objective },
|
|
244
|
+
metadata: {
|
|
245
|
+
capabilities: agent.capabilities,
|
|
246
|
+
organismId: this.id,
|
|
247
|
+
geneId: agent.geneId,
|
|
248
|
+
needId: agent.birthProposal?.needId,
|
|
249
|
+
terminationCriteria: agent.terminationCriteria,
|
|
250
|
+
},
|
|
251
|
+
version: '1.0.0',
|
|
252
|
+
});
|
|
253
|
+
const AgentClass = (0, agent_1.createAgentClassFromDna)(dna);
|
|
254
|
+
this.agentRuntime.registerAgent(AgentClass);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// DNA re-registration is best-effort; observe/spawn still work via capabilities.
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
get status() {
|
|
261
|
+
return this.record.status;
|
|
262
|
+
}
|
|
263
|
+
getMission() {
|
|
264
|
+
return this.record.mission;
|
|
265
|
+
}
|
|
266
|
+
async start() {
|
|
267
|
+
if (this.record.emergencyStopped) {
|
|
268
|
+
throw new organism_errors_1.OrganismStateError('Cannot start after emergency stop');
|
|
269
|
+
}
|
|
270
|
+
this.record.status = 'initializing';
|
|
271
|
+
await this.persist();
|
|
272
|
+
this.record.status = 'operating';
|
|
273
|
+
await this.persist();
|
|
274
|
+
this.startCycles();
|
|
275
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_STARTED, this.id, {
|
|
276
|
+
status: this.record.status,
|
|
277
|
+
});
|
|
278
|
+
this.log(`[ORGANISM] Mission started: ${this.record.mission.objective}`);
|
|
279
|
+
}
|
|
280
|
+
async pause() {
|
|
281
|
+
this.stopCycles();
|
|
282
|
+
this.record.status = 'paused';
|
|
283
|
+
await this.persist();
|
|
284
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_PAUSED, this.id, {});
|
|
285
|
+
this.log('[ORGANISM] Paused');
|
|
286
|
+
}
|
|
287
|
+
async resume() {
|
|
288
|
+
if (this.record.emergencyStopped) {
|
|
289
|
+
throw new organism_errors_1.OrganismStateError('Cannot resume after emergency stop');
|
|
290
|
+
}
|
|
291
|
+
this.record.status = 'operating';
|
|
292
|
+
await this.persist();
|
|
293
|
+
this.startCycles();
|
|
294
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_RESUMED, this.id, {});
|
|
295
|
+
this.log('[ORGANISM] Resumed');
|
|
296
|
+
}
|
|
297
|
+
async terminate() {
|
|
298
|
+
this.stopCycles();
|
|
299
|
+
const agents = await this.liveAgents();
|
|
300
|
+
for (const agent of agents) {
|
|
301
|
+
await this.terminationEngine.terminate(agent.id, 'manual');
|
|
302
|
+
this.metrics.recordTermination();
|
|
303
|
+
}
|
|
304
|
+
this.record.status = 'terminated';
|
|
305
|
+
await this.persist();
|
|
306
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_TERMINATED, this.id, {});
|
|
307
|
+
this.log('[ORGANISM] Terminated');
|
|
308
|
+
}
|
|
309
|
+
async emergencyStop() {
|
|
310
|
+
this.record.emergencyStopped = true;
|
|
311
|
+
this.stopCycles();
|
|
312
|
+
this.record.status = 'terminated';
|
|
313
|
+
await this.persist();
|
|
314
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_EMERGENCY_STOP, this.id, {});
|
|
315
|
+
this.log('[ORGANISM] Emergency stop');
|
|
316
|
+
}
|
|
317
|
+
async observe(raw) {
|
|
318
|
+
if (this.record.status === 'paused' || this.record.emergencyStopped) {
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
this.record.status = 'observing';
|
|
322
|
+
const signal = this.perception.normalize({
|
|
323
|
+
...raw,
|
|
324
|
+
timestamp: raw.timestamp ?? this.clock.now(),
|
|
325
|
+
});
|
|
326
|
+
const filtered = this.perception.filter(signal, this.record.mission);
|
|
327
|
+
await this.repo.appendSignal(this.id, filtered.signal);
|
|
328
|
+
await this.events.emit(organism_events_1.OrganismEventType.ENVIRONMENT_SIGNAL_RECEIVED, this.id, filtered.signal);
|
|
329
|
+
this.log(`[ENVIRONMENT] ${signal.type} ${filtered.accepted ? 'accepted' : 'ignored'}`);
|
|
330
|
+
if (!filtered.accepted) {
|
|
331
|
+
this.record.status = 'operating';
|
|
332
|
+
await this.persist();
|
|
333
|
+
return {
|
|
334
|
+
action: 'observe',
|
|
335
|
+
reasoningSummary: filtered.reason,
|
|
336
|
+
confidence: 1,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const need = this.needDetector.detect(filtered.signal, this.record.mission);
|
|
340
|
+
if (!need) {
|
|
341
|
+
this.record.status = 'operating';
|
|
342
|
+
await this.persist();
|
|
343
|
+
return {
|
|
344
|
+
action: 'observe',
|
|
345
|
+
reasoningSummary: `No need detected for ${signal.type}`,
|
|
346
|
+
confidence: 0.7,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_NEED_DETECTED, this.id, need);
|
|
350
|
+
this.log(`[NEED] ${need.need} — ${need.reason}`);
|
|
351
|
+
this.record.status = 'planning';
|
|
352
|
+
const live = await this.liveAgents();
|
|
353
|
+
const spawnCheck = this.allocator.canSpawn(this.record, live.length);
|
|
354
|
+
const decision = this.decisionEngine.decide({
|
|
355
|
+
need,
|
|
356
|
+
liveAgents: live,
|
|
357
|
+
genes: this.record.genes,
|
|
358
|
+
canSpawn: spawnCheck.ok,
|
|
359
|
+
spawnBlockReason: spawnCheck.reason,
|
|
360
|
+
});
|
|
361
|
+
await this.repo.appendDecision(this.id, decision);
|
|
362
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_DECISION, this.id, decision);
|
|
363
|
+
if (this.debug) {
|
|
364
|
+
this.log(`[DECISION] ${decision.action}: ${decision.reasoningSummary} (confidence=${decision.confidence})`);
|
|
365
|
+
}
|
|
366
|
+
await this.applyDecision(decision);
|
|
367
|
+
this.record.status = 'operating';
|
|
368
|
+
await this.persist();
|
|
369
|
+
return decision;
|
|
370
|
+
}
|
|
371
|
+
async applyDecision(decision) {
|
|
372
|
+
if (decision.action === 'delegate' && decision.targetAgentId) {
|
|
373
|
+
await this.delegateInternal(decision.targetAgentId, decision.needId ?? 'task');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if ((decision.action === 'spawn' || decision.action === 'specialize') &&
|
|
377
|
+
decision.birthProposal) {
|
|
378
|
+
await this.spawnFromProposal(decision);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (decision.action === 'reproduce' && decision.birthProposal?.parentAgentId) {
|
|
382
|
+
await this.reproduceAgent(decision.birthProposal.parentAgentId, {
|
|
383
|
+
reason: decision.birthProposal.reason,
|
|
384
|
+
specialization: decision.birthProposal.specialize,
|
|
385
|
+
objective: decision.birthProposal.expectedOutcome,
|
|
386
|
+
needId: decision.birthProposal.needId,
|
|
387
|
+
confidence: decision.confidence,
|
|
388
|
+
tokens: decision.resourceRequest?.tokens,
|
|
389
|
+
terminationCriteria: decision.birthProposal.terminationCriteria,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async spawnFromProposal(decision) {
|
|
394
|
+
const proposal = decision.birthProposal;
|
|
395
|
+
this.constitutionEnforcer.assertAllows('spawn', {});
|
|
396
|
+
const live = await this.liveAgents();
|
|
397
|
+
const spawnCheck = this.allocator.canSpawn(this.record, live.length);
|
|
398
|
+
if (!spawnCheck.ok) {
|
|
399
|
+
throw new organism_errors_1.OrganismStateError(spawnCheck.reason);
|
|
400
|
+
}
|
|
401
|
+
const geneId = proposal.geneId ?? this.record.genes[0]?.id;
|
|
402
|
+
const gene = this.record.genes.find((g) => g.id === geneId);
|
|
403
|
+
if (!gene) {
|
|
404
|
+
throw new organism_errors_1.OrganismStateError(`Gene not found: ${geneId}`);
|
|
405
|
+
}
|
|
406
|
+
const agentId = `pending_${Date.now()}`;
|
|
407
|
+
const allocation = this.allocator.allocate(this.record, {
|
|
408
|
+
agentId,
|
|
409
|
+
requestedResources: decision.resourceRequest ?? { tokens: 50000 },
|
|
410
|
+
expectedUtility: proposal.expectedUtility ?? 0.5,
|
|
411
|
+
confidence: proposal.confidence,
|
|
412
|
+
urgency: 0.7,
|
|
413
|
+
});
|
|
414
|
+
if (!allocation.approved) {
|
|
415
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_RESOURCE_DENIED, this.id, allocation);
|
|
416
|
+
throw new organism_errors_1.OrganismStateError(allocation.reason);
|
|
417
|
+
}
|
|
418
|
+
this.allocator.recordSpawn();
|
|
419
|
+
const parentGeneration = proposal.parentAgentId
|
|
420
|
+
? ((await this.repo.getAgent(this.id, proposal.parentAgentId))?.generation ?? 0)
|
|
421
|
+
: 0;
|
|
422
|
+
const generation = parentGeneration + 1;
|
|
423
|
+
if (generation > this.record.limits.maxGenerationDepth) {
|
|
424
|
+
this.record.pool.tokensRemaining += allocation.wallet.tokensRemaining ?? 0;
|
|
425
|
+
this.record.pool.moneyRemaining.amount += allocation.wallet.moneyRemaining?.amount ?? 0;
|
|
426
|
+
throw new organism_errors_1.OrganismStateError(`maxGenerationDepth (${this.record.limits.maxGenerationDepth}) exceeded`);
|
|
427
|
+
}
|
|
428
|
+
const agent = await this.birthEngine.spawn({
|
|
429
|
+
proposal,
|
|
430
|
+
gene,
|
|
431
|
+
wallet: allocation.wallet,
|
|
432
|
+
generation,
|
|
433
|
+
parentAgentId: proposal.parentAgentId,
|
|
434
|
+
});
|
|
435
|
+
this.agentCache.set(agent.id, agent);
|
|
436
|
+
this.metrics.recordSpawn();
|
|
437
|
+
this.metrics.recordTokens(allocation.wallet.tokensRemaining ?? 0);
|
|
438
|
+
this.log(`[BIRTH] ${agent.name}#${agent.id} born parent: ${agent.parentAgentId ?? agent.geneId} generation: ${agent.generation}`);
|
|
439
|
+
this.log(`[RESOURCE] allocated ${(allocation.wallet.tokensRemaining ?? 0).toLocaleString()} tokens`);
|
|
440
|
+
if (decision.action === 'specialize') {
|
|
441
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_AGENT_SPECIALIZED, this.id, {
|
|
442
|
+
agentId: agent.id,
|
|
443
|
+
specialize: agent.specialize,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
await this.persist();
|
|
447
|
+
return agent;
|
|
448
|
+
}
|
|
449
|
+
/** Public spawn API for explicit births (still requires structured proposal). */
|
|
450
|
+
async spawnAgent(input) {
|
|
451
|
+
const gene = this.record.genes.find((g) => g.id === input.geneId) ??
|
|
452
|
+
this.decisionEngine.selectGene(input.requiredCapabilities, this.record.genes);
|
|
453
|
+
if (!gene)
|
|
454
|
+
throw new organism_errors_1.OrganismStateError('No gene available for spawn');
|
|
455
|
+
const decision = {
|
|
456
|
+
action: input.specialize?.length ? 'specialize' : 'spawn',
|
|
457
|
+
reasoningSummary: input.reason,
|
|
458
|
+
confidence: input.confidence ?? 0.8,
|
|
459
|
+
resourceRequest: { tokens: input.tokens ?? 50000 },
|
|
460
|
+
birthProposal: {
|
|
461
|
+
reason: input.reason,
|
|
462
|
+
needId: input.needId,
|
|
463
|
+
requiredCapabilities: input.requiredCapabilities,
|
|
464
|
+
expectedOutcome: input.objective,
|
|
465
|
+
confidence: input.confidence ?? 0.8,
|
|
466
|
+
geneId: gene.id,
|
|
467
|
+
specialize: input.specialize,
|
|
468
|
+
parentAgentId: input.parentAgentId,
|
|
469
|
+
terminationCriteria: input.terminationCriteria,
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
await this.repo.appendDecision(this.id, decision);
|
|
473
|
+
return this.spawnFromProposal(decision);
|
|
474
|
+
}
|
|
475
|
+
async terminateAgent(agentId, opts = { reason: 'manual' }) {
|
|
476
|
+
const agent = await this.terminationEngine.terminate(agentId, opts.reason);
|
|
477
|
+
if (agent) {
|
|
478
|
+
this.metrics.recordTermination();
|
|
479
|
+
this.log(`[DEATH] ${agent.name}#${agent.id} terminated (${opts.reason})`);
|
|
480
|
+
if ((agent.wallet.tokensRemaining ?? 0) === 0) {
|
|
481
|
+
this.log(`[RESOURCE] unused tokens returned to pool`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
await this.persist();
|
|
485
|
+
}
|
|
486
|
+
async reportOutcome(agentId, report) {
|
|
487
|
+
const agent = await this.repo.getAgent(this.id, agentId);
|
|
488
|
+
if (!agent)
|
|
489
|
+
throw new organism_errors_1.OrganismStateError(`Agent not found: ${agentId}`);
|
|
490
|
+
agent.valueGenerated += report.metrics?.valueGenerated ?? 0;
|
|
491
|
+
agent.costConsumed += report.metrics?.cost ?? 0;
|
|
492
|
+
agent.tokensConsumed += report.metrics?.cost
|
|
493
|
+
? Math.floor((report.metrics.cost ?? 0) * 1000)
|
|
494
|
+
: 0;
|
|
495
|
+
agent.reputation = this.reputationEngine.update(agent, report);
|
|
496
|
+
agent.utility = this.utilityEngine.evaluate(agent, report);
|
|
497
|
+
agent.evaluationCount += 1;
|
|
498
|
+
agent.lastEvaluatedAt = this.clock.now();
|
|
499
|
+
await this.repo.saveAgent(this.id, agent);
|
|
500
|
+
this.agentCache.set(agent.id, agent);
|
|
501
|
+
if (report.missionMetricUpdates) {
|
|
502
|
+
this.record.missionProgress = (0, mission_1.applyMissionMetricUpdates)(this.record.missionProgress, this.record.mission, report.missionMetricUpdates);
|
|
503
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_MISSION_PROGRESS, this.id, this.record.missionProgress);
|
|
504
|
+
if (this.record.missionProgress.completed) {
|
|
505
|
+
this.record.status = 'completed';
|
|
506
|
+
await this.events.emit(organism_events_1.OrganismEventType.ORGANISM_MISSION_COMPLETED, this.id, this.record.missionProgress);
|
|
507
|
+
this.log('[MISSION] Mission completed');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
this.log(`[RESULT] ${report.result}`);
|
|
511
|
+
await this.persist();
|
|
512
|
+
}
|
|
513
|
+
async runSurvivalCycle() {
|
|
514
|
+
const agents = await this.liveAgents();
|
|
515
|
+
const reports = [];
|
|
516
|
+
for (const agent of agents) {
|
|
517
|
+
const verdict = this.survivalEngine.evaluate(agent);
|
|
518
|
+
reports.push(verdict);
|
|
519
|
+
if (verdict.shouldTerminate) {
|
|
520
|
+
this.log(`[SURVIVAL] ${agent.name}#${agent.id} ${verdict.reason}`);
|
|
521
|
+
await this.terminateAgent(agent.id, { reason: 'low_value' });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return reports;
|
|
525
|
+
}
|
|
526
|
+
async inspect() {
|
|
527
|
+
const agents = await this.repo.listAgents(this.id);
|
|
528
|
+
return {
|
|
529
|
+
mission: this.record.mission,
|
|
530
|
+
missionProgress: this.record.missionProgress,
|
|
531
|
+
status: this.record.status,
|
|
532
|
+
agents: agents.map((a) => ({
|
|
533
|
+
id: a.id,
|
|
534
|
+
objective: a.objective,
|
|
535
|
+
capabilities: a.capabilities,
|
|
536
|
+
parentId: a.parentAgentId,
|
|
537
|
+
generation: a.generation,
|
|
538
|
+
status: a.status,
|
|
539
|
+
reputation: a.reputation,
|
|
540
|
+
utility: a.utility,
|
|
541
|
+
resourceConsumption: { tokens: a.tokensConsumed, cost: a.costConsumed },
|
|
542
|
+
})),
|
|
543
|
+
resources: {
|
|
544
|
+
pool: this.record.pool,
|
|
545
|
+
limits: this.record.limits,
|
|
546
|
+
},
|
|
547
|
+
recentSignals: await this.repo.listSignals(this.id, 20),
|
|
548
|
+
recentDecisions: await this.repo.listDecisions(this.id, 20),
|
|
549
|
+
genealogy: await this.repo.listGenealogy(this.id),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
async getGenealogy() {
|
|
553
|
+
return this.repo.listGenealogy(this.id);
|
|
554
|
+
}
|
|
555
|
+
async formatGenealogy() {
|
|
556
|
+
const [agents, genealogy] = await Promise.all([
|
|
557
|
+
this.repo.listAgents(this.id),
|
|
558
|
+
this.genealogyManager.list(),
|
|
559
|
+
]);
|
|
560
|
+
return this.genealogyManager.formatTree(agents, genealogy);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Phase 2 — create a specialized descendant from an existing agent.
|
|
564
|
+
*/
|
|
565
|
+
async reproduceAgent(parentAgentId, request) {
|
|
566
|
+
const parent = await this.repo.getAgent(this.id, parentAgentId);
|
|
567
|
+
if (!parent)
|
|
568
|
+
throw new organism_errors_1.OrganismStateError(`Parent agent not found: ${parentAgentId}`);
|
|
569
|
+
const gene = this.record.genes.find((g) => g.id === parent.geneId);
|
|
570
|
+
if (!gene)
|
|
571
|
+
throw new organism_errors_1.OrganismStateError(`Gene not found for parent: ${parent.geneId}`);
|
|
572
|
+
const live = await this.liveAgents();
|
|
573
|
+
const spawnCheck = this.allocator.canSpawn(this.record, live.length);
|
|
574
|
+
if (!spawnCheck.ok) {
|
|
575
|
+
throw new organism_errors_1.OrganismStateError(spawnCheck.reason);
|
|
576
|
+
}
|
|
577
|
+
// Prefer parent wallet transfer; optionally top up from pool if parent has no tokens
|
|
578
|
+
const parentTokens = parent.wallet.tokensRemaining ?? 0;
|
|
579
|
+
let poolWallet;
|
|
580
|
+
if (parentTokens <= 0 || request.tokens) {
|
|
581
|
+
const allocation = this.allocator.allocate(this.record, {
|
|
582
|
+
agentId: `repro_${parentAgentId}`,
|
|
583
|
+
requestedResources: { tokens: request.tokens ?? 25000 },
|
|
584
|
+
expectedUtility: parent.utility.score,
|
|
585
|
+
confidence: request.confidence ?? 0.8,
|
|
586
|
+
urgency: 0.6,
|
|
587
|
+
reputationScore: parent.reputation.score,
|
|
588
|
+
});
|
|
589
|
+
if (!allocation.approved) {
|
|
590
|
+
throw new organism_errors_1.OrganismStateError(allocation.reason);
|
|
591
|
+
}
|
|
592
|
+
poolWallet = allocation.wallet;
|
|
593
|
+
}
|
|
594
|
+
this.allocator.recordSpawn();
|
|
595
|
+
const { child, parent: updatedParent } = await this.reproductionEngine.reproduce({
|
|
596
|
+
parent,
|
|
597
|
+
gene,
|
|
598
|
+
request,
|
|
599
|
+
limits: this.record.limits,
|
|
600
|
+
liveAgents: live,
|
|
601
|
+
poolWallet,
|
|
602
|
+
});
|
|
603
|
+
this.agentCache.set(child.id, child);
|
|
604
|
+
this.agentCache.set(updatedParent.id, updatedParent);
|
|
605
|
+
this.capabilities.register(child.id, child.capabilities);
|
|
606
|
+
this.metrics.recordReproduction();
|
|
607
|
+
this.metrics.recordTokens(child.wallet.tokensRemaining ?? 0);
|
|
608
|
+
this.log(`[REPRODUCTION] ${child.name}#${child.id} born parent: ${parent.name}#${parent.id} generation: ${child.generation}`);
|
|
609
|
+
await this.persist();
|
|
610
|
+
return child;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Phase 3 — apply a constrained, auditable mutation.
|
|
614
|
+
*/
|
|
615
|
+
async mutateAgent(agentId, input) {
|
|
616
|
+
const agent = await this.repo.getAgent(this.id, agentId);
|
|
617
|
+
if (!agent)
|
|
618
|
+
throw new organism_errors_1.OrganismStateError(`Agent not found: ${agentId}`);
|
|
619
|
+
const gene = this.record.genes.find((g) => g.id === agent.geneId);
|
|
620
|
+
if (!gene)
|
|
621
|
+
throw new organism_errors_1.OrganismStateError(`Gene not found: ${agent.geneId}`);
|
|
622
|
+
this.constitutionEnforcer.assertAllows('mutate', {});
|
|
623
|
+
const updated = await this.mutationEngine.mutate(agent, input, gene);
|
|
624
|
+
this.capabilities.register(updated.id, updated.capabilities);
|
|
625
|
+
this.agentCache.set(updated.id, updated);
|
|
626
|
+
this.metrics.recordMutation();
|
|
627
|
+
this.log(`[MUTATION] ${updated.name}#${updated.id}: ${input.reason}`);
|
|
628
|
+
await this.persist();
|
|
629
|
+
return updated;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Phase 3 — evaluate a competing population and promote the winner's strategy id.
|
|
633
|
+
*/
|
|
634
|
+
async evaluateGeneration(input) {
|
|
635
|
+
const result = await this.evolutionEngine.evaluateGeneration(input);
|
|
636
|
+
this.log(`[EVOLUTION] population=${result.populationId} winner=${result.winner} scores=${JSON.stringify(result.scores)}`);
|
|
637
|
+
if (input.promoteToLosers && result.winner) {
|
|
638
|
+
const winner = await this.repo.getAgent(this.id, result.winner);
|
|
639
|
+
const gene = winner ? this.record.genes.find((g) => g.id === winner.geneId) : undefined;
|
|
640
|
+
if (winner && gene) {
|
|
641
|
+
for (const member of result.members) {
|
|
642
|
+
if (member.agentId === result.winner)
|
|
643
|
+
continue;
|
|
644
|
+
await this.evolutionEngine.promoteStrategy({
|
|
645
|
+
winnerId: result.winner,
|
|
646
|
+
targetId: member.agentId,
|
|
647
|
+
gene,
|
|
648
|
+
});
|
|
649
|
+
this.metrics.recordMutation();
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
await this.persist();
|
|
654
|
+
return result;
|
|
655
|
+
}
|
|
656
|
+
getEvolutionaryHistory(limit = 50) {
|
|
657
|
+
return this.generationManager.getHistory(limit);
|
|
658
|
+
}
|
|
659
|
+
/** Phase 4 — forecast expected utility / opportunity cost for a resource request. */
|
|
660
|
+
async forecastUtility(input) {
|
|
661
|
+
const agent = await this.repo.getAgent(this.id, input.agentId);
|
|
662
|
+
if (!agent)
|
|
663
|
+
throw new organism_errors_1.OrganismStateError(`Agent not found: ${input.agentId}`);
|
|
664
|
+
return this.forecaster.forecast({
|
|
665
|
+
agent,
|
|
666
|
+
record: this.record,
|
|
667
|
+
requested: input.requested,
|
|
668
|
+
expectedValue: input.expectedValue,
|
|
669
|
+
confidence: input.confidence,
|
|
670
|
+
urgency: input.urgency,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
/** Phase 4 — place a resource bid into the internal market. */
|
|
674
|
+
placeBid(input) {
|
|
675
|
+
const bid = this.marketEngine.placeBid(input);
|
|
676
|
+
this.log(`[BID] ${bid.id} agent=${bid.agentId} value=${bid.expectedValue} tokens=${bid.requested.tokens ?? 0}`);
|
|
677
|
+
return bid;
|
|
678
|
+
}
|
|
679
|
+
listOpenBids() {
|
|
680
|
+
return this.marketEngine.listOpenBids();
|
|
681
|
+
}
|
|
682
|
+
/** Phase 4 — clear open bids against the organism pool. */
|
|
683
|
+
async clearMarket() {
|
|
684
|
+
const agents = await this.repo.listAgents(this.id);
|
|
685
|
+
const map = new Map(agents.map((a) => [a.id, a]));
|
|
686
|
+
const result = this.marketEngine.clearMarket({ record: this.record, agents: map });
|
|
687
|
+
for (const win of result.awarded) {
|
|
688
|
+
const agent = map.get(win.agentId);
|
|
689
|
+
if (!agent)
|
|
690
|
+
continue;
|
|
691
|
+
agent.wallet = {
|
|
692
|
+
tokensRemaining: (agent.wallet.tokensRemaining ?? 0) + (win.wallet.tokensRemaining ?? 0),
|
|
693
|
+
moneyRemaining: {
|
|
694
|
+
amount: (agent.wallet.moneyRemaining?.amount ?? 0) + (win.wallet.moneyRemaining?.amount ?? 0),
|
|
695
|
+
currency: this.record.pool.moneyRemaining.currency,
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
await this.repo.saveAgent(this.id, agent);
|
|
699
|
+
this.agentCache.set(agent.id, agent);
|
|
700
|
+
this.metrics.recordTokens(win.wallet.tokensRemaining ?? 0);
|
|
701
|
+
}
|
|
702
|
+
// Persist any bid-price charges on losers/winners wallets
|
|
703
|
+
for (const agent of map.values()) {
|
|
704
|
+
await this.repo.saveAgent(this.id, agent);
|
|
705
|
+
this.agentCache.set(agent.id, agent);
|
|
706
|
+
}
|
|
707
|
+
this.log(`[MARKET] cleared ${result.roundId}: awarded=${result.awarded.length} denied=${result.denied.length}`);
|
|
708
|
+
await this.persist();
|
|
709
|
+
return result;
|
|
710
|
+
}
|
|
711
|
+
/** Phase 4 — peer resource negotiation between two agents. */
|
|
712
|
+
async negotiate(offer) {
|
|
713
|
+
const from = await this.repo.getAgent(this.id, offer.fromAgentId);
|
|
714
|
+
const to = await this.repo.getAgent(this.id, offer.toAgentId);
|
|
715
|
+
if (!from || !to) {
|
|
716
|
+
return { approved: false, reason: 'Agent not found' };
|
|
717
|
+
}
|
|
718
|
+
const result = this.marketEngine.negotiate({
|
|
719
|
+
offer,
|
|
720
|
+
from,
|
|
721
|
+
to,
|
|
722
|
+
record: this.record,
|
|
723
|
+
});
|
|
724
|
+
if (result.approved) {
|
|
725
|
+
await this.repo.saveAgent(this.id, from);
|
|
726
|
+
await this.repo.saveAgent(this.id, to);
|
|
727
|
+
this.agentCache.set(from.id, from);
|
|
728
|
+
this.agentCache.set(to.id, to);
|
|
729
|
+
this.log(`[NEGOTIATION] ${from.id} → ${to.id} tokens=${offer.transfer.tokens ?? 0} money=${offer.transfer.money ?? 0}`);
|
|
730
|
+
}
|
|
731
|
+
await this.persist();
|
|
732
|
+
return result;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Phase 4 — negotiate-aware resource request (forecast first, then allocate).
|
|
736
|
+
*/
|
|
737
|
+
async requestResourcesForAgent(agentId, input) {
|
|
738
|
+
const agent = await this.repo.getAgent(this.id, agentId);
|
|
739
|
+
if (!agent)
|
|
740
|
+
return { approved: false, reason: `Agent not found: ${agentId}` };
|
|
741
|
+
const expectedValue = input.expectedValue ?? 100;
|
|
742
|
+
const confidence = input.confidence ?? 0.5;
|
|
743
|
+
const forecast = this.forecaster.forecast({
|
|
744
|
+
agent,
|
|
745
|
+
record: this.record,
|
|
746
|
+
requested: input.requested,
|
|
747
|
+
expectedValue,
|
|
748
|
+
confidence,
|
|
749
|
+
urgency: input.urgency,
|
|
750
|
+
});
|
|
751
|
+
if (input.useMarket) {
|
|
752
|
+
this.placeBid({
|
|
753
|
+
agentId,
|
|
754
|
+
reason: input.reason,
|
|
755
|
+
requested: input.requested,
|
|
756
|
+
expectedValue,
|
|
757
|
+
confidence,
|
|
758
|
+
urgency: input.urgency,
|
|
759
|
+
});
|
|
760
|
+
const cleared = await this.clearMarket();
|
|
761
|
+
const win = cleared.awarded.find((a) => a.agentId === agentId);
|
|
762
|
+
if (win) {
|
|
763
|
+
return {
|
|
764
|
+
approved: true,
|
|
765
|
+
reason: 'Won market clearing',
|
|
766
|
+
wallet: win.wallet,
|
|
767
|
+
forecast,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
const denial = cleared.denied.find((d) => d.agentId === agentId);
|
|
771
|
+
return {
|
|
772
|
+
approved: false,
|
|
773
|
+
reason: denial?.reason ?? 'Lost market clearing',
|
|
774
|
+
forecast,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
if (forecast.netExpectedValue < 0 && expectedValue > 0) {
|
|
778
|
+
return {
|
|
779
|
+
approved: false,
|
|
780
|
+
reason: `Forecast net value negative (${forecast.netExpectedValue.toFixed(2)})`,
|
|
781
|
+
forecast,
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
const allocation = this.allocator.allocate(this.record, {
|
|
785
|
+
agentId,
|
|
786
|
+
requestedResources: input.requested,
|
|
787
|
+
expectedUtility: forecast.expectedUtility,
|
|
788
|
+
confidence,
|
|
789
|
+
urgency: input.urgency ?? 0.5,
|
|
790
|
+
reputationScore: agent.reputation.score,
|
|
791
|
+
});
|
|
792
|
+
if (allocation.approved) {
|
|
793
|
+
agent.wallet = {
|
|
794
|
+
tokensRemaining: (agent.wallet.tokensRemaining ?? 0) + (allocation.wallet.tokensRemaining ?? 0),
|
|
795
|
+
moneyRemaining: {
|
|
796
|
+
amount: (agent.wallet.moneyRemaining?.amount ?? 0) +
|
|
797
|
+
(allocation.wallet.moneyRemaining?.amount ?? 0),
|
|
798
|
+
currency: this.record.pool.moneyRemaining.currency,
|
|
799
|
+
},
|
|
800
|
+
};
|
|
801
|
+
await this.repo.saveAgent(this.id, agent);
|
|
802
|
+
this.agentCache.set(agent.id, agent);
|
|
803
|
+
await this.persist();
|
|
804
|
+
}
|
|
805
|
+
return {
|
|
806
|
+
approved: allocation.approved,
|
|
807
|
+
reason: allocation.reason,
|
|
808
|
+
wallet: allocation.wallet,
|
|
809
|
+
forecast,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
getMarketHistory(limit = 20) {
|
|
813
|
+
return this.marketEngine.getHistory(limit);
|
|
814
|
+
}
|
|
815
|
+
async getGraph() {
|
|
816
|
+
const agents = await this.repo.listAgents(this.id);
|
|
817
|
+
const nodes = agents.map((a) => ({
|
|
818
|
+
id: a.id,
|
|
819
|
+
label: a.name,
|
|
820
|
+
status: a.status,
|
|
821
|
+
generation: a.generation,
|
|
822
|
+
utility: a.utility.score,
|
|
823
|
+
reputation: a.reputation.score,
|
|
824
|
+
cost: a.costConsumed,
|
|
825
|
+
tokens: a.tokensConsumed,
|
|
826
|
+
objective: a.objective,
|
|
827
|
+
geneId: a.geneId,
|
|
828
|
+
parentId: a.parentAgentId,
|
|
829
|
+
}));
|
|
830
|
+
const edges = agents
|
|
831
|
+
.filter((a) => a.parentAgentId)
|
|
832
|
+
.map((a) => ({
|
|
833
|
+
from: a.parentAgentId,
|
|
834
|
+
to: a.id,
|
|
835
|
+
kind: 'parent',
|
|
836
|
+
}));
|
|
837
|
+
return { nodes, edges };
|
|
838
|
+
}
|
|
839
|
+
createAgentContext(agentId) {
|
|
840
|
+
return new organism_context_1.OrganismAgentContext({
|
|
841
|
+
getMission: () => this.record.mission,
|
|
842
|
+
getConstitution: () => this.record.constitution,
|
|
843
|
+
getWallet: () => {
|
|
844
|
+
const agent = this.syncGetAgent(agentId);
|
|
845
|
+
return agent?.wallet ?? {};
|
|
846
|
+
},
|
|
847
|
+
findAgents: async (query) => {
|
|
848
|
+
const all = await this.liveAgents();
|
|
849
|
+
if (!query.capabilities?.length)
|
|
850
|
+
return all;
|
|
851
|
+
return this.capabilities.findCapableAgents(query.capabilities, all);
|
|
852
|
+
},
|
|
853
|
+
delegate: async (input) => this.delegateInternal(input.to, input.task),
|
|
854
|
+
requestResources: async (input) => this.requestResourcesForAgent(agentId, input),
|
|
855
|
+
placeBid: (input) => this.placeBid({
|
|
856
|
+
agentId,
|
|
857
|
+
...input,
|
|
858
|
+
}),
|
|
859
|
+
negotiate: async (input) => this.negotiate({
|
|
860
|
+
fromAgentId: agentId,
|
|
861
|
+
toAgentId: input.toAgentId,
|
|
862
|
+
reason: input.reason,
|
|
863
|
+
transfer: input.transfer,
|
|
864
|
+
expectedValue: input.expectedValue,
|
|
865
|
+
confidence: input.confidence,
|
|
866
|
+
}),
|
|
867
|
+
reportOutcome: async (report) => this.reportOutcome(agentId, report),
|
|
868
|
+
requestApproval: async (input) => {
|
|
869
|
+
const key = `${input.action}:${input.reason}`;
|
|
870
|
+
if (this.pendingApprovals.has(key)) {
|
|
871
|
+
return {
|
|
872
|
+
approved: this.pendingApprovals.get(key),
|
|
873
|
+
reason: 'Cached approval decision',
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
const approved = (input.risk ?? 0) < 0.5;
|
|
877
|
+
this.pendingApprovals.set(key, approved);
|
|
878
|
+
return {
|
|
879
|
+
approved,
|
|
880
|
+
reason: approved ? 'Auto-approved low risk' : 'Requires human approval',
|
|
881
|
+
};
|
|
882
|
+
},
|
|
883
|
+
spawn: async (input) => this.spawnAgent({
|
|
884
|
+
...input,
|
|
885
|
+
parentAgentId: agentId,
|
|
886
|
+
}),
|
|
887
|
+
reproduce: async (request) => this.reproduceAgent(agentId, request),
|
|
888
|
+
mutate: async (input) => this.mutateAgent(agentId, input),
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
/** Grant/deny a pending human approval key (for tests / HITL bridge). */
|
|
892
|
+
setApproval(action, reason, approved) {
|
|
893
|
+
this.pendingApprovals.set(`${action}:${reason}`, approved);
|
|
894
|
+
}
|
|
895
|
+
async simulate(options) {
|
|
896
|
+
this.record.simulation = true;
|
|
897
|
+
if (options.environment?.clock !== 'real') {
|
|
898
|
+
this.clock.useAccelerated(this.clock.now().getTime());
|
|
899
|
+
}
|
|
900
|
+
const log = options.onEvent ?? ((line) => this.log(line));
|
|
901
|
+
const prevLog = this.log;
|
|
902
|
+
this.log = log;
|
|
903
|
+
if (this.record.status === 'created') {
|
|
904
|
+
await this.start();
|
|
905
|
+
}
|
|
906
|
+
const durationMs = (0, clock_1.parseDurationMs)(options.duration, 86400000);
|
|
907
|
+
const stepMs = options.stepMs ?? Math.max(1000, Math.floor(durationMs / 20));
|
|
908
|
+
const signals = options.signals ?? [];
|
|
909
|
+
let elapsed = 0;
|
|
910
|
+
let signalIndex = 0;
|
|
911
|
+
while (elapsed < durationMs && this.record.status !== 'terminated') {
|
|
912
|
+
this.clock.advance(stepMs);
|
|
913
|
+
elapsed += stepMs;
|
|
914
|
+
if (signalIndex < signals.length) {
|
|
915
|
+
const at = (signalIndex + 1) * (durationMs / (signals.length + 1));
|
|
916
|
+
if (elapsed >= at) {
|
|
917
|
+
await this.observe(signals[signalIndex]);
|
|
918
|
+
signalIndex += 1;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (elapsed % (0, clock_1.parseDurationMs)(this.record.cycles.survival, 600000) < stepMs) {
|
|
922
|
+
await this.runSurvivalCycle();
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
this.log = prevLog;
|
|
926
|
+
return this.inspect();
|
|
927
|
+
}
|
|
928
|
+
getAgentRuntime() {
|
|
929
|
+
return this.agentRuntime;
|
|
930
|
+
}
|
|
931
|
+
getRecord() {
|
|
932
|
+
return { ...this.record };
|
|
933
|
+
}
|
|
934
|
+
async listAgents() {
|
|
935
|
+
return this.repo.listAgents(this.id);
|
|
936
|
+
}
|
|
937
|
+
async listEvents(limit = 50) {
|
|
938
|
+
return this.events.getHistory(limit);
|
|
939
|
+
}
|
|
940
|
+
syncGetAgent(agentId) {
|
|
941
|
+
return this.agentCache.get(agentId);
|
|
942
|
+
}
|
|
943
|
+
async liveAgents() {
|
|
944
|
+
const all = await this.repo.listAgents(this.id);
|
|
945
|
+
for (const a of all)
|
|
946
|
+
this.agentCache.set(a.id, a);
|
|
947
|
+
return all.filter((a) => a.status !== 'terminated' && a.status !== 'failed');
|
|
948
|
+
}
|
|
949
|
+
async delegateInternal(to, task) {
|
|
950
|
+
const agent = await this.repo.getAgent(this.id, to);
|
|
951
|
+
if (!agent || agent.status === 'terminated') {
|
|
952
|
+
return { ok: false, result: 'Agent not available' };
|
|
953
|
+
}
|
|
954
|
+
agent.status = 'active';
|
|
955
|
+
await this.repo.saveAgent(this.id, agent);
|
|
956
|
+
this.agentCache.set(agent.id, agent);
|
|
957
|
+
this.log(`[DELEGATE] task to ${agent.name}#${agent.id}: ${task}`);
|
|
958
|
+
try {
|
|
959
|
+
if (this.agentRuntime.getAgentMetadata(agent.dnaAgentName)) {
|
|
960
|
+
await this.agentRuntime.execute(agent.dnaAgentName, task);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
catch {
|
|
964
|
+
// mock / missing agent — still count as delegated assignment
|
|
965
|
+
}
|
|
966
|
+
return { ok: true, result: `Assigned: ${task}` };
|
|
967
|
+
}
|
|
968
|
+
startCycles() {
|
|
969
|
+
this.stopCycles();
|
|
970
|
+
if (this.record.simulation || this.clock.isAccelerated) {
|
|
971
|
+
// simulation drives cycles explicitly
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const survivalMs = (0, clock_1.parseDurationMs)(this.record.cycles.survival, 600000);
|
|
975
|
+
const timer = setInterval(() => {
|
|
976
|
+
void this.runSurvivalCycle();
|
|
977
|
+
}, survivalMs);
|
|
978
|
+
if (typeof timer.unref === 'function')
|
|
979
|
+
timer.unref();
|
|
980
|
+
this.cycleTimers.push(timer);
|
|
981
|
+
}
|
|
982
|
+
stopCycles() {
|
|
983
|
+
for (const t of this.cycleTimers)
|
|
984
|
+
clearInterval(t);
|
|
985
|
+
this.cycleTimers = [];
|
|
986
|
+
}
|
|
987
|
+
async persist() {
|
|
988
|
+
this.record.updatedAt = this.clock.now();
|
|
989
|
+
await this.repo.saveOrganism(this.record);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
exports.OrganismRuntime = OrganismRuntime;
|
|
993
|
+
function asDate(value) {
|
|
994
|
+
return value instanceof Date ? value : new Date(value);
|
|
995
|
+
}
|
|
996
|
+
function normalizeOrganismRecord(record) {
|
|
997
|
+
return {
|
|
998
|
+
...record,
|
|
999
|
+
createdAt: asDate(record.createdAt),
|
|
1000
|
+
updatedAt: asDate(record.updatedAt),
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
function normalizeAgentRecord(agent) {
|
|
1004
|
+
return {
|
|
1005
|
+
...agent,
|
|
1006
|
+
createdAt: asDate(agent.createdAt),
|
|
1007
|
+
terminatedAt: agent.terminatedAt ? asDate(agent.terminatedAt) : undefined,
|
|
1008
|
+
lastEvaluatedAt: agent.lastEvaluatedAt ? asDate(agent.lastEvaluatedAt) : undefined,
|
|
1009
|
+
lastReproductionAt: agent.lastReproductionAt ? asDate(agent.lastReproductionAt) : undefined,
|
|
1010
|
+
lastMutationAt: agent.lastMutationAt ? asDate(agent.lastMutationAt) : undefined,
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
async function createOrganism(options) {
|
|
1014
|
+
return OrganismRuntime.create(options);
|
|
1015
|
+
}
|
|
1016
|
+
//# sourceMappingURL=organism-runtime.js.map
|