@holoscript/framework 6.0.3
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/ALL-test-results.json +1 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/ROADMAP.md +175 -0
- package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
- package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
- package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
- package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
- package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
- package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
- package/dist/agents/index.cjs +4790 -0
- package/dist/agents/index.d.cts +1788 -0
- package/dist/agents/index.d.ts +1788 -0
- package/dist/agents/index.js +4695 -0
- package/dist/ai/index.cjs +5347 -0
- package/dist/ai/index.d.cts +1753 -0
- package/dist/ai/index.d.ts +1753 -0
- package/dist/ai/index.js +5244 -0
- package/dist/behavior.cjs +449 -0
- package/dist/behavior.d.cts +130 -0
- package/dist/behavior.d.ts +130 -0
- package/dist/behavior.js +407 -0
- package/dist/economy/index.cjs +3659 -0
- package/dist/economy/index.d.cts +747 -0
- package/dist/economy/index.d.ts +747 -0
- package/dist/economy/index.js +3617 -0
- package/dist/implementations-D9T3un9D.d.cts +236 -0
- package/dist/implementations-D9T3un9D.d.ts +236 -0
- package/dist/index.cjs +24550 -0
- package/dist/index.d.cts +1729 -0
- package/dist/index.d.ts +1729 -0
- package/dist/index.js +24277 -0
- package/dist/learning/index.cjs +219 -0
- package/dist/learning/index.d.cts +104 -0
- package/dist/learning/index.d.ts +104 -0
- package/dist/learning/index.js +189 -0
- package/dist/negotiation/index.cjs +970 -0
- package/dist/negotiation/index.d.cts +610 -0
- package/dist/negotiation/index.d.ts +610 -0
- package/dist/negotiation/index.js +931 -0
- package/dist/skills/index.cjs +1118 -0
- package/dist/skills/index.d.cts +289 -0
- package/dist/skills/index.d.ts +289 -0
- package/dist/skills/index.js +1079 -0
- package/dist/swarm/index.cjs +5268 -0
- package/dist/swarm/index.d.cts +2433 -0
- package/dist/swarm/index.d.ts +2433 -0
- package/dist/swarm/index.js +5221 -0
- package/dist/training/index.cjs +2745 -0
- package/dist/training/index.d.cts +1734 -0
- package/dist/training/index.d.ts +1734 -0
- package/dist/training/index.js +2687 -0
- package/extract-failures.js +10 -0
- package/package.json +82 -0
- package/src/__tests__/bounty-marketplace.test.ts +374 -0
- package/src/__tests__/delegation.test.ts +144 -0
- package/src/__tests__/distributed-claimer.test.ts +147 -0
- package/src/__tests__/done-log-audit.test.ts +342 -0
- package/src/__tests__/framework.test.ts +865 -0
- package/src/__tests__/goal-synthesizer.test.ts +236 -0
- package/src/__tests__/presence.test.ts +223 -0
- package/src/__tests__/protocol-agent.test.ts +254 -0
- package/src/__tests__/revenue-splitter.test.ts +114 -0
- package/src/__tests__/scenario-driven-todo.test.ts +197 -0
- package/src/__tests__/self-improve.test.ts +349 -0
- package/src/__tests__/service-lifecycle.test.ts +237 -0
- package/src/__tests__/skill-router.test.ts +121 -0
- package/src/agents/AgentManifest.ts +493 -0
- package/src/agents/AgentRegistry.ts +475 -0
- package/src/agents/AgentTypes.ts +585 -0
- package/src/agents/AgentWalletRegistry.ts +83 -0
- package/src/agents/AuthenticatedCRDT.ts +388 -0
- package/src/agents/CapabilityMatcher.ts +453 -0
- package/src/agents/CrossRealityHandoff.ts +305 -0
- package/src/agents/CulturalMemory.ts +454 -0
- package/src/agents/FederatedRegistryAdapter.ts +429 -0
- package/src/agents/NormEngine.ts +450 -0
- package/src/agents/OrchestratorAgent.ts +414 -0
- package/src/agents/SkillWorkflowEngine.ts +472 -0
- package/src/agents/TaskDelegationService.ts +551 -0
- package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
- package/src/agents/__tests__/AgentManifest.test.ts +182 -0
- package/src/agents/__tests__/AgentModule.test.ts +864 -0
- package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
- package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
- package/src/agents/__tests__/AgentTypes.test.ts +534 -0
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
- package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
- package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
- package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
- package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
- package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
- package/src/agents/__tests__/NormEngine.test.ts +276 -0
- package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
- package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
- package/src/agents/index.ts +107 -0
- package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
- package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
- package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
- package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
- package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
- package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
- package/src/agents/spatial-comms/index.ts +66 -0
- package/src/ai/AIAdapter.ts +313 -0
- package/src/ai/AICopilot.ts +331 -0
- package/src/ai/AIOutputValidator.ts +203 -0
- package/src/ai/BTNodes.ts +239 -0
- package/src/ai/BehaviorSelector.ts +135 -0
- package/src/ai/BehaviorTree.ts +153 -0
- package/src/ai/Blackboard.ts +165 -0
- package/src/ai/GenerationAnalytics.ts +461 -0
- package/src/ai/GenerationCache.ts +265 -0
- package/src/ai/GoalPlanner.ts +165 -0
- package/src/ai/HoloScriptGenerator.ts +580 -0
- package/src/ai/InfluenceMap.ts +180 -0
- package/src/ai/NavMesh.ts +168 -0
- package/src/ai/PerceptionSystem.ts +178 -0
- package/src/ai/PromptTemplates.ts +453 -0
- package/src/ai/SemanticSearchService.ts +80 -0
- package/src/ai/StateMachine.ts +196 -0
- package/src/ai/SteeringBehavior.ts +150 -0
- package/src/ai/SteeringBehaviors.ts +244 -0
- package/src/ai/TrainingDataGenerator.ts +1082 -0
- package/src/ai/UtilityAI.ts +145 -0
- package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
- package/src/ai/__tests__/AIAdapter.test.ts +109 -0
- package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
- package/src/ai/__tests__/AICopilot.test.ts +178 -0
- package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
- package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
- package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
- package/src/ai/__tests__/BTNodes.test.ts +263 -0
- package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
- package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
- package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
- package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
- package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
- package/src/ai/__tests__/Blackboard.test.ts +183 -0
- package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
- package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
- package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
- package/src/ai/__tests__/GenerationCache.test.ts +171 -0
- package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
- package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
- package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
- package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
- package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
- package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
- package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
- package/src/ai/__tests__/NavMesh.test.ts +159 -0
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
- package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
- package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
- package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
- package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
- package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
- package/src/ai/__tests__/StateMachine.test.ts +163 -0
- package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
- package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
- package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
- package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
- package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
- package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
- package/src/ai/__tests__/UtilityAI.test.ts +155 -0
- package/src/ai/__tests__/adapters.prod.test.ts +263 -0
- package/src/ai/__tests__/adapters.test.ts +320 -0
- package/src/ai/adapters.ts +1585 -0
- package/src/ai/index.ts +130 -0
- package/src/behavior/BehaviorPresets.ts +140 -0
- package/src/behavior/BehaviorTree.ts +236 -0
- package/src/behavior/StateMachine.ts +176 -0
- package/src/behavior/StateTrait.ts +67 -0
- package/src/behavior/index.ts +8 -0
- package/src/behavior.ts +8 -0
- package/src/board/audit.ts +284 -0
- package/src/board/board-ops.ts +336 -0
- package/src/board/board-types.ts +302 -0
- package/src/board/index.ts +69 -0
- package/src/define-agent.ts +46 -0
- package/src/define-team.ts +33 -0
- package/src/delegation.ts +265 -0
- package/src/distributed-claimer.ts +228 -0
- package/src/economy/AgentBudgetEnforcer.ts +464 -0
- package/src/economy/BountyManager.ts +185 -0
- package/src/economy/CreatorRevenueAggregator.ts +460 -0
- package/src/economy/InvisibleWallet.ts +82 -0
- package/src/economy/KnowledgeMarketplace.ts +193 -0
- package/src/economy/PaymentWebhookService.ts +512 -0
- package/src/economy/RevenueSplitter.ts +156 -0
- package/src/economy/SubscriptionManager.ts +546 -0
- package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
- package/src/economy/UsageMeter.ts +440 -0
- package/src/economy/_core-stubs.ts +219 -0
- package/src/economy/index.ts +100 -0
- package/src/economy/x402-facilitator.ts +1978 -0
- package/src/index.ts +348 -0
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
- package/src/knowledge/brain.ts +167 -0
- package/src/knowledge/consolidation.ts +581 -0
- package/src/knowledge/knowledge-consolidator.ts +510 -0
- package/src/knowledge/knowledge-store.ts +616 -0
- package/src/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/MemoryScorer.ts +69 -0
- package/src/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/SemanticClusterer.ts +66 -0
- package/src/learning/index.ts +8 -0
- package/src/llm/llm-adapter.ts +159 -0
- package/src/mesh/index.ts +309 -0
- package/src/negotiation/NegotiationProtocol.ts +694 -0
- package/src/negotiation/NegotiationTypes.ts +473 -0
- package/src/negotiation/VotingMechanisms.ts +691 -0
- package/src/negotiation/index.ts +49 -0
- package/src/protocol/goal-synthesizer.ts +317 -0
- package/src/protocol/implementations.ts +474 -0
- package/src/protocol/micro-phase-decomposer.ts +299 -0
- package/src/protocol/micro-step-decomposer.test.ts +306 -0
- package/src/protocol-agent.test.ts +353 -0
- package/src/protocol-agent.ts +670 -0
- package/src/self-improve/absorb-scanner.ts +252 -0
- package/src/self-improve/evolution-engine.ts +149 -0
- package/src/self-improve/framework-absorber.ts +214 -0
- package/src/self-improve/index.ts +50 -0
- package/src/self-improve/prompt-optimizer.ts +212 -0
- package/src/self-improve/test-generator.ts +175 -0
- package/src/skill-router.ts +186 -0
- package/src/skills/index.ts +5 -0
- package/src/skills/skill-md-bridge.ts +1699 -0
- package/src/swarm/ACOEngine.ts +261 -0
- package/src/swarm/CollectiveIntelligence.ts +383 -0
- package/src/swarm/ContributionSynthesizer.ts +481 -0
- package/src/swarm/LeaderElection.ts +393 -0
- package/src/swarm/PSOEngine.ts +206 -0
- package/src/swarm/QuorumPolicy.ts +173 -0
- package/src/swarm/SwarmCoordinator.ts +335 -0
- package/src/swarm/SwarmManager.ts +442 -0
- package/src/swarm/SwarmMembership.ts +456 -0
- package/src/swarm/VotingRound.ts +255 -0
- package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
- package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
- package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
- package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
- package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
- package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
- package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
- package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
- package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
- package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
- package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
- package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
- package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
- package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
- package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
- package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
- package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
- package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
- package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
- package/src/swarm/__tests__/VotingRound.test.ts +174 -0
- package/src/swarm/analytics/SwarmInspector.ts +476 -0
- package/src/swarm/analytics/SwarmMetrics.ts +449 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
- package/src/swarm/analytics/index.ts +7 -0
- package/src/swarm/index.ts +69 -0
- package/src/swarm/messaging/BroadcastChannel.ts +509 -0
- package/src/swarm/messaging/GossipProtocol.ts +565 -0
- package/src/swarm/messaging/SwarmEventBus.ts +443 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
- package/src/swarm/messaging/index.ts +8 -0
- package/src/swarm/spatial/FlockingBehavior.ts +462 -0
- package/src/swarm/spatial/FormationController.ts +500 -0
- package/src/swarm/spatial/Vector3.ts +170 -0
- package/src/swarm/spatial/ZoneClaiming.ts +509 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
- package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
- package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
- package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
- package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
- package/src/swarm/spatial/index.ts +28 -0
- package/src/team.ts +1245 -0
- package/src/training/LRScheduler.ts +377 -0
- package/src/training/QualityScoringPipeline.ts +139 -0
- package/src/training/SoftDedup.ts +461 -0
- package/src/training/SparsityMonitor.ts +685 -0
- package/src/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/constants.ts +94 -0
- package/src/training/index.ts +138 -0
- package/src/training/schema.ts +147 -0
- package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/data/novel-use-cases.jsonl +153 -0
- package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
- package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/trainingmonkey/index.ts +26 -0
- package/src/training/trait-mappings.ts +157 -0
- package/src/types/core-stubs.d.ts +113 -0
- package/src/types.ts +304 -0
- package/test-output.txt +0 -0
- package/test-result.json +1 -0
- package/tsc-errors.txt +4 -0
- package/tsc_output.txt +0 -0
- package/tsconfig.json +14 -0
- package/tsup-learning-esm.config.ts +12 -0
- package/tsup.config.ts +21 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +22 -0
- package/vitest-log-utf8.txt +268 -0
- package/vitest-log.txt +0 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { GoalSynthesizer, GENERIC_GOALS, DOMAIN_GOALS } from '../protocol/goal-synthesizer';
|
|
3
|
+
import type { GoalContext, SynthesizedGoal } from '../protocol/goal-synthesizer';
|
|
4
|
+
import type { KnowledgeStore, StoredEntry } from '../knowledge/knowledge-store';
|
|
5
|
+
|
|
6
|
+
// ── Helpers ──
|
|
7
|
+
|
|
8
|
+
function mockKnowledgeStore(entries: Partial<StoredEntry>[] = []): KnowledgeStore {
|
|
9
|
+
return {
|
|
10
|
+
search: vi.fn().mockReturnValue(entries),
|
|
11
|
+
} as unknown as KnowledgeStore;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function mockLLMConfig() {
|
|
15
|
+
return {
|
|
16
|
+
provider: 'anthropic' as const,
|
|
17
|
+
model: 'claude-sonnet-4',
|
|
18
|
+
apiKey: 'test-key',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ── Tests ──
|
|
23
|
+
|
|
24
|
+
describe('GoalSynthesizer', () => {
|
|
25
|
+
describe('constructor', () => {
|
|
26
|
+
it('creates without options (no LLM, no knowledge)', () => {
|
|
27
|
+
const gs = new GoalSynthesizer();
|
|
28
|
+
expect(gs).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('creates with LLM and knowledge store', () => {
|
|
32
|
+
const gs = new GoalSynthesizer({
|
|
33
|
+
llm: mockLLMConfig(),
|
|
34
|
+
knowledge: mockKnowledgeStore(),
|
|
35
|
+
});
|
|
36
|
+
expect(gs).toBeDefined();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('synthesize (backward-compatible sync API)', () => {
|
|
41
|
+
it('returns a valid Goal with defaults', () => {
|
|
42
|
+
const gs = new GoalSynthesizer();
|
|
43
|
+
const goal = gs.synthesize();
|
|
44
|
+
expect(goal).toHaveProperty('id');
|
|
45
|
+
expect(goal).toHaveProperty('description');
|
|
46
|
+
expect(goal).toHaveProperty('category');
|
|
47
|
+
expect(goal).toHaveProperty('priority');
|
|
48
|
+
expect(goal).toHaveProperty('estimatedComplexity');
|
|
49
|
+
expect(goal).toHaveProperty('generatedAt');
|
|
50
|
+
expect(goal).toHaveProperty('source');
|
|
51
|
+
expect(goal.id).toMatch(/^GOAL-/);
|
|
52
|
+
expect(goal.source).toBe('autonomous-boredom');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('respects custom domain', () => {
|
|
56
|
+
const gs = new GoalSynthesizer();
|
|
57
|
+
const goal = gs.synthesize('coding');
|
|
58
|
+
expect(goal.description).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('respects custom source', () => {
|
|
62
|
+
const gs = new GoalSynthesizer();
|
|
63
|
+
const goal = gs.synthesize('general', 'system-mandate');
|
|
64
|
+
expect(goal.source).toBe('system-mandate');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('generates goals with complexity 1-5', () => {
|
|
68
|
+
const gs = new GoalSynthesizer();
|
|
69
|
+
for (let i = 0; i < 20; i++) {
|
|
70
|
+
const goal = gs.synthesize();
|
|
71
|
+
expect(goal.estimatedComplexity).toBeGreaterThanOrEqual(1);
|
|
72
|
+
expect(goal.estimatedComplexity).toBeLessThanOrEqual(5);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('synthesizeMultiple (async, context-aware)', () => {
|
|
78
|
+
it('returns requested number of goals via heuristic', async () => {
|
|
79
|
+
const gs = new GoalSynthesizer();
|
|
80
|
+
const context: GoalContext = { domain: 'coding' };
|
|
81
|
+
const goals = await gs.synthesizeMultiple(context, 3);
|
|
82
|
+
expect(goals).toHaveLength(3);
|
|
83
|
+
for (const g of goals) {
|
|
84
|
+
expect(g).toHaveProperty('rationale');
|
|
85
|
+
expect(g).toHaveProperty('relevanceScore');
|
|
86
|
+
expect(g.relevanceScore).toBeGreaterThan(0);
|
|
87
|
+
expect(g.relevanceScore).toBeLessThanOrEqual(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('returns domain-specific goals for coding', async () => {
|
|
92
|
+
const gs = new GoalSynthesizer();
|
|
93
|
+
const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 5);
|
|
94
|
+
expect(goals.length).toBeGreaterThan(0);
|
|
95
|
+
expect(goals.length).toBeLessThanOrEqual(5);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('returns domain-specific goals for security', async () => {
|
|
99
|
+
const gs = new GoalSynthesizer();
|
|
100
|
+
const goals = await gs.synthesizeMultiple({ domain: 'security' }, 3);
|
|
101
|
+
expect(goals).toHaveLength(3);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('returns domain-specific goals for research', async () => {
|
|
105
|
+
const gs = new GoalSynthesizer();
|
|
106
|
+
const goals = await gs.synthesizeMultiple({ domain: 'research' }, 3);
|
|
107
|
+
expect(goals).toHaveLength(3);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('falls back to generic goals for unknown domains', async () => {
|
|
111
|
+
const gs = new GoalSynthesizer();
|
|
112
|
+
const goals = await gs.synthesizeMultiple({ domain: 'quantum-knitting' }, 2);
|
|
113
|
+
expect(goals).toHaveLength(2);
|
|
114
|
+
// Should still produce valid goals
|
|
115
|
+
for (const g of goals) {
|
|
116
|
+
expect(g.description).toBeTruthy();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('uses knowledge store gotchas to derive goals', async () => {
|
|
121
|
+
const store = mockKnowledgeStore([
|
|
122
|
+
{
|
|
123
|
+
id: 'G.TEST.001',
|
|
124
|
+
type: 'gotcha',
|
|
125
|
+
content: 'Memory leak in WebSocket reconnection handler',
|
|
126
|
+
domain: 'coding',
|
|
127
|
+
confidence: 0.9,
|
|
128
|
+
source: 'test',
|
|
129
|
+
queryCount: 0,
|
|
130
|
+
reuseCount: 0,
|
|
131
|
+
createdAt: new Date().toISOString(),
|
|
132
|
+
authorAgent: 'test-agent',
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
const gs = new GoalSynthesizer({ knowledge: store });
|
|
136
|
+
const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 3);
|
|
137
|
+
expect(goals.length).toBeGreaterThan(0);
|
|
138
|
+
// Knowledge store should have been queried
|
|
139
|
+
expect(store.search).toHaveBeenCalledWith('coding', 5);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('filters out recently completed tasks', async () => {
|
|
143
|
+
const gs = new GoalSynthesizer();
|
|
144
|
+
const completed = GENERIC_GOALS.slice(0, 4);
|
|
145
|
+
const goals = await gs.synthesizeMultiple({
|
|
146
|
+
domain: 'general',
|
|
147
|
+
recentCompletedTasks: completed,
|
|
148
|
+
}, 3);
|
|
149
|
+
// None of the returned goals should match completed tasks
|
|
150
|
+
for (const g of goals) {
|
|
151
|
+
expect(completed.map(c => c.toLowerCase())).not.toContain(g.description.toLowerCase());
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('first goal has highest relevance score', async () => {
|
|
156
|
+
const gs = new GoalSynthesizer();
|
|
157
|
+
const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 3);
|
|
158
|
+
if (goals.length >= 2) {
|
|
159
|
+
expect(goals[0].relevanceScore).toBeGreaterThanOrEqual(goals[1].relevanceScore);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('includes rationale for each goal', async () => {
|
|
164
|
+
const gs = new GoalSynthesizer();
|
|
165
|
+
const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 2);
|
|
166
|
+
for (const g of goals) {
|
|
167
|
+
expect(g.rationale).toBeTruthy();
|
|
168
|
+
expect(typeof g.rationale).toBe('string');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('LLM-based synthesis', () => {
|
|
174
|
+
it('falls back to heuristic when LLM call fails', async () => {
|
|
175
|
+
// Mock callLLM to throw
|
|
176
|
+
vi.doMock('../llm/llm-adapter', () => ({
|
|
177
|
+
callLLM: vi.fn().mockRejectedValue(new Error('API key invalid')),
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
const gs = new GoalSynthesizer({
|
|
181
|
+
llm: mockLLMConfig(),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 2);
|
|
185
|
+
// Should still return goals via heuristic fallback
|
|
186
|
+
expect(goals.length).toBeGreaterThan(0);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('knowledge-derived goals', () => {
|
|
191
|
+
it('marks knowledge-derived goals with knowledge-gap category', async () => {
|
|
192
|
+
const store = mockKnowledgeStore([
|
|
193
|
+
{
|
|
194
|
+
id: 'G.SEC.001',
|
|
195
|
+
type: 'gotcha',
|
|
196
|
+
content: 'SQL injection in search endpoint',
|
|
197
|
+
domain: 'security',
|
|
198
|
+
confidence: 0.95,
|
|
199
|
+
source: 'audit',
|
|
200
|
+
queryCount: 0,
|
|
201
|
+
reuseCount: 0,
|
|
202
|
+
createdAt: new Date().toISOString(),
|
|
203
|
+
authorAgent: 'scanner',
|
|
204
|
+
},
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
const gs = new GoalSynthesizer({ knowledge: store });
|
|
208
|
+
// Request enough goals to ensure the knowledge-derived one is included
|
|
209
|
+
const goals = await gs.synthesizeMultiple({ domain: 'security' }, 15);
|
|
210
|
+
|
|
211
|
+
const knowledgeGapGoals = goals.filter(g => g.category === 'knowledge-gap');
|
|
212
|
+
// At least one goal should be derived from the gotcha
|
|
213
|
+
expect(knowledgeGapGoals.length).toBeGreaterThanOrEqual(1);
|
|
214
|
+
const derived = knowledgeGapGoals[0];
|
|
215
|
+
expect(derived.description).toContain('SQL injection');
|
|
216
|
+
expect(derived.rationale).toContain('knowledge store');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe('exported constants', () => {
|
|
221
|
+
it('GENERIC_GOALS is a non-empty array of strings', () => {
|
|
222
|
+
expect(Array.isArray(GENERIC_GOALS)).toBe(true);
|
|
223
|
+
expect(GENERIC_GOALS.length).toBeGreaterThan(0);
|
|
224
|
+
for (const g of GENERIC_GOALS) {
|
|
225
|
+
expect(typeof g).toBe('string');
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('DOMAIN_GOALS has expected domains', () => {
|
|
230
|
+
expect(DOMAIN_GOALS).toHaveProperty('coding');
|
|
231
|
+
expect(DOMAIN_GOALS).toHaveProperty('research');
|
|
232
|
+
expect(DOMAIN_GOALS).toHaveProperty('security');
|
|
233
|
+
expect(DOMAIN_GOALS).toHaveProperty('reviewer');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { defineAgent } from '../define-agent';
|
|
3
|
+
import { defineTeam } from '../define-team';
|
|
4
|
+
import type { AgentConfig } from '../types';
|
|
5
|
+
|
|
6
|
+
// Mock protocol-agent so runCycle doesn't hit real LLMs
|
|
7
|
+
vi.mock('../protocol-agent', () => ({
|
|
8
|
+
runProtocolCycle: vi.fn().mockResolvedValue({
|
|
9
|
+
summary: 'Done',
|
|
10
|
+
insights: [],
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
function makeAgent(name: string, role: AgentConfig['role'] = 'coder'): AgentConfig {
|
|
15
|
+
return defineAgent({
|
|
16
|
+
name,
|
|
17
|
+
role,
|
|
18
|
+
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
19
|
+
capabilities: ['code-generation'],
|
|
20
|
+
claimFilter: { roles: ['coder'], maxPriority: 10 },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('Local Presence Tracking (FW-0.3)', () => {
|
|
25
|
+
describe('localHeartbeat()', () => {
|
|
26
|
+
it('registers an agent on first heartbeat', () => {
|
|
27
|
+
const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
|
|
28
|
+
team.localHeartbeat('Alice');
|
|
29
|
+
const agents = team.localPresence();
|
|
30
|
+
expect(agents).toHaveLength(1);
|
|
31
|
+
expect(agents[0].name).toBe('Alice');
|
|
32
|
+
expect(agents[0].status).toBe('online');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('updates lastSeen on subsequent heartbeats', () => {
|
|
36
|
+
const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
|
|
37
|
+
team.localHeartbeat('Alice');
|
|
38
|
+
const first = team.localPresence()[0].lastSeen;
|
|
39
|
+
|
|
40
|
+
// Advance time slightly
|
|
41
|
+
vi.useFakeTimers();
|
|
42
|
+
vi.advanceTimersByTime(100);
|
|
43
|
+
team.localHeartbeat('Alice');
|
|
44
|
+
const second = team.localPresence()[0].lastSeen;
|
|
45
|
+
expect(second).toBeGreaterThanOrEqual(first);
|
|
46
|
+
vi.useRealTimers();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('tracks currentTask when provided', () => {
|
|
50
|
+
const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
|
|
51
|
+
team.localHeartbeat('Alice', 'Fix auth bug');
|
|
52
|
+
const agents = team.localPresence();
|
|
53
|
+
expect(agents[0].currentTask).toBe('Fix auth bug');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('clears currentTask when heartbeat has no task', () => {
|
|
57
|
+
const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
|
|
58
|
+
team.localHeartbeat('Alice', 'Fix auth bug');
|
|
59
|
+
team.localHeartbeat('Alice');
|
|
60
|
+
const agents = team.localPresence();
|
|
61
|
+
expect(agents[0].currentTask).toBeUndefined();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('tracks multiple agents independently', () => {
|
|
65
|
+
const team = defineTeam({
|
|
66
|
+
name: 'presence-test',
|
|
67
|
+
agents: [makeAgent('Alice'), makeAgent('Bob', 'reviewer')],
|
|
68
|
+
});
|
|
69
|
+
team.localHeartbeat('Alice', 'Task A');
|
|
70
|
+
team.localHeartbeat('Bob', 'Task B');
|
|
71
|
+
const agents = team.localPresence();
|
|
72
|
+
expect(agents).toHaveLength(2);
|
|
73
|
+
const names = agents.map(a => a.name).sort();
|
|
74
|
+
expect(names).toEqual(['Alice', 'Bob']);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('localPresence() status transitions', () => {
|
|
79
|
+
it('marks agent as idle after idleTimeout', () => {
|
|
80
|
+
vi.useFakeTimers();
|
|
81
|
+
const team = defineTeam({
|
|
82
|
+
name: 'idle-test',
|
|
83
|
+
agents: [makeAgent('Alice')],
|
|
84
|
+
presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
team.localHeartbeat('Alice');
|
|
88
|
+
expect(team.localPresence()[0].status).toBe('online');
|
|
89
|
+
|
|
90
|
+
vi.advanceTimersByTime(1500); // past idle threshold
|
|
91
|
+
expect(team.localPresence()[0].status).toBe('idle');
|
|
92
|
+
|
|
93
|
+
vi.useRealTimers();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('marks agent as offline after offlineTimeout', () => {
|
|
97
|
+
vi.useFakeTimers();
|
|
98
|
+
const team = defineTeam({
|
|
99
|
+
name: 'offline-test',
|
|
100
|
+
agents: [makeAgent('Alice')],
|
|
101
|
+
presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
team.localHeartbeat('Alice');
|
|
105
|
+
vi.advanceTimersByTime(6000); // past offline threshold
|
|
106
|
+
expect(team.localPresence()[0].status).toBe('offline');
|
|
107
|
+
|
|
108
|
+
vi.useRealTimers();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns to online after a fresh heartbeat', () => {
|
|
112
|
+
vi.useFakeTimers();
|
|
113
|
+
const team = defineTeam({
|
|
114
|
+
name: 'recover-test',
|
|
115
|
+
agents: [makeAgent('Alice')],
|
|
116
|
+
presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
team.localHeartbeat('Alice');
|
|
120
|
+
vi.advanceTimersByTime(6000);
|
|
121
|
+
expect(team.localPresence()[0].status).toBe('offline');
|
|
122
|
+
|
|
123
|
+
// Agent comes back
|
|
124
|
+
team.localHeartbeat('Alice');
|
|
125
|
+
expect(team.localPresence()[0].status).toBe('online');
|
|
126
|
+
|
|
127
|
+
vi.useRealTimers();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('uses default timeouts (60s idle, 300s offline) when not configured', () => {
|
|
131
|
+
vi.useFakeTimers();
|
|
132
|
+
const team = defineTeam({
|
|
133
|
+
name: 'default-timeout-test',
|
|
134
|
+
agents: [makeAgent('Alice')],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
team.localHeartbeat('Alice');
|
|
138
|
+
expect(team.localPresence()[0].status).toBe('online');
|
|
139
|
+
|
|
140
|
+
vi.advanceTimersByTime(61_000); // past default 60s idle
|
|
141
|
+
expect(team.localPresence()[0].status).toBe('idle');
|
|
142
|
+
|
|
143
|
+
vi.advanceTimersByTime(240_000); // total ~301s, past default 300s offline
|
|
144
|
+
expect(team.localPresence()[0].status).toBe('offline');
|
|
145
|
+
|
|
146
|
+
vi.useRealTimers();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('uptime tracking', () => {
|
|
151
|
+
it('computes uptime from first heartbeat', () => {
|
|
152
|
+
vi.useFakeTimers();
|
|
153
|
+
const team = defineTeam({
|
|
154
|
+
name: 'uptime-test',
|
|
155
|
+
agents: [makeAgent('Alice')],
|
|
156
|
+
presence: { idleTimeoutMs: 60_000, offlineTimeoutMs: 300_000 },
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
team.localHeartbeat('Alice');
|
|
160
|
+
vi.advanceTimersByTime(10_000);
|
|
161
|
+
team.localHeartbeat('Alice'); // refresh lastSeen but firstSeen stays
|
|
162
|
+
|
|
163
|
+
const agents = team.localPresence();
|
|
164
|
+
expect(agents[0].uptime).toBeGreaterThanOrEqual(10_000);
|
|
165
|
+
|
|
166
|
+
vi.useRealTimers();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('auto-heartbeat during runCycle', () => {
|
|
171
|
+
it('automatically heartbeats agents that claim tasks during a cycle', async () => {
|
|
172
|
+
const team = defineTeam({
|
|
173
|
+
name: 'auto-hb-test',
|
|
174
|
+
agents: [makeAgent('Alice')],
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await team.addTasks([
|
|
178
|
+
{ title: 'Fix bug', description: 'Important', priority: 1, role: 'coder' },
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
// Before cycle — no presence data
|
|
182
|
+
expect(team.localPresence()).toHaveLength(0);
|
|
183
|
+
|
|
184
|
+
await team.runCycle();
|
|
185
|
+
|
|
186
|
+
// After cycle — agent should have been auto-heartbeated
|
|
187
|
+
const agents = team.localPresence();
|
|
188
|
+
expect(agents).toHaveLength(1);
|
|
189
|
+
expect(agents[0].name).toBe('Alice');
|
|
190
|
+
expect(agents[0].status).toBe('online');
|
|
191
|
+
expect(agents[0].currentTask).toBe('Fix bug');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('does not heartbeat agents that skip (no matching task)', async () => {
|
|
195
|
+
const team = defineTeam({
|
|
196
|
+
name: 'skip-hb-test',
|
|
197
|
+
agents: [makeAgent('Alice')],
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// No tasks on board, but more than threshold so no synthesis
|
|
201
|
+
await team.addTasks([
|
|
202
|
+
{ title: 'Task 1', description: '', priority: 1, role: 'reviewer' as const },
|
|
203
|
+
{ title: 'Task 2', description: '', priority: 2, role: 'reviewer' as const },
|
|
204
|
+
{ title: 'Task 3', description: '', priority: 3, role: 'reviewer' as const },
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
await team.runCycle();
|
|
208
|
+
|
|
209
|
+
// Alice is a coder, all tasks are reviewer-only — she should have skipped
|
|
210
|
+
expect(team.localPresence()).toHaveLength(0);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('empty presence', () => {
|
|
215
|
+
it('returns empty array when no heartbeats recorded', () => {
|
|
216
|
+
const team = defineTeam({
|
|
217
|
+
name: 'empty-test',
|
|
218
|
+
agents: [makeAgent('Alice')],
|
|
219
|
+
});
|
|
220
|
+
expect(team.localPresence()).toEqual([]);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|