@holoscript/framework 6.0.3 → 6.0.4
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/CHANGELOG.md +1 -2
- package/ROADMAP.md +68 -66
- package/dist/{InvisibleWallet-BB6tFvRA.d.cts → InvisibleWallet-EFiuaLn3.d.cts} +1 -1
- package/dist/{OrchestratorAgent-BvWgf9uw.d.cts → OrchestratorAgent-CrLDGNL6.d.cts} +1 -1
- package/dist/agents/index.cjs +11 -10
- package/dist/agents/index.d.cts +4 -16
- package/dist/ai/index.cjs +2 -2
- package/dist/behavior.cjs +10 -0
- package/dist/economy/index.cjs +4 -4
- package/dist/economy/index.d.cts +2 -2
- package/dist/index.cjs +33 -11
- package/dist/index.d.cts +3 -3
- package/dist/swarm/index.cjs +3 -0
- package/package.json +14 -9
- package/src/__tests__/bounty-marketplace.test.ts +53 -21
- package/src/__tests__/delegation.test.ts +1 -4
- package/src/__tests__/done-log-audit.test.ts +38 -46
- package/src/__tests__/framework.test.ts +172 -53
- package/src/__tests__/goal-synthesizer.test.ts +9 -6
- package/src/__tests__/presence.test.ts +1 -1
- package/src/__tests__/protocol-agent.test.ts +12 -11
- package/src/__tests__/revenue-splitter.test.ts +22 -15
- package/src/__tests__/scenario-driven-todo.test.ts +55 -35
- package/src/__tests__/self-improve.test.ts +28 -9
- package/src/__tests__/service-lifecycle.test.ts +9 -3
- package/src/__tests__/skill-router.test.ts +3 -3
- package/src/agents/CulturalMemory.ts +6 -6
- package/src/agents/DelegationTraceHooks.ts +560 -0
- package/src/agents/FederatedRegistryAdapter.ts +1 -1
- package/src/agents/NormEngine.ts +3 -8
- package/src/agents/OrchestratorAgent.ts +1 -1
- package/src/agents/TaskDelegationService.ts +5 -9
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +5 -4
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +9 -3
- package/src/agents/__tests__/DelegationTraceHooks.test.ts +390 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +4 -2
- package/src/agents/spatial-comms/Layer1RealTime.ts +36 -19
- package/src/agents/spatial-comms/Layer2A2A.ts +1 -3
- package/src/agents/spatial-comms/Layer3MCP.ts +13 -4
- package/src/agents/spatial-comms/ProtocolTypes.ts +5 -2
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +2 -2
- package/src/ai/HoloScriptGenerator.ts +2 -2
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +1 -1
- package/src/ai/__tests__/PerceptionSystem.test.ts +14 -14
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +1 -1
- package/src/ai/index.ts +5 -1
- package/src/board/audit.ts +17 -6
- package/src/board/board-ops.ts +45 -15
- package/src/board/board-types.ts +94 -20
- package/src/delegation.ts +5 -3
- package/src/distributed-claimer.ts +13 -2
- package/src/economy/BountyManager.ts +40 -18
- package/src/economy/KnowledgeMarketplace.ts +27 -8
- package/src/economy/PaymentWebhookService.ts +0 -1
- package/src/economy/RevenueSplitter.ts +2 -4
- package/src/economy/UnifiedBudgetOptimizer.ts +8 -9
- package/src/economy/_core-stubs.ts +1 -1
- package/src/economy/x402-facilitator.ts +17 -8
- package/src/index.ts +16 -12
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +138 -89
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +59 -16
- package/src/knowledge/brain.ts +7 -7
- package/src/knowledge/consolidation.ts +16 -16
- package/src/knowledge/knowledge-consolidator.ts +60 -30
- package/src/knowledge/knowledge-store.ts +83 -45
- package/src/learning/ProceduralCompiler.ts +6 -1
- package/src/learning/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/learning/MemoryScorer.ts +69 -0
- package/src/learning/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/learning/SemanticClusterer.ts +66 -0
- package/src/llm/llm-adapter.ts +24 -10
- package/src/mesh/index.ts +37 -17
- package/src/protocol/goal-synthesizer.ts +24 -34
- package/src/protocol/implementations.ts +91 -22
- package/src/protocol/micro-phase-decomposer.ts +25 -17
- package/src/protocol/micro-step-decomposer.test.ts +104 -39
- package/src/protocol-agent.test.ts +17 -7
- package/src/protocol-agent.ts +45 -42
- package/src/self-improve/absorb-scanner.ts +9 -6
- package/src/self-improve/evolution-engine.ts +36 -18
- package/src/self-improve/framework-absorber.ts +21 -16
- package/src/self-improve/index.ts +2 -10
- package/src/self-improve/prompt-optimizer.ts +31 -19
- package/src/self-improve/test-generator.ts +16 -12
- package/src/skill-router.ts +7 -6
- package/src/swarm/messaging/GossipProtocol.ts +1 -1
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +31 -9
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +21 -7
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +24 -8
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +6 -2
- package/src/team.ts +277 -122
- package/src/training/scripts/generate-spatial-dataset.ts +1 -1
- package/src/training/training/LRScheduler.ts +377 -0
- package/src/training/training/QualityScoringPipeline.ts +139 -0
- package/src/training/training/SoftDedup.ts +461 -0
- package/src/training/training/SparsityMonitor.ts +685 -0
- package/src/training/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/training/__tests__/CorpusValidation.test.ts +87 -0
- package/src/training/training/__tests__/LRScheduler.test.ts +592 -0
- package/src/training/training/__tests__/SoftDedup.test.ts +415 -0
- package/src/training/training/__tests__/SparsityMonitor.test.ts +1623 -0
- package/src/training/training/__tests__/SpatialCorpusValidation.test.ts +72 -0
- package/src/training/training/__tests__/SpatialTrainingDataGenerator.test.ts +1244 -0
- package/src/training/training/__tests__/TrainingMonkeyIntegration.test.ts +897 -0
- package/src/training/training/__tests__/TrainingPipelineConfig.test.ts +202 -0
- package/src/training/training/__tests__/schema.test.ts +72 -0
- package/src/training/training/__tests__/training-constants.test.ts +106 -0
- package/src/training/training/__tests__/trait-mappings.test.ts +81 -0
- package/src/training/training/constants.ts +94 -0
- package/src/training/training/index.ts +17 -0
- package/src/training/training/schema.ts +147 -0
- package/src/training/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/training/trainingmonkey/index.ts +26 -0
- package/src/training/training/trait-mappings.ts +157 -0
- package/src/types.ts +2 -7
- package/ALL-test-results.json +0 -1
- package/LICENSE +0 -21
- package/dist/AgentManifest-CB4xM-Ma.d.ts +0 -704
- package/dist/BehaviorTree-BrBFECv5.d.ts +0 -103
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +0 -1732
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +0 -798
- package/dist/agents/index.d.ts +0 -1788
- package/dist/agents/index.js +0 -4695
- package/dist/ai/index.d.ts +0 -1753
- package/dist/ai/index.js +0 -5244
- package/dist/behavior.d.ts +0 -130
- package/dist/behavior.js +0 -407
- package/dist/economy/index.d.ts +0 -747
- package/dist/economy/index.js +0 -3617
- package/dist/implementations-D9T3un9D.d.ts +0 -236
- package/dist/index.d.ts +0 -1729
- package/dist/index.js +0 -24277
- package/dist/learning/index.d.ts +0 -104
- package/dist/learning/index.js +0 -189
- package/dist/negotiation/index.d.ts +0 -610
- package/dist/negotiation/index.js +0 -931
- package/dist/skills/index.d.ts +0 -289
- package/dist/skills/index.js +0 -1079
- package/dist/swarm/index.d.ts +0 -2433
- package/dist/swarm/index.js +0 -5221
- package/dist/training/index.d.ts +0 -1734
- package/dist/training/index.js +0 -2687
- package/extract-failures.js +0 -10
- package/src/training/training/data/novel-use-cases.jsonl +0 -153
- package/src/training/training/data/spatial-reasoning-10k.jsonl +0 -9354
- package/src/types/core-stubs.d.ts +0 -113
- package/test-output.txt +0 -0
- package/test-result.json +0 -1
- package/tsc-errors.txt +0 -4
- package/tsc_output.txt +0 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +0 -22
- package/vitest-log-utf8.txt +0 -268
- package/vitest-log.txt +0 -0
package/dist/agents/index.js
DELETED
|
@@ -1,4695 +0,0 @@
|
|
|
1
|
-
// src/agents/AgentTypes.ts
|
|
2
|
-
var PHASE_ORDER = [
|
|
3
|
-
"INTAKE",
|
|
4
|
-
"REFLECT",
|
|
5
|
-
"EXECUTE",
|
|
6
|
-
"COMPRESS",
|
|
7
|
-
"REINTAKE",
|
|
8
|
-
"GROW",
|
|
9
|
-
"EVOLVE"
|
|
10
|
-
];
|
|
11
|
-
var DEFAULT_PHASE_TIMINGS = {
|
|
12
|
-
INTAKE: 1e3,
|
|
13
|
-
REFLECT: 2e3,
|
|
14
|
-
EXECUTE: 5e3,
|
|
15
|
-
COMPRESS: 1e3,
|
|
16
|
-
REINTAKE: 1e3,
|
|
17
|
-
GROW: 2e3,
|
|
18
|
-
EVOLVE: 1e3
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// src/agents/AgentManifest.ts
|
|
22
|
-
var LATENCY_THRESHOLDS = {
|
|
23
|
-
instant: 10,
|
|
24
|
-
fast: 100,
|
|
25
|
-
medium: 1e3,
|
|
26
|
-
slow: 1e4,
|
|
27
|
-
background: Infinity
|
|
28
|
-
};
|
|
29
|
-
var AgentManifestBuilder = class {
|
|
30
|
-
manifest = {
|
|
31
|
-
capabilities: [],
|
|
32
|
-
endpoints: [],
|
|
33
|
-
trustLevel: "local",
|
|
34
|
-
status: "unknown"
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Set agent identity
|
|
38
|
-
*/
|
|
39
|
-
identity(id, name, version) {
|
|
40
|
-
this.manifest.id = id;
|
|
41
|
-
this.manifest.name = name;
|
|
42
|
-
this.manifest.version = version;
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Set agent description
|
|
47
|
-
*/
|
|
48
|
-
description(desc) {
|
|
49
|
-
this.manifest.description = desc;
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Set classification
|
|
54
|
-
*/
|
|
55
|
-
classify(categories, position, section) {
|
|
56
|
-
this.manifest.categories = categories;
|
|
57
|
-
this.manifest.position = position;
|
|
58
|
-
this.manifest.section = section;
|
|
59
|
-
return this;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Add a capability
|
|
63
|
-
*/
|
|
64
|
-
addCapability(capability) {
|
|
65
|
-
this.manifest.capabilities.push(capability);
|
|
66
|
-
return this;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Add multiple capabilities
|
|
70
|
-
*/
|
|
71
|
-
addCapabilities(capabilities) {
|
|
72
|
-
this.manifest.capabilities.push(...capabilities);
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Add an endpoint
|
|
77
|
-
*/
|
|
78
|
-
addEndpoint(endpoint) {
|
|
79
|
-
this.manifest.endpoints.push(endpoint);
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Set spatial scope
|
|
84
|
-
*/
|
|
85
|
-
spatial(scope) {
|
|
86
|
-
this.manifest.spatialScope = scope;
|
|
87
|
-
return this;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Set trust level
|
|
91
|
-
*/
|
|
92
|
-
trust(level, verification) {
|
|
93
|
-
this.manifest.trustLevel = level;
|
|
94
|
-
this.manifest.verification = verification;
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Set health check interval
|
|
99
|
-
*/
|
|
100
|
-
healthCheck(intervalMs) {
|
|
101
|
-
this.manifest.healthCheckInterval = intervalMs;
|
|
102
|
-
return this;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Add custom tags
|
|
106
|
-
*/
|
|
107
|
-
tags(...tags) {
|
|
108
|
-
this.manifest.tags = [...this.manifest.tags || [], ...tags];
|
|
109
|
-
return this;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Set metadata
|
|
113
|
-
*/
|
|
114
|
-
metadata(data) {
|
|
115
|
-
this.manifest.metadata = { ...this.manifest.metadata, ...data };
|
|
116
|
-
return this;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Build the manifest
|
|
120
|
-
*/
|
|
121
|
-
build() {
|
|
122
|
-
if (!this.manifest.id || !this.manifest.name || !this.manifest.version) {
|
|
123
|
-
throw new Error("AgentManifest requires id, name, and version");
|
|
124
|
-
}
|
|
125
|
-
if (this.manifest.capabilities.length === 0) {
|
|
126
|
-
throw new Error("AgentManifest requires at least one capability");
|
|
127
|
-
}
|
|
128
|
-
if (this.manifest.endpoints.length === 0) {
|
|
129
|
-
throw new Error("AgentManifest requires at least one endpoint");
|
|
130
|
-
}
|
|
131
|
-
const now = Date.now();
|
|
132
|
-
return {
|
|
133
|
-
...this.manifest,
|
|
134
|
-
registeredAt: now,
|
|
135
|
-
updatedAt: now,
|
|
136
|
-
status: "online"
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
function createManifest() {
|
|
141
|
-
return new AgentManifestBuilder();
|
|
142
|
-
}
|
|
143
|
-
function validateManifest(manifest) {
|
|
144
|
-
const errors = [];
|
|
145
|
-
const warnings = [];
|
|
146
|
-
if (!manifest.id) errors.push("Missing required field: id");
|
|
147
|
-
if (!manifest.name) errors.push("Missing required field: name");
|
|
148
|
-
if (!manifest.version) errors.push("Missing required field: version");
|
|
149
|
-
if (!manifest.capabilities || manifest.capabilities.length === 0) {
|
|
150
|
-
errors.push("At least one capability is required");
|
|
151
|
-
}
|
|
152
|
-
if (!manifest.endpoints || manifest.endpoints.length === 0) {
|
|
153
|
-
errors.push("At least one endpoint is required");
|
|
154
|
-
}
|
|
155
|
-
manifest.capabilities?.forEach((cap, i) => {
|
|
156
|
-
if (!cap.type) errors.push(`Capability ${i}: missing type`);
|
|
157
|
-
if (!cap.domain) errors.push(`Capability ${i}: missing domain`);
|
|
158
|
-
});
|
|
159
|
-
manifest.endpoints?.forEach((ep, i) => {
|
|
160
|
-
if (!ep.protocol) errors.push(`Endpoint ${i}: missing protocol`);
|
|
161
|
-
if (!ep.address) errors.push(`Endpoint ${i}: missing address`);
|
|
162
|
-
});
|
|
163
|
-
if (!manifest.description) {
|
|
164
|
-
warnings.push("Consider adding a description for better discovery");
|
|
165
|
-
}
|
|
166
|
-
if (!manifest.healthCheckInterval) {
|
|
167
|
-
warnings.push("No health check interval set, agent health may not be tracked");
|
|
168
|
-
}
|
|
169
|
-
if (manifest.trustLevel === "untrusted") {
|
|
170
|
-
warnings.push("Untrusted agents have limited capabilities");
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
valid: errors.length === 0,
|
|
174
|
-
errors,
|
|
175
|
-
warnings
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// src/agents/CapabilityMatcher.ts
|
|
180
|
-
var TRUST_LEVELS = ["local", "verified", "known", "external", "untrusted"];
|
|
181
|
-
function getTrustScore(level) {
|
|
182
|
-
const index = TRUST_LEVELS.indexOf(level);
|
|
183
|
-
return index >= 0 ? (TRUST_LEVELS.length - index) / TRUST_LEVELS.length : 0;
|
|
184
|
-
}
|
|
185
|
-
function meetsMinTrust(agentTrust, minTrust) {
|
|
186
|
-
return TRUST_LEVELS.indexOf(agentTrust) <= TRUST_LEVELS.indexOf(minTrust);
|
|
187
|
-
}
|
|
188
|
-
var LATENCY_ORDER = ["instant", "fast", "medium", "slow", "background"];
|
|
189
|
-
function getLatencyScore(profile) {
|
|
190
|
-
const index = LATENCY_ORDER.indexOf(profile);
|
|
191
|
-
return index >= 0 ? (LATENCY_ORDER.length - index) / LATENCY_ORDER.length : 0;
|
|
192
|
-
}
|
|
193
|
-
function meetsMaxLatency(capLatency, maxLatency) {
|
|
194
|
-
if (!capLatency) return true;
|
|
195
|
-
return LATENCY_ORDER.indexOf(capLatency) <= LATENCY_ORDER.indexOf(maxLatency);
|
|
196
|
-
}
|
|
197
|
-
function pointInBounds(point, min, max) {
|
|
198
|
-
return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z;
|
|
199
|
-
}
|
|
200
|
-
function boundsOverlap(a, b) {
|
|
201
|
-
return a.min.x <= b.max.x && a.max.x >= b.min.x && a.min.y <= b.max.y && a.max.y >= b.min.y && a.min.z <= b.max.z && a.max.z >= b.min.z;
|
|
202
|
-
}
|
|
203
|
-
function matchesSpatialQuery(scope, query) {
|
|
204
|
-
if (scope?.global) return true;
|
|
205
|
-
if (!scope) return query.requireGlobal !== true;
|
|
206
|
-
if (query.point && scope.bounds) {
|
|
207
|
-
if (!pointInBounds(query.point, scope.bounds.min, scope.bounds.max)) {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (query.point && scope.radius) {
|
|
212
|
-
const dx = query.point.x - scope.radius.center.x;
|
|
213
|
-
const dy = query.point.y - scope.radius.center.y;
|
|
214
|
-
const dz = query.point.z - scope.radius.center.z;
|
|
215
|
-
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
216
|
-
if (distance > scope.radius.distance) return false;
|
|
217
|
-
}
|
|
218
|
-
if (query.scene && scope.scene && scope.scene !== query.scene) {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
if (query.nodes && scope.nodes) {
|
|
222
|
-
const hasOverlap = query.nodes.some((n) => scope.nodes.includes(n));
|
|
223
|
-
if (!hasOverlap) return false;
|
|
224
|
-
}
|
|
225
|
-
if (query.overlaps && scope.bounds) {
|
|
226
|
-
if (!boundsOverlap(scope.bounds, query.overlaps)) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
var CapabilityMatcher = class {
|
|
233
|
-
/**
|
|
234
|
-
* Check if a capability matches the query
|
|
235
|
-
*/
|
|
236
|
-
matchCapability(capability, query) {
|
|
237
|
-
const matchedCriteria = [];
|
|
238
|
-
let score = 0;
|
|
239
|
-
let criteriaCount = 0;
|
|
240
|
-
if (query.type) {
|
|
241
|
-
criteriaCount++;
|
|
242
|
-
const types = Array.isArray(query.type) ? query.type : [query.type];
|
|
243
|
-
if (types.includes(capability.type)) {
|
|
244
|
-
matchedCriteria.push("type");
|
|
245
|
-
score += 1;
|
|
246
|
-
} else {
|
|
247
|
-
return null;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
if (query.domain) {
|
|
251
|
-
criteriaCount++;
|
|
252
|
-
const domains = Array.isArray(query.domain) ? query.domain : [query.domain];
|
|
253
|
-
if (domains.includes(capability.domain)) {
|
|
254
|
-
matchedCriteria.push("domain");
|
|
255
|
-
score += 1;
|
|
256
|
-
} else {
|
|
257
|
-
return null;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (query.maxLatency && capability.latency) {
|
|
261
|
-
criteriaCount++;
|
|
262
|
-
if (meetsMaxLatency(capability.latency, query.maxLatency)) {
|
|
263
|
-
matchedCriteria.push("latency");
|
|
264
|
-
score += getLatencyScore(capability.latency);
|
|
265
|
-
} else {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if (capability.available === false) {
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
if (criteriaCount > 0 && matchedCriteria.length === 0) {
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
const normalizedScore = criteriaCount > 0 ? score / criteriaCount : 1;
|
|
276
|
-
const priorityBonus = (capability.priority || 0) / 100;
|
|
277
|
-
return {
|
|
278
|
-
capability,
|
|
279
|
-
score: Math.min(normalizedScore + priorityBonus, 1),
|
|
280
|
-
matchedCriteria
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Check if an agent matches the query
|
|
285
|
-
*/
|
|
286
|
-
matchAgent(manifest, query) {
|
|
287
|
-
const reasons = [];
|
|
288
|
-
if (!query.includeOffline && manifest.status === "offline") {
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
if (query.minTrust && !meetsMinTrust(manifest.trustLevel, query.minTrust)) {
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
if (query.spatial && !matchesSpatialQuery(manifest.spatialScope, query.spatial)) {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
if (query.tags && query.tags.length > 0) {
|
|
298
|
-
const agentTags = manifest.tags || [];
|
|
299
|
-
const hasAllTags = query.tags.every((t) => agentTags.includes(t));
|
|
300
|
-
if (!hasAllTags) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
reasons.push("tags matched");
|
|
304
|
-
}
|
|
305
|
-
const capabilityMatches = [];
|
|
306
|
-
for (const capability of manifest.capabilities) {
|
|
307
|
-
const match = this.matchCapability(capability, query);
|
|
308
|
-
if (match) {
|
|
309
|
-
capabilityMatches.push(match);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
if (capabilityMatches.length === 0) {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
const avgCapabilityScore = capabilityMatches.reduce((sum, m) => sum + m.score, 0) / capabilityMatches.length;
|
|
316
|
-
const trustScore = getTrustScore(manifest.trustLevel);
|
|
317
|
-
const overallScore = avgCapabilityScore * 0.7 + trustScore * 0.3;
|
|
318
|
-
reasons.push(`${capabilityMatches.length} capability match(es)`);
|
|
319
|
-
reasons.push(`trust: ${manifest.trustLevel}`);
|
|
320
|
-
if (manifest.status === "online") {
|
|
321
|
-
reasons.push("online");
|
|
322
|
-
}
|
|
323
|
-
return {
|
|
324
|
-
manifest,
|
|
325
|
-
score: overallScore,
|
|
326
|
-
capabilities: capabilityMatches,
|
|
327
|
-
reasons
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Find all matching agents from a list
|
|
332
|
-
*/
|
|
333
|
-
findMatches(manifests, query) {
|
|
334
|
-
const matches = [];
|
|
335
|
-
for (const manifest of manifests) {
|
|
336
|
-
const match = this.matchAgent(manifest, query);
|
|
337
|
-
if (match) {
|
|
338
|
-
matches.push(match);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
this.sortMatches(matches, query.sortBy || "score", query.sortOrder || "desc");
|
|
342
|
-
if (query.limit && query.limit > 0) {
|
|
343
|
-
return matches.slice(0, query.limit);
|
|
344
|
-
}
|
|
345
|
-
return matches;
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Find the best matching agent
|
|
349
|
-
*/
|
|
350
|
-
findBest(manifests, query) {
|
|
351
|
-
const matches = this.findMatches(manifests, { ...query, limit: 1 });
|
|
352
|
-
return matches.length > 0 ? matches[0] : null;
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Sort matches by criteria
|
|
356
|
-
*/
|
|
357
|
-
sortMatches(matches, sortBy, sortOrder) {
|
|
358
|
-
const multiplier = sortOrder === "asc" ? 1 : -1;
|
|
359
|
-
matches.sort((a, b) => {
|
|
360
|
-
switch (sortBy) {
|
|
361
|
-
case "latency": {
|
|
362
|
-
const aLatency = this.getFastestLatency(a.capabilities);
|
|
363
|
-
const bLatency = this.getFastestLatency(b.capabilities);
|
|
364
|
-
return multiplier * (LATENCY_ORDER.indexOf(aLatency) - LATENCY_ORDER.indexOf(bLatency));
|
|
365
|
-
}
|
|
366
|
-
case "trust":
|
|
367
|
-
return multiplier * (TRUST_LEVELS.indexOf(a.manifest.trustLevel) - TRUST_LEVELS.indexOf(b.manifest.trustLevel));
|
|
368
|
-
case "priority": {
|
|
369
|
-
const aPriority = this.getHighestPriority(a.capabilities);
|
|
370
|
-
const bPriority = this.getHighestPriority(b.capabilities);
|
|
371
|
-
return multiplier * (bPriority - aPriority);
|
|
372
|
-
}
|
|
373
|
-
case "name":
|
|
374
|
-
return multiplier * a.manifest.name.localeCompare(b.manifest.name);
|
|
375
|
-
case "score":
|
|
376
|
-
default:
|
|
377
|
-
return multiplier * (a.score - b.score);
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
getFastestLatency(capabilities) {
|
|
382
|
-
let fastest = "background";
|
|
383
|
-
for (const cap of capabilities) {
|
|
384
|
-
if (cap.capability.latency) {
|
|
385
|
-
const idx = LATENCY_ORDER.indexOf(cap.capability.latency);
|
|
386
|
-
if (idx < LATENCY_ORDER.indexOf(fastest)) {
|
|
387
|
-
fastest = cap.capability.latency;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return fastest;
|
|
392
|
-
}
|
|
393
|
-
getHighestPriority(capabilities) {
|
|
394
|
-
return Math.max(...capabilities.map((c) => c.capability.priority || 0));
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
var defaultMatcher = new CapabilityMatcher();
|
|
398
|
-
function findAgents(manifests, query) {
|
|
399
|
-
return defaultMatcher.findMatches(manifests, query);
|
|
400
|
-
}
|
|
401
|
-
function findBestAgent(manifests, query) {
|
|
402
|
-
return defaultMatcher.findBest(manifests, query);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// src/agents/AgentRegistry.ts
|
|
406
|
-
import { EventEmitter } from "events";
|
|
407
|
-
var DEFAULT_REGISTRY_CONFIG = {
|
|
408
|
-
mode: "central",
|
|
409
|
-
defaultTTL: 3e5,
|
|
410
|
-
// 5 minutes
|
|
411
|
-
healthCheckInterval: 1e4,
|
|
412
|
-
// 10 seconds
|
|
413
|
-
offlineThreshold: 3e4,
|
|
414
|
-
// 30 seconds
|
|
415
|
-
autoCleanup: true,
|
|
416
|
-
cleanupInterval: 6e4,
|
|
417
|
-
// 1 minute
|
|
418
|
-
maxAgents: 1e3,
|
|
419
|
-
minTrustForRegistration: "external"
|
|
420
|
-
};
|
|
421
|
-
var AgentRegistry = class extends EventEmitter {
|
|
422
|
-
agents = /* @__PURE__ */ new Map();
|
|
423
|
-
matcher = new CapabilityMatcher();
|
|
424
|
-
config;
|
|
425
|
-
healthCheckTimer;
|
|
426
|
-
cleanupTimer;
|
|
427
|
-
isShuttingDown = false;
|
|
428
|
-
constructor(config = {}) {
|
|
429
|
-
super();
|
|
430
|
-
this.config = { ...DEFAULT_REGISTRY_CONFIG, ...config };
|
|
431
|
-
}
|
|
432
|
-
// ==========================================================================
|
|
433
|
-
// LIFECYCLE
|
|
434
|
-
// ==========================================================================
|
|
435
|
-
/**
|
|
436
|
-
* Start the registry (begins health checks and cleanup)
|
|
437
|
-
*/
|
|
438
|
-
start() {
|
|
439
|
-
if (this.isShuttingDown) {
|
|
440
|
-
throw new Error("Registry is shutting down");
|
|
441
|
-
}
|
|
442
|
-
this.healthCheckTimer = setInterval(() => {
|
|
443
|
-
this.performHealthCheck();
|
|
444
|
-
}, this.config.healthCheckInterval);
|
|
445
|
-
if (this.config.autoCleanup) {
|
|
446
|
-
this.cleanupTimer = setInterval(() => {
|
|
447
|
-
this.cleanup();
|
|
448
|
-
}, this.config.cleanupInterval);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Stop the registry
|
|
453
|
-
*/
|
|
454
|
-
stop() {
|
|
455
|
-
this.isShuttingDown = true;
|
|
456
|
-
if (this.healthCheckTimer) {
|
|
457
|
-
clearInterval(this.healthCheckTimer);
|
|
458
|
-
this.healthCheckTimer = void 0;
|
|
459
|
-
}
|
|
460
|
-
if (this.cleanupTimer) {
|
|
461
|
-
clearInterval(this.cleanupTimer);
|
|
462
|
-
this.cleanupTimer = void 0;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Clear all agents and reset
|
|
467
|
-
*/
|
|
468
|
-
clear() {
|
|
469
|
-
this.agents.clear();
|
|
470
|
-
}
|
|
471
|
-
// ==========================================================================
|
|
472
|
-
// REGISTRATION
|
|
473
|
-
// ==========================================================================
|
|
474
|
-
/**
|
|
475
|
-
* Register an agent
|
|
476
|
-
*/
|
|
477
|
-
async register(manifest) {
|
|
478
|
-
if (this.isShuttingDown) {
|
|
479
|
-
throw new Error("Registry is shutting down");
|
|
480
|
-
}
|
|
481
|
-
const validation = validateManifest(manifest);
|
|
482
|
-
if (!validation.valid) {
|
|
483
|
-
throw new Error(`Invalid manifest: ${validation.errors.join(", ")}`);
|
|
484
|
-
}
|
|
485
|
-
const trustLevels = ["local", "verified", "known", "external", "untrusted"];
|
|
486
|
-
const minTrustIndex = trustLevels.indexOf(this.config.minTrustForRegistration);
|
|
487
|
-
const agentTrustIndex = trustLevels.indexOf(manifest.trustLevel);
|
|
488
|
-
if (agentTrustIndex > minTrustIndex) {
|
|
489
|
-
throw new Error(
|
|
490
|
-
`Trust level ${manifest.trustLevel} does not meet minimum ${this.config.minTrustForRegistration}`
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
if (this.agents.size >= this.config.maxAgents && !this.agents.has(manifest.id)) {
|
|
494
|
-
throw new Error(`Registry full: maximum ${this.config.maxAgents} agents`);
|
|
495
|
-
}
|
|
496
|
-
const now = Date.now();
|
|
497
|
-
const entry = {
|
|
498
|
-
manifest: {
|
|
499
|
-
...manifest,
|
|
500
|
-
registeredAt: now,
|
|
501
|
-
updatedAt: now,
|
|
502
|
-
lastHeartbeat: now,
|
|
503
|
-
status: "online"
|
|
504
|
-
},
|
|
505
|
-
registeredAt: now,
|
|
506
|
-
lastHeartbeat: now,
|
|
507
|
-
heartbeatCount: 0,
|
|
508
|
-
missedHeartbeats: 0,
|
|
509
|
-
ttl: manifest.healthCheckInterval || this.config.defaultTTL
|
|
510
|
-
};
|
|
511
|
-
const isUpdate = this.agents.has(manifest.id);
|
|
512
|
-
this.agents.set(manifest.id, entry);
|
|
513
|
-
if (isUpdate) {
|
|
514
|
-
this.emit("agent:updated", entry.manifest);
|
|
515
|
-
} else {
|
|
516
|
-
this.emit("agent:registered", entry.manifest);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Deregister an agent
|
|
521
|
-
*/
|
|
522
|
-
async deregister(agentId) {
|
|
523
|
-
const entry = this.agents.get(agentId);
|
|
524
|
-
if (entry) {
|
|
525
|
-
this.agents.delete(agentId);
|
|
526
|
-
this.emit("agent:deregistered", agentId, "explicit");
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
/**
|
|
530
|
-
* Update an agent's heartbeat
|
|
531
|
-
*/
|
|
532
|
-
async heartbeat(agentId) {
|
|
533
|
-
const entry = this.agents.get(agentId);
|
|
534
|
-
if (!entry) {
|
|
535
|
-
throw new Error(`Agent not found: ${agentId}`);
|
|
536
|
-
}
|
|
537
|
-
const now = Date.now();
|
|
538
|
-
const wasOffline = entry.manifest.status === "offline";
|
|
539
|
-
entry.lastHeartbeat = now;
|
|
540
|
-
entry.heartbeatCount++;
|
|
541
|
-
entry.missedHeartbeats = 0;
|
|
542
|
-
entry.manifest.lastHeartbeat = now;
|
|
543
|
-
entry.manifest.status = "online";
|
|
544
|
-
if (wasOffline) {
|
|
545
|
-
this.emit("agent:online", agentId);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
// ==========================================================================
|
|
549
|
-
// DISCOVERY
|
|
550
|
-
// ==========================================================================
|
|
551
|
-
/**
|
|
552
|
-
* Discover agents matching a capability query
|
|
553
|
-
*/
|
|
554
|
-
async discover(query) {
|
|
555
|
-
const manifests = this.getAllManifests();
|
|
556
|
-
const matches = this.matcher.findMatches(manifests, query);
|
|
557
|
-
return matches.map((m) => m.manifest);
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Discover agents with full match details
|
|
561
|
-
*/
|
|
562
|
-
async discoverWithScores(query) {
|
|
563
|
-
const manifests = this.getAllManifests();
|
|
564
|
-
return this.matcher.findMatches(manifests, query);
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* Find the best agent for a query
|
|
568
|
-
*/
|
|
569
|
-
async findBest(query) {
|
|
570
|
-
const manifests = this.getAllManifests();
|
|
571
|
-
const match = this.matcher.findBest(manifests, query);
|
|
572
|
-
return match?.manifest || null;
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Get a specific agent by ID
|
|
576
|
-
*/
|
|
577
|
-
get(agentId) {
|
|
578
|
-
return this.agents.get(agentId)?.manifest;
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Check if an agent is registered
|
|
582
|
-
*/
|
|
583
|
-
has(agentId) {
|
|
584
|
-
return this.agents.has(agentId);
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Get all registered manifests
|
|
588
|
-
*/
|
|
589
|
-
getAllManifests() {
|
|
590
|
-
return Array.from(this.agents.values()).map((e) => e.manifest);
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Get count of registered agents
|
|
594
|
-
*/
|
|
595
|
-
get size() {
|
|
596
|
-
return this.agents.size;
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Get count by status
|
|
600
|
-
*/
|
|
601
|
-
getStatusCounts() {
|
|
602
|
-
const counts = {
|
|
603
|
-
online: 0,
|
|
604
|
-
offline: 0,
|
|
605
|
-
degraded: 0,
|
|
606
|
-
unknown: 0
|
|
607
|
-
};
|
|
608
|
-
for (const entry of this.agents.values()) {
|
|
609
|
-
const status = entry.manifest.status || "unknown";
|
|
610
|
-
counts[status] = (counts[status] || 0) + 1;
|
|
611
|
-
}
|
|
612
|
-
return counts;
|
|
613
|
-
}
|
|
614
|
-
// ==========================================================================
|
|
615
|
-
// HEALTH CHECKS
|
|
616
|
-
// ==========================================================================
|
|
617
|
-
/**
|
|
618
|
-
* Perform health check on all agents
|
|
619
|
-
*/
|
|
620
|
-
performHealthCheck() {
|
|
621
|
-
const now = Date.now();
|
|
622
|
-
for (const [agentId, entry] of this.agents) {
|
|
623
|
-
const timeSinceHeartbeat = now - entry.lastHeartbeat;
|
|
624
|
-
if (timeSinceHeartbeat > this.config.offlineThreshold) {
|
|
625
|
-
const wasOnline = entry.manifest.status === "online";
|
|
626
|
-
entry.manifest.status = "offline";
|
|
627
|
-
entry.missedHeartbeats++;
|
|
628
|
-
if (wasOnline) {
|
|
629
|
-
this.emit("agent:offline", agentId);
|
|
630
|
-
}
|
|
631
|
-
} else if (timeSinceHeartbeat > this.config.healthCheckInterval * 2) {
|
|
632
|
-
const wasOnline = entry.manifest.status === "online";
|
|
633
|
-
entry.manifest.status = "degraded";
|
|
634
|
-
if (wasOnline) {
|
|
635
|
-
this.emit("agent:degraded", agentId);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Cleanup expired/offline agents
|
|
642
|
-
*/
|
|
643
|
-
cleanup() {
|
|
644
|
-
const now = Date.now();
|
|
645
|
-
let removedCount = 0;
|
|
646
|
-
for (const [agentId, entry] of this.agents) {
|
|
647
|
-
const _age = now - entry.registeredAt;
|
|
648
|
-
const timeSinceHeartbeat = now - entry.lastHeartbeat;
|
|
649
|
-
if (entry.manifest.status === "offline" && timeSinceHeartbeat > entry.ttl) {
|
|
650
|
-
this.agents.delete(agentId);
|
|
651
|
-
this.emit("agent:deregistered", agentId, "ttl-expired");
|
|
652
|
-
removedCount++;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
if (removedCount > 0) {
|
|
656
|
-
this.emit("registry:cleanup", removedCount);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
// ==========================================================================
|
|
660
|
-
// QUERIES
|
|
661
|
-
// ==========================================================================
|
|
662
|
-
/**
|
|
663
|
-
* Find agents by trust level
|
|
664
|
-
*/
|
|
665
|
-
findByTrust(trustLevel) {
|
|
666
|
-
return this.getAllManifests().filter((m) => m.trustLevel === trustLevel);
|
|
667
|
-
}
|
|
668
|
-
/**
|
|
669
|
-
* Find agents by tag
|
|
670
|
-
*/
|
|
671
|
-
findByTag(tag) {
|
|
672
|
-
return this.getAllManifests().filter((m) => m.tags?.includes(tag));
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Find online agents
|
|
676
|
-
*/
|
|
677
|
-
findOnline() {
|
|
678
|
-
return this.getAllManifests().filter((m) => m.status === "online");
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Find agents in a scene
|
|
682
|
-
*/
|
|
683
|
-
findInScene(scene) {
|
|
684
|
-
return this.getAllManifests().filter(
|
|
685
|
-
(m) => m.spatialScope?.scene === scene || m.spatialScope?.global
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
// ==========================================================================
|
|
689
|
-
// SERIALIZATION
|
|
690
|
-
// ==========================================================================
|
|
691
|
-
/**
|
|
692
|
-
* Export registry state
|
|
693
|
-
*/
|
|
694
|
-
export() {
|
|
695
|
-
return {
|
|
696
|
-
agents: this.getAllManifests(),
|
|
697
|
-
config: this.config,
|
|
698
|
-
timestamp: Date.now()
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Import registry state
|
|
703
|
-
*/
|
|
704
|
-
async import(data) {
|
|
705
|
-
for (const manifest of data.agents) {
|
|
706
|
-
await this.register(manifest);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
};
|
|
710
|
-
var defaultRegistry = null;
|
|
711
|
-
function getDefaultRegistry(config) {
|
|
712
|
-
if (!defaultRegistry) {
|
|
713
|
-
defaultRegistry = new AgentRegistry(config);
|
|
714
|
-
}
|
|
715
|
-
return defaultRegistry;
|
|
716
|
-
}
|
|
717
|
-
function resetDefaultRegistry() {
|
|
718
|
-
if (defaultRegistry) {
|
|
719
|
-
defaultRegistry.stop();
|
|
720
|
-
defaultRegistry.clear();
|
|
721
|
-
defaultRegistry = null;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// src/agents/FederatedRegistryAdapter.ts
|
|
726
|
-
var DEFAULT_CONFIG = {
|
|
727
|
-
seedUrls: [],
|
|
728
|
-
pollIntervalMs: 6e4,
|
|
729
|
-
maxRemoteAgents: 100,
|
|
730
|
-
trustRemoteAs: "external",
|
|
731
|
-
timeout: 5e3
|
|
732
|
-
};
|
|
733
|
-
var TAG_TO_TYPE = {
|
|
734
|
-
parsing: "analyze",
|
|
735
|
-
validation: "validate",
|
|
736
|
-
compilation: "transform",
|
|
737
|
-
generation: "generate",
|
|
738
|
-
rendering: "render",
|
|
739
|
-
analysis: "analyze",
|
|
740
|
-
optimization: "optimize",
|
|
741
|
-
storage: "store",
|
|
742
|
-
retrieval: "retrieve",
|
|
743
|
-
orchestration: "orchestrate",
|
|
744
|
-
detection: "detect",
|
|
745
|
-
communication: "communicate"
|
|
746
|
-
};
|
|
747
|
-
var TAG_TO_DOMAIN = {
|
|
748
|
-
spatial: "spatial",
|
|
749
|
-
"3d": "spatial",
|
|
750
|
-
vr: "spatial",
|
|
751
|
-
ar: "spatial",
|
|
752
|
-
nlp: "nlp",
|
|
753
|
-
language: "nlp",
|
|
754
|
-
vision: "vision",
|
|
755
|
-
blockchain: "blockchain",
|
|
756
|
-
web3: "blockchain",
|
|
757
|
-
audio: "audio",
|
|
758
|
-
video: "video",
|
|
759
|
-
physics: "physics",
|
|
760
|
-
network: "networking",
|
|
761
|
-
security: "security",
|
|
762
|
-
trading: "trading",
|
|
763
|
-
social: "social",
|
|
764
|
-
gaming: "gaming"
|
|
765
|
-
};
|
|
766
|
-
var FederatedRegistryAdapter = class {
|
|
767
|
-
registry;
|
|
768
|
-
config;
|
|
769
|
-
pollTimer;
|
|
770
|
-
remoteAgentIds = /* @__PURE__ */ new Set();
|
|
771
|
-
lastPollResults = /* @__PURE__ */ new Map();
|
|
772
|
-
constructor(registry, config = {}) {
|
|
773
|
-
this.registry = registry;
|
|
774
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
775
|
-
}
|
|
776
|
-
// ===========================================================================
|
|
777
|
-
// CORE: FETCH & REGISTER
|
|
778
|
-
// ===========================================================================
|
|
779
|
-
/**
|
|
780
|
-
* Fetch a remote agent card and register it into the local registry.
|
|
781
|
-
* Returns the converted manifest on success, null on failure.
|
|
782
|
-
*/
|
|
783
|
-
async fetchAndRegister(url) {
|
|
784
|
-
try {
|
|
785
|
-
const card = await this.fetchAgentCard(url);
|
|
786
|
-
if (!card || !card.id || !card.name) {
|
|
787
|
-
this.lastPollResults.set(url, { timestamp: Date.now(), success: false });
|
|
788
|
-
return null;
|
|
789
|
-
}
|
|
790
|
-
if (this.remoteAgentIds.size >= this.config.maxRemoteAgents && !this.remoteAgentIds.has(card.id)) {
|
|
791
|
-
this.lastPollResults.set(url, { timestamp: Date.now(), success: false });
|
|
792
|
-
return null;
|
|
793
|
-
}
|
|
794
|
-
const manifest = this.a2aCardToManifest(card, url);
|
|
795
|
-
await this.registry.register(manifest);
|
|
796
|
-
this.remoteAgentIds.add(card.id);
|
|
797
|
-
this.lastPollResults.set(url, { timestamp: Date.now(), success: true });
|
|
798
|
-
return manifest;
|
|
799
|
-
} catch {
|
|
800
|
-
this.lastPollResults.set(url, { timestamp: Date.now(), success: false });
|
|
801
|
-
return null;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
/**
|
|
805
|
-
* Poll all seed URLs once. Returns summary of results.
|
|
806
|
-
*/
|
|
807
|
-
async pollAll() {
|
|
808
|
-
let added = 0;
|
|
809
|
-
let updated = 0;
|
|
810
|
-
const failed = [];
|
|
811
|
-
const results = await Promise.allSettled(
|
|
812
|
-
this.config.seedUrls.map(async (url) => {
|
|
813
|
-
const wasKnown = this.isKnownUrl(url);
|
|
814
|
-
const manifest = await this.fetchAndRegister(url);
|
|
815
|
-
if (manifest) {
|
|
816
|
-
if (wasKnown) {
|
|
817
|
-
updated++;
|
|
818
|
-
} else {
|
|
819
|
-
added++;
|
|
820
|
-
}
|
|
821
|
-
} else {
|
|
822
|
-
failed.push(url);
|
|
823
|
-
}
|
|
824
|
-
})
|
|
825
|
-
);
|
|
826
|
-
return { added, updated, failed };
|
|
827
|
-
}
|
|
828
|
-
// ===========================================================================
|
|
829
|
-
// POLLING LIFECYCLE
|
|
830
|
-
// ===========================================================================
|
|
831
|
-
/**
|
|
832
|
-
* Start periodic polling of seed URLs.
|
|
833
|
-
*/
|
|
834
|
-
startPolling() {
|
|
835
|
-
if (this.pollTimer) return;
|
|
836
|
-
this.pollTimer = setInterval(() => {
|
|
837
|
-
void this.pollAll();
|
|
838
|
-
}, this.config.pollIntervalMs);
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Stop periodic polling.
|
|
842
|
-
*/
|
|
843
|
-
stopPolling() {
|
|
844
|
-
if (this.pollTimer) {
|
|
845
|
-
clearInterval(this.pollTimer);
|
|
846
|
-
this.pollTimer = void 0;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Whether polling is currently active.
|
|
851
|
-
*/
|
|
852
|
-
get isPolling() {
|
|
853
|
-
return this.pollTimer !== void 0;
|
|
854
|
-
}
|
|
855
|
-
// ===========================================================================
|
|
856
|
-
// CONVERSION: A2A AgentCard → AgentManifest
|
|
857
|
-
// ===========================================================================
|
|
858
|
-
/**
|
|
859
|
-
* Convert an A2A AgentCard to an AgentManifest.
|
|
860
|
-
*/
|
|
861
|
-
a2aCardToManifest(card, sourceUrl) {
|
|
862
|
-
const capabilities = this.extractCapabilities(card);
|
|
863
|
-
const endpoint = this.extractEndpoint(card);
|
|
864
|
-
return {
|
|
865
|
-
id: card.id,
|
|
866
|
-
name: card.name,
|
|
867
|
-
version: card.version || "0.0.0",
|
|
868
|
-
description: card.description,
|
|
869
|
-
capabilities,
|
|
870
|
-
endpoints: [endpoint],
|
|
871
|
-
trustLevel: this.config.trustRemoteAs,
|
|
872
|
-
tags: ["remote", "a2a", ...card.provider?.organization ? [card.provider.organization] : []],
|
|
873
|
-
status: "online",
|
|
874
|
-
metadata: {
|
|
875
|
-
sourceUrl,
|
|
876
|
-
a2aEndpoint: card.endpoint,
|
|
877
|
-
provider: card.provider,
|
|
878
|
-
a2aCapabilities: card.capabilities,
|
|
879
|
-
skillCount: card.skills?.length ?? 0
|
|
880
|
-
}
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
// ===========================================================================
|
|
884
|
-
// FEDERATED DISCOVERY
|
|
885
|
-
// ===========================================================================
|
|
886
|
-
/**
|
|
887
|
-
* Discover agents across local registry + remote seeds.
|
|
888
|
-
* Ensures all seed URLs are polled before querying.
|
|
889
|
-
*/
|
|
890
|
-
async discoverFederated(query) {
|
|
891
|
-
if (this.remoteAgentIds.size === 0 && this.config.seedUrls.length > 0) {
|
|
892
|
-
await this.pollAll();
|
|
893
|
-
}
|
|
894
|
-
return this.registry.discoverWithScores(query);
|
|
895
|
-
}
|
|
896
|
-
// ===========================================================================
|
|
897
|
-
// QUERIES
|
|
898
|
-
// ===========================================================================
|
|
899
|
-
/**
|
|
900
|
-
* Get all remote agent IDs tracked by this adapter.
|
|
901
|
-
*/
|
|
902
|
-
getRemoteAgentIds() {
|
|
903
|
-
return Array.from(this.remoteAgentIds);
|
|
904
|
-
}
|
|
905
|
-
/**
|
|
906
|
-
* Get the number of remote agents currently tracked.
|
|
907
|
-
*/
|
|
908
|
-
get remoteAgentCount() {
|
|
909
|
-
return this.remoteAgentIds.size;
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Get poll results for a specific URL.
|
|
913
|
-
*/
|
|
914
|
-
getPollResult(url) {
|
|
915
|
-
return this.lastPollResults.get(url);
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Add a seed URL dynamically (does not trigger immediate poll).
|
|
919
|
-
*/
|
|
920
|
-
addSeedUrl(url) {
|
|
921
|
-
if (!this.config.seedUrls.includes(url)) {
|
|
922
|
-
this.config.seedUrls.push(url);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Remove a seed URL and optionally deregister its agent.
|
|
927
|
-
*/
|
|
928
|
-
async removeSeedUrl(url, deregister = true) {
|
|
929
|
-
this.config.seedUrls = this.config.seedUrls.filter((u) => u !== url);
|
|
930
|
-
if (deregister) {
|
|
931
|
-
for (const agentId of this.remoteAgentIds) {
|
|
932
|
-
const manifest = this.registry.get(agentId);
|
|
933
|
-
if (manifest?.metadata?.sourceUrl === url) {
|
|
934
|
-
await this.registry.deregister(agentId);
|
|
935
|
-
this.remoteAgentIds.delete(agentId);
|
|
936
|
-
break;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
// ===========================================================================
|
|
942
|
-
// PRIVATE HELPERS
|
|
943
|
-
// ===========================================================================
|
|
944
|
-
/**
|
|
945
|
-
* Fetch an agent card from a URL.
|
|
946
|
-
*/
|
|
947
|
-
async fetchAgentCard(url) {
|
|
948
|
-
const fetchFn = this.config.fetchFn || globalThis.fetch;
|
|
949
|
-
const controller = new AbortController();
|
|
950
|
-
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
951
|
-
try {
|
|
952
|
-
const response = await fetchFn(url, {
|
|
953
|
-
signal: controller.signal,
|
|
954
|
-
headers: { Accept: "application/json" }
|
|
955
|
-
});
|
|
956
|
-
if (!response.ok) {
|
|
957
|
-
return null;
|
|
958
|
-
}
|
|
959
|
-
const data = await response.json();
|
|
960
|
-
return data;
|
|
961
|
-
} catch {
|
|
962
|
-
return null;
|
|
963
|
-
} finally {
|
|
964
|
-
clearTimeout(timeoutId);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
/**
|
|
968
|
-
* Extract capabilities from an A2A AgentCard's skills.
|
|
969
|
-
*/
|
|
970
|
-
extractCapabilities(card) {
|
|
971
|
-
if (!card.skills || card.skills.length === 0) {
|
|
972
|
-
return [{ type: "custom", domain: "general", name: card.name }];
|
|
973
|
-
}
|
|
974
|
-
const capMap = /* @__PURE__ */ new Map();
|
|
975
|
-
for (const skill of card.skills) {
|
|
976
|
-
const tags = skill.tags || [];
|
|
977
|
-
const type = this.deriveType(tags);
|
|
978
|
-
const domain = this.deriveDomain(tags);
|
|
979
|
-
const key = `${type}:${domain}`;
|
|
980
|
-
if (!capMap.has(key)) {
|
|
981
|
-
capMap.set(key, {
|
|
982
|
-
type,
|
|
983
|
-
domain,
|
|
984
|
-
name: skill.name,
|
|
985
|
-
description: skill.description,
|
|
986
|
-
available: true
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
return Array.from(capMap.values());
|
|
991
|
-
}
|
|
992
|
-
/**
|
|
993
|
-
* Extract endpoint from an A2A AgentCard.
|
|
994
|
-
*/
|
|
995
|
-
extractEndpoint(card) {
|
|
996
|
-
const url = card.endpoint || "";
|
|
997
|
-
const isSecure = url.startsWith("https");
|
|
998
|
-
return {
|
|
999
|
-
protocol: isSecure ? "https" : "http",
|
|
1000
|
-
address: url,
|
|
1001
|
-
primary: true,
|
|
1002
|
-
formats: ["json"]
|
|
1003
|
-
};
|
|
1004
|
-
}
|
|
1005
|
-
/**
|
|
1006
|
-
* Derive capability type from A2A skill tags.
|
|
1007
|
-
*/
|
|
1008
|
-
deriveType(tags) {
|
|
1009
|
-
for (const tag of tags) {
|
|
1010
|
-
const mapped = TAG_TO_TYPE[tag.toLowerCase()];
|
|
1011
|
-
if (mapped) return mapped;
|
|
1012
|
-
}
|
|
1013
|
-
return "custom";
|
|
1014
|
-
}
|
|
1015
|
-
/**
|
|
1016
|
-
* Derive capability domain from A2A skill tags.
|
|
1017
|
-
*/
|
|
1018
|
-
deriveDomain(tags) {
|
|
1019
|
-
for (const tag of tags) {
|
|
1020
|
-
const mapped = TAG_TO_DOMAIN[tag.toLowerCase()];
|
|
1021
|
-
if (mapped) return mapped;
|
|
1022
|
-
}
|
|
1023
|
-
return "general";
|
|
1024
|
-
}
|
|
1025
|
-
/**
|
|
1026
|
-
* Check if a URL has been successfully polled before.
|
|
1027
|
-
*/
|
|
1028
|
-
isKnownUrl(url) {
|
|
1029
|
-
const result = this.lastPollResults.get(url);
|
|
1030
|
-
return !!result?.success;
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
// src/agents/TaskDelegationService.ts
|
|
1035
|
-
import { randomUUID } from "crypto";
|
|
1036
|
-
var CANONICAL_TASK_BRIDGE_SCHEMA = "holoscript.task-bridge.v1";
|
|
1037
|
-
function createCanonicalTaskEnvelope(task) {
|
|
1038
|
-
return {
|
|
1039
|
-
schema: CANONICAL_TASK_BRIDGE_SCHEMA,
|
|
1040
|
-
task
|
|
1041
|
-
};
|
|
1042
|
-
}
|
|
1043
|
-
function canonicalTaskToA2ASendMessage(envelope, requestId, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1044
|
-
return {
|
|
1045
|
-
jsonrpc: "2.0",
|
|
1046
|
-
id: requestId,
|
|
1047
|
-
method: "a2a.sendMessage",
|
|
1048
|
-
params: {
|
|
1049
|
-
message: {
|
|
1050
|
-
role: "user",
|
|
1051
|
-
parts: [
|
|
1052
|
-
{
|
|
1053
|
-
type: "data",
|
|
1054
|
-
mimeType: "application/json",
|
|
1055
|
-
data: {
|
|
1056
|
-
schema: envelope.schema,
|
|
1057
|
-
task: envelope.task,
|
|
1058
|
-
skillId: envelope.task.skillId,
|
|
1059
|
-
arguments: envelope.task.input,
|
|
1060
|
-
idempotencyKey: envelope.task.idempotency_key
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
],
|
|
1064
|
-
timestamp
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
var DEFAULT_CONFIG2 = {
|
|
1070
|
-
defaultTimeout: 3e4,
|
|
1071
|
-
maxHistory: 1e3
|
|
1072
|
-
};
|
|
1073
|
-
var TaskDelegationService = class {
|
|
1074
|
-
registry;
|
|
1075
|
-
adapter;
|
|
1076
|
-
config;
|
|
1077
|
-
history = [];
|
|
1078
|
-
traceHistory = [];
|
|
1079
|
-
requestHistory = /* @__PURE__ */ new Map();
|
|
1080
|
-
constructor(registry, adapter, config = {}) {
|
|
1081
|
-
this.registry = registry;
|
|
1082
|
-
this.adapter = adapter;
|
|
1083
|
-
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
1084
|
-
}
|
|
1085
|
-
// ===========================================================================
|
|
1086
|
-
// DELEGATION
|
|
1087
|
-
// ===========================================================================
|
|
1088
|
-
/**
|
|
1089
|
-
* Delegate a task to a specific agent by ID.
|
|
1090
|
-
*/
|
|
1091
|
-
async delegateTo(request) {
|
|
1092
|
-
const startTime = Date.now();
|
|
1093
|
-
const taskId = randomUUID();
|
|
1094
|
-
const timeout = request.timeout ?? this.config.defaultTimeout;
|
|
1095
|
-
const maxRetries = request.retries ?? 0;
|
|
1096
|
-
this.requestHistory.set(taskId, { ...request, arguments: { ...request.arguments } });
|
|
1097
|
-
this.emitTrace(taskId, "start", {
|
|
1098
|
-
targetAgentId: request.targetAgentId,
|
|
1099
|
-
skillId: request.skillId,
|
|
1100
|
-
timeout,
|
|
1101
|
-
maxRetries
|
|
1102
|
-
});
|
|
1103
|
-
const manifest = this.registry.get(request.targetAgentId);
|
|
1104
|
-
if (!manifest) {
|
|
1105
|
-
const result2 = {
|
|
1106
|
-
taskId,
|
|
1107
|
-
status: "rejected",
|
|
1108
|
-
error: `Agent not found: ${request.targetAgentId}`,
|
|
1109
|
-
durationMs: Date.now() - startTime,
|
|
1110
|
-
delegatedTo: { agentId: request.targetAgentId, endpoint: "unknown" }
|
|
1111
|
-
};
|
|
1112
|
-
this.addToHistory(result2);
|
|
1113
|
-
this.emitTrace(taskId, "rejected", { reason: result2.error });
|
|
1114
|
-
return result2;
|
|
1115
|
-
}
|
|
1116
|
-
const endpoint = this.getPrimaryEndpoint(manifest);
|
|
1117
|
-
const delegatedTo = { agentId: manifest.id, endpoint: endpoint?.address || "local" };
|
|
1118
|
-
let lastError = "";
|
|
1119
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1120
|
-
this.emitTrace(taskId, "attempt", { attempt, maxRetries });
|
|
1121
|
-
if (attempt > 0) {
|
|
1122
|
-
const delay = Math.min(1e3 * Math.pow(2, attempt - 1) + Math.random() * 200, 1e4);
|
|
1123
|
-
this.emitTrace(taskId, "retry", { attempt, delayMs: delay });
|
|
1124
|
-
await this.sleep(delay);
|
|
1125
|
-
}
|
|
1126
|
-
try {
|
|
1127
|
-
const result2 = await this.executeWithTimeout(
|
|
1128
|
-
() => this.executeOnAgent(manifest, request.skillId, request.arguments, taskId, attempt),
|
|
1129
|
-
timeout
|
|
1130
|
-
);
|
|
1131
|
-
const delegationResult = {
|
|
1132
|
-
taskId,
|
|
1133
|
-
status: "completed",
|
|
1134
|
-
result: result2,
|
|
1135
|
-
durationMs: Date.now() - startTime,
|
|
1136
|
-
delegatedTo
|
|
1137
|
-
};
|
|
1138
|
-
this.addToHistory(delegationResult);
|
|
1139
|
-
this.emitTrace(taskId, "success", { attempt });
|
|
1140
|
-
return delegationResult;
|
|
1141
|
-
} catch (err) {
|
|
1142
|
-
lastError = err instanceof Error ? err.message : String(err);
|
|
1143
|
-
if (lastError === "TIMEOUT") {
|
|
1144
|
-
const result2 = {
|
|
1145
|
-
taskId,
|
|
1146
|
-
status: "timeout",
|
|
1147
|
-
error: `Delegation timed out after ${timeout}ms`,
|
|
1148
|
-
durationMs: Date.now() - startTime,
|
|
1149
|
-
delegatedTo
|
|
1150
|
-
};
|
|
1151
|
-
this.addToHistory(result2);
|
|
1152
|
-
this.emitTrace(taskId, "timeout", { attempt, timeoutMs: timeout });
|
|
1153
|
-
return result2;
|
|
1154
|
-
}
|
|
1155
|
-
this.emitTrace(taskId, "failure", { attempt, error: lastError });
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
const result = {
|
|
1159
|
-
taskId,
|
|
1160
|
-
status: "failed",
|
|
1161
|
-
error: lastError || "Unknown error",
|
|
1162
|
-
durationMs: Date.now() - startTime,
|
|
1163
|
-
delegatedTo
|
|
1164
|
-
};
|
|
1165
|
-
this.addToHistory(result);
|
|
1166
|
-
this.emitTrace(taskId, "failure", { retriesExhausted: true, error: result.error });
|
|
1167
|
-
return result;
|
|
1168
|
-
}
|
|
1169
|
-
/**
|
|
1170
|
-
* Auto-delegate: find the best agent for a capability then delegate.
|
|
1171
|
-
*/
|
|
1172
|
-
async autoDelegate(query, skillId, args, options) {
|
|
1173
|
-
const bestAgent = await this.registry.findBest({
|
|
1174
|
-
...query,
|
|
1175
|
-
includeOffline: false
|
|
1176
|
-
});
|
|
1177
|
-
if (!bestAgent) {
|
|
1178
|
-
const startTime = Date.now();
|
|
1179
|
-
const result = {
|
|
1180
|
-
taskId: randomUUID(),
|
|
1181
|
-
status: "rejected",
|
|
1182
|
-
error: `No agent found matching query: ${JSON.stringify(query)}`,
|
|
1183
|
-
durationMs: Date.now() - startTime,
|
|
1184
|
-
delegatedTo: { agentId: "none", endpoint: "none" }
|
|
1185
|
-
};
|
|
1186
|
-
this.addToHistory(result);
|
|
1187
|
-
return result;
|
|
1188
|
-
}
|
|
1189
|
-
return this.delegateTo({
|
|
1190
|
-
targetAgentId: bestAgent.id,
|
|
1191
|
-
skillId,
|
|
1192
|
-
arguments: args,
|
|
1193
|
-
timeout: options?.timeout,
|
|
1194
|
-
retries: options?.retries
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
/**
|
|
1198
|
-
* Get the status of a previously delegated task from history.
|
|
1199
|
-
*/
|
|
1200
|
-
getStatus(taskId) {
|
|
1201
|
-
return this.history.find((r) => r.taskId === taskId);
|
|
1202
|
-
}
|
|
1203
|
-
/**
|
|
1204
|
-
* Get the full delegation history.
|
|
1205
|
-
*/
|
|
1206
|
-
getDelegationHistory() {
|
|
1207
|
-
return [...this.history];
|
|
1208
|
-
}
|
|
1209
|
-
/**
|
|
1210
|
-
* Get observability trace events for delegations (optionally filtered by taskId).
|
|
1211
|
-
*/
|
|
1212
|
-
getTraceHistory(taskId) {
|
|
1213
|
-
if (!taskId) return [...this.traceHistory];
|
|
1214
|
-
return this.traceHistory.filter((event) => event.taskId === taskId);
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Replay a previously delegated task using its original request payload.
|
|
1218
|
-
*/
|
|
1219
|
-
async replay(taskId, overrides = {}) {
|
|
1220
|
-
const original = this.requestHistory.get(taskId);
|
|
1221
|
-
if (!original) {
|
|
1222
|
-
throw new Error(`Replay unavailable for taskId: ${taskId}`);
|
|
1223
|
-
}
|
|
1224
|
-
const replayRequest = {
|
|
1225
|
-
...original,
|
|
1226
|
-
...overrides,
|
|
1227
|
-
arguments: {
|
|
1228
|
-
...original.arguments,
|
|
1229
|
-
...overrides.arguments ?? {}
|
|
1230
|
-
}
|
|
1231
|
-
};
|
|
1232
|
-
this.emitTrace(taskId, "replay_requested", {
|
|
1233
|
-
targetAgentId: replayRequest.targetAgentId,
|
|
1234
|
-
skillId: replayRequest.skillId
|
|
1235
|
-
});
|
|
1236
|
-
try {
|
|
1237
|
-
const replayResult = await this.delegateTo(replayRequest);
|
|
1238
|
-
this.emitTrace(taskId, "replay_completed", { replayTaskId: replayResult.taskId });
|
|
1239
|
-
return replayResult;
|
|
1240
|
-
} catch (error) {
|
|
1241
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1242
|
-
this.emitTrace(taskId, "replay_failed", { error: message });
|
|
1243
|
-
throw error;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
/**
|
|
1247
|
-
* Get delegation stats.
|
|
1248
|
-
*/
|
|
1249
|
-
getStats() {
|
|
1250
|
-
return {
|
|
1251
|
-
total: this.history.length,
|
|
1252
|
-
completed: this.history.filter((r) => r.status === "completed").length,
|
|
1253
|
-
failed: this.history.filter((r) => r.status === "failed").length,
|
|
1254
|
-
timeout: this.history.filter((r) => r.status === "timeout").length,
|
|
1255
|
-
rejected: this.history.filter((r) => r.status === "rejected").length
|
|
1256
|
-
};
|
|
1257
|
-
}
|
|
1258
|
-
// ===========================================================================
|
|
1259
|
-
// PRIVATE HELPERS
|
|
1260
|
-
// ===========================================================================
|
|
1261
|
-
/**
|
|
1262
|
-
* Execute a skill on an agent (local or remote).
|
|
1263
|
-
*/
|
|
1264
|
-
async executeOnAgent(manifest, skillId, args, taskId, attempt) {
|
|
1265
|
-
const endpoint = this.getPrimaryEndpoint(manifest);
|
|
1266
|
-
if (!endpoint || endpoint.protocol === "local") {
|
|
1267
|
-
if (this.config.localExecutor) {
|
|
1268
|
-
return this.config.localExecutor(skillId, args);
|
|
1269
|
-
}
|
|
1270
|
-
throw new Error(`No local executor configured for agent ${manifest.id}`);
|
|
1271
|
-
}
|
|
1272
|
-
if (endpoint.protocol === "http" || endpoint.protocol === "https") {
|
|
1273
|
-
return this.executeRemote(endpoint.address, skillId, args, taskId, attempt);
|
|
1274
|
-
}
|
|
1275
|
-
throw new Error(`Unsupported endpoint protocol: ${endpoint.protocol}`);
|
|
1276
|
-
}
|
|
1277
|
-
/**
|
|
1278
|
-
* Execute via remote A2A JSON-RPC.
|
|
1279
|
-
*/
|
|
1280
|
-
async executeRemote(endpointUrl, skillId, args, taskId, attempt) {
|
|
1281
|
-
const fetchFn = this.config.fetchFn || globalThis.fetch;
|
|
1282
|
-
const idempotencyKey = this.config.idempotencyKeyFactory?.({
|
|
1283
|
-
taskId,
|
|
1284
|
-
attempt,
|
|
1285
|
-
endpointUrl,
|
|
1286
|
-
skillId
|
|
1287
|
-
}) ?? `hs-delegation-${taskId}-attempt-${attempt}`;
|
|
1288
|
-
const envelope = createCanonicalTaskEnvelope({
|
|
1289
|
-
id: taskId,
|
|
1290
|
-
intent: skillId,
|
|
1291
|
-
skillId,
|
|
1292
|
-
input: args,
|
|
1293
|
-
idempotency_key: idempotencyKey,
|
|
1294
|
-
timeout: this.config.defaultTimeout
|
|
1295
|
-
});
|
|
1296
|
-
const jsonRpcRequest = canonicalTaskToA2ASendMessage(envelope, randomUUID());
|
|
1297
|
-
if (this.config.transportAdapter) {
|
|
1298
|
-
return this.config.transportAdapter.send({
|
|
1299
|
-
endpointUrl,
|
|
1300
|
-
requestBody: jsonRpcRequest,
|
|
1301
|
-
idempotencyKey,
|
|
1302
|
-
fetchFn
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
const response = await fetchFn(endpointUrl, {
|
|
1306
|
-
method: "POST",
|
|
1307
|
-
headers: {
|
|
1308
|
-
"Content-Type": "application/json",
|
|
1309
|
-
"Idempotency-Key": idempotencyKey
|
|
1310
|
-
},
|
|
1311
|
-
body: JSON.stringify(jsonRpcRequest)
|
|
1312
|
-
});
|
|
1313
|
-
if (!response.ok) {
|
|
1314
|
-
throw new Error(`Remote agent returned HTTP ${response.status}`);
|
|
1315
|
-
}
|
|
1316
|
-
const data = await response.json();
|
|
1317
|
-
if (data.error) {
|
|
1318
|
-
throw new Error(data.error.message);
|
|
1319
|
-
}
|
|
1320
|
-
return data.result;
|
|
1321
|
-
}
|
|
1322
|
-
/**
|
|
1323
|
-
* Execute a function with a timeout.
|
|
1324
|
-
*/
|
|
1325
|
-
async executeWithTimeout(fn, timeoutMs) {
|
|
1326
|
-
return Promise.race([
|
|
1327
|
-
fn(),
|
|
1328
|
-
new Promise((_, reject) => {
|
|
1329
|
-
setTimeout(() => reject(new Error("TIMEOUT")), timeoutMs);
|
|
1330
|
-
})
|
|
1331
|
-
]);
|
|
1332
|
-
}
|
|
1333
|
-
/**
|
|
1334
|
-
* Get the primary endpoint from a manifest.
|
|
1335
|
-
*/
|
|
1336
|
-
getPrimaryEndpoint(manifest) {
|
|
1337
|
-
return manifest.endpoints.find((e) => e.primary) || manifest.endpoints[0];
|
|
1338
|
-
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Add a result to history with LRU eviction.
|
|
1341
|
-
*/
|
|
1342
|
-
addToHistory(result) {
|
|
1343
|
-
this.history.push(result);
|
|
1344
|
-
while (this.history.length > this.config.maxHistory) {
|
|
1345
|
-
const evicted = this.history.shift();
|
|
1346
|
-
if (evicted) {
|
|
1347
|
-
this.requestHistory.delete(evicted.taskId);
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
/**
|
|
1352
|
-
* Emit and store delegation observability traces.
|
|
1353
|
-
*/
|
|
1354
|
-
emitTrace(taskId, phase, metadata) {
|
|
1355
|
-
const event = {
|
|
1356
|
-
taskId,
|
|
1357
|
-
phase,
|
|
1358
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1359
|
-
...metadata ? { metadata } : {}
|
|
1360
|
-
};
|
|
1361
|
-
this.traceHistory.push(event);
|
|
1362
|
-
this.config.traceHook?.(event);
|
|
1363
|
-
}
|
|
1364
|
-
/**
|
|
1365
|
-
* Sleep utility.
|
|
1366
|
-
*/
|
|
1367
|
-
sleep(ms) {
|
|
1368
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1369
|
-
}
|
|
1370
|
-
};
|
|
1371
|
-
|
|
1372
|
-
// src/agents/SkillWorkflowEngine.ts
|
|
1373
|
-
var SkillWorkflowEngine = class {
|
|
1374
|
-
// ===========================================================================
|
|
1375
|
-
// VALIDATION
|
|
1376
|
-
// ===========================================================================
|
|
1377
|
-
/**
|
|
1378
|
-
* Validate a workflow definition.
|
|
1379
|
-
*/
|
|
1380
|
-
validate(definition, availableSkills) {
|
|
1381
|
-
const errors = [];
|
|
1382
|
-
const warnings = [];
|
|
1383
|
-
const stepIds = new Set(definition.steps.map((s) => s.id));
|
|
1384
|
-
if (definition.steps.length === 0) {
|
|
1385
|
-
errors.push("Workflow must have at least one step");
|
|
1386
|
-
return { valid: false, errors, warnings, executionPlan: { groups: [], estimatedSteps: 0 } };
|
|
1387
|
-
}
|
|
1388
|
-
if (stepIds.size !== definition.steps.length) {
|
|
1389
|
-
errors.push("Duplicate step IDs detected");
|
|
1390
|
-
}
|
|
1391
|
-
for (const step of definition.steps) {
|
|
1392
|
-
if (!step.id) {
|
|
1393
|
-
errors.push('Step missing required "id" field');
|
|
1394
|
-
}
|
|
1395
|
-
if (!step.skillId) {
|
|
1396
|
-
errors.push(`Step "${step.id}": missing required "skillId" field`);
|
|
1397
|
-
} else if (availableSkills && !availableSkills.includes(step.skillId)) {
|
|
1398
|
-
errors.push(`Step "${step.id}": skill "${step.skillId}" not found in available skills`);
|
|
1399
|
-
}
|
|
1400
|
-
if (step.dependsOn) {
|
|
1401
|
-
for (const depId of step.dependsOn) {
|
|
1402
|
-
if (!stepIds.has(depId)) {
|
|
1403
|
-
errors.push(`Step "${step.id}": dependency "${depId}" does not exist`);
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
for (const [paramName, input] of Object.entries(step.inputs || {})) {
|
|
1408
|
-
if (input.type === "ref") {
|
|
1409
|
-
if (!stepIds.has(input.stepId)) {
|
|
1410
|
-
errors.push(
|
|
1411
|
-
`Step "${step.id}": input "${paramName}" references non-existent step "${input.stepId}"`
|
|
1412
|
-
);
|
|
1413
|
-
}
|
|
1414
|
-
if (!step.dependsOn || !step.dependsOn.includes(input.stepId)) {
|
|
1415
|
-
warnings.push(
|
|
1416
|
-
`Step "${step.id}": input "${paramName}" references step "${input.stepId}" which is not in dependsOn \u2014 adding implicit dependency`
|
|
1417
|
-
);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
if (step.onError === "fallback" && !step.fallbackSkillId) {
|
|
1422
|
-
warnings.push(`Step "${step.id}": onError='fallback' but no fallbackSkillId specified`);
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
const cycleCheck = this.detectCycles(definition.steps);
|
|
1426
|
-
if (cycleCheck) {
|
|
1427
|
-
errors.push(`Cycle detected: ${cycleCheck}`);
|
|
1428
|
-
}
|
|
1429
|
-
const groups = errors.length === 0 ? this.buildExecutionGroups(definition.steps) : [];
|
|
1430
|
-
return {
|
|
1431
|
-
valid: errors.length === 0,
|
|
1432
|
-
errors,
|
|
1433
|
-
warnings,
|
|
1434
|
-
executionPlan: {
|
|
1435
|
-
groups,
|
|
1436
|
-
estimatedSteps: definition.steps.length
|
|
1437
|
-
}
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
// ===========================================================================
|
|
1441
|
-
// EXECUTION
|
|
1442
|
-
// ===========================================================================
|
|
1443
|
-
/**
|
|
1444
|
-
* Execute a workflow using the provided executor function.
|
|
1445
|
-
*/
|
|
1446
|
-
async execute(definition, executor, onProgress) {
|
|
1447
|
-
const startTime = Date.now();
|
|
1448
|
-
const stepResults = [];
|
|
1449
|
-
const stepOutputs = /* @__PURE__ */ new Map();
|
|
1450
|
-
const context = definition.context || {};
|
|
1451
|
-
const groups = this.buildExecutionGroups(definition.steps);
|
|
1452
|
-
const stepMap = new Map(definition.steps.map((s) => [s.id, s]));
|
|
1453
|
-
let hasFailed = false;
|
|
1454
|
-
for (const group of groups) {
|
|
1455
|
-
const groupResults = await Promise.all(
|
|
1456
|
-
group.map(async (stepId) => {
|
|
1457
|
-
const step = stepMap.get(stepId);
|
|
1458
|
-
if (hasFailed && step.onError !== "skip") {
|
|
1459
|
-
const result = {
|
|
1460
|
-
stepId,
|
|
1461
|
-
status: "skipped",
|
|
1462
|
-
output: {},
|
|
1463
|
-
durationMs: 0,
|
|
1464
|
-
error: "Skipped due to previous failure"
|
|
1465
|
-
};
|
|
1466
|
-
return result;
|
|
1467
|
-
}
|
|
1468
|
-
onProgress?.(stepId, "starting");
|
|
1469
|
-
const resolvedInputs = this.resolveInputs(step, stepOutputs, context);
|
|
1470
|
-
const stepStart = Date.now();
|
|
1471
|
-
try {
|
|
1472
|
-
const output = await this.executeStep(step, resolvedInputs, executor);
|
|
1473
|
-
stepOutputs.set(stepId, output);
|
|
1474
|
-
onProgress?.(stepId, "completed");
|
|
1475
|
-
return {
|
|
1476
|
-
stepId,
|
|
1477
|
-
status: "completed",
|
|
1478
|
-
output,
|
|
1479
|
-
durationMs: Date.now() - stepStart
|
|
1480
|
-
};
|
|
1481
|
-
} catch (err) {
|
|
1482
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
1483
|
-
onProgress?.(stepId, "failed");
|
|
1484
|
-
if (step.onError === "skip") {
|
|
1485
|
-
stepOutputs.set(stepId, {});
|
|
1486
|
-
return {
|
|
1487
|
-
stepId,
|
|
1488
|
-
status: "skipped",
|
|
1489
|
-
output: {},
|
|
1490
|
-
durationMs: Date.now() - stepStart,
|
|
1491
|
-
error
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
hasFailed = true;
|
|
1495
|
-
return {
|
|
1496
|
-
stepId,
|
|
1497
|
-
status: "failed",
|
|
1498
|
-
output: {},
|
|
1499
|
-
durationMs: Date.now() - stepStart,
|
|
1500
|
-
error
|
|
1501
|
-
};
|
|
1502
|
-
}
|
|
1503
|
-
})
|
|
1504
|
-
);
|
|
1505
|
-
stepResults.push(...groupResults);
|
|
1506
|
-
}
|
|
1507
|
-
const completedCount = stepResults.filter((r) => r.status === "completed").length;
|
|
1508
|
-
let status;
|
|
1509
|
-
if (completedCount === definition.steps.length) {
|
|
1510
|
-
status = "completed";
|
|
1511
|
-
} else if (completedCount > 0) {
|
|
1512
|
-
status = "partial";
|
|
1513
|
-
} else {
|
|
1514
|
-
status = "failed";
|
|
1515
|
-
}
|
|
1516
|
-
return {
|
|
1517
|
-
workflowId: definition.id,
|
|
1518
|
-
status,
|
|
1519
|
-
stepResults,
|
|
1520
|
-
totalDurationMs: Date.now() - startTime
|
|
1521
|
-
};
|
|
1522
|
-
}
|
|
1523
|
-
// ===========================================================================
|
|
1524
|
-
// PRIVATE HELPERS
|
|
1525
|
-
// ===========================================================================
|
|
1526
|
-
/**
|
|
1527
|
-
* Execute a single step with optional fallback.
|
|
1528
|
-
*/
|
|
1529
|
-
async executeStep(step, resolvedInputs, executor) {
|
|
1530
|
-
try {
|
|
1531
|
-
if (step.timeout) {
|
|
1532
|
-
return await Promise.race([
|
|
1533
|
-
executor(step.skillId, resolvedInputs),
|
|
1534
|
-
new Promise(
|
|
1535
|
-
(_, reject) => setTimeout(
|
|
1536
|
-
() => reject(new Error(`Step "${step.id}" timed out after ${step.timeout}ms`)),
|
|
1537
|
-
step.timeout
|
|
1538
|
-
)
|
|
1539
|
-
)
|
|
1540
|
-
]);
|
|
1541
|
-
}
|
|
1542
|
-
return await executor(step.skillId, resolvedInputs);
|
|
1543
|
-
} catch (err) {
|
|
1544
|
-
if (step.onError === "fallback" && step.fallbackSkillId) {
|
|
1545
|
-
return executor(step.fallbackSkillId, resolvedInputs);
|
|
1546
|
-
}
|
|
1547
|
-
throw err;
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
/**
|
|
1551
|
-
* Resolve step inputs from literal values, step outputs, or context.
|
|
1552
|
-
*/
|
|
1553
|
-
resolveInputs(step, stepOutputs, context) {
|
|
1554
|
-
const resolved = {};
|
|
1555
|
-
for (const [paramName, input] of Object.entries(step.inputs || {})) {
|
|
1556
|
-
switch (input.type) {
|
|
1557
|
-
case "literal":
|
|
1558
|
-
resolved[paramName] = input.value;
|
|
1559
|
-
break;
|
|
1560
|
-
case "ref": {
|
|
1561
|
-
const outputs = stepOutputs.get(input.stepId);
|
|
1562
|
-
resolved[paramName] = outputs?.[input.outputKey];
|
|
1563
|
-
break;
|
|
1564
|
-
}
|
|
1565
|
-
case "context":
|
|
1566
|
-
resolved[paramName] = context[input.key];
|
|
1567
|
-
break;
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
return resolved;
|
|
1571
|
-
}
|
|
1572
|
-
/**
|
|
1573
|
-
* Detect cycles in the step dependency graph.
|
|
1574
|
-
* Returns a cycle description string, or null if no cycles.
|
|
1575
|
-
*/
|
|
1576
|
-
detectCycles(steps) {
|
|
1577
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1578
|
-
const inStack = /* @__PURE__ */ new Set();
|
|
1579
|
-
const adjList = /* @__PURE__ */ new Map();
|
|
1580
|
-
for (const step of steps) {
|
|
1581
|
-
const deps = [...step.dependsOn || []];
|
|
1582
|
-
for (const input of Object.values(step.inputs || {})) {
|
|
1583
|
-
if (input.type === "ref" && !deps.includes(input.stepId)) {
|
|
1584
|
-
deps.push(input.stepId);
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
adjList.set(step.id, deps);
|
|
1588
|
-
}
|
|
1589
|
-
const dfs = (nodeId, path) => {
|
|
1590
|
-
if (inStack.has(nodeId)) {
|
|
1591
|
-
return path.concat(nodeId).join(" \u2192 ");
|
|
1592
|
-
}
|
|
1593
|
-
if (visited.has(nodeId)) return null;
|
|
1594
|
-
visited.add(nodeId);
|
|
1595
|
-
inStack.add(nodeId);
|
|
1596
|
-
for (const dep of adjList.get(nodeId) || []) {
|
|
1597
|
-
const cycle = dfs(dep, [...path, nodeId]);
|
|
1598
|
-
if (cycle) return cycle;
|
|
1599
|
-
}
|
|
1600
|
-
inStack.delete(nodeId);
|
|
1601
|
-
return null;
|
|
1602
|
-
};
|
|
1603
|
-
for (const step of steps) {
|
|
1604
|
-
if (!visited.has(step.id)) {
|
|
1605
|
-
const cycle = dfs(step.id, []);
|
|
1606
|
-
if (cycle) return cycle;
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
return null;
|
|
1610
|
-
}
|
|
1611
|
-
/**
|
|
1612
|
-
* Build parallel execution groups via topological sort.
|
|
1613
|
-
* Each group contains steps that can run concurrently.
|
|
1614
|
-
*/
|
|
1615
|
-
buildExecutionGroups(steps) {
|
|
1616
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
1617
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
1618
|
-
for (const step of steps) {
|
|
1619
|
-
if (!inDegree.has(step.id)) inDegree.set(step.id, 0);
|
|
1620
|
-
if (!dependents.has(step.id)) dependents.set(step.id, []);
|
|
1621
|
-
const allDeps = this.getAllDependencies(step);
|
|
1622
|
-
for (const dep of allDeps) {
|
|
1623
|
-
inDegree.set(step.id, (inDegree.get(step.id) || 0) + 1);
|
|
1624
|
-
if (!dependents.has(dep)) dependents.set(dep, []);
|
|
1625
|
-
dependents.get(dep).push(step.id);
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
const groups = [];
|
|
1629
|
-
let ready = [...inDegree.entries()].filter(([, deg]) => deg === 0).map(([id]) => id);
|
|
1630
|
-
while (ready.length > 0) {
|
|
1631
|
-
groups.push([...ready]);
|
|
1632
|
-
const nextReady = [];
|
|
1633
|
-
for (const id of ready) {
|
|
1634
|
-
for (const dependent of dependents.get(id) || []) {
|
|
1635
|
-
const newDeg = (inDegree.get(dependent) || 1) - 1;
|
|
1636
|
-
inDegree.set(dependent, newDeg);
|
|
1637
|
-
if (newDeg === 0) {
|
|
1638
|
-
nextReady.push(dependent);
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
ready = nextReady;
|
|
1643
|
-
}
|
|
1644
|
-
return groups;
|
|
1645
|
-
}
|
|
1646
|
-
/**
|
|
1647
|
-
* Get all dependencies for a step (explicit + implicit from ref inputs).
|
|
1648
|
-
*/
|
|
1649
|
-
getAllDependencies(step) {
|
|
1650
|
-
const deps = new Set(step.dependsOn || []);
|
|
1651
|
-
for (const input of Object.values(step.inputs || {})) {
|
|
1652
|
-
if (input.type === "ref") {
|
|
1653
|
-
deps.add(input.stepId);
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
return Array.from(deps);
|
|
1657
|
-
}
|
|
1658
|
-
};
|
|
1659
|
-
|
|
1660
|
-
// src/protocol/implementations.ts
|
|
1661
|
-
var BaseAgent = class {
|
|
1662
|
-
/**
|
|
1663
|
-
* Execute a complete 7-phase cycle
|
|
1664
|
-
*/
|
|
1665
|
-
async runCycle(task, context = {}) {
|
|
1666
|
-
const startedAt = Date.now();
|
|
1667
|
-
const cycleId = `cycle_${startedAt}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1668
|
-
const phases = [];
|
|
1669
|
-
const runPhase = async (phase, fn, input) => {
|
|
1670
|
-
const start = Date.now();
|
|
1671
|
-
try {
|
|
1672
|
-
const result = await fn.call(this, input);
|
|
1673
|
-
result.durationMs = Date.now() - start;
|
|
1674
|
-
phases.push(result);
|
|
1675
|
-
return result;
|
|
1676
|
-
} catch (err) {
|
|
1677
|
-
const failResult = {
|
|
1678
|
-
phase,
|
|
1679
|
-
status: "failure",
|
|
1680
|
-
data: err instanceof Error ? err.message : String(err),
|
|
1681
|
-
durationMs: Date.now() - start,
|
|
1682
|
-
timestamp: Date.now()
|
|
1683
|
-
};
|
|
1684
|
-
phases.push(failResult);
|
|
1685
|
-
return failResult;
|
|
1686
|
-
}
|
|
1687
|
-
};
|
|
1688
|
-
const intakeResult = await runPhase(0 /* INTAKE */, this.intake, { task, ...context });
|
|
1689
|
-
const reflectResult = await runPhase(1 /* REFLECT */, this.reflect, intakeResult.data);
|
|
1690
|
-
const executeResult = await runPhase(2 /* EXECUTE */, this.execute, reflectResult.data);
|
|
1691
|
-
const compressResult = await runPhase(
|
|
1692
|
-
3 /* COMPRESS */,
|
|
1693
|
-
this.compress,
|
|
1694
|
-
executeResult.data
|
|
1695
|
-
);
|
|
1696
|
-
const reintakeResult = await runPhase(
|
|
1697
|
-
4 /* REINTAKE */,
|
|
1698
|
-
this.reintake,
|
|
1699
|
-
compressResult.data
|
|
1700
|
-
);
|
|
1701
|
-
const growResult = await runPhase(5 /* GROW */, this.grow, reintakeResult.data);
|
|
1702
|
-
await runPhase(6 /* EVOLVE */, this.evolve, growResult.data);
|
|
1703
|
-
const failed = phases.some((p) => p.status === "failure");
|
|
1704
|
-
return {
|
|
1705
|
-
cycleId,
|
|
1706
|
-
task,
|
|
1707
|
-
domain: this.identity.domain,
|
|
1708
|
-
phases,
|
|
1709
|
-
status: failed ? "partial" : "complete",
|
|
1710
|
-
totalDurationMs: Date.now() - startedAt,
|
|
1711
|
-
startedAt,
|
|
1712
|
-
completedAt: Date.now()
|
|
1713
|
-
};
|
|
1714
|
-
}
|
|
1715
|
-
};
|
|
1716
|
-
|
|
1717
|
-
// src/agents/OrchestratorAgent.ts
|
|
1718
|
-
var OrchestratorAgent = class extends BaseAgent {
|
|
1719
|
-
identity;
|
|
1720
|
-
registry;
|
|
1721
|
-
adapter;
|
|
1722
|
-
delegator;
|
|
1723
|
-
workflowEngine;
|
|
1724
|
-
config;
|
|
1725
|
-
/** Learned delegation patterns (GROW phase) */
|
|
1726
|
-
patterns = /* @__PURE__ */ new Map();
|
|
1727
|
-
/** Routing preferences (EVOLVE phase) */
|
|
1728
|
-
preferences = /* @__PURE__ */ new Map();
|
|
1729
|
-
// skillId → preferred agentId
|
|
1730
|
-
/** Last discovered agents */
|
|
1731
|
-
lastDiscovery = [];
|
|
1732
|
-
constructor(config) {
|
|
1733
|
-
super();
|
|
1734
|
-
this.config = config;
|
|
1735
|
-
this.identity = {
|
|
1736
|
-
id: `orchestrator-${config.name.toLowerCase().replace(/\s+/g, "-")}`,
|
|
1737
|
-
name: config.name,
|
|
1738
|
-
domain: config.domain,
|
|
1739
|
-
version: "1.0.0",
|
|
1740
|
-
capabilities: ["orchestrate", "delegate", "discover", "workflow"]
|
|
1741
|
-
};
|
|
1742
|
-
this.registry = getDefaultRegistry();
|
|
1743
|
-
this.adapter = new FederatedRegistryAdapter(this.registry, {
|
|
1744
|
-
seedUrls: config.seedUrls || [],
|
|
1745
|
-
pollIntervalMs: config.discoveryIntervalMs || 6e4,
|
|
1746
|
-
fetchFn: config.fetchFn
|
|
1747
|
-
});
|
|
1748
|
-
this.delegator = new TaskDelegationService(this.registry, this.adapter, {
|
|
1749
|
-
localExecutor: config.localExecutor
|
|
1750
|
-
});
|
|
1751
|
-
this.workflowEngine = new SkillWorkflowEngine();
|
|
1752
|
-
}
|
|
1753
|
-
// ===========================================================================
|
|
1754
|
-
// PHASE 0: INTAKE — Discover available agents
|
|
1755
|
-
// ===========================================================================
|
|
1756
|
-
async intake(input) {
|
|
1757
|
-
const startTime = Date.now();
|
|
1758
|
-
const data = input;
|
|
1759
|
-
if (this.config.autoDiscovery !== false) {
|
|
1760
|
-
await this.adapter.pollAll();
|
|
1761
|
-
}
|
|
1762
|
-
const allAgents = this.registry.getAllManifests();
|
|
1763
|
-
const onlineAgents = allAgents.filter((a) => a.status === "online");
|
|
1764
|
-
return {
|
|
1765
|
-
phase: 0 /* INTAKE */,
|
|
1766
|
-
status: "success",
|
|
1767
|
-
data: {
|
|
1768
|
-
task: data.task || "orchestrate",
|
|
1769
|
-
context: data,
|
|
1770
|
-
totalAgents: allAgents.length,
|
|
1771
|
-
onlineAgents: onlineAgents.length,
|
|
1772
|
-
remoteAgents: this.adapter.remoteAgentCount,
|
|
1773
|
-
agents: onlineAgents.map((a) => ({
|
|
1774
|
-
id: a.id,
|
|
1775
|
-
name: a.name,
|
|
1776
|
-
capabilities: a.capabilities.map((c) => `${c.type}:${c.domain}`)
|
|
1777
|
-
}))
|
|
1778
|
-
},
|
|
1779
|
-
durationMs: Date.now() - startTime,
|
|
1780
|
-
timestamp: Date.now()
|
|
1781
|
-
};
|
|
1782
|
-
}
|
|
1783
|
-
// ===========================================================================
|
|
1784
|
-
// PHASE 1: REFLECT — Match capabilities to task requirements
|
|
1785
|
-
// ===========================================================================
|
|
1786
|
-
async reflect(data) {
|
|
1787
|
-
const startTime = Date.now();
|
|
1788
|
-
const intakeData = data;
|
|
1789
|
-
const task = intakeData.task || "";
|
|
1790
|
-
const query = this.taskToQuery(task, intakeData.context);
|
|
1791
|
-
this.lastDiscovery = await this.registry.discoverWithScores(query);
|
|
1792
|
-
const preferredAgents = this.getPreferredAgents(task);
|
|
1793
|
-
return {
|
|
1794
|
-
phase: 1 /* REFLECT */,
|
|
1795
|
-
status: "success",
|
|
1796
|
-
data: {
|
|
1797
|
-
task,
|
|
1798
|
-
matchingAgents: this.lastDiscovery.length,
|
|
1799
|
-
topAgent: this.lastDiscovery[0] ? { id: this.lastDiscovery[0].manifest.id, score: this.lastDiscovery[0].score } : null,
|
|
1800
|
-
preferredAgents,
|
|
1801
|
-
query
|
|
1802
|
-
},
|
|
1803
|
-
durationMs: Date.now() - startTime,
|
|
1804
|
-
timestamp: Date.now()
|
|
1805
|
-
};
|
|
1806
|
-
}
|
|
1807
|
-
// ===========================================================================
|
|
1808
|
-
// PHASE 2: EXECUTE — Delegate tasks or run workflows
|
|
1809
|
-
// ===========================================================================
|
|
1810
|
-
async execute(plan) {
|
|
1811
|
-
const startTime = Date.now();
|
|
1812
|
-
const reflectData = plan;
|
|
1813
|
-
const task = reflectData.task || "";
|
|
1814
|
-
let result = null;
|
|
1815
|
-
let executionType = "none";
|
|
1816
|
-
if (this.lastDiscovery.length > 0) {
|
|
1817
|
-
const bestAgent = this.lastDiscovery[0].manifest;
|
|
1818
|
-
result = await this.delegator.delegateTo({
|
|
1819
|
-
targetAgentId: bestAgent.id,
|
|
1820
|
-
skillId: task,
|
|
1821
|
-
arguments: reflectData.query || {}
|
|
1822
|
-
});
|
|
1823
|
-
executionType = "delegation";
|
|
1824
|
-
}
|
|
1825
|
-
return {
|
|
1826
|
-
phase: 2 /* EXECUTE */,
|
|
1827
|
-
status: "success",
|
|
1828
|
-
data: {
|
|
1829
|
-
executionType,
|
|
1830
|
-
result,
|
|
1831
|
-
task
|
|
1832
|
-
},
|
|
1833
|
-
durationMs: Date.now() - startTime,
|
|
1834
|
-
timestamp: Date.now()
|
|
1835
|
-
};
|
|
1836
|
-
}
|
|
1837
|
-
// ===========================================================================
|
|
1838
|
-
// PHASE 3: COMPRESS — Summarize results
|
|
1839
|
-
// ===========================================================================
|
|
1840
|
-
async compress(results) {
|
|
1841
|
-
const startTime = Date.now();
|
|
1842
|
-
const execData = results;
|
|
1843
|
-
const result = execData.result;
|
|
1844
|
-
return {
|
|
1845
|
-
phase: 3 /* COMPRESS */,
|
|
1846
|
-
status: "success",
|
|
1847
|
-
data: {
|
|
1848
|
-
summary: {
|
|
1849
|
-
executionType: execData.executionType,
|
|
1850
|
-
status: result?.status || "no-execution",
|
|
1851
|
-
task: execData.task,
|
|
1852
|
-
durationMs: result?.durationMs
|
|
1853
|
-
}
|
|
1854
|
-
},
|
|
1855
|
-
durationMs: Date.now() - startTime,
|
|
1856
|
-
timestamp: Date.now()
|
|
1857
|
-
};
|
|
1858
|
-
}
|
|
1859
|
-
// ===========================================================================
|
|
1860
|
-
// PHASE 4: REINTAKE — Check delegation results
|
|
1861
|
-
// ===========================================================================
|
|
1862
|
-
async reintake(compressed) {
|
|
1863
|
-
const startTime = Date.now();
|
|
1864
|
-
const summary = compressed.summary;
|
|
1865
|
-
const stats = this.delegator.getStats();
|
|
1866
|
-
return {
|
|
1867
|
-
phase: 4 /* REINTAKE */,
|
|
1868
|
-
status: "success",
|
|
1869
|
-
data: {
|
|
1870
|
-
delegationStats: stats,
|
|
1871
|
-
lastResult: summary,
|
|
1872
|
-
registryHealth: this.registry.getStatusCounts()
|
|
1873
|
-
},
|
|
1874
|
-
durationMs: Date.now() - startTime,
|
|
1875
|
-
timestamp: Date.now()
|
|
1876
|
-
};
|
|
1877
|
-
}
|
|
1878
|
-
// ===========================================================================
|
|
1879
|
-
// PHASE 5: GROW — Learn patterns from delegations
|
|
1880
|
-
// ===========================================================================
|
|
1881
|
-
async grow(learnings) {
|
|
1882
|
-
const startTime = Date.now();
|
|
1883
|
-
const data = learnings;
|
|
1884
|
-
const lastResult = data.lastResult;
|
|
1885
|
-
if (lastResult?.status === "completed") {
|
|
1886
|
-
const key = `${lastResult.task}`;
|
|
1887
|
-
const existing = this.patterns.get(key);
|
|
1888
|
-
if (existing) {
|
|
1889
|
-
existing.successCount++;
|
|
1890
|
-
existing.avgDurationMs = (existing.avgDurationMs + (lastResult.durationMs || 0)) / 2;
|
|
1891
|
-
existing.lastUsed = Date.now();
|
|
1892
|
-
} else {
|
|
1893
|
-
this.patterns.set(key, {
|
|
1894
|
-
agentId: "unknown",
|
|
1895
|
-
skillId: key,
|
|
1896
|
-
successCount: 1,
|
|
1897
|
-
failureCount: 0,
|
|
1898
|
-
avgDurationMs: lastResult.durationMs || 0,
|
|
1899
|
-
lastUsed: Date.now()
|
|
1900
|
-
});
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
return {
|
|
1904
|
-
phase: 5 /* GROW */,
|
|
1905
|
-
status: "success",
|
|
1906
|
-
data: {
|
|
1907
|
-
totalPatterns: this.patterns.size,
|
|
1908
|
-
newPattern: lastResult?.task || null
|
|
1909
|
-
},
|
|
1910
|
-
durationMs: Date.now() - startTime,
|
|
1911
|
-
timestamp: Date.now()
|
|
1912
|
-
};
|
|
1913
|
-
}
|
|
1914
|
-
// ===========================================================================
|
|
1915
|
-
// PHASE 6: EVOLVE — Optimize routing preferences
|
|
1916
|
-
// ===========================================================================
|
|
1917
|
-
async evolve(adaptations) {
|
|
1918
|
-
const startTime = Date.now();
|
|
1919
|
-
for (const [skillId, pattern] of this.patterns) {
|
|
1920
|
-
if (pattern.successCount > pattern.failureCount) {
|
|
1921
|
-
this.preferences.set(skillId, pattern.agentId);
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
return {
|
|
1925
|
-
phase: 6 /* EVOLVE */,
|
|
1926
|
-
status: "success",
|
|
1927
|
-
data: {
|
|
1928
|
-
totalPreferences: this.preferences.size,
|
|
1929
|
-
totalPatterns: this.patterns.size
|
|
1930
|
-
},
|
|
1931
|
-
durationMs: Date.now() - startTime,
|
|
1932
|
-
timestamp: Date.now()
|
|
1933
|
-
};
|
|
1934
|
-
}
|
|
1935
|
-
// ===========================================================================
|
|
1936
|
-
// CONVENIENCE METHODS
|
|
1937
|
-
// ===========================================================================
|
|
1938
|
-
/**
|
|
1939
|
-
* Delegate a task without running a full cycle.
|
|
1940
|
-
*/
|
|
1941
|
-
async delegateTask(skillId, args) {
|
|
1942
|
-
const preferredAgentId = this.preferences.get(skillId);
|
|
1943
|
-
if (preferredAgentId && this.registry.has(preferredAgentId)) {
|
|
1944
|
-
return this.delegator.delegateTo({
|
|
1945
|
-
targetAgentId: preferredAgentId,
|
|
1946
|
-
skillId,
|
|
1947
|
-
arguments: args
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
return this.delegator.autoDelegate({}, skillId, args);
|
|
1951
|
-
}
|
|
1952
|
-
/**
|
|
1953
|
-
* Run a workflow without running a full cycle.
|
|
1954
|
-
*/
|
|
1955
|
-
async runWorkflow(definition) {
|
|
1956
|
-
const executor = this.config.localExecutor ? async (skillId, inputs) => {
|
|
1957
|
-
const result = await this.config.localExecutor(skillId, inputs);
|
|
1958
|
-
return typeof result === "object" && result !== null ? result : { result };
|
|
1959
|
-
} : async (skillId, inputs) => {
|
|
1960
|
-
return { skillId, inputs, note: "No executor configured" };
|
|
1961
|
-
};
|
|
1962
|
-
return this.workflowEngine.execute(definition, executor);
|
|
1963
|
-
}
|
|
1964
|
-
/**
|
|
1965
|
-
* Get all discovered agents.
|
|
1966
|
-
*/
|
|
1967
|
-
getDiscoveredAgents() {
|
|
1968
|
-
return this.registry.getAllManifests();
|
|
1969
|
-
}
|
|
1970
|
-
/**
|
|
1971
|
-
* Get learned patterns.
|
|
1972
|
-
*/
|
|
1973
|
-
getPatterns() {
|
|
1974
|
-
return Array.from(this.patterns.values());
|
|
1975
|
-
}
|
|
1976
|
-
/**
|
|
1977
|
-
* Stop polling and cleanup.
|
|
1978
|
-
*/
|
|
1979
|
-
shutdown() {
|
|
1980
|
-
this.adapter.stopPolling();
|
|
1981
|
-
}
|
|
1982
|
-
// ===========================================================================
|
|
1983
|
-
// PRIVATE HELPERS
|
|
1984
|
-
// ===========================================================================
|
|
1985
|
-
taskToQuery(task, context) {
|
|
1986
|
-
const query = { includeOffline: false };
|
|
1987
|
-
if (context?.type) query.type = context.type;
|
|
1988
|
-
if (context?.domain) query.domain = context.domain;
|
|
1989
|
-
if (context?.tags) query.tags = context.tags;
|
|
1990
|
-
return query;
|
|
1991
|
-
}
|
|
1992
|
-
getPreferredAgents(task) {
|
|
1993
|
-
const preferred = [];
|
|
1994
|
-
const agentId = this.preferences.get(task);
|
|
1995
|
-
if (agentId) preferred.push(agentId);
|
|
1996
|
-
return preferred;
|
|
1997
|
-
}
|
|
1998
|
-
};
|
|
1999
|
-
|
|
2000
|
-
// src/agents/AgentWalletRegistry.ts
|
|
2001
|
-
var AgentWalletRegistry = class _AgentWalletRegistry {
|
|
2002
|
-
static instance;
|
|
2003
|
-
wallets = /* @__PURE__ */ new Map();
|
|
2004
|
-
constructor() {
|
|
2005
|
-
}
|
|
2006
|
-
static getInstance() {
|
|
2007
|
-
if (!_AgentWalletRegistry.instance) {
|
|
2008
|
-
_AgentWalletRegistry.instance = new _AgentWalletRegistry();
|
|
2009
|
-
}
|
|
2010
|
-
return _AgentWalletRegistry.instance;
|
|
2011
|
-
}
|
|
2012
|
-
/**
|
|
2013
|
-
* Registers a new agent wallet mapping
|
|
2014
|
-
*/
|
|
2015
|
-
registerWallet(agentId, walletAddress, networkId = 8453) {
|
|
2016
|
-
const wallet = {
|
|
2017
|
-
agentId,
|
|
2018
|
-
walletAddress,
|
|
2019
|
-
networkId,
|
|
2020
|
-
balanceThreshold: 1e-3
|
|
2021
|
-
// 0.001 ETH
|
|
2022
|
-
};
|
|
2023
|
-
this.wallets.set(agentId, wallet);
|
|
2024
|
-
return wallet;
|
|
2025
|
-
}
|
|
2026
|
-
/**
|
|
2027
|
-
* Retrieves an agent's registered wallet
|
|
2028
|
-
*/
|
|
2029
|
-
getWallet(agentId) {
|
|
2030
|
-
return this.wallets.get(agentId);
|
|
2031
|
-
}
|
|
2032
|
-
/**
|
|
2033
|
-
* Removes an agent's wallet from the registry
|
|
2034
|
-
*/
|
|
2035
|
-
unregisterWallet(agentId) {
|
|
2036
|
-
return this.wallets.delete(agentId);
|
|
2037
|
-
}
|
|
2038
|
-
/**
|
|
2039
|
-
* Authorizes an agent transaction using EIP-712 signature fallback
|
|
2040
|
-
* (Placeholder for Coinbase AgentKit KMS signing)
|
|
2041
|
-
*/
|
|
2042
|
-
async authorizeTransaction(agentId, payload) {
|
|
2043
|
-
const wallet = this.getWallet(agentId);
|
|
2044
|
-
if (!wallet) {
|
|
2045
|
-
throw new Error(`[AgentWalletRegistry] No wallet registered for agent ${agentId}`);
|
|
2046
|
-
}
|
|
2047
|
-
const mockHash = "0x" + Buffer.from(JSON.stringify(payload)).toString("hex").slice(0, 64);
|
|
2048
|
-
return mockHash;
|
|
2049
|
-
}
|
|
2050
|
-
};
|
|
2051
|
-
|
|
2052
|
-
// src/agents/AuthenticatedCRDT.ts
|
|
2053
|
-
function computeSignature(payload, signer, timestamp) {
|
|
2054
|
-
const data = JSON.stringify({ payload, signer: signer.id, timestamp });
|
|
2055
|
-
let hash = 0;
|
|
2056
|
-
for (let i = 0; i < data.length; i++) {
|
|
2057
|
-
hash = (hash << 5) - hash + data.charCodeAt(i) | 0;
|
|
2058
|
-
}
|
|
2059
|
-
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
2060
|
-
}
|
|
2061
|
-
function signOperation(payload, signer, scopeTag, timestamp) {
|
|
2062
|
-
return {
|
|
2063
|
-
payload,
|
|
2064
|
-
signer,
|
|
2065
|
-
timestamp,
|
|
2066
|
-
signature: computeSignature(payload, signer, timestamp),
|
|
2067
|
-
scopeTag
|
|
2068
|
-
};
|
|
2069
|
-
}
|
|
2070
|
-
function verifyOperation(op) {
|
|
2071
|
-
if (op.signer.revoked) return { valid: false, reason: "Signer DID revoked" };
|
|
2072
|
-
if (!op.signer.scope.includes(op.scopeTag) && !op.signer.scope.includes("*")) {
|
|
2073
|
-
return { valid: false, reason: `Signer lacks scope '${op.scopeTag}'` };
|
|
2074
|
-
}
|
|
2075
|
-
const expected = computeSignature(op.payload, op.signer, op.timestamp);
|
|
2076
|
-
if (op.signature !== expected) return { valid: false, reason: "Signature mismatch" };
|
|
2077
|
-
return { valid: true };
|
|
2078
|
-
}
|
|
2079
|
-
var LWWRegister = class {
|
|
2080
|
-
value;
|
|
2081
|
-
timestamp;
|
|
2082
|
-
lastSigner;
|
|
2083
|
-
history = [];
|
|
2084
|
-
constructor(initialValue) {
|
|
2085
|
-
this.value = initialValue;
|
|
2086
|
-
this.timestamp = 0;
|
|
2087
|
-
this.lastSigner = null;
|
|
2088
|
-
}
|
|
2089
|
-
/** Get current value */
|
|
2090
|
-
get() {
|
|
2091
|
-
return this.value;
|
|
2092
|
-
}
|
|
2093
|
-
/** Get last write timestamp */
|
|
2094
|
-
getTimestamp() {
|
|
2095
|
-
return this.timestamp;
|
|
2096
|
-
}
|
|
2097
|
-
/** Set value with a signed operation */
|
|
2098
|
-
set(op) {
|
|
2099
|
-
const verification = verifyOperation(op);
|
|
2100
|
-
if (!verification.valid) return { accepted: false, reason: verification.reason };
|
|
2101
|
-
if (op.timestamp <= this.timestamp) return { accepted: false, reason: "Stale timestamp" };
|
|
2102
|
-
this.value = op.payload;
|
|
2103
|
-
this.timestamp = op.timestamp;
|
|
2104
|
-
this.lastSigner = op.signer;
|
|
2105
|
-
this.history.push(op);
|
|
2106
|
-
return { accepted: true };
|
|
2107
|
-
}
|
|
2108
|
-
/** Merge with another register (LWW semantics) */
|
|
2109
|
-
merge(other) {
|
|
2110
|
-
if (other.timestamp > this.timestamp) {
|
|
2111
|
-
this.value = other.value;
|
|
2112
|
-
this.timestamp = other.timestamp;
|
|
2113
|
-
this.lastSigner = other.lastSigner;
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
/** Get operation history */
|
|
2117
|
-
getHistory() {
|
|
2118
|
-
return [...this.history];
|
|
2119
|
-
}
|
|
2120
|
-
};
|
|
2121
|
-
var GCounter = class _GCounter {
|
|
2122
|
-
counts = /* @__PURE__ */ new Map();
|
|
2123
|
-
// nodeId → count
|
|
2124
|
-
/** Increment for a specific node */
|
|
2125
|
-
increment(nodeId, amount = 1) {
|
|
2126
|
-
this.counts.set(nodeId, (this.counts.get(nodeId) || 0) + amount);
|
|
2127
|
-
}
|
|
2128
|
-
/** Get the total value */
|
|
2129
|
-
value() {
|
|
2130
|
-
let total = 0;
|
|
2131
|
-
for (const v of this.counts.values()) total += v;
|
|
2132
|
-
return total;
|
|
2133
|
-
}
|
|
2134
|
-
/** Get the count for a specific node */
|
|
2135
|
-
nodeValue(nodeId) {
|
|
2136
|
-
return this.counts.get(nodeId) || 0;
|
|
2137
|
-
}
|
|
2138
|
-
/** Merge with another counter (take max per node) */
|
|
2139
|
-
merge(other) {
|
|
2140
|
-
for (const [nodeId, count] of other.counts) {
|
|
2141
|
-
this.counts.set(nodeId, Math.max(this.counts.get(nodeId) || 0, count));
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
/** Export state */
|
|
2145
|
-
toJSON() {
|
|
2146
|
-
const obj = {};
|
|
2147
|
-
for (const [k, v] of this.counts) obj[k] = v;
|
|
2148
|
-
return obj;
|
|
2149
|
-
}
|
|
2150
|
-
/** Import state */
|
|
2151
|
-
static fromJSON(data) {
|
|
2152
|
-
const counter = new _GCounter();
|
|
2153
|
-
for (const [k, v] of Object.entries(data)) counter.counts.set(k, v);
|
|
2154
|
-
return counter;
|
|
2155
|
-
}
|
|
2156
|
-
};
|
|
2157
|
-
var ORSet = class {
|
|
2158
|
-
elements = /* @__PURE__ */ new Map();
|
|
2159
|
-
// tag → element
|
|
2160
|
-
tombstones = /* @__PURE__ */ new Set();
|
|
2161
|
-
// removed tags
|
|
2162
|
-
tagCounter = 0;
|
|
2163
|
-
/** Add an element with a signed operation */
|
|
2164
|
-
add(value, signer, timestamp) {
|
|
2165
|
-
if (signer.revoked) return "";
|
|
2166
|
-
const tag = `${signer.id}_${timestamp}_${this.tagCounter++}`;
|
|
2167
|
-
this.elements.set(tag, { value, tag, signer, timestamp });
|
|
2168
|
-
return tag;
|
|
2169
|
-
}
|
|
2170
|
-
/** Remove an element by value (removes all copies) */
|
|
2171
|
-
remove(value, _signer) {
|
|
2172
|
-
let removed = 0;
|
|
2173
|
-
for (const [tag, elem] of this.elements) {
|
|
2174
|
-
if (this.valueEquals(elem.value, value)) {
|
|
2175
|
-
this.tombstones.add(tag);
|
|
2176
|
-
this.elements.delete(tag);
|
|
2177
|
-
removed++;
|
|
2178
|
-
}
|
|
2179
|
-
}
|
|
2180
|
-
return removed;
|
|
2181
|
-
}
|
|
2182
|
-
/** Check if the set contains a value */
|
|
2183
|
-
has(value) {
|
|
2184
|
-
for (const elem of this.elements.values()) {
|
|
2185
|
-
if (this.valueEquals(elem.value, value)) return true;
|
|
2186
|
-
}
|
|
2187
|
-
return false;
|
|
2188
|
-
}
|
|
2189
|
-
/** Get all current values (deduplicated) */
|
|
2190
|
-
values() {
|
|
2191
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2192
|
-
const result = [];
|
|
2193
|
-
for (const elem of this.elements.values()) {
|
|
2194
|
-
const key = JSON.stringify(elem.value);
|
|
2195
|
-
if (!seen.has(key)) {
|
|
2196
|
-
seen.add(key);
|
|
2197
|
-
result.push(elem.value);
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
return result;
|
|
2201
|
-
}
|
|
2202
|
-
/** Size of the set (unique values) */
|
|
2203
|
-
get size() {
|
|
2204
|
-
return this.values().length;
|
|
2205
|
-
}
|
|
2206
|
-
/** Merge with another OR-Set (adds win over concurrent removes) */
|
|
2207
|
-
merge(other) {
|
|
2208
|
-
for (const [tag, elem] of other.elements) {
|
|
2209
|
-
if (!this.tombstones.has(tag) && !this.elements.has(tag)) {
|
|
2210
|
-
if (!elem.signer.revoked) {
|
|
2211
|
-
this.elements.set(tag, elem);
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
for (const tag of other.tombstones) {
|
|
2216
|
-
this.tombstones.add(tag);
|
|
2217
|
-
this.elements.delete(tag);
|
|
2218
|
-
}
|
|
2219
|
-
}
|
|
2220
|
-
valueEquals(a, b) {
|
|
2221
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
2222
|
-
}
|
|
2223
|
-
};
|
|
2224
|
-
function createAgentState(agentDID) {
|
|
2225
|
-
return {
|
|
2226
|
-
agentDID,
|
|
2227
|
-
registers: /* @__PURE__ */ new Map(),
|
|
2228
|
-
counters: /* @__PURE__ */ new Map(),
|
|
2229
|
-
sets: /* @__PURE__ */ new Map(),
|
|
2230
|
-
lastSync: 0
|
|
2231
|
-
};
|
|
2232
|
-
}
|
|
2233
|
-
function setRegister(state, key, value, signer, timestamp) {
|
|
2234
|
-
if (!state.registers.has(key)) {
|
|
2235
|
-
state.registers.set(key, new LWWRegister(void 0));
|
|
2236
|
-
}
|
|
2237
|
-
const op = signOperation(value, signer, `state:${key}`, timestamp);
|
|
2238
|
-
return state.registers.get(key).set(op);
|
|
2239
|
-
}
|
|
2240
|
-
function getRegister(state, key) {
|
|
2241
|
-
return state.registers.get(key)?.get();
|
|
2242
|
-
}
|
|
2243
|
-
function incrementCounter(state, key, nodeId, amount = 1) {
|
|
2244
|
-
if (!state.counters.has(key)) state.counters.set(key, new GCounter());
|
|
2245
|
-
state.counters.get(key).increment(nodeId, amount);
|
|
2246
|
-
}
|
|
2247
|
-
function getCounter(state, key) {
|
|
2248
|
-
return state.counters.get(key)?.value() ?? 0;
|
|
2249
|
-
}
|
|
2250
|
-
function mergeStates(local, remote) {
|
|
2251
|
-
for (const [key, reg] of remote.registers) {
|
|
2252
|
-
if (local.registers.has(key)) {
|
|
2253
|
-
local.registers.get(key).merge(reg);
|
|
2254
|
-
} else {
|
|
2255
|
-
local.registers.set(key, reg);
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
for (const [key, counter] of remote.counters) {
|
|
2259
|
-
if (local.counters.has(key)) {
|
|
2260
|
-
local.counters.get(key).merge(counter);
|
|
2261
|
-
} else {
|
|
2262
|
-
local.counters.set(key, counter);
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
|
-
for (const [key, set] of remote.sets) {
|
|
2266
|
-
if (local.sets.has(key)) {
|
|
2267
|
-
local.sets.get(key).merge(set);
|
|
2268
|
-
} else {
|
|
2269
|
-
local.sets.set(key, set);
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
local.lastSync = Math.max(local.lastSync, remote.lastSync);
|
|
2273
|
-
}
|
|
2274
|
-
|
|
2275
|
-
// src/agents/CrossRealityHandoff.ts
|
|
2276
|
-
var PLATFORM_CAPABILITIES = {};
|
|
2277
|
-
var embodimentFor = (platform) => {
|
|
2278
|
-
if (platform === "quest3" || platform === "pcvr") return "Avatar3D";
|
|
2279
|
-
if (platform === "android-auto") return "VoiceHUD";
|
|
2280
|
-
return "UI2D";
|
|
2281
|
-
};
|
|
2282
|
-
var platformCategory = (platform) => {
|
|
2283
|
-
if (platform.includes("android-auto")) return "automotive";
|
|
2284
|
-
if (platform.includes("android") || platform.includes("ios")) return "mobile";
|
|
2285
|
-
if (platform.includes("quest") || platform.includes("pcvr")) return "vr";
|
|
2286
|
-
return "desktop";
|
|
2287
|
-
};
|
|
2288
|
-
function negotiateHandoff(source, target) {
|
|
2289
|
-
const gained = [];
|
|
2290
|
-
const lost = [];
|
|
2291
|
-
const boolCaps = [
|
|
2292
|
-
"spatialTracking",
|
|
2293
|
-
"handTracking",
|
|
2294
|
-
"eyeTracking",
|
|
2295
|
-
"haptics",
|
|
2296
|
-
"spatialAudio",
|
|
2297
|
-
"gpu3D",
|
|
2298
|
-
"arCamera",
|
|
2299
|
-
"gps",
|
|
2300
|
-
"npu",
|
|
2301
|
-
"webxrSupport"
|
|
2302
|
-
];
|
|
2303
|
-
for (const cap of boolCaps) {
|
|
2304
|
-
const srcHas = !!source.capabilities[cap];
|
|
2305
|
-
const tgtHas = !!target.capabilities[cap];
|
|
2306
|
-
if (!srcHas && tgtHas) gained.push(cap);
|
|
2307
|
-
if (srcHas && !tgtHas) lost.push(cap);
|
|
2308
|
-
}
|
|
2309
|
-
const srcCat = platformCategory(source.platform);
|
|
2310
|
-
const tgtCat = platformCategory(target.platform);
|
|
2311
|
-
let latency = 200;
|
|
2312
|
-
if (srcCat === tgtCat) latency = 100;
|
|
2313
|
-
if (tgtCat === "automotive") latency = 500;
|
|
2314
|
-
const feasible = target.available;
|
|
2315
|
-
return {
|
|
2316
|
-
sourceDevice: source,
|
|
2317
|
-
targetDevice: target,
|
|
2318
|
-
gained,
|
|
2319
|
-
lost,
|
|
2320
|
-
transition: { from: source.embodiment, to: target.embodiment },
|
|
2321
|
-
estimatedLatencyMs: latency,
|
|
2322
|
-
feasible,
|
|
2323
|
-
reason: feasible ? void 0 : "Target device not available"
|
|
2324
|
-
};
|
|
2325
|
-
}
|
|
2326
|
-
function createMVCPayload(agentDID, sessionId, source, data) {
|
|
2327
|
-
const trimmedDecisions = data.decisions.slice(-10);
|
|
2328
|
-
const trimmedEvidence = data.evidence.sort((a, b) => b.relevance - a.relevance).slice(0, 15);
|
|
2329
|
-
return {
|
|
2330
|
-
version: "1.0",
|
|
2331
|
-
agentDID,
|
|
2332
|
-
sessionId,
|
|
2333
|
-
decisions: trimmedDecisions,
|
|
2334
|
-
task: data.task,
|
|
2335
|
-
preferences: data.preferences,
|
|
2336
|
-
spatial: data.spatial,
|
|
2337
|
-
evidence: trimmedEvidence,
|
|
2338
|
-
handoff: {
|
|
2339
|
-
sourceDevice: source.deviceId,
|
|
2340
|
-
sourcePlatform: source.platform,
|
|
2341
|
-
sourceEmbodiment: embodimentFor(source.platform),
|
|
2342
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2343
|
-
}
|
|
2344
|
-
};
|
|
2345
|
-
}
|
|
2346
|
-
function estimatePayloadSize(payload) {
|
|
2347
|
-
return new TextEncoder().encode(JSON.stringify(payload)).length;
|
|
2348
|
-
}
|
|
2349
|
-
function validatePayloadBudget(payload) {
|
|
2350
|
-
const BUDGET = 10 * 1024;
|
|
2351
|
-
const size = estimatePayloadSize(payload);
|
|
2352
|
-
return { valid: size <= BUDGET, sizeBytes: size, budgetBytes: BUDGET };
|
|
2353
|
-
}
|
|
2354
|
-
|
|
2355
|
-
// src/agents/CulturalMemory.ts
|
|
2356
|
-
var DEFAULT_CONFIG3 = {
|
|
2357
|
-
episodicCapacity: 100,
|
|
2358
|
-
episodicDecayRate: 0.01,
|
|
2359
|
-
stigmergicCapacity: 500,
|
|
2360
|
-
traceDecayRate: 5e-3,
|
|
2361
|
-
consolidationThreshold: 5,
|
|
2362
|
-
sopRetentionThreshold: 0.3
|
|
2363
|
-
};
|
|
2364
|
-
var CulturalMemory = class {
|
|
2365
|
-
config;
|
|
2366
|
-
episodic = /* @__PURE__ */ new Map();
|
|
2367
|
-
// agentId → memories
|
|
2368
|
-
stigmergic = /* @__PURE__ */ new Map();
|
|
2369
|
-
// zoneId → traces
|
|
2370
|
-
sops = /* @__PURE__ */ new Map();
|
|
2371
|
-
// sopId → SOP
|
|
2372
|
-
currentTick = 0;
|
|
2373
|
-
constructor(config = {}) {
|
|
2374
|
-
this.config = { ...DEFAULT_CONFIG3, ...config };
|
|
2375
|
-
}
|
|
2376
|
-
// ── Episodic Memory ──────────────────────────────────────────────────────
|
|
2377
|
-
/**
|
|
2378
|
-
* Record an episodic memory for an agent.
|
|
2379
|
-
*/
|
|
2380
|
-
record(agentId, event, opts = {}) {
|
|
2381
|
-
const memories = this.episodic.get(agentId) || [];
|
|
2382
|
-
const memory = {
|
|
2383
|
-
id: `ep_${agentId}_${this.currentTick}_${memories.length}`,
|
|
2384
|
-
agentId,
|
|
2385
|
-
event,
|
|
2386
|
-
participants: opts.participants || [],
|
|
2387
|
-
valence: opts.valence ?? 0,
|
|
2388
|
-
importance: opts.importance ?? 0.5,
|
|
2389
|
-
timestamp: this.currentTick,
|
|
2390
|
-
strength: 1,
|
|
2391
|
-
normId: opts.normId,
|
|
2392
|
-
tags: opts.tags || []
|
|
2393
|
-
};
|
|
2394
|
-
memories.push(memory);
|
|
2395
|
-
if (memories.length > this.config.episodicCapacity) {
|
|
2396
|
-
memories.sort((a, b) => b.strength * b.importance - a.strength * a.importance);
|
|
2397
|
-
memories.length = this.config.episodicCapacity;
|
|
2398
|
-
}
|
|
2399
|
-
this.episodic.set(agentId, memories);
|
|
2400
|
-
return memory;
|
|
2401
|
-
}
|
|
2402
|
-
/**
|
|
2403
|
-
* Recall memories for an agent, optionally filtered.
|
|
2404
|
-
*/
|
|
2405
|
-
recall(agentId, filter) {
|
|
2406
|
-
const memories = this.episodic.get(agentId) || [];
|
|
2407
|
-
return memories.filter((m) => {
|
|
2408
|
-
if (filter?.minStrength && m.strength < filter.minStrength) return false;
|
|
2409
|
-
if (filter?.normId && m.normId !== filter.normId) return false;
|
|
2410
|
-
if (filter?.tags && !filter.tags.some((t) => m.tags.includes(t))) return false;
|
|
2411
|
-
return true;
|
|
2412
|
-
}).sort((a, b) => b.strength * b.importance - a.strength * a.importance);
|
|
2413
|
-
}
|
|
2414
|
-
/**
|
|
2415
|
-
* Get the number of memories for an agent.
|
|
2416
|
-
*/
|
|
2417
|
-
memoryCount(agentId) {
|
|
2418
|
-
return (this.episodic.get(agentId) || []).length;
|
|
2419
|
-
}
|
|
2420
|
-
// ── Stigmergic Memory ────────────────────────────────────────────────────
|
|
2421
|
-
/**
|
|
2422
|
-
* Leave a stigmergic trace in the environment.
|
|
2423
|
-
*/
|
|
2424
|
-
leaveTrace(creatorId, zoneId, label, position, opts = {}) {
|
|
2425
|
-
const traces = this.stigmergic.get(zoneId) || [];
|
|
2426
|
-
const intensity = opts.intensity ?? opts.initialIntensity ?? 1;
|
|
2427
|
-
const trace = {
|
|
2428
|
-
id: `st_${zoneId}_${this.currentTick}_${traces.length}`,
|
|
2429
|
-
creatorId,
|
|
2430
|
-
position,
|
|
2431
|
-
zoneId,
|
|
2432
|
-
type: opts.type || "marker",
|
|
2433
|
-
label,
|
|
2434
|
-
intensity,
|
|
2435
|
-
initialIntensity: intensity,
|
|
2436
|
-
decayRate: opts.decayRate ?? this.config.traceDecayRate,
|
|
2437
|
-
radius: opts.radius ?? 10,
|
|
2438
|
-
timestamp: this.currentTick,
|
|
2439
|
-
reinforcements: 0
|
|
2440
|
-
};
|
|
2441
|
-
traces.push(trace);
|
|
2442
|
-
if (traces.length > this.config.stigmergicCapacity) {
|
|
2443
|
-
traces.sort((a, b) => b.intensity - a.intensity);
|
|
2444
|
-
traces.length = this.config.stigmergicCapacity;
|
|
2445
|
-
}
|
|
2446
|
-
this.stigmergic.set(zoneId, traces);
|
|
2447
|
-
return trace;
|
|
2448
|
-
}
|
|
2449
|
-
/**
|
|
2450
|
-
* Perceive nearby traces from a position.
|
|
2451
|
-
*/
|
|
2452
|
-
perceiveTraces(zoneId, position) {
|
|
2453
|
-
const traces = this.stigmergic.get(zoneId) || [];
|
|
2454
|
-
return traces.filter((t) => {
|
|
2455
|
-
const dx = t.position.x - position.x;
|
|
2456
|
-
const dy = t.position.y - position.y;
|
|
2457
|
-
const dz = t.position.z - position.z;
|
|
2458
|
-
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
2459
|
-
return dist <= t.radius && t.intensity > 0.01;
|
|
2460
|
-
}).sort((a, b) => b.intensity - a.intensity);
|
|
2461
|
-
}
|
|
2462
|
-
/**
|
|
2463
|
-
* Reinforce a trace (another agent validates it).
|
|
2464
|
-
* Increases intensity and slows decay.
|
|
2465
|
-
*/
|
|
2466
|
-
reinforceTrace(traceId, zoneId) {
|
|
2467
|
-
const traces = this.stigmergic.get(zoneId) || [];
|
|
2468
|
-
const trace = traces.find((t) => t.id === traceId);
|
|
2469
|
-
if (!trace) return false;
|
|
2470
|
-
trace.reinforcements++;
|
|
2471
|
-
trace.intensity = Math.min(trace.initialIntensity * 2, trace.intensity + 0.1);
|
|
2472
|
-
trace.decayRate *= 0.95;
|
|
2473
|
-
return true;
|
|
2474
|
-
}
|
|
2475
|
-
/**
|
|
2476
|
-
* Get all traces in a zone.
|
|
2477
|
-
*/
|
|
2478
|
-
zoneTraces(zoneId) {
|
|
2479
|
-
return (this.stigmergic.get(zoneId) || []).filter((t) => t.intensity > 0.01);
|
|
2480
|
-
}
|
|
2481
|
-
// ── Semantic SOPs ────────────────────────────────────────────────────────
|
|
2482
|
-
/**
|
|
2483
|
-
* Attempt to consolidate episodic memories into a semantic SOP.
|
|
2484
|
-
* Finds repeated patterns (same normId, high frequency) and forms SOPs.
|
|
2485
|
-
*/
|
|
2486
|
-
consolidate(agentId) {
|
|
2487
|
-
const memories = this.episodic.get(agentId) || [];
|
|
2488
|
-
const newSops = [];
|
|
2489
|
-
const byNorm = /* @__PURE__ */ new Map();
|
|
2490
|
-
for (const m of memories) {
|
|
2491
|
-
if (m.normId) {
|
|
2492
|
-
const group = byNorm.get(m.normId) || [];
|
|
2493
|
-
group.push(m);
|
|
2494
|
-
byNorm.set(m.normId, group);
|
|
2495
|
-
}
|
|
2496
|
-
}
|
|
2497
|
-
for (const [normId, episodes] of byNorm) {
|
|
2498
|
-
if (episodes.length < this.config.consolidationThreshold) continue;
|
|
2499
|
-
const existing = this.sops.get(`sop_${agentId}_${normId}`);
|
|
2500
|
-
if (existing) {
|
|
2501
|
-
existing.episodeCount = episodes.length;
|
|
2502
|
-
existing.confidence = Math.min(
|
|
2503
|
-
1,
|
|
2504
|
-
episodes.length / (this.config.consolidationThreshold * 3)
|
|
2505
|
-
);
|
|
2506
|
-
existing.updatedAt = this.currentTick;
|
|
2507
|
-
continue;
|
|
2508
|
-
}
|
|
2509
|
-
const avgValence = episodes.reduce((s, e) => s + e.valence, 0) / episodes.length;
|
|
2510
|
-
const sop = {
|
|
2511
|
-
id: `sop_${agentId}_${normId}`,
|
|
2512
|
-
normId,
|
|
2513
|
-
description: `Learned behavior for norm '${normId}' from ${episodes.length} experiences (avg valence: ${avgValence.toFixed(2)})`,
|
|
2514
|
-
conditions: [...new Set(episodes.flatMap((e) => e.tags))],
|
|
2515
|
-
actions: avgValence > 0 ? ["comply", "reinforce"] : ["avoid", "report"],
|
|
2516
|
-
confidence: Math.min(1, episodes.length / (this.config.consolidationThreshold * 3)),
|
|
2517
|
-
episodeCount: episodes.length,
|
|
2518
|
-
createdAt: this.currentTick,
|
|
2519
|
-
updatedAt: this.currentTick
|
|
2520
|
-
};
|
|
2521
|
-
this.sops.set(sop.id, sop);
|
|
2522
|
-
newSops.push(sop);
|
|
2523
|
-
}
|
|
2524
|
-
return newSops;
|
|
2525
|
-
}
|
|
2526
|
-
/**
|
|
2527
|
-
* Get all SOPs for an agent.
|
|
2528
|
-
*/
|
|
2529
|
-
getSOPs(agentId) {
|
|
2530
|
-
const prefix = `sop_${agentId}_`;
|
|
2531
|
-
return [...this.sops.values()].filter((s) => s.id.startsWith(prefix));
|
|
2532
|
-
}
|
|
2533
|
-
/**
|
|
2534
|
-
* Get a specific SOP by agent and norm.
|
|
2535
|
-
*/
|
|
2536
|
-
getSOP(agentId, normId) {
|
|
2537
|
-
return this.sops.get(`sop_${agentId}_${normId}`);
|
|
2538
|
-
}
|
|
2539
|
-
// ── Tick / Lifecycle ─────────────────────────────────────────────────────
|
|
2540
|
-
/**
|
|
2541
|
-
* Advance one tick: decay memories and traces, prune dead entries.
|
|
2542
|
-
*/
|
|
2543
|
-
tick() {
|
|
2544
|
-
this.currentTick++;
|
|
2545
|
-
let decayedMemories = 0;
|
|
2546
|
-
let evaporatedTraces = 0;
|
|
2547
|
-
for (const [agentId, memories] of this.episodic) {
|
|
2548
|
-
for (const m of memories) {
|
|
2549
|
-
m.strength *= 1 - this.config.episodicDecayRate;
|
|
2550
|
-
}
|
|
2551
|
-
const before = memories.length;
|
|
2552
|
-
const alive = memories.filter((m) => m.strength > 0.01);
|
|
2553
|
-
decayedMemories += before - alive.length;
|
|
2554
|
-
this.episodic.set(agentId, alive);
|
|
2555
|
-
}
|
|
2556
|
-
for (const [zoneId, traces] of this.stigmergic) {
|
|
2557
|
-
for (const t of traces) {
|
|
2558
|
-
t.intensity -= t.decayRate;
|
|
2559
|
-
}
|
|
2560
|
-
const before = traces.length;
|
|
2561
|
-
const alive = traces.filter((t) => t.intensity > 0.01);
|
|
2562
|
-
evaporatedTraces += before - alive.length;
|
|
2563
|
-
this.stigmergic.set(zoneId, alive);
|
|
2564
|
-
}
|
|
2565
|
-
for (const [id, sop] of this.sops) {
|
|
2566
|
-
if (sop.confidence < this.config.sopRetentionThreshold) {
|
|
2567
|
-
this.sops.delete(id);
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
return { decayedMemories, evaporatedTraces };
|
|
2571
|
-
}
|
|
2572
|
-
/**
|
|
2573
|
-
* Get current tick.
|
|
2574
|
-
*/
|
|
2575
|
-
getTick() {
|
|
2576
|
-
return this.currentTick;
|
|
2577
|
-
}
|
|
2578
|
-
/**
|
|
2579
|
-
* Get global statistics.
|
|
2580
|
-
*/
|
|
2581
|
-
stats() {
|
|
2582
|
-
let totalMemories = 0;
|
|
2583
|
-
let totalTraces = 0;
|
|
2584
|
-
for (const mems of this.episodic.values()) totalMemories += mems.length;
|
|
2585
|
-
for (const traces of this.stigmergic.values()) totalTraces += traces.length;
|
|
2586
|
-
return {
|
|
2587
|
-
agents: this.episodic.size,
|
|
2588
|
-
totalMemories,
|
|
2589
|
-
totalTraces,
|
|
2590
|
-
totalSOPs: this.sops.size,
|
|
2591
|
-
zones: this.stigmergic.size
|
|
2592
|
-
};
|
|
2593
|
-
}
|
|
2594
|
-
/**
|
|
2595
|
-
* Export full state for persistence / cross-session continuity.
|
|
2596
|
-
*/
|
|
2597
|
-
exportState() {
|
|
2598
|
-
const episodic = {};
|
|
2599
|
-
for (const [k, v] of this.episodic) episodic[k] = v;
|
|
2600
|
-
const stigmergic = {};
|
|
2601
|
-
for (const [k, v] of this.stigmergic) stigmergic[k] = v;
|
|
2602
|
-
return { episodic, stigmergic, sops: [...this.sops.values()], tick: this.currentTick };
|
|
2603
|
-
}
|
|
2604
|
-
/**
|
|
2605
|
-
* Import state from persistence.
|
|
2606
|
-
*/
|
|
2607
|
-
importState(state) {
|
|
2608
|
-
for (const [k, v] of Object.entries(state.episodic)) this.episodic.set(k, v);
|
|
2609
|
-
for (const [k, v] of Object.entries(state.stigmergic)) this.stigmergic.set(k, v);
|
|
2610
|
-
for (const sop of state.sops) this.sops.set(sop.id, sop);
|
|
2611
|
-
this.currentTick = state.tick;
|
|
2612
|
-
}
|
|
2613
|
-
};
|
|
2614
|
-
|
|
2615
|
-
// src/agents/NormEngine.ts
|
|
2616
|
-
var BUILTIN_NORMS = [
|
|
2617
|
-
{
|
|
2618
|
-
id: "no_griefing",
|
|
2619
|
-
name: "No Griefing",
|
|
2620
|
-
category: "safety",
|
|
2621
|
-
description: "Do not cause harm to others",
|
|
2622
|
-
enforcement: "hard",
|
|
2623
|
-
scope: "world",
|
|
2624
|
-
activationThreshold: 0.1,
|
|
2625
|
-
strength: "strong",
|
|
2626
|
-
forbiddenEffects: ["agent:kill", "inventory:steal"]
|
|
2627
|
-
},
|
|
2628
|
-
{
|
|
2629
|
-
id: "resource_sharing",
|
|
2630
|
-
name: "Resource Sharing",
|
|
2631
|
-
category: "cooperation",
|
|
2632
|
-
description: "Share resources when abundant",
|
|
2633
|
-
enforcement: "soft",
|
|
2634
|
-
scope: "world",
|
|
2635
|
-
activationThreshold: 0.5,
|
|
2636
|
-
strength: "moderate",
|
|
2637
|
-
forbiddenEffects: ["inventory:hoard", "inventory:horde"]
|
|
2638
|
-
},
|
|
2639
|
-
{
|
|
2640
|
-
id: "fair_trade",
|
|
2641
|
-
name: "Fair Trade",
|
|
2642
|
-
category: "economy",
|
|
2643
|
-
description: "Trade at mutually agreeable values",
|
|
2644
|
-
enforcement: "soft",
|
|
2645
|
-
scope: "world",
|
|
2646
|
-
activationThreshold: 0.3,
|
|
2647
|
-
strength: "weak",
|
|
2648
|
-
forbiddenEffects: ["trade:scam", "trade:extort"]
|
|
2649
|
-
}
|
|
2650
|
-
];
|
|
2651
|
-
function criticalMassForChange(norm, populationSize) {
|
|
2652
|
-
if (norm.strength === "strong") return populationSize * 0.5;
|
|
2653
|
-
if (norm.strength === "moderate") return populationSize * 0.25;
|
|
2654
|
-
return populationSize * 0.02;
|
|
2655
|
-
}
|
|
2656
|
-
var EffectRow = class {
|
|
2657
|
-
effects;
|
|
2658
|
-
constructor(effects) {
|
|
2659
|
-
this.effects = new Set(effects);
|
|
2660
|
-
}
|
|
2661
|
-
has(effect) {
|
|
2662
|
-
return this.effects.has(effect);
|
|
2663
|
-
}
|
|
2664
|
-
};
|
|
2665
|
-
var DEFAULT_CONFIG4 = {
|
|
2666
|
-
activationThreshold: 0.3,
|
|
2667
|
-
complianceReward: 0.05,
|
|
2668
|
-
violationPenalty: 0.15,
|
|
2669
|
-
proposalThreshold: 0.6,
|
|
2670
|
-
enableMetanorms: true
|
|
2671
|
-
};
|
|
2672
|
-
var NormEngine = class {
|
|
2673
|
-
config;
|
|
2674
|
-
norms = /* @__PURE__ */ new Map();
|
|
2675
|
-
agents = /* @__PURE__ */ new Map();
|
|
2676
|
-
proposals = /* @__PURE__ */ new Map();
|
|
2677
|
-
violationLog = [];
|
|
2678
|
-
adoptionHistory = [];
|
|
2679
|
-
currentTick = 0;
|
|
2680
|
-
constructor(config = {}) {
|
|
2681
|
-
this.config = { ...DEFAULT_CONFIG4, ...config };
|
|
2682
|
-
for (const norm of BUILTIN_NORMS) {
|
|
2683
|
-
this.norms.set(norm.id, norm);
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
// ── C: Creation ──────────────────────────────────────────────────────────
|
|
2687
|
-
/**
|
|
2688
|
-
* Register a custom norm.
|
|
2689
|
-
*/
|
|
2690
|
-
registerNorm(norm) {
|
|
2691
|
-
this.norms.set(norm.id, norm);
|
|
2692
|
-
}
|
|
2693
|
-
/**
|
|
2694
|
-
* Agent proposes a new norm.
|
|
2695
|
-
*/
|
|
2696
|
-
proposeNorm(proposerId, norm) {
|
|
2697
|
-
const proposal = {
|
|
2698
|
-
id: `prop_${this.currentTick}_${proposerId}`,
|
|
2699
|
-
proposerId,
|
|
2700
|
-
norm,
|
|
2701
|
-
votes: /* @__PURE__ */ new Map(),
|
|
2702
|
-
timestamp: this.currentTick,
|
|
2703
|
-
status: "pending"
|
|
2704
|
-
};
|
|
2705
|
-
this.proposals.set(proposal.id, proposal);
|
|
2706
|
-
const state = this.getOrCreateAgent(proposerId);
|
|
2707
|
-
state.proposed.add(proposal.id);
|
|
2708
|
-
return proposal;
|
|
2709
|
-
}
|
|
2710
|
-
/**
|
|
2711
|
-
* Vote on a pending proposal.
|
|
2712
|
-
*/
|
|
2713
|
-
vote(proposalId, agentId, approve) {
|
|
2714
|
-
const proposal = this.proposals.get(proposalId);
|
|
2715
|
-
if (!proposal || proposal.status !== "pending") return false;
|
|
2716
|
-
proposal.votes.set(agentId, approve);
|
|
2717
|
-
const totalAgents = this.agents.size;
|
|
2718
|
-
if (totalAgents === 0) return true;
|
|
2719
|
-
const approvals = [...proposal.votes.values()].filter((v) => v).length;
|
|
2720
|
-
const ratio = approvals / totalAgents;
|
|
2721
|
-
if (ratio >= this.config.proposalThreshold) {
|
|
2722
|
-
proposal.status = "adopted";
|
|
2723
|
-
this.norms.set(proposal.norm.id, proposal.norm);
|
|
2724
|
-
} else if (proposal.votes.size >= totalAgents) {
|
|
2725
|
-
proposal.status = "rejected";
|
|
2726
|
-
}
|
|
2727
|
-
return true;
|
|
2728
|
-
}
|
|
2729
|
-
// ── R: Representation ────────────────────────────────────────────────────
|
|
2730
|
-
/**
|
|
2731
|
-
* Get a norm by ID.
|
|
2732
|
-
*/
|
|
2733
|
-
getNorm(normId) {
|
|
2734
|
-
return this.norms.get(normId);
|
|
2735
|
-
}
|
|
2736
|
-
/**
|
|
2737
|
-
* List all registered norms.
|
|
2738
|
-
*/
|
|
2739
|
-
listNorms() {
|
|
2740
|
-
return [...this.norms.values()];
|
|
2741
|
-
}
|
|
2742
|
-
// ── S: Spreading ─────────────────────────────────────────────────────────
|
|
2743
|
-
/**
|
|
2744
|
-
* Agent adopts a norm.
|
|
2745
|
-
*/
|
|
2746
|
-
adopt(agentId, normId) {
|
|
2747
|
-
if (!this.norms.has(normId)) return false;
|
|
2748
|
-
const state = this.getOrCreateAgent(agentId);
|
|
2749
|
-
state.adopted.add(normId);
|
|
2750
|
-
state.compliance.set(normId, 1);
|
|
2751
|
-
return true;
|
|
2752
|
-
}
|
|
2753
|
-
/**
|
|
2754
|
-
* Agent abandons a norm.
|
|
2755
|
-
*/
|
|
2756
|
-
abandon(agentId, normId) {
|
|
2757
|
-
const state = this.agents.get(agentId);
|
|
2758
|
-
if (!state) return false;
|
|
2759
|
-
state.adopted.delete(normId);
|
|
2760
|
-
state.compliance.delete(normId);
|
|
2761
|
-
return true;
|
|
2762
|
-
}
|
|
2763
|
-
/**
|
|
2764
|
-
* Get adoption rate for a norm (0-1).
|
|
2765
|
-
*/
|
|
2766
|
-
adoptionRate(normId) {
|
|
2767
|
-
if (this.agents.size === 0) return 0;
|
|
2768
|
-
let adopters = 0;
|
|
2769
|
-
for (const state of this.agents.values()) {
|
|
2770
|
-
if (state.adopted.has(normId)) adopters++;
|
|
2771
|
-
}
|
|
2772
|
-
return adopters / this.agents.size;
|
|
2773
|
-
}
|
|
2774
|
-
/**
|
|
2775
|
-
* Check if a norm is active (adoption > threshold).
|
|
2776
|
-
*/
|
|
2777
|
-
isActive(normId) {
|
|
2778
|
-
const norm = this.norms.get(normId);
|
|
2779
|
-
if (!norm) return false;
|
|
2780
|
-
return this.adoptionRate(normId) >= (norm.activationThreshold || this.config.activationThreshold);
|
|
2781
|
-
}
|
|
2782
|
-
// ── E: Evaluation ────────────────────────────────────────────────────────
|
|
2783
|
-
/**
|
|
2784
|
-
* Check if an agent's intended effects comply with active norms.
|
|
2785
|
-
* Returns violations found.
|
|
2786
|
-
*/
|
|
2787
|
-
evaluate(agentId, effects, zoneId) {
|
|
2788
|
-
const violations = [];
|
|
2789
|
-
const effectRow = new EffectRow(effects);
|
|
2790
|
-
for (const norm of this.norms.values()) {
|
|
2791
|
-
if (!this.isActive(norm.id)) continue;
|
|
2792
|
-
if (norm.scope === "zone" && !zoneId) continue;
|
|
2793
|
-
if (norm.forbiddenEffects) {
|
|
2794
|
-
for (const forbidden of norm.forbiddenEffects) {
|
|
2795
|
-
if (effectRow.has(forbidden)) {
|
|
2796
|
-
violations.push({
|
|
2797
|
-
normId: norm.id,
|
|
2798
|
-
agentId,
|
|
2799
|
-
effect: forbidden,
|
|
2800
|
-
timestamp: this.currentTick,
|
|
2801
|
-
severity: norm.enforcement,
|
|
2802
|
-
witnessed: this.witnessesIn(zoneId)
|
|
2803
|
-
});
|
|
2804
|
-
}
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
return violations;
|
|
2809
|
-
}
|
|
2810
|
-
// ── C: Compliance ────────────────────────────────────────────────────────
|
|
2811
|
-
/**
|
|
2812
|
-
* Record that an agent complied with a norm.
|
|
2813
|
-
*/
|
|
2814
|
-
recordCompliance(agentId, normId) {
|
|
2815
|
-
const state = this.getOrCreateAgent(agentId);
|
|
2816
|
-
const current = state.compliance.get(normId) || 0.5;
|
|
2817
|
-
state.compliance.set(normId, Math.min(1, current + this.config.complianceReward));
|
|
2818
|
-
state.violations.delete(normId);
|
|
2819
|
-
}
|
|
2820
|
-
/**
|
|
2821
|
-
* Record that an agent violated a norm.
|
|
2822
|
-
*/
|
|
2823
|
-
recordViolation(violation) {
|
|
2824
|
-
const state = this.getOrCreateAgent(violation.agentId);
|
|
2825
|
-
const current = state.compliance.get(violation.normId) || 0.5;
|
|
2826
|
-
state.compliance.set(violation.normId, Math.max(0, current - this.config.violationPenalty));
|
|
2827
|
-
state.violations.add(violation.normId);
|
|
2828
|
-
this.violationLog.push(violation);
|
|
2829
|
-
if (this.config.enableMetanorms) {
|
|
2830
|
-
for (const witnessId of violation.witnessed) {
|
|
2831
|
-
const witnessState = this.getOrCreateAgent(witnessId);
|
|
2832
|
-
witnessState.enforcementCount++;
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
|
-
/**
|
|
2837
|
-
* Get compliance score for an agent on a norm.
|
|
2838
|
-
*/
|
|
2839
|
-
getCompliance(agentId, normId) {
|
|
2840
|
-
return this.agents.get(agentId)?.compliance.get(normId) ?? 0.5;
|
|
2841
|
-
}
|
|
2842
|
-
// ── Lifecycle ────────────────────────────────────────────────────────────
|
|
2843
|
-
/**
|
|
2844
|
-
* Register an agent in the norm engine.
|
|
2845
|
-
*/
|
|
2846
|
-
registerAgent(agentId, adoptNorms) {
|
|
2847
|
-
const state = this.getOrCreateAgent(agentId);
|
|
2848
|
-
if (adoptNorms) {
|
|
2849
|
-
for (const normId of adoptNorms) this.adopt(agentId, normId);
|
|
2850
|
-
}
|
|
2851
|
-
return state;
|
|
2852
|
-
}
|
|
2853
|
-
/**
|
|
2854
|
-
* Advance one tick: record adoption history, snapshot state.
|
|
2855
|
-
*/
|
|
2856
|
-
tick() {
|
|
2857
|
-
this.currentTick++;
|
|
2858
|
-
for (const norm of this.norms.values()) {
|
|
2859
|
-
this.adoptionHistory.push({
|
|
2860
|
-
normId: norm.id,
|
|
2861
|
-
tick: this.currentTick,
|
|
2862
|
-
rate: this.adoptionRate(norm.id)
|
|
2863
|
-
});
|
|
2864
|
-
}
|
|
2865
|
-
}
|
|
2866
|
-
/**
|
|
2867
|
-
* Get adoption curve data for a norm.
|
|
2868
|
-
*/
|
|
2869
|
-
adoptionCurve(normId) {
|
|
2870
|
-
return this.adoptionHistory.filter((h) => h.normId === normId);
|
|
2871
|
-
}
|
|
2872
|
-
/**
|
|
2873
|
-
* Get the cultural health score for the whole population (0-1).
|
|
2874
|
-
* High = norms well-adopted, low violations. Low = cultural breakdown.
|
|
2875
|
-
*/
|
|
2876
|
-
culturalHealth() {
|
|
2877
|
-
if (this.agents.size === 0) return 1;
|
|
2878
|
-
let totalCompliance = 0;
|
|
2879
|
-
let count = 0;
|
|
2880
|
-
for (const state of this.agents.values()) {
|
|
2881
|
-
for (const score of state.compliance.values()) {
|
|
2882
|
-
totalCompliance += score;
|
|
2883
|
-
count++;
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
return count > 0 ? totalCompliance / count : 1;
|
|
2887
|
-
}
|
|
2888
|
-
/**
|
|
2889
|
-
* Get statistics.
|
|
2890
|
-
*/
|
|
2891
|
-
stats() {
|
|
2892
|
-
return {
|
|
2893
|
-
norms: this.norms.size,
|
|
2894
|
-
agents: this.agents.size,
|
|
2895
|
-
activeNorms: [...this.norms.keys()].filter((id) => this.isActive(id)).length,
|
|
2896
|
-
violations: this.violationLog.length,
|
|
2897
|
-
proposals: this.proposals.size,
|
|
2898
|
-
culturalHealth: this.culturalHealth()
|
|
2899
|
-
};
|
|
2900
|
-
}
|
|
2901
|
-
// ── Internal ─────────────────────────────────────────────────────────────
|
|
2902
|
-
getOrCreateAgent(agentId) {
|
|
2903
|
-
let state = this.agents.get(agentId);
|
|
2904
|
-
if (!state) {
|
|
2905
|
-
state = {
|
|
2906
|
-
agentId,
|
|
2907
|
-
adopted: /* @__PURE__ */ new Set(),
|
|
2908
|
-
compliance: /* @__PURE__ */ new Map(),
|
|
2909
|
-
violations: /* @__PURE__ */ new Set(),
|
|
2910
|
-
proposed: /* @__PURE__ */ new Set(),
|
|
2911
|
-
enforcementCount: 0
|
|
2912
|
-
};
|
|
2913
|
-
this.agents.set(agentId, state);
|
|
2914
|
-
}
|
|
2915
|
-
return state;
|
|
2916
|
-
}
|
|
2917
|
-
witnessesIn(zoneId) {
|
|
2918
|
-
return [...this.agents.keys()].slice(0, 5);
|
|
2919
|
-
}
|
|
2920
|
-
};
|
|
2921
|
-
|
|
2922
|
-
// src/agents/spatial-comms/ProtocolTypes.ts
|
|
2923
|
-
var DEFAULT_REALTIME_CONFIG = {
|
|
2924
|
-
binary: true,
|
|
2925
|
-
maxMessageSize: 512,
|
|
2926
|
-
// 512 bytes max
|
|
2927
|
-
targetLatency: 1,
|
|
2928
|
-
// <1ms target
|
|
2929
|
-
messagesPerSecond: 90,
|
|
2930
|
-
// 90fps coordination
|
|
2931
|
-
compression: false,
|
|
2932
|
-
// No compression for minimal latency
|
|
2933
|
-
udpPort: 9001
|
|
2934
|
-
};
|
|
2935
|
-
var DEFAULT_A2A_CONFIG = {
|
|
2936
|
-
endpoint: "http://localhost:3002/a2a",
|
|
2937
|
-
timeout: 5e3,
|
|
2938
|
-
// 5 seconds
|
|
2939
|
-
maxRetries: 3,
|
|
2940
|
-
retryBackoffBase: 100,
|
|
2941
|
-
// 100ms, 200ms, 400ms
|
|
2942
|
-
requireAck: true,
|
|
2943
|
-
enableBatching: true,
|
|
2944
|
-
batchSize: 10
|
|
2945
|
-
};
|
|
2946
|
-
var DEFAULT_MCP_CONFIG = {
|
|
2947
|
-
endpoint: "http://localhost:5567",
|
|
2948
|
-
apiKey: process.env.MCP_API_KEY || "",
|
|
2949
|
-
timeout: 3e4
|
|
2950
|
-
// 30 seconds
|
|
2951
|
-
};
|
|
2952
|
-
var DEFAULT_SPATIAL_COMM_CONFIG = {
|
|
2953
|
-
layer1: DEFAULT_REALTIME_CONFIG,
|
|
2954
|
-
layer2: DEFAULT_A2A_CONFIG,
|
|
2955
|
-
layer3: DEFAULT_MCP_CONFIG
|
|
2956
|
-
};
|
|
2957
|
-
var PROTOCOL_VERSION = "1.0.0";
|
|
2958
|
-
var PROTOCOL_COMPATIBILITY = {
|
|
2959
|
-
version: PROTOCOL_VERSION,
|
|
2960
|
-
minVersion: "1.0.0",
|
|
2961
|
-
maxVersion: "1.x.x"
|
|
2962
|
-
};
|
|
2963
|
-
|
|
2964
|
-
// src/agents/spatial-comms/Layer1RealTime.ts
|
|
2965
|
-
import { EventEmitter as EventEmitter2 } from "events";
|
|
2966
|
-
var HEADER_SIZE = 12;
|
|
2967
|
-
function encodeRealTimeMessage(message) {
|
|
2968
|
-
const agentIdBytes = Buffer.from(message.agent_id, "utf-8");
|
|
2969
|
-
const agentIdLen = agentIdBytes.length;
|
|
2970
|
-
let typeCode;
|
|
2971
|
-
switch (message.type) {
|
|
2972
|
-
case "position_sync":
|
|
2973
|
-
typeCode = 1 /* POSITION_SYNC */;
|
|
2974
|
-
break;
|
|
2975
|
-
case "frame_budget":
|
|
2976
|
-
typeCode = 2 /* FRAME_BUDGET */;
|
|
2977
|
-
break;
|
|
2978
|
-
case "spatial_conflict":
|
|
2979
|
-
typeCode = 3 /* SPATIAL_CONFLICT */;
|
|
2980
|
-
break;
|
|
2981
|
-
case "performance_metric":
|
|
2982
|
-
typeCode = 4 /* PERFORMANCE_METRIC */;
|
|
2983
|
-
break;
|
|
2984
|
-
default:
|
|
2985
|
-
throw new Error(
|
|
2986
|
-
`Unknown message type: ${message.type}`
|
|
2987
|
-
);
|
|
2988
|
-
}
|
|
2989
|
-
if (message.type === "position_sync") {
|
|
2990
|
-
const msg = message;
|
|
2991
|
-
const bodySize = agentIdLen + 12 + 16 + 12 + (msg.velocity ? 12 : 0);
|
|
2992
|
-
const buffer = Buffer.allocUnsafe(HEADER_SIZE + bodySize);
|
|
2993
|
-
let offset = 0;
|
|
2994
|
-
buffer.writeUInt8(typeCode, offset);
|
|
2995
|
-
offset += 1;
|
|
2996
|
-
buffer.writeUInt8(agentIdLen, offset);
|
|
2997
|
-
offset += 1;
|
|
2998
|
-
buffer.writeBigInt64BE(BigInt(msg.timestamp), offset);
|
|
2999
|
-
offset += 8;
|
|
3000
|
-
buffer.writeUInt16BE(0, offset);
|
|
3001
|
-
offset += 2;
|
|
3002
|
-
agentIdBytes.copy(buffer, offset);
|
|
3003
|
-
offset += agentIdLen;
|
|
3004
|
-
buffer.writeFloatBE(msg.position[0], offset);
|
|
3005
|
-
offset += 4;
|
|
3006
|
-
buffer.writeFloatBE(msg.position[1], offset);
|
|
3007
|
-
offset += 4;
|
|
3008
|
-
buffer.writeFloatBE(msg.position[2], offset);
|
|
3009
|
-
offset += 4;
|
|
3010
|
-
buffer.writeFloatBE(msg.rotation[0], offset);
|
|
3011
|
-
offset += 4;
|
|
3012
|
-
buffer.writeFloatBE(msg.rotation[1], offset);
|
|
3013
|
-
offset += 4;
|
|
3014
|
-
buffer.writeFloatBE(msg.rotation[2], offset);
|
|
3015
|
-
offset += 4;
|
|
3016
|
-
buffer.writeFloatBE(msg.rotation[3], offset);
|
|
3017
|
-
offset += 4;
|
|
3018
|
-
buffer.writeFloatBE(msg.scale[0], offset);
|
|
3019
|
-
offset += 4;
|
|
3020
|
-
buffer.writeFloatBE(msg.scale[1], offset);
|
|
3021
|
-
offset += 4;
|
|
3022
|
-
buffer.writeFloatBE(msg.scale[2], offset);
|
|
3023
|
-
offset += 4;
|
|
3024
|
-
if (msg.velocity) {
|
|
3025
|
-
buffer.writeFloatBE(msg.velocity[0], offset);
|
|
3026
|
-
offset += 4;
|
|
3027
|
-
buffer.writeFloatBE(msg.velocity[1], offset);
|
|
3028
|
-
offset += 4;
|
|
3029
|
-
buffer.writeFloatBE(msg.velocity[2], offset);
|
|
3030
|
-
offset += 4;
|
|
3031
|
-
}
|
|
3032
|
-
return buffer;
|
|
3033
|
-
} else if (message.type === "frame_budget") {
|
|
3034
|
-
const msg = message;
|
|
3035
|
-
const bodySize = agentIdLen + 17;
|
|
3036
|
-
const buffer = Buffer.allocUnsafe(HEADER_SIZE + bodySize);
|
|
3037
|
-
let offset = 0;
|
|
3038
|
-
buffer.writeUInt8(typeCode, offset);
|
|
3039
|
-
offset += 1;
|
|
3040
|
-
buffer.writeUInt8(agentIdLen, offset);
|
|
3041
|
-
offset += 1;
|
|
3042
|
-
buffer.writeBigInt64BE(BigInt(msg.timestamp), offset);
|
|
3043
|
-
offset += 8;
|
|
3044
|
-
buffer.writeUInt16BE(0, offset);
|
|
3045
|
-
offset += 2;
|
|
3046
|
-
agentIdBytes.copy(buffer, offset);
|
|
3047
|
-
offset += agentIdLen;
|
|
3048
|
-
buffer.writeFloatBE(msg.frame_time_ms, offset);
|
|
3049
|
-
offset += 4;
|
|
3050
|
-
buffer.writeFloatBE(msg.budget_remaining_ms, offset);
|
|
3051
|
-
offset += 4;
|
|
3052
|
-
buffer.writeFloatBE(msg.target_fps, offset);
|
|
3053
|
-
offset += 4;
|
|
3054
|
-
buffer.writeFloatBE(msg.actual_fps, offset);
|
|
3055
|
-
offset += 4;
|
|
3056
|
-
const qualityCode = { high: 0, medium: 1, low: 2, minimal: 3 }[msg.quality_level];
|
|
3057
|
-
buffer.writeUInt8(qualityCode, offset);
|
|
3058
|
-
offset += 1;
|
|
3059
|
-
return buffer;
|
|
3060
|
-
} else {
|
|
3061
|
-
const json = JSON.stringify(message);
|
|
3062
|
-
const jsonBytes = Buffer.from(json, "utf-8");
|
|
3063
|
-
const buffer = Buffer.allocUnsafe(HEADER_SIZE + agentIdLen + jsonBytes.length);
|
|
3064
|
-
let offset = 0;
|
|
3065
|
-
buffer.writeUInt8(typeCode, offset);
|
|
3066
|
-
offset += 1;
|
|
3067
|
-
buffer.writeUInt8(agentIdLen, offset);
|
|
3068
|
-
offset += 1;
|
|
3069
|
-
buffer.writeBigInt64BE(BigInt(message.timestamp), offset);
|
|
3070
|
-
offset += 8;
|
|
3071
|
-
buffer.writeUInt16BE(0, offset);
|
|
3072
|
-
offset += 2;
|
|
3073
|
-
agentIdBytes.copy(buffer, offset);
|
|
3074
|
-
offset += agentIdLen;
|
|
3075
|
-
jsonBytes.copy(buffer, offset);
|
|
3076
|
-
return buffer;
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
function decodeRealTimeMessage(buffer) {
|
|
3080
|
-
let offset = 0;
|
|
3081
|
-
const typeCode = buffer.readUInt8(offset);
|
|
3082
|
-
offset += 1;
|
|
3083
|
-
const agentIdLen = buffer.readUInt8(offset);
|
|
3084
|
-
offset += 1;
|
|
3085
|
-
const timestamp = Number(buffer.readBigInt64BE(offset));
|
|
3086
|
-
offset += 8;
|
|
3087
|
-
offset += 2;
|
|
3088
|
-
const agentId = buffer.toString("utf-8", offset, offset + agentIdLen);
|
|
3089
|
-
offset += agentIdLen;
|
|
3090
|
-
if (typeCode === 1 /* POSITION_SYNC */) {
|
|
3091
|
-
const px = buffer.readFloatBE(offset);
|
|
3092
|
-
offset += 4;
|
|
3093
|
-
const py = buffer.readFloatBE(offset);
|
|
3094
|
-
offset += 4;
|
|
3095
|
-
const pz = buffer.readFloatBE(offset);
|
|
3096
|
-
offset += 4;
|
|
3097
|
-
const position = [px, py, pz];
|
|
3098
|
-
const rx = buffer.readFloatBE(offset);
|
|
3099
|
-
offset += 4;
|
|
3100
|
-
const ry = buffer.readFloatBE(offset);
|
|
3101
|
-
offset += 4;
|
|
3102
|
-
const rz = buffer.readFloatBE(offset);
|
|
3103
|
-
offset += 4;
|
|
3104
|
-
const rw = buffer.readFloatBE(offset);
|
|
3105
|
-
offset += 4;
|
|
3106
|
-
const rotation = [rx, ry, rz, rw];
|
|
3107
|
-
const sx = buffer.readFloatBE(offset);
|
|
3108
|
-
offset += 4;
|
|
3109
|
-
const sy = buffer.readFloatBE(offset);
|
|
3110
|
-
offset += 4;
|
|
3111
|
-
const sz = buffer.readFloatBE(offset);
|
|
3112
|
-
offset += 4;
|
|
3113
|
-
const scale = [sx, sy, sz];
|
|
3114
|
-
let velocity;
|
|
3115
|
-
if (offset < buffer.length) {
|
|
3116
|
-
const vx = buffer.readFloatBE(offset);
|
|
3117
|
-
offset += 4;
|
|
3118
|
-
const vy = buffer.readFloatBE(offset);
|
|
3119
|
-
offset += 4;
|
|
3120
|
-
const vz = buffer.readFloatBE(offset);
|
|
3121
|
-
offset += 4;
|
|
3122
|
-
velocity = [vx, vy, vz];
|
|
3123
|
-
}
|
|
3124
|
-
return {
|
|
3125
|
-
type: "position_sync",
|
|
3126
|
-
agent_id: agentId,
|
|
3127
|
-
timestamp,
|
|
3128
|
-
position,
|
|
3129
|
-
rotation,
|
|
3130
|
-
scale,
|
|
3131
|
-
velocity
|
|
3132
|
-
};
|
|
3133
|
-
} else if (typeCode === 2 /* FRAME_BUDGET */) {
|
|
3134
|
-
const frame_time_ms = buffer.readFloatBE(offset);
|
|
3135
|
-
offset += 4;
|
|
3136
|
-
const budget_remaining_ms = buffer.readFloatBE(offset);
|
|
3137
|
-
offset += 4;
|
|
3138
|
-
const target_fps = buffer.readFloatBE(offset);
|
|
3139
|
-
offset += 4;
|
|
3140
|
-
const actual_fps = buffer.readFloatBE(offset);
|
|
3141
|
-
offset += 4;
|
|
3142
|
-
const qualityCode = buffer.readUInt8(offset);
|
|
3143
|
-
offset += 1;
|
|
3144
|
-
const qualityLevels = [
|
|
3145
|
-
"high",
|
|
3146
|
-
"medium",
|
|
3147
|
-
"low",
|
|
3148
|
-
"minimal"
|
|
3149
|
-
];
|
|
3150
|
-
const quality_level = qualityLevels[qualityCode] ?? "medium";
|
|
3151
|
-
return {
|
|
3152
|
-
type: "frame_budget",
|
|
3153
|
-
agent_id: agentId,
|
|
3154
|
-
timestamp,
|
|
3155
|
-
frame_time_ms,
|
|
3156
|
-
budget_remaining_ms,
|
|
3157
|
-
target_fps,
|
|
3158
|
-
actual_fps,
|
|
3159
|
-
quality_level
|
|
3160
|
-
};
|
|
3161
|
-
} else {
|
|
3162
|
-
const json = buffer.toString("utf-8", offset);
|
|
3163
|
-
return JSON.parse(json);
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
var UDPRealTimeTransport = class {
|
|
3167
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- dgram.Socket dynamically imported at runtime
|
|
3168
|
-
socket;
|
|
3169
|
-
port;
|
|
3170
|
-
targetHost = "localhost";
|
|
3171
|
-
constructor(port) {
|
|
3172
|
-
this.port = port;
|
|
3173
|
-
}
|
|
3174
|
-
async init() {
|
|
3175
|
-
const dgram = await import("dgram");
|
|
3176
|
-
this.socket = dgram.createSocket("udp4");
|
|
3177
|
-
return new Promise((resolve, reject) => {
|
|
3178
|
-
this.socket.bind(this.port, () => {
|
|
3179
|
-
this.socket.setBroadcast(true);
|
|
3180
|
-
resolve();
|
|
3181
|
-
});
|
|
3182
|
-
this.socket.on("error", (err) => {
|
|
3183
|
-
reject(err);
|
|
3184
|
-
});
|
|
3185
|
-
});
|
|
3186
|
-
}
|
|
3187
|
-
async send(buffer, _targetAgent) {
|
|
3188
|
-
if (!this.socket) throw new Error("Transport not initialized");
|
|
3189
|
-
return new Promise((resolve, reject) => {
|
|
3190
|
-
this.socket.send(buffer, this.port, this.targetHost, (err) => {
|
|
3191
|
-
if (err) reject(err);
|
|
3192
|
-
else resolve();
|
|
3193
|
-
});
|
|
3194
|
-
});
|
|
3195
|
-
}
|
|
3196
|
-
async broadcast(buffer) {
|
|
3197
|
-
if (!this.socket) throw new Error("Transport not initialized");
|
|
3198
|
-
return new Promise((resolve, reject) => {
|
|
3199
|
-
this.socket.send(buffer, this.port, "255.255.255.255", (err) => {
|
|
3200
|
-
if (err) reject(err);
|
|
3201
|
-
else resolve();
|
|
3202
|
-
});
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
|
-
async close() {
|
|
3206
|
-
if (this.socket) {
|
|
3207
|
-
return new Promise((resolve) => {
|
|
3208
|
-
this.socket.close(() => resolve());
|
|
3209
|
-
});
|
|
3210
|
-
}
|
|
3211
|
-
}
|
|
3212
|
-
onMessage(callback) {
|
|
3213
|
-
if (!this.socket) throw new Error("Transport not initialized");
|
|
3214
|
-
this.socket.on("message", callback);
|
|
3215
|
-
}
|
|
3216
|
-
};
|
|
3217
|
-
var WebRTCRealTimeTransport = class {
|
|
3218
|
-
constructor(config) {
|
|
3219
|
-
this.config = config;
|
|
3220
|
-
}
|
|
3221
|
-
dataChannel;
|
|
3222
|
-
peerConnection;
|
|
3223
|
-
async init(remoteDescription) {
|
|
3224
|
-
this.peerConnection = new RTCPeerConnection(this.config);
|
|
3225
|
-
this.dataChannel = this.peerConnection.createDataChannel("realtime", {
|
|
3226
|
-
ordered: false,
|
|
3227
|
-
// Unordered for minimal latency
|
|
3228
|
-
maxRetransmits: 0
|
|
3229
|
-
// No retransmits (UDP-like)
|
|
3230
|
-
});
|
|
3231
|
-
this.dataChannel.bufferedAmountLowThreshold = 0;
|
|
3232
|
-
if (remoteDescription) {
|
|
3233
|
-
await this.peerConnection.setRemoteDescription(remoteDescription);
|
|
3234
|
-
}
|
|
3235
|
-
}
|
|
3236
|
-
async send(buffer, _targetAgent) {
|
|
3237
|
-
if (!this.dataChannel || this.dataChannel.readyState !== "open") {
|
|
3238
|
-
throw new Error("Data channel not ready");
|
|
3239
|
-
}
|
|
3240
|
-
this.dataChannel.send(new Uint8Array(buffer));
|
|
3241
|
-
}
|
|
3242
|
-
async broadcast(buffer) {
|
|
3243
|
-
return this.send(buffer);
|
|
3244
|
-
}
|
|
3245
|
-
async close() {
|
|
3246
|
-
if (this.dataChannel) {
|
|
3247
|
-
this.dataChannel.close();
|
|
3248
|
-
}
|
|
3249
|
-
if (this.peerConnection) {
|
|
3250
|
-
this.peerConnection.close();
|
|
3251
|
-
}
|
|
3252
|
-
}
|
|
3253
|
-
onMessage(callback) {
|
|
3254
|
-
if (!this.dataChannel) throw new Error("Data channel not initialized");
|
|
3255
|
-
this.dataChannel.onmessage = (event) => {
|
|
3256
|
-
const buffer = Buffer.from(event.data);
|
|
3257
|
-
callback(buffer);
|
|
3258
|
-
};
|
|
3259
|
-
}
|
|
3260
|
-
async createOffer() {
|
|
3261
|
-
if (!this.peerConnection) throw new Error("Peer connection not initialized");
|
|
3262
|
-
const offer = await this.peerConnection.createOffer();
|
|
3263
|
-
await this.peerConnection.setLocalDescription(offer);
|
|
3264
|
-
return offer;
|
|
3265
|
-
}
|
|
3266
|
-
async createAnswer() {
|
|
3267
|
-
if (!this.peerConnection) throw new Error("Peer connection not initialized");
|
|
3268
|
-
const answer = await this.peerConnection.createAnswer();
|
|
3269
|
-
await this.peerConnection.setLocalDescription(answer);
|
|
3270
|
-
return answer;
|
|
3271
|
-
}
|
|
3272
|
-
};
|
|
3273
|
-
var Layer1RealTimeClient = class extends EventEmitter2 {
|
|
3274
|
-
config;
|
|
3275
|
-
transport;
|
|
3276
|
-
agentId;
|
|
3277
|
-
messageCount = 0;
|
|
3278
|
-
lastMessageTime = 0;
|
|
3279
|
-
_messageBuffer = [];
|
|
3280
|
-
constructor(agentId, config) {
|
|
3281
|
-
super();
|
|
3282
|
-
this.agentId = agentId;
|
|
3283
|
-
this.config = { ...DEFAULT_REALTIME_CONFIG, ...config };
|
|
3284
|
-
}
|
|
3285
|
-
/**
|
|
3286
|
-
* Initialize transport and start listening
|
|
3287
|
-
*/
|
|
3288
|
-
async init(useWebRTC = false) {
|
|
3289
|
-
if (useWebRTC) {
|
|
3290
|
-
const transport = new WebRTCRealTimeTransport(
|
|
3291
|
-
this.config.webrtc?.iceServers ? { iceServers: this.config.webrtc.iceServers } : {}
|
|
3292
|
-
);
|
|
3293
|
-
await transport.init();
|
|
3294
|
-
this.transport = transport;
|
|
3295
|
-
transport.onMessage((buffer) => {
|
|
3296
|
-
this.handleIncomingMessage(buffer);
|
|
3297
|
-
});
|
|
3298
|
-
} else {
|
|
3299
|
-
const transport = new UDPRealTimeTransport(this.config.udpPort || 9001);
|
|
3300
|
-
await transport.init();
|
|
3301
|
-
this.transport = transport;
|
|
3302
|
-
transport.onMessage((buffer) => {
|
|
3303
|
-
this.handleIncomingMessage(buffer);
|
|
3304
|
-
});
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
/**
|
|
3308
|
-
* Send real-time message
|
|
3309
|
-
*/
|
|
3310
|
-
async send(message, targetAgent) {
|
|
3311
|
-
if (!this.transport) throw new Error("Transport not initialized");
|
|
3312
|
-
const fullMessage = {
|
|
3313
|
-
...message,
|
|
3314
|
-
agent_id: this.agentId,
|
|
3315
|
-
timestamp: this.getMicroseconds()
|
|
3316
|
-
};
|
|
3317
|
-
const buffer = this.config.binary ? encodeRealTimeMessage(fullMessage) : Buffer.from(JSON.stringify(fullMessage), "utf-8");
|
|
3318
|
-
if (buffer.length > this.config.maxMessageSize) {
|
|
3319
|
-
throw new Error(`Message size ${buffer.length} exceeds max ${this.config.maxMessageSize}`);
|
|
3320
|
-
}
|
|
3321
|
-
await this.enforceRateLimit();
|
|
3322
|
-
if (targetAgent) {
|
|
3323
|
-
await this.transport.send(buffer, targetAgent);
|
|
3324
|
-
} else {
|
|
3325
|
-
await this.transport.broadcast(buffer);
|
|
3326
|
-
}
|
|
3327
|
-
this.messageCount++;
|
|
3328
|
-
this.lastMessageTime = Date.now();
|
|
3329
|
-
}
|
|
3330
|
-
/**
|
|
3331
|
-
* Send position sync message
|
|
3332
|
-
*/
|
|
3333
|
-
async sendPositionSync(position, rotation, scale, velocity) {
|
|
3334
|
-
await this.send({
|
|
3335
|
-
type: "position_sync",
|
|
3336
|
-
position,
|
|
3337
|
-
rotation,
|
|
3338
|
-
scale,
|
|
3339
|
-
velocity
|
|
3340
|
-
});
|
|
3341
|
-
}
|
|
3342
|
-
/**
|
|
3343
|
-
* Send frame budget message
|
|
3344
|
-
*/
|
|
3345
|
-
async sendFrameBudget(frameTimeMs, budgetRemainingMs, targetFps, actualFps, qualityLevel) {
|
|
3346
|
-
await this.send({
|
|
3347
|
-
type: "frame_budget",
|
|
3348
|
-
frame_time_ms: frameTimeMs,
|
|
3349
|
-
budget_remaining_ms: budgetRemainingMs,
|
|
3350
|
-
target_fps: targetFps,
|
|
3351
|
-
actual_fps: actualFps,
|
|
3352
|
-
quality_level: qualityLevel
|
|
3353
|
-
});
|
|
3354
|
-
}
|
|
3355
|
-
/**
|
|
3356
|
-
* Close transport
|
|
3357
|
-
*/
|
|
3358
|
-
async close() {
|
|
3359
|
-
if (this.transport) {
|
|
3360
|
-
await this.transport.close();
|
|
3361
|
-
}
|
|
3362
|
-
}
|
|
3363
|
-
/**
|
|
3364
|
-
* Handle incoming message
|
|
3365
|
-
*/
|
|
3366
|
-
handleIncomingMessage(buffer) {
|
|
3367
|
-
try {
|
|
3368
|
-
const message = this.config.binary ? decodeRealTimeMessage(buffer) : JSON.parse(buffer.toString("utf-8"));
|
|
3369
|
-
this.emit("message", message);
|
|
3370
|
-
this.emit(message.type, message);
|
|
3371
|
-
const latency = (this.getMicroseconds() - message.timestamp) / 1e3;
|
|
3372
|
-
this.emit("latency", latency);
|
|
3373
|
-
if (latency > this.config.targetLatency) {
|
|
3374
|
-
this.emit("latency_warning", { message, latency });
|
|
3375
|
-
}
|
|
3376
|
-
} catch (err) {
|
|
3377
|
-
this.emit("error", err);
|
|
3378
|
-
}
|
|
3379
|
-
}
|
|
3380
|
-
/**
|
|
3381
|
-
* Enforce rate limiting
|
|
3382
|
-
*/
|
|
3383
|
-
async enforceRateLimit() {
|
|
3384
|
-
const now = Date.now();
|
|
3385
|
-
const timeSinceLastMessage = now - this.lastMessageTime;
|
|
3386
|
-
const minInterval = 1e3 / this.config.messagesPerSecond;
|
|
3387
|
-
if (timeSinceLastMessage < minInterval) {
|
|
3388
|
-
const delay = minInterval - timeSinceLastMessage;
|
|
3389
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
3390
|
-
}
|
|
3391
|
-
}
|
|
3392
|
-
/**
|
|
3393
|
-
* Get current time in microseconds
|
|
3394
|
-
*/
|
|
3395
|
-
getMicroseconds() {
|
|
3396
|
-
const hrTime = process.hrtime ? process.hrtime() : [Date.now() / 1e3, 0];
|
|
3397
|
-
return hrTime[0] * 1e6 + Math.floor(hrTime[1] / 1e3);
|
|
3398
|
-
}
|
|
3399
|
-
};
|
|
3400
|
-
|
|
3401
|
-
// src/agents/spatial-comms/Layer2A2A.ts
|
|
3402
|
-
import { EventEmitter as EventEmitter3 } from "events";
|
|
3403
|
-
var MessageQueue = class {
|
|
3404
|
-
queue = /* @__PURE__ */ new Map();
|
|
3405
|
-
retryTimers = /* @__PURE__ */ new Map();
|
|
3406
|
-
/**
|
|
3407
|
-
* Add message to queue
|
|
3408
|
-
*/
|
|
3409
|
-
add(message, maxRetries, backoffBase) {
|
|
3410
|
-
return new Promise((resolve, reject) => {
|
|
3411
|
-
this.queue.set(message.message_id, {
|
|
3412
|
-
message,
|
|
3413
|
-
attempt: 0,
|
|
3414
|
-
maxRetries,
|
|
3415
|
-
backoffBase,
|
|
3416
|
-
resolve,
|
|
3417
|
-
reject
|
|
3418
|
-
});
|
|
3419
|
-
});
|
|
3420
|
-
}
|
|
3421
|
-
/**
|
|
3422
|
-
* Get message from queue
|
|
3423
|
-
*/
|
|
3424
|
-
get(messageId) {
|
|
3425
|
-
return this.queue.get(messageId);
|
|
3426
|
-
}
|
|
3427
|
-
/**
|
|
3428
|
-
* Remove message from queue
|
|
3429
|
-
*/
|
|
3430
|
-
remove(messageId) {
|
|
3431
|
-
const timer = this.retryTimers.get(messageId);
|
|
3432
|
-
if (timer) {
|
|
3433
|
-
clearTimeout(timer);
|
|
3434
|
-
this.retryTimers.delete(messageId);
|
|
3435
|
-
}
|
|
3436
|
-
this.queue.delete(messageId);
|
|
3437
|
-
}
|
|
3438
|
-
/**
|
|
3439
|
-
* Schedule retry for message
|
|
3440
|
-
*/
|
|
3441
|
-
scheduleRetry(messageId, callback) {
|
|
3442
|
-
const queued = this.queue.get(messageId);
|
|
3443
|
-
if (!queued) return;
|
|
3444
|
-
queued.attempt++;
|
|
3445
|
-
const delay = queued.backoffBase * Math.pow(2, queued.attempt - 1);
|
|
3446
|
-
const timer = setTimeout(() => {
|
|
3447
|
-
this.retryTimers.delete(messageId);
|
|
3448
|
-
callback();
|
|
3449
|
-
}, delay);
|
|
3450
|
-
this.retryTimers.set(messageId, timer);
|
|
3451
|
-
}
|
|
3452
|
-
/**
|
|
3453
|
-
* Check if message should retry
|
|
3454
|
-
*/
|
|
3455
|
-
shouldRetry(messageId) {
|
|
3456
|
-
const queued = this.queue.get(messageId);
|
|
3457
|
-
if (!queued) return false;
|
|
3458
|
-
return queued.attempt < queued.maxRetries;
|
|
3459
|
-
}
|
|
3460
|
-
/**
|
|
3461
|
-
* Get queue size
|
|
3462
|
-
*/
|
|
3463
|
-
get size() {
|
|
3464
|
-
return this.queue.size;
|
|
3465
|
-
}
|
|
3466
|
-
/**
|
|
3467
|
-
* Clear all queued messages
|
|
3468
|
-
*/
|
|
3469
|
-
clear() {
|
|
3470
|
-
for (const timer of this.retryTimers.values()) {
|
|
3471
|
-
clearTimeout(timer);
|
|
3472
|
-
}
|
|
3473
|
-
this.retryTimers.clear();
|
|
3474
|
-
this.queue.clear();
|
|
3475
|
-
}
|
|
3476
|
-
};
|
|
3477
|
-
var SpatialClaimManager = class {
|
|
3478
|
-
claims = /* @__PURE__ */ new Map();
|
|
3479
|
-
/**
|
|
3480
|
-
* Add spatial claim
|
|
3481
|
-
*/
|
|
3482
|
-
addClaim(claim) {
|
|
3483
|
-
this.claims.set(claim.claim_id, claim);
|
|
3484
|
-
}
|
|
3485
|
-
/**
|
|
3486
|
-
* Remove spatial claim
|
|
3487
|
-
*/
|
|
3488
|
-
removeClaim(claimId) {
|
|
3489
|
-
this.claims.delete(claimId);
|
|
3490
|
-
}
|
|
3491
|
-
/**
|
|
3492
|
-
* Get claims by agent
|
|
3493
|
-
*/
|
|
3494
|
-
getClaimsByAgent(agentId) {
|
|
3495
|
-
return Array.from(this.claims.values()).filter((c) => c.agent_id === agentId);
|
|
3496
|
-
}
|
|
3497
|
-
/**
|
|
3498
|
-
* Check for conflicts with new claim
|
|
3499
|
-
*/
|
|
3500
|
-
checkConflicts(newClaim) {
|
|
3501
|
-
const conflicts = [];
|
|
3502
|
-
for (const existingClaim of this.claims.values()) {
|
|
3503
|
-
if (existingClaim.agent_id === newClaim.agent_id) continue;
|
|
3504
|
-
if (this.boundingBoxesOverlap(newClaim.bounding_box, existingClaim.bounding_box)) {
|
|
3505
|
-
if (newClaim.exclusive || existingClaim.exclusive) {
|
|
3506
|
-
conflicts.push(existingClaim);
|
|
3507
|
-
}
|
|
3508
|
-
}
|
|
3509
|
-
}
|
|
3510
|
-
return conflicts;
|
|
3511
|
-
}
|
|
3512
|
-
/**
|
|
3513
|
-
* Check if two bounding boxes overlap
|
|
3514
|
-
*/
|
|
3515
|
-
boundingBoxesOverlap(box1, box2) {
|
|
3516
|
-
return box1.min[0] <= box2.max[0] && box1.max[0] >= box2.min[0] && box1.min[1] <= box2.max[1] && box1.max[1] >= box2.min[1] && box1.min[2] <= box2.max[2] && box1.max[2] >= box2.min[2];
|
|
3517
|
-
}
|
|
3518
|
-
/**
|
|
3519
|
-
* Cleanup expired claims
|
|
3520
|
-
*/
|
|
3521
|
-
cleanup() {
|
|
3522
|
-
const now = Date.now();
|
|
3523
|
-
for (const [claimId, claim] of this.claims) {
|
|
3524
|
-
if (claim.expires_at && claim.expires_at < now) {
|
|
3525
|
-
this.claims.delete(claimId);
|
|
3526
|
-
}
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
/**
|
|
3530
|
-
* Get all claims
|
|
3531
|
-
*/
|
|
3532
|
-
getAllClaims() {
|
|
3533
|
-
return Array.from(this.claims.values());
|
|
3534
|
-
}
|
|
3535
|
-
/**
|
|
3536
|
-
* Clear all claims
|
|
3537
|
-
*/
|
|
3538
|
-
clear() {
|
|
3539
|
-
this.claims.clear();
|
|
3540
|
-
}
|
|
3541
|
-
};
|
|
3542
|
-
var Layer2A2AClient = class extends EventEmitter3 {
|
|
3543
|
-
config;
|
|
3544
|
-
agentId;
|
|
3545
|
-
messageQueue = new MessageQueue();
|
|
3546
|
-
claimManager = new SpatialClaimManager();
|
|
3547
|
-
messageHandlers = /* @__PURE__ */ new Map();
|
|
3548
|
-
batchBuffer = [];
|
|
3549
|
-
batchTimer;
|
|
3550
|
-
constructor(agentId, config) {
|
|
3551
|
-
super();
|
|
3552
|
-
this.agentId = agentId;
|
|
3553
|
-
this.config = { ...DEFAULT_A2A_CONFIG, ...config };
|
|
3554
|
-
setInterval(() => {
|
|
3555
|
-
this.claimManager.cleanup();
|
|
3556
|
-
}, 6e4);
|
|
3557
|
-
}
|
|
3558
|
-
/**
|
|
3559
|
-
* Send A2A message with retry
|
|
3560
|
-
*/
|
|
3561
|
-
async send(message) {
|
|
3562
|
-
const fullMessage = {
|
|
3563
|
-
...message,
|
|
3564
|
-
message_id: this.generateMessageId(),
|
|
3565
|
-
from_agent: this.agentId,
|
|
3566
|
-
timestamp: Date.now()
|
|
3567
|
-
};
|
|
3568
|
-
if (this.config.enableBatching) {
|
|
3569
|
-
return this.addToBatch(fullMessage);
|
|
3570
|
-
}
|
|
3571
|
-
return this.sendMessage(fullMessage);
|
|
3572
|
-
}
|
|
3573
|
-
/**
|
|
3574
|
-
* Send task assignment
|
|
3575
|
-
*/
|
|
3576
|
-
async assignTask(toAgent, task) {
|
|
3577
|
-
return this.send({
|
|
3578
|
-
type: "task_assignment",
|
|
3579
|
-
to_agent: toAgent,
|
|
3580
|
-
task
|
|
3581
|
-
});
|
|
3582
|
-
}
|
|
3583
|
-
/**
|
|
3584
|
-
* Send task completion
|
|
3585
|
-
*/
|
|
3586
|
-
async completeTask(taskId, success, result, error, performanceMetrics) {
|
|
3587
|
-
return this.send({
|
|
3588
|
-
type: "task_complete",
|
|
3589
|
-
task_id: taskId,
|
|
3590
|
-
success,
|
|
3591
|
-
result,
|
|
3592
|
-
error,
|
|
3593
|
-
performance_metrics: performanceMetrics
|
|
3594
|
-
});
|
|
3595
|
-
}
|
|
3596
|
-
/**
|
|
3597
|
-
* Claim spatial region
|
|
3598
|
-
*/
|
|
3599
|
-
async claimSpatialRegion(claimId, boundingBox, priority, durationMs, exclusive = true) {
|
|
3600
|
-
const claim = {
|
|
3601
|
-
claim_id: claimId,
|
|
3602
|
-
agent_id: this.agentId,
|
|
3603
|
-
bounding_box: boundingBox,
|
|
3604
|
-
priority,
|
|
3605
|
-
exclusive,
|
|
3606
|
-
expires_at: durationMs ? Date.now() + durationMs : void 0
|
|
3607
|
-
};
|
|
3608
|
-
const conflicts = this.claimManager.checkConflicts(claim);
|
|
3609
|
-
if (conflicts.length > 0) {
|
|
3610
|
-
this.emit("spatial_conflict", {
|
|
3611
|
-
claim,
|
|
3612
|
-
conflicts
|
|
3613
|
-
});
|
|
3614
|
-
const hasHigherPriority = conflicts.some((c) => {
|
|
3615
|
-
const priorities = ["low", "medium", "high", "critical"];
|
|
3616
|
-
return priorities.indexOf(c.priority) >= priorities.indexOf(priority);
|
|
3617
|
-
});
|
|
3618
|
-
if (hasHigherPriority) {
|
|
3619
|
-
return {
|
|
3620
|
-
message_id: this.generateMessageId(),
|
|
3621
|
-
success: false,
|
|
3622
|
-
error: "Spatial conflict with higher priority claim",
|
|
3623
|
-
data: { conflicts },
|
|
3624
|
-
timestamp: Date.now()
|
|
3625
|
-
};
|
|
3626
|
-
}
|
|
3627
|
-
}
|
|
3628
|
-
this.claimManager.addClaim(claim);
|
|
3629
|
-
return this.send({
|
|
3630
|
-
type: "spatial_claim",
|
|
3631
|
-
claim_id: claimId,
|
|
3632
|
-
bounding_box: boundingBox,
|
|
3633
|
-
priority,
|
|
3634
|
-
duration_ms: durationMs,
|
|
3635
|
-
exclusive
|
|
3636
|
-
});
|
|
3637
|
-
}
|
|
3638
|
-
/**
|
|
3639
|
-
* Resolve spatial conflict
|
|
3640
|
-
*/
|
|
3641
|
-
async resolveConflict(conflictId, involvedAgents, strategy, resolutionParams) {
|
|
3642
|
-
return this.send({
|
|
3643
|
-
type: "conflict_resolution",
|
|
3644
|
-
conflict_id: conflictId,
|
|
3645
|
-
strategy,
|
|
3646
|
-
involved_agents: involvedAgents,
|
|
3647
|
-
resolution_params: resolutionParams
|
|
3648
|
-
});
|
|
3649
|
-
}
|
|
3650
|
-
/**
|
|
3651
|
-
* Request resource
|
|
3652
|
-
*/
|
|
3653
|
-
async requestResource(resourceId, resourceType, amount, priority = "medium") {
|
|
3654
|
-
return this.send({
|
|
3655
|
-
type: "resource_request",
|
|
3656
|
-
resource_id: resourceId,
|
|
3657
|
-
resource_type: resourceType,
|
|
3658
|
-
amount,
|
|
3659
|
-
priority
|
|
3660
|
-
});
|
|
3661
|
-
}
|
|
3662
|
-
/**
|
|
3663
|
-
* Release resource
|
|
3664
|
-
*/
|
|
3665
|
-
async releaseResource(resourceId) {
|
|
3666
|
-
return this.send({
|
|
3667
|
-
type: "resource_release",
|
|
3668
|
-
resource_id: resourceId
|
|
3669
|
-
});
|
|
3670
|
-
}
|
|
3671
|
-
/**
|
|
3672
|
-
* Perform agent handshake
|
|
3673
|
-
*/
|
|
3674
|
-
async handshake(toAgent, capabilities, protocolVersion) {
|
|
3675
|
-
return this.send({
|
|
3676
|
-
type: "agent_handshake",
|
|
3677
|
-
to_agent: toAgent,
|
|
3678
|
-
capabilities,
|
|
3679
|
-
protocol_version: protocolVersion
|
|
3680
|
-
});
|
|
3681
|
-
}
|
|
3682
|
-
/**
|
|
3683
|
-
* Register message handler
|
|
3684
|
-
*/
|
|
3685
|
-
onMessage(messageType, handler) {
|
|
3686
|
-
this.messageHandlers.set(messageType, handler);
|
|
3687
|
-
}
|
|
3688
|
-
/**
|
|
3689
|
-
* Handle incoming message
|
|
3690
|
-
*/
|
|
3691
|
-
async handleIncoming(message) {
|
|
3692
|
-
this.emit("message", message);
|
|
3693
|
-
this.emit(message.type, message);
|
|
3694
|
-
const handler = this.messageHandlers.get(message.type);
|
|
3695
|
-
if (handler) {
|
|
3696
|
-
return handler(message);
|
|
3697
|
-
}
|
|
3698
|
-
return {
|
|
3699
|
-
message_id: message.message_id,
|
|
3700
|
-
success: true,
|
|
3701
|
-
timestamp: Date.now()
|
|
3702
|
-
};
|
|
3703
|
-
}
|
|
3704
|
-
/**
|
|
3705
|
-
* Get spatial claims for this agent
|
|
3706
|
-
*/
|
|
3707
|
-
getMyClaims() {
|
|
3708
|
-
return this.claimManager.getClaimsByAgent(this.agentId);
|
|
3709
|
-
}
|
|
3710
|
-
/**
|
|
3711
|
-
* Get all spatial claims
|
|
3712
|
-
*/
|
|
3713
|
-
getAllClaims() {
|
|
3714
|
-
return this.claimManager.getAllClaims();
|
|
3715
|
-
}
|
|
3716
|
-
/**
|
|
3717
|
-
* Send message with retry logic
|
|
3718
|
-
*/
|
|
3719
|
-
async sendMessage(message) {
|
|
3720
|
-
const responsePromise = this.messageQueue.add(
|
|
3721
|
-
message,
|
|
3722
|
-
this.config.maxRetries,
|
|
3723
|
-
this.config.retryBackoffBase
|
|
3724
|
-
);
|
|
3725
|
-
this.attemptSend(message);
|
|
3726
|
-
return responsePromise;
|
|
3727
|
-
}
|
|
3728
|
-
/**
|
|
3729
|
-
* Attempt to send message
|
|
3730
|
-
*/
|
|
3731
|
-
async attemptSend(message) {
|
|
3732
|
-
try {
|
|
3733
|
-
const response = await this.httpRequest(message);
|
|
3734
|
-
const queued = this.messageQueue.get(message.message_id);
|
|
3735
|
-
if (!queued) return;
|
|
3736
|
-
queued.resolve(response);
|
|
3737
|
-
this.messageQueue.remove(message.message_id);
|
|
3738
|
-
this.emit("message_sent", { message, response });
|
|
3739
|
-
} catch (error) {
|
|
3740
|
-
const queued = this.messageQueue.get(message.message_id);
|
|
3741
|
-
if (!queued) return;
|
|
3742
|
-
if (this.messageQueue.shouldRetry(message.message_id)) {
|
|
3743
|
-
this.emit("retry", { message, attempt: queued.attempt });
|
|
3744
|
-
this.messageQueue.scheduleRetry(message.message_id, () => {
|
|
3745
|
-
this.attemptSend(message);
|
|
3746
|
-
});
|
|
3747
|
-
} else {
|
|
3748
|
-
queued.reject(error);
|
|
3749
|
-
this.messageQueue.remove(message.message_id);
|
|
3750
|
-
this.emit("message_failed", { message, error });
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
}
|
|
3754
|
-
/**
|
|
3755
|
-
* HTTP/2 request
|
|
3756
|
-
*/
|
|
3757
|
-
async httpRequest(message) {
|
|
3758
|
-
const controller = new AbortController();
|
|
3759
|
-
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
3760
|
-
try {
|
|
3761
|
-
const response = await fetch(this.config.endpoint, {
|
|
3762
|
-
method: "POST",
|
|
3763
|
-
headers: {
|
|
3764
|
-
"Content-Type": "application/json"
|
|
3765
|
-
},
|
|
3766
|
-
body: JSON.stringify(message),
|
|
3767
|
-
signal: controller.signal
|
|
3768
|
-
});
|
|
3769
|
-
if (!response.ok) {
|
|
3770
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
3771
|
-
}
|
|
3772
|
-
const data = await response.json();
|
|
3773
|
-
return data;
|
|
3774
|
-
} finally {
|
|
3775
|
-
clearTimeout(timeoutId);
|
|
3776
|
-
}
|
|
3777
|
-
}
|
|
3778
|
-
/**
|
|
3779
|
-
* Add message to batch
|
|
3780
|
-
*/
|
|
3781
|
-
addToBatch(message) {
|
|
3782
|
-
this.batchBuffer.push(message);
|
|
3783
|
-
const responsePromise = new Promise((resolve, reject) => {
|
|
3784
|
-
this.messageQueue.add(message, this.config.maxRetries, this.config.retryBackoffBase).then(resolve).catch(reject);
|
|
3785
|
-
});
|
|
3786
|
-
if (!this.batchTimer) {
|
|
3787
|
-
this.batchTimer = setTimeout(() => {
|
|
3788
|
-
this.flushBatch();
|
|
3789
|
-
}, 10);
|
|
3790
|
-
}
|
|
3791
|
-
if (this.batchBuffer.length >= this.config.batchSize) {
|
|
3792
|
-
this.flushBatch();
|
|
3793
|
-
}
|
|
3794
|
-
return responsePromise;
|
|
3795
|
-
}
|
|
3796
|
-
/**
|
|
3797
|
-
* Flush batch of messages
|
|
3798
|
-
*/
|
|
3799
|
-
flushBatch() {
|
|
3800
|
-
if (this.batchTimer) {
|
|
3801
|
-
clearTimeout(this.batchTimer);
|
|
3802
|
-
this.batchTimer = void 0;
|
|
3803
|
-
}
|
|
3804
|
-
if (this.batchBuffer.length === 0) return;
|
|
3805
|
-
const batch = this.batchBuffer.splice(0);
|
|
3806
|
-
for (const message of batch) {
|
|
3807
|
-
this.attemptSend(message);
|
|
3808
|
-
}
|
|
3809
|
-
}
|
|
3810
|
-
/**
|
|
3811
|
-
* Generate unique message ID
|
|
3812
|
-
*/
|
|
3813
|
-
generateMessageId() {
|
|
3814
|
-
return `${this.agentId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
3815
|
-
}
|
|
3816
|
-
/**
|
|
3817
|
-
* Get queue statistics
|
|
3818
|
-
*/
|
|
3819
|
-
getQueueStats() {
|
|
3820
|
-
return {
|
|
3821
|
-
queueSize: this.messageQueue.size,
|
|
3822
|
-
claimCount: this.getAllClaims().length
|
|
3823
|
-
};
|
|
3824
|
-
}
|
|
3825
|
-
/**
|
|
3826
|
-
* Shutdown client
|
|
3827
|
-
*/
|
|
3828
|
-
async shutdown() {
|
|
3829
|
-
this.flushBatch();
|
|
3830
|
-
this.claimManager.clear();
|
|
3831
|
-
this.messageQueue.clear();
|
|
3832
|
-
this.emit("shutdown");
|
|
3833
|
-
}
|
|
3834
|
-
};
|
|
3835
|
-
|
|
3836
|
-
// src/agents/spatial-comms/Layer3MCP.ts
|
|
3837
|
-
import { EventEmitter as EventEmitter4 } from "events";
|
|
3838
|
-
var SPATIAL_MCP_TOOLS = [
|
|
3839
|
-
{
|
|
3840
|
-
name: "create_world",
|
|
3841
|
-
description: "Create a new VR world with multi-agent support",
|
|
3842
|
-
parameters: {
|
|
3843
|
-
type: "object",
|
|
3844
|
-
properties: {
|
|
3845
|
-
world_spec: {
|
|
3846
|
-
type: "object",
|
|
3847
|
-
description: "World specification including dimensions, features, and agent roles"
|
|
3848
|
-
}
|
|
3849
|
-
},
|
|
3850
|
-
required: ["world_spec"]
|
|
3851
|
-
}
|
|
3852
|
-
},
|
|
3853
|
-
{
|
|
3854
|
-
name: "get_world_status",
|
|
3855
|
-
description: "Get current status of a VR world including agent activity and performance",
|
|
3856
|
-
parameters: {
|
|
3857
|
-
type: "object",
|
|
3858
|
-
properties: {
|
|
3859
|
-
world_id: {
|
|
3860
|
-
type: "string",
|
|
3861
|
-
description: "ID of the world to query"
|
|
3862
|
-
}
|
|
3863
|
-
},
|
|
3864
|
-
required: ["world_id"]
|
|
3865
|
-
}
|
|
3866
|
-
},
|
|
3867
|
-
{
|
|
3868
|
-
name: "export_world",
|
|
3869
|
-
description: "Export VR world to specified format",
|
|
3870
|
-
parameters: {
|
|
3871
|
-
type: "object",
|
|
3872
|
-
properties: {
|
|
3873
|
-
world_id: {
|
|
3874
|
-
type: "string",
|
|
3875
|
-
description: "ID of the world to export"
|
|
3876
|
-
},
|
|
3877
|
-
format: {
|
|
3878
|
-
type: "string",
|
|
3879
|
-
enum: ["gltf", "fbx", "usdz", "vrm", "json", "holoscript"],
|
|
3880
|
-
description: "Export format"
|
|
3881
|
-
}
|
|
3882
|
-
},
|
|
3883
|
-
required: ["world_id", "format"]
|
|
3884
|
-
}
|
|
3885
|
-
},
|
|
3886
|
-
{
|
|
3887
|
-
name: "get_agent_registry",
|
|
3888
|
-
description: "Get all registered agents in the spatial communication system",
|
|
3889
|
-
parameters: {
|
|
3890
|
-
type: "object",
|
|
3891
|
-
properties: {
|
|
3892
|
-
filter: {
|
|
3893
|
-
type: "object",
|
|
3894
|
-
description: "Optional filter criteria (status, role, etc.)"
|
|
3895
|
-
}
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
},
|
|
3899
|
-
{
|
|
3900
|
-
name: "get_performance_metrics",
|
|
3901
|
-
description: "Get real-time performance metrics for agents and system",
|
|
3902
|
-
parameters: {
|
|
3903
|
-
type: "object",
|
|
3904
|
-
properties: {
|
|
3905
|
-
world_id: {
|
|
3906
|
-
type: "string",
|
|
3907
|
-
description: "Optional world ID to filter metrics"
|
|
3908
|
-
},
|
|
3909
|
-
agent_id: {
|
|
3910
|
-
type: "string",
|
|
3911
|
-
description: "Optional agent ID to filter metrics"
|
|
3912
|
-
}
|
|
3913
|
-
}
|
|
3914
|
-
}
|
|
3915
|
-
},
|
|
3916
|
-
{
|
|
3917
|
-
name: "set_global_config",
|
|
3918
|
-
description: "Set global configuration for spatial communication system",
|
|
3919
|
-
parameters: {
|
|
3920
|
-
type: "object",
|
|
3921
|
-
properties: {
|
|
3922
|
-
config: {
|
|
3923
|
-
type: "object",
|
|
3924
|
-
description: "Configuration object with settings to update"
|
|
3925
|
-
}
|
|
3926
|
-
},
|
|
3927
|
-
required: ["config"]
|
|
3928
|
-
}
|
|
3929
|
-
},
|
|
3930
|
-
{
|
|
3931
|
-
name: "trigger_event",
|
|
3932
|
-
description: "Trigger a system-wide event for agent coordination",
|
|
3933
|
-
parameters: {
|
|
3934
|
-
type: "object",
|
|
3935
|
-
properties: {
|
|
3936
|
-
event_type: {
|
|
3937
|
-
type: "string",
|
|
3938
|
-
description: "Type of event to trigger"
|
|
3939
|
-
},
|
|
3940
|
-
event_data: {
|
|
3941
|
-
type: "object",
|
|
3942
|
-
description: "Event payload data"
|
|
3943
|
-
}
|
|
3944
|
-
},
|
|
3945
|
-
required: ["event_type"]
|
|
3946
|
-
}
|
|
3947
|
-
}
|
|
3948
|
-
];
|
|
3949
|
-
var Layer3MCPClient = class extends EventEmitter4 {
|
|
3950
|
-
config;
|
|
3951
|
-
agentId;
|
|
3952
|
-
constructor(agentId, config) {
|
|
3953
|
-
super();
|
|
3954
|
-
this.agentId = agentId;
|
|
3955
|
-
this.config = { ...DEFAULT_MCP_CONFIG, ...config };
|
|
3956
|
-
}
|
|
3957
|
-
/**
|
|
3958
|
-
* Execute MCP command
|
|
3959
|
-
*/
|
|
3960
|
-
async execute(command, params) {
|
|
3961
|
-
const request = {
|
|
3962
|
-
command,
|
|
3963
|
-
params
|
|
3964
|
-
};
|
|
3965
|
-
try {
|
|
3966
|
-
const response = await this.sendMCPRequest(request);
|
|
3967
|
-
this.emit("command_success", { command, params, response });
|
|
3968
|
-
return response;
|
|
3969
|
-
} catch (error) {
|
|
3970
|
-
this.emit("command_error", { command, params, error });
|
|
3971
|
-
throw error;
|
|
3972
|
-
}
|
|
3973
|
-
}
|
|
3974
|
-
/**
|
|
3975
|
-
* Create new VR world
|
|
3976
|
-
*/
|
|
3977
|
-
async createWorld(worldSpec) {
|
|
3978
|
-
const response = await this.execute("create_world", { world_spec: worldSpec });
|
|
3979
|
-
if (!response.success) {
|
|
3980
|
-
throw new Error(response.error || "Failed to create world");
|
|
3981
|
-
}
|
|
3982
|
-
return response.data;
|
|
3983
|
-
}
|
|
3984
|
-
/**
|
|
3985
|
-
* Get world status
|
|
3986
|
-
*/
|
|
3987
|
-
async getWorldStatus(worldId) {
|
|
3988
|
-
const response = await this.execute("get_world_status", { world_id: worldId });
|
|
3989
|
-
if (!response.success) {
|
|
3990
|
-
throw new Error(response.error || "Failed to get world status");
|
|
3991
|
-
}
|
|
3992
|
-
return response.data;
|
|
3993
|
-
}
|
|
3994
|
-
/**
|
|
3995
|
-
* Export world
|
|
3996
|
-
*/
|
|
3997
|
-
async exportWorld(worldId, format) {
|
|
3998
|
-
const response = await this.execute("export_world", { world_id: worldId, format });
|
|
3999
|
-
if (!response.success) {
|
|
4000
|
-
throw new Error(response.error || "Failed to export world");
|
|
4001
|
-
}
|
|
4002
|
-
return response.data;
|
|
4003
|
-
}
|
|
4004
|
-
/**
|
|
4005
|
-
* Get agent registry
|
|
4006
|
-
*/
|
|
4007
|
-
async getAgentRegistry(filter) {
|
|
4008
|
-
const response = await this.execute("get_agent_registry", { filter });
|
|
4009
|
-
if (!response.success) {
|
|
4010
|
-
throw new Error(response.error || "Failed to get agent registry");
|
|
4011
|
-
}
|
|
4012
|
-
return response.data;
|
|
4013
|
-
}
|
|
4014
|
-
/**
|
|
4015
|
-
* Get performance metrics
|
|
4016
|
-
*/
|
|
4017
|
-
async getPerformanceMetrics(options) {
|
|
4018
|
-
const response = await this.execute("get_performance_metrics", options || {});
|
|
4019
|
-
if (!response.success) {
|
|
4020
|
-
throw new Error(response.error || "Failed to get performance metrics");
|
|
4021
|
-
}
|
|
4022
|
-
return response.data;
|
|
4023
|
-
}
|
|
4024
|
-
/**
|
|
4025
|
-
* Set global configuration
|
|
4026
|
-
*/
|
|
4027
|
-
async setGlobalConfig(config) {
|
|
4028
|
-
const response = await this.execute("set_global_config", { config });
|
|
4029
|
-
if (!response.success) {
|
|
4030
|
-
throw new Error(response.error || "Failed to set global config");
|
|
4031
|
-
}
|
|
4032
|
-
}
|
|
4033
|
-
/**
|
|
4034
|
-
* Trigger system event
|
|
4035
|
-
*/
|
|
4036
|
-
async triggerEvent(eventType, eventData) {
|
|
4037
|
-
const response = await this.execute("trigger_event", {
|
|
4038
|
-
event_type: eventType,
|
|
4039
|
-
event_data: eventData
|
|
4040
|
-
});
|
|
4041
|
-
if (!response.success) {
|
|
4042
|
-
throw new Error(response.error || "Failed to trigger event");
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
/**
|
|
4046
|
-
* Call MCP tool directly
|
|
4047
|
-
*/
|
|
4048
|
-
async callTool(server, tool, args) {
|
|
4049
|
-
try {
|
|
4050
|
-
const response = await this.mcpToolCall(server, tool, args);
|
|
4051
|
-
this.emit("tool_call_success", { server, tool, args, response });
|
|
4052
|
-
return {
|
|
4053
|
-
success: true,
|
|
4054
|
-
data: response,
|
|
4055
|
-
timestamp: Date.now()
|
|
4056
|
-
};
|
|
4057
|
-
} catch (error) {
|
|
4058
|
-
this.emit("tool_call_error", { server, tool, args, error });
|
|
4059
|
-
return {
|
|
4060
|
-
success: false,
|
|
4061
|
-
error: error.message,
|
|
4062
|
-
timestamp: Date.now()
|
|
4063
|
-
};
|
|
4064
|
-
}
|
|
4065
|
-
}
|
|
4066
|
-
/**
|
|
4067
|
-
* Get available MCP tools
|
|
4068
|
-
*/
|
|
4069
|
-
getAvailableTools() {
|
|
4070
|
-
return SPATIAL_MCP_TOOLS;
|
|
4071
|
-
}
|
|
4072
|
-
/**
|
|
4073
|
-
* Send MCP request
|
|
4074
|
-
*/
|
|
4075
|
-
async sendMCPRequest(request) {
|
|
4076
|
-
const controller = new AbortController();
|
|
4077
|
-
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
4078
|
-
try {
|
|
4079
|
-
const response = await fetch(`${this.config.endpoint}/mcp/command`, {
|
|
4080
|
-
method: "POST",
|
|
4081
|
-
headers: {
|
|
4082
|
-
"Content-Type": "application/json",
|
|
4083
|
-
"x-mcp-api-key": this.config.apiKey,
|
|
4084
|
-
"x-agent-id": this.agentId
|
|
4085
|
-
},
|
|
4086
|
-
body: JSON.stringify(request),
|
|
4087
|
-
signal: controller.signal
|
|
4088
|
-
});
|
|
4089
|
-
if (!response.ok) {
|
|
4090
|
-
throw new Error(`MCP HTTP ${response.status}: ${response.statusText}`);
|
|
4091
|
-
}
|
|
4092
|
-
const data = await response.json();
|
|
4093
|
-
return data;
|
|
4094
|
-
} finally {
|
|
4095
|
-
clearTimeout(timeoutId);
|
|
4096
|
-
}
|
|
4097
|
-
}
|
|
4098
|
-
/**
|
|
4099
|
-
* Call MCP tool via orchestrator
|
|
4100
|
-
*/
|
|
4101
|
-
async mcpToolCall(server, tool, args) {
|
|
4102
|
-
const controller = new AbortController();
|
|
4103
|
-
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
4104
|
-
try {
|
|
4105
|
-
const response = await fetch(`${this.config.endpoint}/tools/call`, {
|
|
4106
|
-
method: "POST",
|
|
4107
|
-
headers: {
|
|
4108
|
-
"Content-Type": "application/json",
|
|
4109
|
-
"x-mcp-api-key": this.config.apiKey
|
|
4110
|
-
},
|
|
4111
|
-
body: JSON.stringify({
|
|
4112
|
-
server,
|
|
4113
|
-
tool,
|
|
4114
|
-
args
|
|
4115
|
-
}),
|
|
4116
|
-
signal: controller.signal
|
|
4117
|
-
});
|
|
4118
|
-
if (!response.ok) {
|
|
4119
|
-
throw new Error(`MCP Tool Call HTTP ${response.status}: ${response.statusText}`);
|
|
4120
|
-
}
|
|
4121
|
-
const data = await response.json();
|
|
4122
|
-
return data;
|
|
4123
|
-
} finally {
|
|
4124
|
-
clearTimeout(timeoutId);
|
|
4125
|
-
}
|
|
4126
|
-
}
|
|
4127
|
-
};
|
|
4128
|
-
var Layer3MCPServer = class extends EventEmitter4 {
|
|
4129
|
-
handlers = /* @__PURE__ */ new Map();
|
|
4130
|
-
worlds = /* @__PURE__ */ new Map();
|
|
4131
|
-
constructor() {
|
|
4132
|
-
super();
|
|
4133
|
-
this.registerDefaultHandlers();
|
|
4134
|
-
}
|
|
4135
|
-
/**
|
|
4136
|
-
* Register command handler
|
|
4137
|
-
*/
|
|
4138
|
-
registerHandler(command, handler) {
|
|
4139
|
-
this.handlers.set(command, handler);
|
|
4140
|
-
}
|
|
4141
|
-
/**
|
|
4142
|
-
* Handle incoming MCP request
|
|
4143
|
-
*/
|
|
4144
|
-
async handleRequest(request, context) {
|
|
4145
|
-
try {
|
|
4146
|
-
const handler = this.handlers.get(request.command);
|
|
4147
|
-
if (!handler) {
|
|
4148
|
-
return {
|
|
4149
|
-
success: false,
|
|
4150
|
-
error: `Unknown command: ${request.command}`,
|
|
4151
|
-
timestamp: Date.now()
|
|
4152
|
-
};
|
|
4153
|
-
}
|
|
4154
|
-
const data = await handler(request.params, context);
|
|
4155
|
-
this.emit("command_handled", { request, context, data });
|
|
4156
|
-
return {
|
|
4157
|
-
success: true,
|
|
4158
|
-
data,
|
|
4159
|
-
timestamp: Date.now()
|
|
4160
|
-
};
|
|
4161
|
-
} catch (error) {
|
|
4162
|
-
this.emit("command_error", { request, context, error });
|
|
4163
|
-
return {
|
|
4164
|
-
success: false,
|
|
4165
|
-
error: error.message,
|
|
4166
|
-
timestamp: Date.now()
|
|
4167
|
-
};
|
|
4168
|
-
}
|
|
4169
|
-
}
|
|
4170
|
-
/**
|
|
4171
|
-
* Register default handlers
|
|
4172
|
-
*/
|
|
4173
|
-
registerDefaultHandlers() {
|
|
4174
|
-
this.registerHandler("create_world", async (params, context) => {
|
|
4175
|
-
const worldSpec = params.world_spec;
|
|
4176
|
-
const worldId = worldSpec.world_id || `world-${Date.now()}`;
|
|
4177
|
-
const status = {
|
|
4178
|
-
world_id: worldId,
|
|
4179
|
-
name: worldSpec.name,
|
|
4180
|
-
status: "initializing",
|
|
4181
|
-
active_agents: [],
|
|
4182
|
-
performance: {
|
|
4183
|
-
current_fps: worldSpec.target_fps,
|
|
4184
|
-
target_fps: worldSpec.target_fps,
|
|
4185
|
-
frame_time_avg_ms: 1e3 / worldSpec.target_fps,
|
|
4186
|
-
frame_time_max_ms: 1e3 / worldSpec.target_fps,
|
|
4187
|
-
quality_level: "high"
|
|
4188
|
-
},
|
|
4189
|
-
spatial_conflicts: 0,
|
|
4190
|
-
resource_utilization: {
|
|
4191
|
-
cpu_percent: 0,
|
|
4192
|
-
memory_mb: 0,
|
|
4193
|
-
gpu_percent: 0
|
|
4194
|
-
},
|
|
4195
|
-
uptime_ms: 0,
|
|
4196
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4197
|
-
};
|
|
4198
|
-
this.worlds.set(worldId, status);
|
|
4199
|
-
this.emit("world_created", { worldId, worldSpec, context });
|
|
4200
|
-
return { world_id: worldId, status };
|
|
4201
|
-
});
|
|
4202
|
-
this.registerHandler("get_world_status", async (params, context) => {
|
|
4203
|
-
const worldId = params.world_id;
|
|
4204
|
-
const status = this.worlds.get(worldId);
|
|
4205
|
-
if (!status) {
|
|
4206
|
-
throw new Error(`World not found: ${worldId}`);
|
|
4207
|
-
}
|
|
4208
|
-
return status;
|
|
4209
|
-
});
|
|
4210
|
-
this.registerHandler("export_world", async (params, context) => {
|
|
4211
|
-
const worldId = params.world_id;
|
|
4212
|
-
const format = params.format;
|
|
4213
|
-
const world = this.worlds.get(worldId);
|
|
4214
|
-
if (!world) {
|
|
4215
|
-
throw new Error(`World not found: ${worldId}`);
|
|
4216
|
-
}
|
|
4217
|
-
this.emit("world_exported", { worldId, format, context });
|
|
4218
|
-
return {
|
|
4219
|
-
url: `https://hololand.io/exports/${worldId}.${format}`,
|
|
4220
|
-
size: 1024 * 1024 * 10
|
|
4221
|
-
// 10MB
|
|
4222
|
-
};
|
|
4223
|
-
});
|
|
4224
|
-
this.registerHandler("get_agent_registry", async (params, context) => {
|
|
4225
|
-
const filter = params.filter;
|
|
4226
|
-
const agents = [];
|
|
4227
|
-
for (const world of this.worlds.values()) {
|
|
4228
|
-
for (const agent of world.active_agents) {
|
|
4229
|
-
if (filter) {
|
|
4230
|
-
if (filter.status && agent.status !== filter.status) continue;
|
|
4231
|
-
if (filter.role && agent.role !== filter.role) continue;
|
|
4232
|
-
if (filter.world_id && world.world_id !== filter.world_id) continue;
|
|
4233
|
-
}
|
|
4234
|
-
agents.push({
|
|
4235
|
-
...agent,
|
|
4236
|
-
world_id: world.world_id,
|
|
4237
|
-
capabilities: []
|
|
4238
|
-
});
|
|
4239
|
-
}
|
|
4240
|
-
}
|
|
4241
|
-
return {
|
|
4242
|
-
agents,
|
|
4243
|
-
total: agents.length
|
|
4244
|
-
};
|
|
4245
|
-
});
|
|
4246
|
-
this.registerHandler("get_performance_metrics", async (params, context) => {
|
|
4247
|
-
const worldId = params.world_id;
|
|
4248
|
-
const agentId = params.agent_id;
|
|
4249
|
-
const metrics = {
|
|
4250
|
-
timestamp: Date.now(),
|
|
4251
|
-
agents: [],
|
|
4252
|
-
system: {
|
|
4253
|
-
total_fps: 90,
|
|
4254
|
-
target_fps: 90,
|
|
4255
|
-
frame_time_avg_ms: 11.1,
|
|
4256
|
-
frame_time_max_ms: 15,
|
|
4257
|
-
quality_level: "high",
|
|
4258
|
-
cpu_percent: 45,
|
|
4259
|
-
memory_mb: 2048,
|
|
4260
|
-
gpu_percent: 60
|
|
4261
|
-
}
|
|
4262
|
-
};
|
|
4263
|
-
for (const world of this.worlds.values()) {
|
|
4264
|
-
if (worldId && world.world_id !== worldId) continue;
|
|
4265
|
-
for (const agent of world.active_agents) {
|
|
4266
|
-
if (agentId && agent.agent_id !== agentId) continue;
|
|
4267
|
-
metrics.agents.push({
|
|
4268
|
-
agent_id: agent.agent_id,
|
|
4269
|
-
role: agent.role,
|
|
4270
|
-
frame_time_avg_ms: 10,
|
|
4271
|
-
frame_time_max_ms: 12,
|
|
4272
|
-
messages_sent: 0,
|
|
4273
|
-
messages_received: 0,
|
|
4274
|
-
spatial_conflicts: 0
|
|
4275
|
-
});
|
|
4276
|
-
}
|
|
4277
|
-
}
|
|
4278
|
-
return metrics;
|
|
4279
|
-
});
|
|
4280
|
-
this.registerHandler("set_global_config", async (params, context) => {
|
|
4281
|
-
const config = params.config;
|
|
4282
|
-
this.emit("config_updated", { config, context });
|
|
4283
|
-
return { success: true };
|
|
4284
|
-
});
|
|
4285
|
-
this.registerHandler("trigger_event", async (params, context) => {
|
|
4286
|
-
const eventType = params.event_type;
|
|
4287
|
-
const eventData = params.event_data;
|
|
4288
|
-
this.emit("system_event", { eventType, eventData, context });
|
|
4289
|
-
return { success: true };
|
|
4290
|
-
});
|
|
4291
|
-
}
|
|
4292
|
-
/**
|
|
4293
|
-
* Get all worlds
|
|
4294
|
-
*/
|
|
4295
|
-
getWorlds() {
|
|
4296
|
-
return Array.from(this.worlds.values());
|
|
4297
|
-
}
|
|
4298
|
-
/**
|
|
4299
|
-
* Update world status
|
|
4300
|
-
*/
|
|
4301
|
-
updateWorld(worldId, updates) {
|
|
4302
|
-
const world = this.worlds.get(worldId);
|
|
4303
|
-
if (world) {
|
|
4304
|
-
Object.assign(world, updates);
|
|
4305
|
-
this.emit("world_updated", { worldId, updates });
|
|
4306
|
-
}
|
|
4307
|
-
}
|
|
4308
|
-
};
|
|
4309
|
-
|
|
4310
|
-
// src/agents/spatial-comms/SpatialCommClient.ts
|
|
4311
|
-
import { EventEmitter as EventEmitter5 } from "events";
|
|
4312
|
-
var FrameBudgetTracker = class {
|
|
4313
|
-
targetFps;
|
|
4314
|
-
targetFrameTimeMs;
|
|
4315
|
-
frameTimeSamples = [];
|
|
4316
|
-
maxSamples = 60;
|
|
4317
|
-
// Track last 60 frames
|
|
4318
|
-
qualityLevel = "high";
|
|
4319
|
-
constructor(targetFps = 90) {
|
|
4320
|
-
this.targetFps = targetFps;
|
|
4321
|
-
this.targetFrameTimeMs = 1e3 / targetFps;
|
|
4322
|
-
}
|
|
4323
|
-
/**
|
|
4324
|
-
* Record frame time
|
|
4325
|
-
*/
|
|
4326
|
-
recordFrameTime(frameTimeMs) {
|
|
4327
|
-
this.frameTimeSamples.push(frameTimeMs);
|
|
4328
|
-
if (this.frameTimeSamples.length > this.maxSamples) {
|
|
4329
|
-
this.frameTimeSamples.shift();
|
|
4330
|
-
}
|
|
4331
|
-
this.autoAdjustQuality();
|
|
4332
|
-
}
|
|
4333
|
-
/**
|
|
4334
|
-
* Get average frame time
|
|
4335
|
-
*/
|
|
4336
|
-
getAverageFrameTime() {
|
|
4337
|
-
if (this.frameTimeSamples.length === 0) return this.targetFrameTimeMs;
|
|
4338
|
-
const sum = this.frameTimeSamples.reduce((a, b) => a + b, 0);
|
|
4339
|
-
return sum / this.frameTimeSamples.length;
|
|
4340
|
-
}
|
|
4341
|
-
/**
|
|
4342
|
-
* Get maximum frame time
|
|
4343
|
-
*/
|
|
4344
|
-
getMaxFrameTime() {
|
|
4345
|
-
if (this.frameTimeSamples.length === 0) return this.targetFrameTimeMs;
|
|
4346
|
-
return Math.max(...this.frameTimeSamples);
|
|
4347
|
-
}
|
|
4348
|
-
/**
|
|
4349
|
-
* Get current FPS
|
|
4350
|
-
*/
|
|
4351
|
-
getCurrentFps() {
|
|
4352
|
-
const avgFrameTime = this.getAverageFrameTime();
|
|
4353
|
-
return 1e3 / avgFrameTime;
|
|
4354
|
-
}
|
|
4355
|
-
/**
|
|
4356
|
-
* Get budget remaining for current frame
|
|
4357
|
-
*/
|
|
4358
|
-
getBudgetRemaining() {
|
|
4359
|
-
const avgFrameTime = this.getAverageFrameTime();
|
|
4360
|
-
return Math.max(0, this.targetFrameTimeMs - avgFrameTime);
|
|
4361
|
-
}
|
|
4362
|
-
/**
|
|
4363
|
-
* Check if within budget
|
|
4364
|
-
*/
|
|
4365
|
-
isWithinBudget() {
|
|
4366
|
-
return this.getAverageFrameTime() <= this.targetFrameTimeMs * 1.1;
|
|
4367
|
-
}
|
|
4368
|
-
/**
|
|
4369
|
-
* Get current quality level
|
|
4370
|
-
*/
|
|
4371
|
-
getQualityLevel() {
|
|
4372
|
-
return this.qualityLevel;
|
|
4373
|
-
}
|
|
4374
|
-
/**
|
|
4375
|
-
* Set quality level
|
|
4376
|
-
*/
|
|
4377
|
-
setQualityLevel(level) {
|
|
4378
|
-
this.qualityLevel = level;
|
|
4379
|
-
}
|
|
4380
|
-
/**
|
|
4381
|
-
* Auto-adjust quality based on performance
|
|
4382
|
-
*/
|
|
4383
|
-
autoAdjustQuality() {
|
|
4384
|
-
const avgFrameTime = this.getAverageFrameTime();
|
|
4385
|
-
const targetFrameTime = this.targetFrameTimeMs;
|
|
4386
|
-
if (avgFrameTime > targetFrameTime * 1.3) {
|
|
4387
|
-
this.qualityLevel = "minimal";
|
|
4388
|
-
} else if (avgFrameTime > targetFrameTime * 1.2) {
|
|
4389
|
-
this.qualityLevel = "low";
|
|
4390
|
-
} else if (avgFrameTime > targetFrameTime * 1.1) {
|
|
4391
|
-
this.qualityLevel = "medium";
|
|
4392
|
-
} else {
|
|
4393
|
-
this.qualityLevel = "high";
|
|
4394
|
-
}
|
|
4395
|
-
}
|
|
4396
|
-
/**
|
|
4397
|
-
* Get frame budget stats
|
|
4398
|
-
*/
|
|
4399
|
-
getStats() {
|
|
4400
|
-
return {
|
|
4401
|
-
targetFps: this.targetFps,
|
|
4402
|
-
currentFps: this.getCurrentFps(),
|
|
4403
|
-
avgFrameTimeMs: this.getAverageFrameTime(),
|
|
4404
|
-
maxFrameTimeMs: this.getMaxFrameTime(),
|
|
4405
|
-
budgetRemainingMs: this.getBudgetRemaining(),
|
|
4406
|
-
qualityLevel: this.qualityLevel,
|
|
4407
|
-
withinBudget: this.isWithinBudget()
|
|
4408
|
-
};
|
|
4409
|
-
}
|
|
4410
|
-
/**
|
|
4411
|
-
* Reset tracker
|
|
4412
|
-
*/
|
|
4413
|
-
reset() {
|
|
4414
|
-
this.frameTimeSamples = [];
|
|
4415
|
-
this.qualityLevel = "high";
|
|
4416
|
-
}
|
|
4417
|
-
};
|
|
4418
|
-
var SpatialCommClient = class extends EventEmitter5 {
|
|
4419
|
-
agentId;
|
|
4420
|
-
config;
|
|
4421
|
-
// Layer clients
|
|
4422
|
-
layer1;
|
|
4423
|
-
layer2;
|
|
4424
|
-
layer3;
|
|
4425
|
-
// Frame budget tracker
|
|
4426
|
-
frameBudget;
|
|
4427
|
-
// State
|
|
4428
|
-
initialized = false;
|
|
4429
|
-
currentWorldId;
|
|
4430
|
-
constructor(agentId, config) {
|
|
4431
|
-
super();
|
|
4432
|
-
this.agentId = agentId;
|
|
4433
|
-
this.config = {
|
|
4434
|
-
layer1: { ...DEFAULT_SPATIAL_COMM_CONFIG.layer1, ...config?.layer1 || {} },
|
|
4435
|
-
layer2: { ...DEFAULT_SPATIAL_COMM_CONFIG.layer2, ...config?.layer2 || {} },
|
|
4436
|
-
layer3: { ...DEFAULT_SPATIAL_COMM_CONFIG.layer3, ...config?.layer3 || {} }
|
|
4437
|
-
};
|
|
4438
|
-
this.frameBudget = new FrameBudgetTracker(this.config.layer1.targetLatency);
|
|
4439
|
-
}
|
|
4440
|
-
/**
|
|
4441
|
-
* Initialize all layers
|
|
4442
|
-
*/
|
|
4443
|
-
async init(options) {
|
|
4444
|
-
if (this.initialized) {
|
|
4445
|
-
throw new Error("Client already initialized");
|
|
4446
|
-
}
|
|
4447
|
-
this.layer1 = new Layer1RealTimeClient(this.agentId, this.config.layer1);
|
|
4448
|
-
await this.layer1.init(options?.useWebRTC);
|
|
4449
|
-
this.layer1.on("message", (msg) => this.emit("layer1:message", msg));
|
|
4450
|
-
this.layer1.on("latency_warning", (data) => this.emit("layer1:latency_warning", data));
|
|
4451
|
-
this.layer2 = new Layer2A2AClient(this.agentId, this.config.layer2);
|
|
4452
|
-
this.layer2.on("message", (msg) => this.emit("layer2:message", msg));
|
|
4453
|
-
this.layer2.on("spatial_conflict", (data) => this.emit("layer2:spatial_conflict", data));
|
|
4454
|
-
this.layer2.on("retry", (data) => this.emit("layer2:retry", data));
|
|
4455
|
-
this.layer3 = new Layer3MCPClient(this.agentId, this.config.layer3);
|
|
4456
|
-
this.layer3.on("command_success", (data) => this.emit("layer3:command_success", data));
|
|
4457
|
-
this.layer3.on("command_error", (data) => this.emit("layer3:command_error", data));
|
|
4458
|
-
this.initialized = true;
|
|
4459
|
-
this.emit("initialized", { agentId: this.agentId });
|
|
4460
|
-
}
|
|
4461
|
-
// ==========================================================================
|
|
4462
|
-
// LAYER 1: REAL-TIME OPERATIONS
|
|
4463
|
-
// ==========================================================================
|
|
4464
|
-
/**
|
|
4465
|
-
* Send position sync (Layer 1)
|
|
4466
|
-
*/
|
|
4467
|
-
async syncPosition(position, rotation, scale, velocity) {
|
|
4468
|
-
if (!this.layer1) throw new Error("Layer 1 not initialized");
|
|
4469
|
-
await this.layer1.sendPositionSync(position, rotation, scale, velocity);
|
|
4470
|
-
}
|
|
4471
|
-
/**
|
|
4472
|
-
* Send frame budget update (Layer 1)
|
|
4473
|
-
*/
|
|
4474
|
-
async sendFrameBudget() {
|
|
4475
|
-
if (!this.layer1) throw new Error("Layer 1 not initialized");
|
|
4476
|
-
const stats = this.frameBudget.getStats();
|
|
4477
|
-
await this.layer1.sendFrameBudget(
|
|
4478
|
-
stats.avgFrameTimeMs,
|
|
4479
|
-
stats.budgetRemainingMs,
|
|
4480
|
-
stats.targetFps,
|
|
4481
|
-
stats.currentFps,
|
|
4482
|
-
stats.qualityLevel
|
|
4483
|
-
);
|
|
4484
|
-
}
|
|
4485
|
-
/**
|
|
4486
|
-
* Record frame time (updates budget tracker)
|
|
4487
|
-
*/
|
|
4488
|
-
recordFrameTime(frameTimeMs) {
|
|
4489
|
-
this.frameBudget.recordFrameTime(frameTimeMs);
|
|
4490
|
-
if (!this.frameBudget.isWithinBudget()) {
|
|
4491
|
-
this.emit("budget_warning", this.frameBudget.getStats());
|
|
4492
|
-
}
|
|
4493
|
-
}
|
|
4494
|
-
/**
|
|
4495
|
-
* Get frame budget stats
|
|
4496
|
-
*/
|
|
4497
|
-
getFrameBudgetStats() {
|
|
4498
|
-
return this.frameBudget.getStats();
|
|
4499
|
-
}
|
|
4500
|
-
// ==========================================================================
|
|
4501
|
-
// LAYER 2: COORDINATION OPERATIONS
|
|
4502
|
-
// ==========================================================================
|
|
4503
|
-
/**
|
|
4504
|
-
* Assign task to agent (Layer 2)
|
|
4505
|
-
*/
|
|
4506
|
-
async assignTask(toAgent, task) {
|
|
4507
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4508
|
-
return this.layer2.assignTask(toAgent, task);
|
|
4509
|
-
}
|
|
4510
|
-
/**
|
|
4511
|
-
* Complete task (Layer 2)
|
|
4512
|
-
*/
|
|
4513
|
-
async completeTask(taskId, success, result, error) {
|
|
4514
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4515
|
-
const stats = this.frameBudget.getStats();
|
|
4516
|
-
return this.layer2.completeTask(taskId, success, result, error, {
|
|
4517
|
-
duration_ms: 0,
|
|
4518
|
-
// Would be tracked separately
|
|
4519
|
-
frame_time_avg_ms: stats.avgFrameTimeMs,
|
|
4520
|
-
frame_time_max_ms: stats.maxFrameTimeMs,
|
|
4521
|
-
quality_level: stats.qualityLevel
|
|
4522
|
-
});
|
|
4523
|
-
}
|
|
4524
|
-
/**
|
|
4525
|
-
* Claim spatial region (Layer 2)
|
|
4526
|
-
*/
|
|
4527
|
-
async claimSpatialRegion(claimId, boundingBox, priority, durationMs, exclusive = true) {
|
|
4528
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4529
|
-
return this.layer2.claimSpatialRegion(claimId, boundingBox, priority, durationMs, exclusive);
|
|
4530
|
-
}
|
|
4531
|
-
/**
|
|
4532
|
-
* Request resource (Layer 2)
|
|
4533
|
-
*/
|
|
4534
|
-
async requestResource(resourceId, resourceType, amount, priority = "medium") {
|
|
4535
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4536
|
-
return this.layer2.requestResource(resourceId, resourceType, amount, priority);
|
|
4537
|
-
}
|
|
4538
|
-
/**
|
|
4539
|
-
* Release resource (Layer 2)
|
|
4540
|
-
*/
|
|
4541
|
-
async releaseResource(resourceId) {
|
|
4542
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4543
|
-
return this.layer2.releaseResource(resourceId);
|
|
4544
|
-
}
|
|
4545
|
-
/**
|
|
4546
|
-
* Get spatial claims (Layer 2)
|
|
4547
|
-
*/
|
|
4548
|
-
getMyClaims() {
|
|
4549
|
-
if (!this.layer2) throw new Error("Layer 2 not initialized");
|
|
4550
|
-
return this.layer2.getMyClaims();
|
|
4551
|
-
}
|
|
4552
|
-
// ==========================================================================
|
|
4553
|
-
// LAYER 3: METADATA OPERATIONS
|
|
4554
|
-
// ==========================================================================
|
|
4555
|
-
/**
|
|
4556
|
-
* Create world (Layer 3)
|
|
4557
|
-
*/
|
|
4558
|
-
async createWorld(worldSpec) {
|
|
4559
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4560
|
-
const result = await this.layer3.createWorld(worldSpec);
|
|
4561
|
-
this.currentWorldId = result.world_id;
|
|
4562
|
-
return result;
|
|
4563
|
-
}
|
|
4564
|
-
/**
|
|
4565
|
-
* Get world status (Layer 3)
|
|
4566
|
-
*/
|
|
4567
|
-
async getWorldStatus(worldId) {
|
|
4568
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4569
|
-
const id = worldId || this.currentWorldId;
|
|
4570
|
-
if (!id) throw new Error("No world ID specified");
|
|
4571
|
-
return this.layer3.getWorldStatus(id);
|
|
4572
|
-
}
|
|
4573
|
-
/**
|
|
4574
|
-
* Export world (Layer 3)
|
|
4575
|
-
*/
|
|
4576
|
-
async exportWorld(format, worldId) {
|
|
4577
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4578
|
-
const id = worldId || this.currentWorldId;
|
|
4579
|
-
if (!id) throw new Error("No world ID specified");
|
|
4580
|
-
return this.layer3.exportWorld(id, format);
|
|
4581
|
-
}
|
|
4582
|
-
/**
|
|
4583
|
-
* Get agent registry (Layer 3)
|
|
4584
|
-
*/
|
|
4585
|
-
async getAgentRegistry(filter) {
|
|
4586
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4587
|
-
return this.layer3.getAgentRegistry(filter);
|
|
4588
|
-
}
|
|
4589
|
-
/**
|
|
4590
|
-
* Get performance metrics (Layer 3)
|
|
4591
|
-
*/
|
|
4592
|
-
async getPerformanceMetrics(options) {
|
|
4593
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4594
|
-
return this.layer3.getPerformanceMetrics(options);
|
|
4595
|
-
}
|
|
4596
|
-
/**
|
|
4597
|
-
* Set global configuration (Layer 3)
|
|
4598
|
-
*/
|
|
4599
|
-
async setGlobalConfig(config) {
|
|
4600
|
-
if (!this.layer3) throw new Error("Layer 3 not initialized");
|
|
4601
|
-
return this.layer3.setGlobalConfig(config);
|
|
4602
|
-
}
|
|
4603
|
-
// ==========================================================================
|
|
4604
|
-
// LIFECYCLE
|
|
4605
|
-
// ==========================================================================
|
|
4606
|
-
/**
|
|
4607
|
-
* Shutdown client
|
|
4608
|
-
*/
|
|
4609
|
-
async shutdown() {
|
|
4610
|
-
if (!this.initialized) return;
|
|
4611
|
-
if (this.layer3) {
|
|
4612
|
-
}
|
|
4613
|
-
if (this.layer2) {
|
|
4614
|
-
await this.layer2.shutdown();
|
|
4615
|
-
}
|
|
4616
|
-
if (this.layer1) {
|
|
4617
|
-
await this.layer1.close();
|
|
4618
|
-
}
|
|
4619
|
-
this.initialized = false;
|
|
4620
|
-
this.emit("shutdown");
|
|
4621
|
-
}
|
|
4622
|
-
/**
|
|
4623
|
-
* Get client status
|
|
4624
|
-
*/
|
|
4625
|
-
getStatus() {
|
|
4626
|
-
return {
|
|
4627
|
-
agentId: this.agentId,
|
|
4628
|
-
initialized: this.initialized,
|
|
4629
|
-
currentWorldId: this.currentWorldId,
|
|
4630
|
-
frameBudget: this.frameBudget.getStats(),
|
|
4631
|
-
queueStats: this.layer2?.getQueueStats() || { queueSize: 0, claimCount: 0 }
|
|
4632
|
-
};
|
|
4633
|
-
}
|
|
4634
|
-
};
|
|
4635
|
-
export {
|
|
4636
|
-
AgentManifestBuilder,
|
|
4637
|
-
AgentRegistry,
|
|
4638
|
-
AgentWalletRegistry,
|
|
4639
|
-
BUILTIN_NORMS,
|
|
4640
|
-
CapabilityMatcher,
|
|
4641
|
-
CulturalMemory,
|
|
4642
|
-
DEFAULT_A2A_CONFIG,
|
|
4643
|
-
DEFAULT_MCP_CONFIG,
|
|
4644
|
-
DEFAULT_PHASE_TIMINGS,
|
|
4645
|
-
DEFAULT_REALTIME_CONFIG,
|
|
4646
|
-
DEFAULT_REGISTRY_CONFIG,
|
|
4647
|
-
DEFAULT_SPATIAL_COMM_CONFIG,
|
|
4648
|
-
EffectRow,
|
|
4649
|
-
FederatedRegistryAdapter,
|
|
4650
|
-
FrameBudgetTracker,
|
|
4651
|
-
GCounter,
|
|
4652
|
-
LATENCY_THRESHOLDS,
|
|
4653
|
-
LWWRegister,
|
|
4654
|
-
Layer1RealTimeClient,
|
|
4655
|
-
Layer2A2AClient,
|
|
4656
|
-
Layer3MCPClient,
|
|
4657
|
-
Layer3MCPServer,
|
|
4658
|
-
NormEngine,
|
|
4659
|
-
ORSet,
|
|
4660
|
-
OrchestratorAgent,
|
|
4661
|
-
PHASE_ORDER,
|
|
4662
|
-
PLATFORM_CAPABILITIES,
|
|
4663
|
-
PROTOCOL_COMPATIBILITY,
|
|
4664
|
-
PROTOCOL_VERSION,
|
|
4665
|
-
SPATIAL_MCP_TOOLS,
|
|
4666
|
-
SkillWorkflowEngine,
|
|
4667
|
-
SpatialCommClient,
|
|
4668
|
-
TaskDelegationService,
|
|
4669
|
-
UDPRealTimeTransport,
|
|
4670
|
-
WebRTCRealTimeTransport,
|
|
4671
|
-
createManifest as createAgentManifest,
|
|
4672
|
-
createAgentState,
|
|
4673
|
-
createMVCPayload,
|
|
4674
|
-
criticalMassForChange,
|
|
4675
|
-
decodeRealTimeMessage,
|
|
4676
|
-
defaultMatcher,
|
|
4677
|
-
embodimentFor,
|
|
4678
|
-
encodeRealTimeMessage,
|
|
4679
|
-
estimatePayloadSize,
|
|
4680
|
-
findAgents,
|
|
4681
|
-
findBestAgent,
|
|
4682
|
-
getCounter,
|
|
4683
|
-
getDefaultRegistry,
|
|
4684
|
-
getRegister,
|
|
4685
|
-
incrementCounter,
|
|
4686
|
-
mergeStates,
|
|
4687
|
-
negotiateHandoff,
|
|
4688
|
-
platformCategory,
|
|
4689
|
-
resetDefaultRegistry,
|
|
4690
|
-
setRegister,
|
|
4691
|
-
signOperation,
|
|
4692
|
-
validateManifest,
|
|
4693
|
-
validatePayloadBudget,
|
|
4694
|
-
verifyOperation
|
|
4695
|
-
};
|