@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
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DelegationTraceHooks Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests agent-to-agent delegation tracing, chain walking, and replay.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
8
|
+
import {
|
|
9
|
+
DelegationTraceStore,
|
|
10
|
+
traceDelegation,
|
|
11
|
+
replayDelegation,
|
|
12
|
+
getDelegationChain,
|
|
13
|
+
resetDefaultTraceStore,
|
|
14
|
+
getDefaultTraceStore,
|
|
15
|
+
type DelegationEvent,
|
|
16
|
+
type DelegationTrace,
|
|
17
|
+
type DelegationExecutor,
|
|
18
|
+
} from '../DelegationTraceHooks';
|
|
19
|
+
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// TESTS
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
describe('DelegationTraceHooks', () => {
|
|
25
|
+
let store: DelegationTraceStore;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
store = new DelegationTraceStore();
|
|
29
|
+
resetDefaultTraceStore();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ===========================================================================
|
|
33
|
+
// traceDelegation
|
|
34
|
+
// ===========================================================================
|
|
35
|
+
|
|
36
|
+
describe('traceDelegation', () => {
|
|
37
|
+
it('creates a root delegation event with no parent', () => {
|
|
38
|
+
const event = store.traceDelegation('agent-a', 'agent-b', 'task-1', { skill: 'parse' });
|
|
39
|
+
|
|
40
|
+
expect(event.fromAgent).toBe('agent-a');
|
|
41
|
+
expect(event.toAgent).toBe('agent-b');
|
|
42
|
+
expect(event.taskId).toBe('task-1');
|
|
43
|
+
expect(event.payload).toEqual({ skill: 'parse' });
|
|
44
|
+
expect(event.parentDelegation).toBeNull();
|
|
45
|
+
expect(event.status).toBe('pending');
|
|
46
|
+
expect(event.id).toBeTruthy();
|
|
47
|
+
expect(event.timestamp).toBeTruthy();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('creates a child delegation linked to parent', () => {
|
|
51
|
+
const root = store.traceDelegation('agent-a', 'agent-b', 'task-1');
|
|
52
|
+
const child = store.traceDelegation('agent-b', 'agent-c', 'task-2', {}, root.id);
|
|
53
|
+
|
|
54
|
+
expect(child.parentDelegation).toBe(root.id);
|
|
55
|
+
|
|
56
|
+
// Both should be in the same trace
|
|
57
|
+
const trace = store.getTrace(root.id);
|
|
58
|
+
expect(trace).toBeDefined();
|
|
59
|
+
expect(trace!.events.size).toBe(2);
|
|
60
|
+
expect(trace!.events.has(root.id)).toBe(true);
|
|
61
|
+
expect(trace!.events.has(child.id)).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('creates a new trace when parent is not found', () => {
|
|
65
|
+
const orphan = store.traceDelegation('agent-x', 'agent-y', 'task-99', {}, 'nonexistent');
|
|
66
|
+
|
|
67
|
+
expect(orphan.parentDelegation).toBe('nonexistent');
|
|
68
|
+
expect(store.size).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('handles empty payload', () => {
|
|
72
|
+
const event = store.traceDelegation('a', 'b', 't');
|
|
73
|
+
expect(event.payload).toEqual({});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ===========================================================================
|
|
78
|
+
// updateStatus
|
|
79
|
+
// ===========================================================================
|
|
80
|
+
|
|
81
|
+
describe('updateStatus', () => {
|
|
82
|
+
it('updates event status', () => {
|
|
83
|
+
const event = store.traceDelegation('a', 'b', 't');
|
|
84
|
+
const updated = store.updateStatus(event.id, 'completed', { durationMs: 150 });
|
|
85
|
+
|
|
86
|
+
expect(updated).toBe(true);
|
|
87
|
+
const retrieved = store.getEvent(event.id);
|
|
88
|
+
expect(retrieved!.status).toBe('completed');
|
|
89
|
+
expect(retrieved!.durationMs).toBe(150);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('records error on failure', () => {
|
|
93
|
+
const event = store.traceDelegation('a', 'b', 't');
|
|
94
|
+
store.updateStatus(event.id, 'failed', { error: 'Connection refused' });
|
|
95
|
+
|
|
96
|
+
const retrieved = store.getEvent(event.id);
|
|
97
|
+
expect(retrieved!.status).toBe('failed');
|
|
98
|
+
expect(retrieved!.error).toBe('Connection refused');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('returns false for unknown event', () => {
|
|
102
|
+
expect(store.updateStatus('nonexistent', 'completed')).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ===========================================================================
|
|
107
|
+
// getDelegationChain
|
|
108
|
+
// ===========================================================================
|
|
109
|
+
|
|
110
|
+
describe('getDelegationChain', () => {
|
|
111
|
+
it('returns the full chain from root to leaf', () => {
|
|
112
|
+
const root = store.traceDelegation('orchestrator', 'agent-a', 'task-1');
|
|
113
|
+
const mid = store.traceDelegation('agent-a', 'agent-b', 'task-2', {}, root.id);
|
|
114
|
+
const leaf = store.traceDelegation('agent-b', 'agent-c', 'task-3', {}, mid.id);
|
|
115
|
+
|
|
116
|
+
const chain = store.getDelegationChain(leaf.id);
|
|
117
|
+
|
|
118
|
+
expect(chain).toHaveLength(3);
|
|
119
|
+
expect(chain[0].event.id).toBe(root.id);
|
|
120
|
+
expect(chain[0].depth).toBe(0);
|
|
121
|
+
expect(chain[1].event.id).toBe(mid.id);
|
|
122
|
+
expect(chain[1].depth).toBe(1);
|
|
123
|
+
expect(chain[2].event.id).toBe(leaf.id);
|
|
124
|
+
expect(chain[2].depth).toBe(2);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('returns single entry for root event', () => {
|
|
128
|
+
const root = store.traceDelegation('a', 'b', 't');
|
|
129
|
+
const chain = store.getDelegationChain(root.id);
|
|
130
|
+
|
|
131
|
+
expect(chain).toHaveLength(1);
|
|
132
|
+
expect(chain[0].depth).toBe(0);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('returns empty for unknown event', () => {
|
|
136
|
+
expect(store.getDelegationChain('nonexistent')).toEqual([]);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ===========================================================================
|
|
141
|
+
// getChildren
|
|
142
|
+
// ===========================================================================
|
|
143
|
+
|
|
144
|
+
describe('getChildren', () => {
|
|
145
|
+
it('returns direct children of an event', () => {
|
|
146
|
+
const root = store.traceDelegation('a', 'b', 't1');
|
|
147
|
+
store.traceDelegation('b', 'c', 't2', {}, root.id);
|
|
148
|
+
store.traceDelegation('b', 'd', 't3', {}, root.id);
|
|
149
|
+
|
|
150
|
+
const children = store.getChildren(root.id);
|
|
151
|
+
expect(children).toHaveLength(2);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('returns empty for leaf events', () => {
|
|
155
|
+
const root = store.traceDelegation('a', 'b', 't');
|
|
156
|
+
expect(store.getChildren(root.id)).toHaveLength(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ===========================================================================
|
|
161
|
+
// replayDelegation
|
|
162
|
+
// ===========================================================================
|
|
163
|
+
|
|
164
|
+
describe('replayDelegation', () => {
|
|
165
|
+
it('performs a dry-run replay of a trace', async () => {
|
|
166
|
+
const root = store.traceDelegation('a', 'b', 't1', { skill: 'parse' });
|
|
167
|
+
store.traceDelegation('b', 'c', 't2', { skill: 'compile' }, root.id);
|
|
168
|
+
|
|
169
|
+
const result = await store.replayDelegation(root.id);
|
|
170
|
+
|
|
171
|
+
expect(result.status).toBe('completed');
|
|
172
|
+
expect(result.steps).toHaveLength(2);
|
|
173
|
+
expect(result.steps[0].status).toBe('dry_run');
|
|
174
|
+
expect(result.steps[1].status).toBe('dry_run');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('executes replay with an executor', async () => {
|
|
178
|
+
const root = store.traceDelegation('a', 'b', 't1', { skill: 'parse' });
|
|
179
|
+
store.traceDelegation('b', 'c', 't2', { skill: 'compile' }, root.id);
|
|
180
|
+
|
|
181
|
+
const executor: DelegationExecutor = vi.fn(async (_from, _to, _task, payload) => ({
|
|
182
|
+
executed: payload.skill,
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
const result = await store.replayDelegation(root.id, executor, { execute: true });
|
|
186
|
+
|
|
187
|
+
expect(result.status).toBe('completed');
|
|
188
|
+
expect(result.steps).toHaveLength(2);
|
|
189
|
+
expect(result.steps[0].status).toBe('executed');
|
|
190
|
+
expect(result.steps[1].status).toBe('executed');
|
|
191
|
+
expect(executor).toHaveBeenCalledTimes(2);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('reports failure when executor throws', async () => {
|
|
195
|
+
const root = store.traceDelegation('a', 'b', 't1');
|
|
196
|
+
|
|
197
|
+
const executor: DelegationExecutor = async () => {
|
|
198
|
+
throw new Error('Replay error');
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const result = await store.replayDelegation(root.id, executor, { execute: true });
|
|
202
|
+
|
|
203
|
+
expect(result.steps[0].status).toBe('failed');
|
|
204
|
+
expect(result.steps[0].error).toBe('Replay error');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('supports beforeStep to skip events', async () => {
|
|
208
|
+
const root = store.traceDelegation('a', 'b', 't1');
|
|
209
|
+
store.traceDelegation('b', 'c', 't2', {}, root.id);
|
|
210
|
+
|
|
211
|
+
const executor: DelegationExecutor = vi.fn(async () => 'ok');
|
|
212
|
+
|
|
213
|
+
const result = await store.replayDelegation(root.id, executor, {
|
|
214
|
+
execute: true,
|
|
215
|
+
beforeStep: (event) => event.fromAgent !== 'b', // skip agent-b delegations
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(result.steps).toHaveLength(2);
|
|
219
|
+
expect(result.steps[0].status).toBe('executed'); // root a->b
|
|
220
|
+
expect(result.steps[1].status).toBe('skipped'); // child b->c
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('supports afterStep callback', async () => {
|
|
224
|
+
const root = store.traceDelegation('a', 'b', 't1');
|
|
225
|
+
|
|
226
|
+
const afterEvents: string[] = [];
|
|
227
|
+
await store.replayDelegation(root.id, undefined, {
|
|
228
|
+
afterStep: (event) => {
|
|
229
|
+
afterEvents.push(event.id);
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
expect(afterEvents).toHaveLength(1);
|
|
234
|
+
expect(afterEvents[0]).toBe(root.id);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('supports payload overrides during replay', async () => {
|
|
238
|
+
const root = store.traceDelegation('a', 'b', 't1', { original: true });
|
|
239
|
+
|
|
240
|
+
const capturedPayloads: Record<string, unknown>[] = [];
|
|
241
|
+
const executor: DelegationExecutor = async (_from, _to, _task, payload) => {
|
|
242
|
+
capturedPayloads.push(payload);
|
|
243
|
+
return 'ok';
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const overrides = new Map([[root.id, { overridden: true }]]);
|
|
247
|
+
|
|
248
|
+
await store.replayDelegation(root.id, executor, {
|
|
249
|
+
execute: true,
|
|
250
|
+
payloadOverrides: overrides,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(capturedPayloads[0]).toEqual({ overridden: true });
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('returns failed for unknown trace', async () => {
|
|
257
|
+
const result = await store.replayDelegation('nonexistent');
|
|
258
|
+
expect(result.status).toBe('failed');
|
|
259
|
+
expect(result.steps).toHaveLength(0);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// ===========================================================================
|
|
264
|
+
// Hooks (onDelegation)
|
|
265
|
+
// ===========================================================================
|
|
266
|
+
|
|
267
|
+
describe('onDelegation hooks', () => {
|
|
268
|
+
it('notifies subscribers on new delegation', () => {
|
|
269
|
+
const events: DelegationEvent[] = [];
|
|
270
|
+
store.onDelegation((event) => events.push(event));
|
|
271
|
+
|
|
272
|
+
store.traceDelegation('a', 'b', 't1');
|
|
273
|
+
store.traceDelegation('b', 'c', 't2');
|
|
274
|
+
|
|
275
|
+
expect(events).toHaveLength(2);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('notifies on status updates', () => {
|
|
279
|
+
const events: DelegationEvent[] = [];
|
|
280
|
+
store.onDelegation((event) => events.push(event));
|
|
281
|
+
|
|
282
|
+
const e = store.traceDelegation('a', 'b', 't1');
|
|
283
|
+
store.updateStatus(e.id, 'completed');
|
|
284
|
+
|
|
285
|
+
expect(events).toHaveLength(2); // creation + update
|
|
286
|
+
expect(events[1].status).toBe('completed');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('unsubscribe stops notifications', () => {
|
|
290
|
+
const events: DelegationEvent[] = [];
|
|
291
|
+
const unsub = store.onDelegation((event) => events.push(event));
|
|
292
|
+
|
|
293
|
+
store.traceDelegation('a', 'b', 't1');
|
|
294
|
+
unsub();
|
|
295
|
+
store.traceDelegation('c', 'd', 't2');
|
|
296
|
+
|
|
297
|
+
expect(events).toHaveLength(1);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('hook errors do not break delegation flow', () => {
|
|
301
|
+
store.onDelegation(() => {
|
|
302
|
+
throw new Error('Hook exploded');
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Should not throw
|
|
306
|
+
const event = store.traceDelegation('a', 'b', 't1');
|
|
307
|
+
expect(event.id).toBeTruthy();
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// ===========================================================================
|
|
312
|
+
// Query methods
|
|
313
|
+
// ===========================================================================
|
|
314
|
+
|
|
315
|
+
describe('query', () => {
|
|
316
|
+
it('getTracesForAgent finds all traces involving an agent', () => {
|
|
317
|
+
store.traceDelegation('agent-a', 'agent-b', 't1');
|
|
318
|
+
store.traceDelegation('agent-c', 'agent-d', 't2');
|
|
319
|
+
store.traceDelegation('agent-b', 'agent-e', 't3');
|
|
320
|
+
|
|
321
|
+
const traces = store.getTracesForAgent('agent-b');
|
|
322
|
+
expect(traces).toHaveLength(2); // t1 (as target) and t3 (as source, separate trace)
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('getAllTraces returns all traces sorted by recency', () => {
|
|
326
|
+
store.traceDelegation('a', 'b', 't1');
|
|
327
|
+
store.traceDelegation('c', 'd', 't2');
|
|
328
|
+
|
|
329
|
+
const all = store.getAllTraces();
|
|
330
|
+
expect(all).toHaveLength(2);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('getEvent returns undefined for unknown', () => {
|
|
334
|
+
expect(store.getEvent('nonexistent')).toBeUndefined();
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// ===========================================================================
|
|
339
|
+
// Eviction
|
|
340
|
+
// ===========================================================================
|
|
341
|
+
|
|
342
|
+
describe('eviction', () => {
|
|
343
|
+
it('evicts oldest traces when maxTraces is exceeded', () => {
|
|
344
|
+
const small = new DelegationTraceStore({ maxTraces: 2 });
|
|
345
|
+
|
|
346
|
+
small.traceDelegation('a', 'b', 't1');
|
|
347
|
+
small.traceDelegation('c', 'd', 't2');
|
|
348
|
+
small.traceDelegation('e', 'f', 't3');
|
|
349
|
+
|
|
350
|
+
expect(small.size).toBe(2);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// ===========================================================================
|
|
355
|
+
// Module-level convenience functions
|
|
356
|
+
// ===========================================================================
|
|
357
|
+
|
|
358
|
+
describe('module-level functions', () => {
|
|
359
|
+
it('traceDelegation uses default store', () => {
|
|
360
|
+
const event = traceDelegation('a', 'b', 't1', { key: 'val' });
|
|
361
|
+
expect(event.fromAgent).toBe('a');
|
|
362
|
+
expect(getDefaultTraceStore().size).toBe(1);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('getDelegationChain uses default store', () => {
|
|
366
|
+
const root = traceDelegation('a', 'b', 't1');
|
|
367
|
+
const child = traceDelegation('b', 'c', 't2', {}, root.id);
|
|
368
|
+
|
|
369
|
+
const chain = getDelegationChain(child.id);
|
|
370
|
+
expect(chain).toHaveLength(2);
|
|
371
|
+
expect(chain[0].event.fromAgent).toBe('a');
|
|
372
|
+
expect(chain[1].event.fromAgent).toBe('b');
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('replayDelegation uses default store', async () => {
|
|
376
|
+
const root = traceDelegation('a', 'b', 't1');
|
|
377
|
+
const result = await replayDelegation(root.id);
|
|
378
|
+
expect(result.status).toBe('completed');
|
|
379
|
+
expect(result.steps).toHaveLength(1);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('resetDefaultTraceStore clears state', () => {
|
|
383
|
+
traceDelegation('a', 'b', 't1');
|
|
384
|
+
expect(getDefaultTraceStore().size).toBe(1);
|
|
385
|
+
|
|
386
|
+
resetDefaultTraceStore();
|
|
387
|
+
expect(getDefaultTraceStore().size).toBe(0);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
});
|
|
@@ -151,13 +151,15 @@ describe('TaskDelegationService', () => {
|
|
|
151
151
|
expect(data?.idempotencyKey).toBe('idem-fixed-key');
|
|
152
152
|
expect(data?.schema).toBe('holoscript.task-bridge.v1');
|
|
153
153
|
expect((data?.task as Record<string, unknown> | undefined)?.skillId).toBe('compile_hs');
|
|
154
|
-
expect((data?.task as Record<string, unknown> | undefined)?.idempotency_key).toBe(
|
|
154
|
+
expect((data?.task as Record<string, unknown> | undefined)?.idempotency_key).toBe(
|
|
155
|
+
'idem-fixed-key'
|
|
156
|
+
);
|
|
155
157
|
});
|
|
156
158
|
|
|
157
159
|
it('uses transport adapter when configured', async () => {
|
|
158
160
|
await registry.register(makeRemoteAgent());
|
|
159
161
|
|
|
160
|
-
const send = vi.fn(async () => ({ status: 'completed', via: 'adapter' }));
|
|
162
|
+
const send = vi.fn(async (_req: any) => ({ status: 'completed', via: 'adapter' }));
|
|
161
163
|
const service = new TaskDelegationService(registry, undefined, {
|
|
162
164
|
transportAdapter: { send },
|
|
163
165
|
idempotencyKeyFactory: () => 'adapter-idem',
|
|
@@ -69,7 +69,9 @@ export function encodeRealTimeMessage(message: RealTimeMessage): Buffer {
|
|
|
69
69
|
typeCode = MessageTypeCode.PERFORMANCE_METRIC;
|
|
70
70
|
break;
|
|
71
71
|
default:
|
|
72
|
-
throw new Error(
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Unknown message type: ${(message as unknown as Record<string, unknown>).type}`
|
|
74
|
+
);
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
// Encode based on type
|
|
@@ -218,27 +220,40 @@ export function decodeRealTimeMessage(buffer: Buffer): RealTimeMessage {
|
|
|
218
220
|
|
|
219
221
|
// Decode based on type
|
|
220
222
|
if (typeCode === MessageTypeCode.POSITION_SYNC) {
|
|
221
|
-
const px = buffer.readFloatBE(offset);
|
|
222
|
-
|
|
223
|
-
const
|
|
223
|
+
const px = buffer.readFloatBE(offset);
|
|
224
|
+
offset += 4;
|
|
225
|
+
const py = buffer.readFloatBE(offset);
|
|
226
|
+
offset += 4;
|
|
227
|
+
const pz = buffer.readFloatBE(offset);
|
|
228
|
+
offset += 4;
|
|
224
229
|
const position: [number, number, number] = [px, py, pz];
|
|
225
230
|
|
|
226
|
-
const rx = buffer.readFloatBE(offset);
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
231
|
+
const rx = buffer.readFloatBE(offset);
|
|
232
|
+
offset += 4;
|
|
233
|
+
const ry = buffer.readFloatBE(offset);
|
|
234
|
+
offset += 4;
|
|
235
|
+
const rz = buffer.readFloatBE(offset);
|
|
236
|
+
offset += 4;
|
|
237
|
+
const rw = buffer.readFloatBE(offset);
|
|
238
|
+
offset += 4;
|
|
230
239
|
const rotation: [number, number, number, number] = [rx, ry, rz, rw];
|
|
231
240
|
|
|
232
|
-
const sx = buffer.readFloatBE(offset);
|
|
233
|
-
|
|
234
|
-
const
|
|
241
|
+
const sx = buffer.readFloatBE(offset);
|
|
242
|
+
offset += 4;
|
|
243
|
+
const sy = buffer.readFloatBE(offset);
|
|
244
|
+
offset += 4;
|
|
245
|
+
const sz = buffer.readFloatBE(offset);
|
|
246
|
+
offset += 4;
|
|
235
247
|
const scale: [number, number, number] = [sx, sy, sz];
|
|
236
248
|
|
|
237
249
|
let velocity: [number, number, number] | undefined;
|
|
238
250
|
if (offset < buffer.length) {
|
|
239
|
-
const vx = buffer.readFloatBE(offset);
|
|
240
|
-
|
|
241
|
-
const
|
|
251
|
+
const vx = buffer.readFloatBE(offset);
|
|
252
|
+
offset += 4;
|
|
253
|
+
const vy = buffer.readFloatBE(offset);
|
|
254
|
+
offset += 4;
|
|
255
|
+
const vz = buffer.readFloatBE(offset);
|
|
256
|
+
offset += 4;
|
|
242
257
|
velocity = [vx, vy, vz];
|
|
243
258
|
}
|
|
244
259
|
|
|
@@ -262,7 +277,12 @@ export function decodeRealTimeMessage(buffer: Buffer): RealTimeMessage {
|
|
|
262
277
|
offset += 4;
|
|
263
278
|
const qualityCode = buffer.readUInt8(offset);
|
|
264
279
|
offset += 1;
|
|
265
|
-
const qualityLevels: Array<FrameBudgetMessage['quality_level']> = [
|
|
280
|
+
const qualityLevels: Array<FrameBudgetMessage['quality_level']> = [
|
|
281
|
+
'high',
|
|
282
|
+
'medium',
|
|
283
|
+
'low',
|
|
284
|
+
'minimal',
|
|
285
|
+
];
|
|
266
286
|
const quality_level = qualityLevels[qualityCode] ?? 'medium';
|
|
267
287
|
|
|
268
288
|
return {
|
|
@@ -488,10 +508,7 @@ export class Layer1RealTimeClient extends EventEmitter {
|
|
|
488
508
|
/**
|
|
489
509
|
* Send real-time message
|
|
490
510
|
*/
|
|
491
|
-
async send(
|
|
492
|
-
message: RealTimeMessageBody,
|
|
493
|
-
targetAgent?: string
|
|
494
|
-
): Promise<void> {
|
|
511
|
+
async send(message: RealTimeMessageBody, targetAgent?: string): Promise<void> {
|
|
495
512
|
if (!this.transport) throw new Error('Transport not initialized');
|
|
496
513
|
|
|
497
514
|
// Add agent ID and timestamp
|
|
@@ -263,9 +263,7 @@ export class Layer2A2AClient extends EventEmitter {
|
|
|
263
263
|
/**
|
|
264
264
|
* Send A2A message with retry
|
|
265
265
|
*/
|
|
266
|
-
async send(
|
|
267
|
-
message: A2AMessageBody
|
|
268
|
-
): Promise<A2AResponse> {
|
|
266
|
+
async send(message: A2AMessageBody): Promise<A2AResponse> {
|
|
269
267
|
// Generate message ID and add metadata
|
|
270
268
|
const fullMessage: A2AMessage = {
|
|
271
269
|
...message,
|
|
@@ -253,7 +253,16 @@ export class Layer3MCPClient extends EventEmitter {
|
|
|
253
253
|
throw new Error(response.error || 'Failed to get agent registry');
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
return response.data as {
|
|
256
|
+
return response.data as {
|
|
257
|
+
agents: Array<{
|
|
258
|
+
agent_id: string;
|
|
259
|
+
role: string;
|
|
260
|
+
status: 'online' | 'offline' | 'degraded';
|
|
261
|
+
world_id?: string;
|
|
262
|
+
capabilities: string[];
|
|
263
|
+
}>;
|
|
264
|
+
total: number;
|
|
265
|
+
};
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
/**
|
|
@@ -510,7 +519,7 @@ export class Layer3MCPServer extends EventEmitter {
|
|
|
510
519
|
});
|
|
511
520
|
|
|
512
521
|
// Get world status handler
|
|
513
|
-
this.registerHandler('get_world_status', async (params,
|
|
522
|
+
this.registerHandler('get_world_status', async (params, _context) => {
|
|
514
523
|
const worldId = params.world_id as string;
|
|
515
524
|
const status = this.worlds.get(worldId);
|
|
516
525
|
|
|
@@ -541,7 +550,7 @@ export class Layer3MCPServer extends EventEmitter {
|
|
|
541
550
|
});
|
|
542
551
|
|
|
543
552
|
// Get agent registry handler
|
|
544
|
-
this.registerHandler('get_agent_registry', async (params,
|
|
553
|
+
this.registerHandler('get_agent_registry', async (params, _context) => {
|
|
545
554
|
const filter = params.filter as Record<string, unknown> | undefined;
|
|
546
555
|
|
|
547
556
|
// Get all agents from worlds
|
|
@@ -570,7 +579,7 @@ export class Layer3MCPServer extends EventEmitter {
|
|
|
570
579
|
});
|
|
571
580
|
|
|
572
581
|
// Get performance metrics handler
|
|
573
|
-
this.registerHandler('get_performance_metrics', async (params,
|
|
582
|
+
this.registerHandler('get_performance_metrics', async (params, _context) => {
|
|
574
583
|
const worldId = params.world_id as string | undefined;
|
|
575
584
|
const agentId = params.agent_id as string | undefined;
|
|
576
585
|
|
|
@@ -304,7 +304,10 @@ type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : n
|
|
|
304
304
|
* A2A message body type for the `send()` method.
|
|
305
305
|
* Strips auto-generated fields so callers only provide the domain payload.
|
|
306
306
|
*/
|
|
307
|
-
export type A2AMessageBody = DistributiveOmit<
|
|
307
|
+
export type A2AMessageBody = DistributiveOmit<
|
|
308
|
+
A2AMessage,
|
|
309
|
+
'message_id' | 'from_agent' | 'timestamp'
|
|
310
|
+
>;
|
|
308
311
|
|
|
309
312
|
/**
|
|
310
313
|
* A2A protocol configuration
|
|
@@ -492,7 +495,7 @@ export interface MCPProtocolConfig {
|
|
|
492
495
|
*/
|
|
493
496
|
export const DEFAULT_MCP_CONFIG: MCPProtocolConfig = {
|
|
494
497
|
endpoint: 'http://localhost:5567',
|
|
495
|
-
apiKey: process.env.
|
|
498
|
+
apiKey: process.env.HOLOSCRIPT_API_KEY || '',
|
|
496
499
|
timeout: 30000, // 30 seconds
|
|
497
500
|
};
|
|
498
501
|
|
|
@@ -102,7 +102,7 @@ class TerrainAgent {
|
|
|
102
102
|
console.log(`[TerrainAgent] Task ${task.task_id} completed in ${duration}ms`);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
private async generateTerrainChunk(
|
|
105
|
+
private async generateTerrainChunk(_index: number): Promise<void> {
|
|
106
106
|
// Simulate work (adjust based on quality level)
|
|
107
107
|
const stats = this.client.getFrameBudgetStats();
|
|
108
108
|
const workAmount = {
|
|
@@ -171,7 +171,7 @@ class AssetAgent {
|
|
|
171
171
|
console.log(`[AssetAgent] Task ${task.task_id} completed`);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
private async placeAsset(
|
|
174
|
+
private async placeAsset(_index: number): Promise<void> {
|
|
175
175
|
const stats = this.client.getFrameBudgetStats();
|
|
176
176
|
const workAmount = {
|
|
177
177
|
high: 8,
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
import type { AIAdapter } from './AIAdapter';
|
|
14
14
|
class HoloScriptPlusParser {
|
|
15
|
-
constructor(
|
|
16
|
-
parse(
|
|
15
|
+
constructor(_opts?: { strict?: boolean }) {}
|
|
16
|
+
parse(_code: string): any {
|
|
17
17
|
return { success: true, errors: [], ast: {} };
|
|
18
18
|
}
|
|
19
19
|
}
|