@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
|
@@ -27,11 +27,15 @@ describe('defineAgent', () => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
it('throws on invalid role', () => {
|
|
30
|
-
expect(() =>
|
|
30
|
+
expect(() =>
|
|
31
|
+
defineAgent({ ...validAgent, role: 'wizard' as unknown as AgentConfig['role'] })
|
|
32
|
+
).toThrow('Invalid role');
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
it('throws on missing model', () => {
|
|
34
|
-
expect(() =>
|
|
36
|
+
expect(() =>
|
|
37
|
+
defineAgent({ ...validAgent, model: { provider: 'anthropic', model: '' } })
|
|
38
|
+
).toThrow('model');
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
it('throws on empty capabilities', () => {
|
|
@@ -80,7 +84,9 @@ describe('defineTeam', () => {
|
|
|
80
84
|
});
|
|
81
85
|
|
|
82
86
|
it('throws when agents exceed max slots', () => {
|
|
83
|
-
expect(() => defineTeam({ name: 'test', agents: [coder, reviewer], maxSlots: 1 })).toThrow(
|
|
87
|
+
expect(() => defineTeam({ name: 'test', agents: [coder, reviewer], maxSlots: 1 })).toThrow(
|
|
88
|
+
'slots'
|
|
89
|
+
);
|
|
84
90
|
});
|
|
85
91
|
});
|
|
86
92
|
|
|
@@ -90,11 +96,15 @@ describe('Team.addTasks', () => {
|
|
|
90
96
|
it('adds tasks and deduplicates', async () => {
|
|
91
97
|
const team = defineTeam({
|
|
92
98
|
name: 'board-test',
|
|
93
|
-
agents: [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
agents: [
|
|
100
|
+
defineAgent({
|
|
101
|
+
name: 'A',
|
|
102
|
+
role: 'coder',
|
|
103
|
+
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
104
|
+
capabilities: ['c'],
|
|
105
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
98
108
|
});
|
|
99
109
|
|
|
100
110
|
const added1 = await team.addTasks([
|
|
@@ -116,11 +126,15 @@ describe('Team.addTasks', () => {
|
|
|
116
126
|
it('sorts open tasks by priority', async () => {
|
|
117
127
|
const team = defineTeam({
|
|
118
128
|
name: 'priority-test',
|
|
119
|
-
agents: [
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
agents: [
|
|
130
|
+
defineAgent({
|
|
131
|
+
name: 'A',
|
|
132
|
+
role: 'coder',
|
|
133
|
+
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
134
|
+
capabilities: ['c'],
|
|
135
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
136
|
+
}),
|
|
137
|
+
],
|
|
124
138
|
});
|
|
125
139
|
|
|
126
140
|
await team.addTasks([
|
|
@@ -142,11 +156,15 @@ describe('Team.scoutFromTodos', () => {
|
|
|
142
156
|
it('parses grep output into tasks', async () => {
|
|
143
157
|
const team = defineTeam({
|
|
144
158
|
name: 'scout-test',
|
|
145
|
-
agents: [
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
159
|
+
agents: [
|
|
160
|
+
defineAgent({
|
|
161
|
+
name: 'A',
|
|
162
|
+
role: 'coder',
|
|
163
|
+
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
164
|
+
capabilities: ['c'],
|
|
165
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
166
|
+
}),
|
|
167
|
+
],
|
|
150
168
|
});
|
|
151
169
|
|
|
152
170
|
const grepOutput = [
|
|
@@ -173,9 +191,36 @@ describe('KnowledgeStore', () => {
|
|
|
173
191
|
it('publishes and searches entries', () => {
|
|
174
192
|
const store = new KnowledgeStore({ persist: false });
|
|
175
193
|
|
|
176
|
-
store.publish(
|
|
177
|
-
|
|
178
|
-
|
|
194
|
+
store.publish(
|
|
195
|
+
{
|
|
196
|
+
type: 'pattern',
|
|
197
|
+
content: 'Use JWT for stateless auth',
|
|
198
|
+
domain: 'security',
|
|
199
|
+
confidence: 0.9,
|
|
200
|
+
source: 'Coder',
|
|
201
|
+
},
|
|
202
|
+
'Coder'
|
|
203
|
+
);
|
|
204
|
+
store.publish(
|
|
205
|
+
{
|
|
206
|
+
type: 'gotcha',
|
|
207
|
+
content: 'Never store tokens in localStorage',
|
|
208
|
+
domain: 'security',
|
|
209
|
+
confidence: 0.95,
|
|
210
|
+
source: 'Reviewer',
|
|
211
|
+
},
|
|
212
|
+
'Reviewer'
|
|
213
|
+
);
|
|
214
|
+
store.publish(
|
|
215
|
+
{
|
|
216
|
+
type: 'wisdom',
|
|
217
|
+
content: 'GraphQL reduces over-fetching',
|
|
218
|
+
domain: 'api',
|
|
219
|
+
confidence: 0.7,
|
|
220
|
+
source: 'Researcher',
|
|
221
|
+
},
|
|
222
|
+
'Researcher'
|
|
223
|
+
);
|
|
179
224
|
|
|
180
225
|
expect(store.size).toBe(3);
|
|
181
226
|
|
|
@@ -190,8 +235,26 @@ describe('KnowledgeStore', () => {
|
|
|
190
235
|
it('deduplicates identical content', () => {
|
|
191
236
|
const store = new KnowledgeStore({ persist: false });
|
|
192
237
|
|
|
193
|
-
const e1 = store.publish(
|
|
194
|
-
|
|
238
|
+
const e1 = store.publish(
|
|
239
|
+
{
|
|
240
|
+
type: 'wisdom',
|
|
241
|
+
content: 'Test your code',
|
|
242
|
+
domain: 'general',
|
|
243
|
+
confidence: 0.8,
|
|
244
|
+
source: 'A',
|
|
245
|
+
},
|
|
246
|
+
'A'
|
|
247
|
+
);
|
|
248
|
+
const e2 = store.publish(
|
|
249
|
+
{
|
|
250
|
+
type: 'wisdom',
|
|
251
|
+
content: 'Test your code',
|
|
252
|
+
domain: 'general',
|
|
253
|
+
confidence: 0.8,
|
|
254
|
+
source: 'B',
|
|
255
|
+
},
|
|
256
|
+
'B'
|
|
257
|
+
);
|
|
195
258
|
|
|
196
259
|
expect(e1.id).toBe(e2.id); // same entry returned
|
|
197
260
|
expect(store.size).toBe(1);
|
|
@@ -200,11 +263,35 @@ describe('KnowledgeStore', () => {
|
|
|
200
263
|
it('compounds cross-domain insights', () => {
|
|
201
264
|
const store = new KnowledgeStore({ persist: false });
|
|
202
265
|
|
|
203
|
-
store.publish(
|
|
204
|
-
|
|
266
|
+
store.publish(
|
|
267
|
+
{
|
|
268
|
+
type: 'pattern',
|
|
269
|
+
content: 'Rate limiting prevents abuse',
|
|
270
|
+
domain: 'security',
|
|
271
|
+
confidence: 0.9,
|
|
272
|
+
source: 'A',
|
|
273
|
+
},
|
|
274
|
+
'A'
|
|
275
|
+
);
|
|
276
|
+
store.publish(
|
|
277
|
+
{
|
|
278
|
+
type: 'pattern',
|
|
279
|
+
content: 'Cache invalidation is hard',
|
|
280
|
+
domain: 'performance',
|
|
281
|
+
confidence: 0.8,
|
|
282
|
+
source: 'B',
|
|
283
|
+
},
|
|
284
|
+
'B'
|
|
285
|
+
);
|
|
205
286
|
|
|
206
287
|
const crossRefs = store.compound([
|
|
207
|
-
{
|
|
288
|
+
{
|
|
289
|
+
type: 'wisdom',
|
|
290
|
+
content: 'Rate limiting and caching need coordination',
|
|
291
|
+
domain: 'architecture',
|
|
292
|
+
confidence: 0.7,
|
|
293
|
+
source: 'C',
|
|
294
|
+
},
|
|
208
295
|
]);
|
|
209
296
|
|
|
210
297
|
expect(crossRefs).toBeGreaterThan(0);
|
|
@@ -216,10 +303,7 @@ describe('KnowledgeStore', () => {
|
|
|
216
303
|
describe('Behavior Tree', () => {
|
|
217
304
|
it('Sequence succeeds when all children succeed', () => {
|
|
218
305
|
const tree = new BehaviorTree(
|
|
219
|
-
new SequenceNode([
|
|
220
|
-
new ActionNode('a', () => 'success'),
|
|
221
|
-
new ActionNode('b', () => 'success'),
|
|
222
|
-
])
|
|
306
|
+
new SequenceNode([new ActionNode('a', () => 'success'), new ActionNode('b', () => 'success')])
|
|
223
307
|
);
|
|
224
308
|
expect(tree.tick(0)).toBe('success');
|
|
225
309
|
});
|
|
@@ -229,7 +313,10 @@ describe('Behavior Tree', () => {
|
|
|
229
313
|
const tree = new BehaviorTree(
|
|
230
314
|
new SequenceNode([
|
|
231
315
|
new ActionNode('a', () => 'failure'),
|
|
232
|
-
new ActionNode('b', () => {
|
|
316
|
+
new ActionNode('b', () => {
|
|
317
|
+
bRan = true;
|
|
318
|
+
return 'success';
|
|
319
|
+
}),
|
|
233
320
|
])
|
|
234
321
|
);
|
|
235
322
|
expect(tree.tick(0)).toBe('failure');
|
|
@@ -252,7 +339,10 @@ describe('Behavior Tree', () => {
|
|
|
252
339
|
const tree = new BehaviorTree(
|
|
253
340
|
new SequenceNode([
|
|
254
341
|
new ConditionNode('check', () => true),
|
|
255
|
-
new ActionNode('do', () => {
|
|
342
|
+
new ActionNode('do', () => {
|
|
343
|
+
executed = true;
|
|
344
|
+
return 'success';
|
|
345
|
+
}),
|
|
256
346
|
])
|
|
257
347
|
);
|
|
258
348
|
tree.tick(0);
|
|
@@ -273,7 +363,13 @@ vi.mock('../protocol-agent', () => ({
|
|
|
273
363
|
runProtocolCycle: vi.fn().mockResolvedValue({
|
|
274
364
|
summary: 'Completed synthesized task',
|
|
275
365
|
insights: [
|
|
276
|
-
{
|
|
366
|
+
{
|
|
367
|
+
type: 'wisdom',
|
|
368
|
+
content: 'Autonomous goals keep agents productive',
|
|
369
|
+
domain: 'security',
|
|
370
|
+
confidence: 0.7,
|
|
371
|
+
source: 'Coder',
|
|
372
|
+
},
|
|
277
373
|
],
|
|
278
374
|
}),
|
|
279
375
|
}));
|
|
@@ -346,9 +442,11 @@ describe('Goal Synthesis (empty board)', () => {
|
|
|
346
442
|
|
|
347
443
|
describe('Team remote facade methods', () => {
|
|
348
444
|
const agent = defineAgent({
|
|
349
|
-
name: 'A',
|
|
445
|
+
name: 'A',
|
|
446
|
+
role: 'coder',
|
|
350
447
|
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
351
|
-
capabilities: ['c'],
|
|
448
|
+
capabilities: ['c'],
|
|
449
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
352
450
|
});
|
|
353
451
|
|
|
354
452
|
// Helper: create a local-only team (no boardUrl)
|
|
@@ -375,8 +473,14 @@ describe('Team remote facade methods', () => {
|
|
|
375
473
|
|
|
376
474
|
describe('suggest() remote', () => {
|
|
377
475
|
it('calls POST /suggestions with correct body', async () => {
|
|
378
|
-
const { team, fetchSpy } = remoteTeam({
|
|
379
|
-
|
|
476
|
+
const { team, fetchSpy } = remoteTeam({
|
|
477
|
+
suggestion: { id: 's1', title: 'idea', status: 'open', votes: 0, createdAt: '2026-01-01' },
|
|
478
|
+
});
|
|
479
|
+
const result = await team.suggest('idea', {
|
|
480
|
+
description: 'desc',
|
|
481
|
+
category: 'ux',
|
|
482
|
+
evidence: 'data',
|
|
483
|
+
});
|
|
380
484
|
expect(result.suggestion.id).toBe('s1');
|
|
381
485
|
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
|
382
486
|
const [url, opts] = fetchSpy.mock.calls[0];
|
|
@@ -401,7 +505,9 @@ describe('Team remote facade methods', () => {
|
|
|
401
505
|
|
|
402
506
|
describe('vote() remote', () => {
|
|
403
507
|
it('calls PATCH /suggestions/:id with vote action', async () => {
|
|
404
|
-
const { team, fetchSpy } = remoteTeam({
|
|
508
|
+
const { team, fetchSpy } = remoteTeam({
|
|
509
|
+
suggestion: { id: 's1', title: 'idea', status: 'open', votes: 1, createdAt: '2026-01-01' },
|
|
510
|
+
});
|
|
405
511
|
const result = await team.vote('s1', 1, 'good idea');
|
|
406
512
|
expect(result.suggestion.votes).toBe(1);
|
|
407
513
|
const [url, opts] = fetchSpy.mock.calls[0];
|
|
@@ -494,7 +600,9 @@ describe('Team remote facade methods', () => {
|
|
|
494
600
|
});
|
|
495
601
|
|
|
496
602
|
it('calls GET /slots', async () => {
|
|
497
|
-
const { team, fetchSpy } = remoteTeam({
|
|
603
|
+
const { team, fetchSpy } = remoteTeam({
|
|
604
|
+
slots: [{ agentName: 'A', role: 'coder', status: 'active' }],
|
|
605
|
+
});
|
|
498
606
|
const result = await team.presence();
|
|
499
607
|
expect(result.slots).toHaveLength(1);
|
|
500
608
|
expect(result.slots[0].agentName).toBe('A');
|
|
@@ -541,14 +649,18 @@ describe('Team remote facade methods', () => {
|
|
|
541
649
|
|
|
542
650
|
describe('Team local suggestions', () => {
|
|
543
651
|
const agent1 = defineAgent({
|
|
544
|
-
name: 'Alice',
|
|
652
|
+
name: 'Alice',
|
|
653
|
+
role: 'coder',
|
|
545
654
|
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
546
|
-
capabilities: ['code-generation'],
|
|
655
|
+
capabilities: ['code-generation'],
|
|
656
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
547
657
|
});
|
|
548
658
|
const agent2 = defineAgent({
|
|
549
|
-
name: 'Bob',
|
|
659
|
+
name: 'Bob',
|
|
660
|
+
role: 'researcher',
|
|
550
661
|
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
551
|
-
capabilities: ['research'],
|
|
662
|
+
capabilities: ['research'],
|
|
663
|
+
claimFilter: { roles: ['researcher'], maxPriority: 10 },
|
|
552
664
|
});
|
|
553
665
|
|
|
554
666
|
function makeTeam() {
|
|
@@ -599,7 +711,7 @@ describe('Team local suggestions', () => {
|
|
|
599
711
|
|
|
600
712
|
it('allows resubmission after dismiss', async () => {
|
|
601
713
|
const team = makeTeam();
|
|
602
|
-
const { suggestion } =
|
|
714
|
+
const { suggestion } = await team.suggest('Add caching');
|
|
603
715
|
team.dismissSuggestion(suggestion.id);
|
|
604
716
|
// Should not throw — dismissed suggestions don't block new ones
|
|
605
717
|
const result = await team.suggest('Add caching');
|
|
@@ -659,7 +771,7 @@ describe('Team local suggestions', () => {
|
|
|
659
771
|
expect(result.promotedTaskId).toBeDefined();
|
|
660
772
|
expect(result.promotedTaskId).toMatch(/^task_/);
|
|
661
773
|
// Verify task was added to board
|
|
662
|
-
expect(team.openTasks.some(t => t.source === `suggestion:${suggestion.id}`)).toBe(true);
|
|
774
|
+
expect(team.openTasks.some((t) => t.source === `suggestion:${suggestion.id}`)).toBe(true);
|
|
663
775
|
});
|
|
664
776
|
|
|
665
777
|
it('auto-dismisses when downvotes reach threshold', async () => {
|
|
@@ -733,7 +845,7 @@ describe('Team local suggestions', () => {
|
|
|
733
845
|
const result = await team.promoteSuggestion(suggestion.id, 'Bob');
|
|
734
846
|
expect(result.suggestion.status).toBe('promoted');
|
|
735
847
|
expect(result.promotedTaskId).toBeDefined();
|
|
736
|
-
const task = team.openTasks.find(t => t.id === result.promotedTaskId);
|
|
848
|
+
const task = team.openTasks.find((t) => t.id === result.promotedTaskId);
|
|
737
849
|
expect(task).toBeDefined();
|
|
738
850
|
expect(task!.title).toBe('Build widget');
|
|
739
851
|
expect(task!.description).toContain('Promoted by Bob');
|
|
@@ -756,7 +868,7 @@ describe('Team local suggestions', () => {
|
|
|
756
868
|
const team = makeTeam();
|
|
757
869
|
const { suggestion } = await team.suggest('Restructure', { category: 'architecture' });
|
|
758
870
|
const result = await team.promoteSuggestion(suggestion.id);
|
|
759
|
-
const task = team.openTasks.find(t => t.id === result.promotedTaskId);
|
|
871
|
+
const task = team.openTasks.find((t) => t.id === result.promotedTaskId);
|
|
760
872
|
expect(task!.priority).toBe(2);
|
|
761
873
|
});
|
|
762
874
|
|
|
@@ -764,7 +876,7 @@ describe('Team local suggestions', () => {
|
|
|
764
876
|
const team = makeTeam();
|
|
765
877
|
const { suggestion } = await team.suggest('Add tests', { category: 'testing' });
|
|
766
878
|
const result = await team.promoteSuggestion(suggestion.id);
|
|
767
|
-
const task = team.openTasks.find(t => t.id === result.promotedTaskId);
|
|
879
|
+
const task = team.openTasks.find((t) => t.id === result.promotedTaskId);
|
|
768
880
|
expect(task!.priority).toBe(3);
|
|
769
881
|
});
|
|
770
882
|
});
|
|
@@ -787,8 +899,10 @@ describe('Team local suggestions', () => {
|
|
|
787
899
|
|
|
788
900
|
it('throws on remote team', async () => {
|
|
789
901
|
const team = defineTeam({
|
|
790
|
-
name: 'remote',
|
|
791
|
-
|
|
902
|
+
name: 'remote',
|
|
903
|
+
agents: [agent1],
|
|
904
|
+
boardUrl: 'https://example.com',
|
|
905
|
+
boardApiKey: 'key',
|
|
792
906
|
});
|
|
793
907
|
expect(() => team.dismissSuggestion('s1')).toThrow('not supported in remote mode');
|
|
794
908
|
});
|
|
@@ -799,7 +913,8 @@ describe('Team local suggestions', () => {
|
|
|
799
913
|
|
|
800
914
|
describe('Team mesh integration', () => {
|
|
801
915
|
const agent1: AgentConfig = {
|
|
802
|
-
name: 'Coder1',
|
|
916
|
+
name: 'Coder1',
|
|
917
|
+
role: 'coder',
|
|
803
918
|
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
804
919
|
capabilities: ['code-gen', 'testing'],
|
|
805
920
|
claimFilter: { roles: ['coder'], maxPriority: 8 },
|
|
@@ -822,8 +937,12 @@ describe('Team mesh integration', () => {
|
|
|
822
937
|
it('registerPeer() + peers() returns registered peer', () => {
|
|
823
938
|
const team = mkTeam();
|
|
824
939
|
team.registerPeer({
|
|
825
|
-
id: 'peer-1',
|
|
826
|
-
|
|
940
|
+
id: 'peer-1',
|
|
941
|
+
hostname: 'localhost',
|
|
942
|
+
port: 3000,
|
|
943
|
+
version: '1.0.0',
|
|
944
|
+
agentCount: 2,
|
|
945
|
+
capabilities: ['code'],
|
|
827
946
|
lastSeen: Date.now(),
|
|
828
947
|
});
|
|
829
948
|
expect(team.peers()).toHaveLength(1);
|
|
@@ -142,13 +142,16 @@ describe('GoalSynthesizer', () => {
|
|
|
142
142
|
it('filters out recently completed tasks', async () => {
|
|
143
143
|
const gs = new GoalSynthesizer();
|
|
144
144
|
const completed = GENERIC_GOALS.slice(0, 4);
|
|
145
|
-
const goals = await gs.synthesizeMultiple(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
const goals = await gs.synthesizeMultiple(
|
|
146
|
+
{
|
|
147
|
+
domain: 'general',
|
|
148
|
+
recentCompletedTasks: completed,
|
|
149
|
+
},
|
|
150
|
+
3
|
|
151
|
+
);
|
|
149
152
|
// None of the returned goals should match completed tasks
|
|
150
153
|
for (const g of goals) {
|
|
151
|
-
expect(completed.map(c => c.toLowerCase())).not.toContain(g.description.toLowerCase());
|
|
154
|
+
expect(completed.map((c) => c.toLowerCase())).not.toContain(g.description.toLowerCase());
|
|
152
155
|
}
|
|
153
156
|
});
|
|
154
157
|
|
|
@@ -208,7 +211,7 @@ describe('GoalSynthesizer', () => {
|
|
|
208
211
|
// Request enough goals to ensure the knowledge-derived one is included
|
|
209
212
|
const goals = await gs.synthesizeMultiple({ domain: 'security' }, 15);
|
|
210
213
|
|
|
211
|
-
const knowledgeGapGoals = goals.filter(g => g.category === 'knowledge-gap');
|
|
214
|
+
const knowledgeGapGoals = goals.filter((g) => g.category === 'knowledge-gap');
|
|
212
215
|
// At least one goal should be derived from the gotcha
|
|
213
216
|
expect(knowledgeGapGoals.length).toBeGreaterThanOrEqual(1);
|
|
214
217
|
const derived = knowledgeGapGoals[0];
|
|
@@ -70,7 +70,7 @@ describe('Local Presence Tracking (FW-0.3)', () => {
|
|
|
70
70
|
team.localHeartbeat('Bob', 'Task B');
|
|
71
71
|
const agents = team.localPresence();
|
|
72
72
|
expect(agents).toHaveLength(2);
|
|
73
|
-
const names = agents.map(a => a.name).sort();
|
|
73
|
+
const names = agents.map((a) => a.name).sort();
|
|
74
74
|
expect(names).toEqual(['Alice', 'Bob']);
|
|
75
75
|
});
|
|
76
76
|
});
|
|
@@ -80,7 +80,9 @@ describe('ProtocolAgent', () => {
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it('execute phase calls LLM with full model', async () => {
|
|
83
|
-
fetchSpy.mockResolvedValue(
|
|
83
|
+
fetchSpy.mockResolvedValue(
|
|
84
|
+
mockFetchResponse('Fixed the authentication bug by updating JWT validation')
|
|
85
|
+
);
|
|
84
86
|
|
|
85
87
|
const agent = new ProtocolAgent(testAgent);
|
|
86
88
|
const plan = { plan: 'Use TDD', context: { task: 'Fix auth bug' } };
|
|
@@ -101,8 +103,8 @@ describe('ProtocolAgent', () => {
|
|
|
101
103
|
fetchSpy.mockResolvedValue(
|
|
102
104
|
mockFetchResponse(
|
|
103
105
|
'[wisdom] JWT tokens should be validated on every request\n' +
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
'[pattern] Use middleware for auth validation\n' +
|
|
107
|
+
'[gotcha] Never store refresh tokens in localStorage'
|
|
106
108
|
)
|
|
107
109
|
);
|
|
108
110
|
|
|
@@ -168,7 +170,10 @@ describe('runProtocolCycle', () => {
|
|
|
168
170
|
// Phase 2 (execute): full model
|
|
169
171
|
if (callCount === 2) return mockFetchResponse('SUMMARY: Fixed JWT validation\nDone.');
|
|
170
172
|
// Phase 3 (compress): extract knowledge
|
|
171
|
-
if (callCount === 3)
|
|
173
|
+
if (callCount === 3)
|
|
174
|
+
return mockFetchResponse(
|
|
175
|
+
'[wisdom] Always validate token expiry\n[pattern] Use middleware for auth'
|
|
176
|
+
);
|
|
172
177
|
// Phase 4 (reintake): validate
|
|
173
178
|
if (callCount === 4) return mockFetchResponse('[wisdom] Always validate token expiry');
|
|
174
179
|
// Phase 5 (grow): patterns
|
|
@@ -196,9 +201,7 @@ describe('runProtocolCycle', () => {
|
|
|
196
201
|
});
|
|
197
202
|
|
|
198
203
|
it('returns summary from execute phase even when compress finds nothing', async () => {
|
|
199
|
-
fetchSpy.mockImplementation(async () =>
|
|
200
|
-
mockFetchResponse('Completed the task successfully')
|
|
201
|
-
);
|
|
204
|
+
fetchSpy.mockImplementation(async () => mockFetchResponse('Completed the task successfully'));
|
|
202
205
|
|
|
203
206
|
const result = await runProtocolCycle(
|
|
204
207
|
testAgent,
|
|
@@ -218,9 +221,7 @@ describe('runProtocolCycle', () => {
|
|
|
218
221
|
model: { provider: 'openai', model: 'gpt-4o', apiKey: 'test-key' },
|
|
219
222
|
};
|
|
220
223
|
|
|
221
|
-
fetchSpy.mockImplementation(async () =>
|
|
222
|
-
mockOpenAIResponse('Task done')
|
|
223
|
-
);
|
|
224
|
+
fetchSpy.mockImplementation(async () => mockOpenAIResponse('Task done'));
|
|
224
225
|
|
|
225
226
|
const result = await runProtocolCycle(
|
|
226
227
|
openaiAgent,
|
|
@@ -248,7 +249,7 @@ describe('runProtocolCycle', () => {
|
|
|
248
249
|
// Should still return a result (BaseAgent catches phase errors)
|
|
249
250
|
expect(result.phaseResults.length).toBeGreaterThan(0);
|
|
250
251
|
// The reflect phase should fail, which cascades
|
|
251
|
-
const reflectPhase = result.phaseResults.find(p => p.phase === ProtocolPhase.REFLECT);
|
|
252
|
+
const reflectPhase = result.phaseResults.find((p) => p.phase === ProtocolPhase.REFLECT);
|
|
252
253
|
expect(reflectPhase?.status).toBe('failure');
|
|
253
254
|
});
|
|
254
255
|
});
|
|
@@ -39,10 +39,13 @@ describe('RevenueSplitter', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('throws on basis points not summing to 10000', () => {
|
|
42
|
-
expect(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
expect(
|
|
43
|
+
() =>
|
|
44
|
+
new RevenueSplitter([
|
|
45
|
+
{ id: 'a', basisPoints: 5000 },
|
|
46
|
+
{ id: 'b', basisPoints: 4000 },
|
|
47
|
+
])
|
|
48
|
+
).toThrow('sum to 10000');
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
it('throws on empty recipients', () => {
|
|
@@ -50,23 +53,27 @@ describe('RevenueSplitter', () => {
|
|
|
50
53
|
});
|
|
51
54
|
|
|
52
55
|
it('throws on negative basis points', () => {
|
|
53
|
-
expect(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
expect(
|
|
57
|
+
() =>
|
|
58
|
+
new RevenueSplitter([
|
|
59
|
+
{ id: 'a', basisPoints: -1000 },
|
|
60
|
+
{ id: 'b', basisPoints: 11000 },
|
|
61
|
+
])
|
|
62
|
+
).toThrow('Negative');
|
|
57
63
|
});
|
|
58
64
|
|
|
59
65
|
it('throws on duplicate IDs', () => {
|
|
60
|
-
expect(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
expect(
|
|
67
|
+
() =>
|
|
68
|
+
new RevenueSplitter([
|
|
69
|
+
{ id: 'a', basisPoints: 5000 },
|
|
70
|
+
{ id: 'a', basisPoints: 5000 },
|
|
71
|
+
])
|
|
72
|
+
).toThrow('Duplicate');
|
|
64
73
|
});
|
|
65
74
|
|
|
66
75
|
it('throws on negative amount', () => {
|
|
67
|
-
const splitter = new RevenueSplitter([
|
|
68
|
-
{ id: 'a', basisPoints: 10000 },
|
|
69
|
-
]);
|
|
76
|
+
const splitter = new RevenueSplitter([{ id: 'a', basisPoints: 10000 }]);
|
|
70
77
|
expect(() => splitter.split(-1n)).toThrow('negative');
|
|
71
78
|
});
|
|
72
79
|
|