@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.
Files changed (329) hide show
  1. package/ALL-test-results.json +1 -0
  2. package/CHANGELOG.md +8 -0
  3. package/LICENSE +21 -0
  4. package/ROADMAP.md +175 -0
  5. package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
  6. package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
  7. package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
  8. package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
  9. package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
  10. package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
  11. package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
  12. package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
  13. package/dist/agents/index.cjs +4790 -0
  14. package/dist/agents/index.d.cts +1788 -0
  15. package/dist/agents/index.d.ts +1788 -0
  16. package/dist/agents/index.js +4695 -0
  17. package/dist/ai/index.cjs +5347 -0
  18. package/dist/ai/index.d.cts +1753 -0
  19. package/dist/ai/index.d.ts +1753 -0
  20. package/dist/ai/index.js +5244 -0
  21. package/dist/behavior.cjs +449 -0
  22. package/dist/behavior.d.cts +130 -0
  23. package/dist/behavior.d.ts +130 -0
  24. package/dist/behavior.js +407 -0
  25. package/dist/economy/index.cjs +3659 -0
  26. package/dist/economy/index.d.cts +747 -0
  27. package/dist/economy/index.d.ts +747 -0
  28. package/dist/economy/index.js +3617 -0
  29. package/dist/implementations-D9T3un9D.d.cts +236 -0
  30. package/dist/implementations-D9T3un9D.d.ts +236 -0
  31. package/dist/index.cjs +24550 -0
  32. package/dist/index.d.cts +1729 -0
  33. package/dist/index.d.ts +1729 -0
  34. package/dist/index.js +24277 -0
  35. package/dist/learning/index.cjs +219 -0
  36. package/dist/learning/index.d.cts +104 -0
  37. package/dist/learning/index.d.ts +104 -0
  38. package/dist/learning/index.js +189 -0
  39. package/dist/negotiation/index.cjs +970 -0
  40. package/dist/negotiation/index.d.cts +610 -0
  41. package/dist/negotiation/index.d.ts +610 -0
  42. package/dist/negotiation/index.js +931 -0
  43. package/dist/skills/index.cjs +1118 -0
  44. package/dist/skills/index.d.cts +289 -0
  45. package/dist/skills/index.d.ts +289 -0
  46. package/dist/skills/index.js +1079 -0
  47. package/dist/swarm/index.cjs +5268 -0
  48. package/dist/swarm/index.d.cts +2433 -0
  49. package/dist/swarm/index.d.ts +2433 -0
  50. package/dist/swarm/index.js +5221 -0
  51. package/dist/training/index.cjs +2745 -0
  52. package/dist/training/index.d.cts +1734 -0
  53. package/dist/training/index.d.ts +1734 -0
  54. package/dist/training/index.js +2687 -0
  55. package/extract-failures.js +10 -0
  56. package/package.json +82 -0
  57. package/src/__tests__/bounty-marketplace.test.ts +374 -0
  58. package/src/__tests__/delegation.test.ts +144 -0
  59. package/src/__tests__/distributed-claimer.test.ts +147 -0
  60. package/src/__tests__/done-log-audit.test.ts +342 -0
  61. package/src/__tests__/framework.test.ts +865 -0
  62. package/src/__tests__/goal-synthesizer.test.ts +236 -0
  63. package/src/__tests__/presence.test.ts +223 -0
  64. package/src/__tests__/protocol-agent.test.ts +254 -0
  65. package/src/__tests__/revenue-splitter.test.ts +114 -0
  66. package/src/__tests__/scenario-driven-todo.test.ts +197 -0
  67. package/src/__tests__/self-improve.test.ts +349 -0
  68. package/src/__tests__/service-lifecycle.test.ts +237 -0
  69. package/src/__tests__/skill-router.test.ts +121 -0
  70. package/src/agents/AgentManifest.ts +493 -0
  71. package/src/agents/AgentRegistry.ts +475 -0
  72. package/src/agents/AgentTypes.ts +585 -0
  73. package/src/agents/AgentWalletRegistry.ts +83 -0
  74. package/src/agents/AuthenticatedCRDT.ts +388 -0
  75. package/src/agents/CapabilityMatcher.ts +453 -0
  76. package/src/agents/CrossRealityHandoff.ts +305 -0
  77. package/src/agents/CulturalMemory.ts +454 -0
  78. package/src/agents/FederatedRegistryAdapter.ts +429 -0
  79. package/src/agents/NormEngine.ts +450 -0
  80. package/src/agents/OrchestratorAgent.ts +414 -0
  81. package/src/agents/SkillWorkflowEngine.ts +472 -0
  82. package/src/agents/TaskDelegationService.ts +551 -0
  83. package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
  84. package/src/agents/__tests__/AgentManifest.test.ts +182 -0
  85. package/src/agents/__tests__/AgentModule.test.ts +864 -0
  86. package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
  87. package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
  88. package/src/agents/__tests__/AgentTypes.test.ts +534 -0
  89. package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
  90. package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
  91. package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
  92. package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
  93. package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
  94. package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
  95. package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
  96. package/src/agents/__tests__/NormEngine.test.ts +276 -0
  97. package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
  98. package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
  99. package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
  100. package/src/agents/index.ts +107 -0
  101. package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
  102. package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
  103. package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
  104. package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
  105. package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
  106. package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
  107. package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
  108. package/src/agents/spatial-comms/index.ts +66 -0
  109. package/src/ai/AIAdapter.ts +313 -0
  110. package/src/ai/AICopilot.ts +331 -0
  111. package/src/ai/AIOutputValidator.ts +203 -0
  112. package/src/ai/BTNodes.ts +239 -0
  113. package/src/ai/BehaviorSelector.ts +135 -0
  114. package/src/ai/BehaviorTree.ts +153 -0
  115. package/src/ai/Blackboard.ts +165 -0
  116. package/src/ai/GenerationAnalytics.ts +461 -0
  117. package/src/ai/GenerationCache.ts +265 -0
  118. package/src/ai/GoalPlanner.ts +165 -0
  119. package/src/ai/HoloScriptGenerator.ts +580 -0
  120. package/src/ai/InfluenceMap.ts +180 -0
  121. package/src/ai/NavMesh.ts +168 -0
  122. package/src/ai/PerceptionSystem.ts +178 -0
  123. package/src/ai/PromptTemplates.ts +453 -0
  124. package/src/ai/SemanticSearchService.ts +80 -0
  125. package/src/ai/StateMachine.ts +196 -0
  126. package/src/ai/SteeringBehavior.ts +150 -0
  127. package/src/ai/SteeringBehaviors.ts +244 -0
  128. package/src/ai/TrainingDataGenerator.ts +1082 -0
  129. package/src/ai/UtilityAI.ts +145 -0
  130. package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
  131. package/src/ai/__tests__/AIAdapter.test.ts +109 -0
  132. package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
  133. package/src/ai/__tests__/AICopilot.test.ts +178 -0
  134. package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
  135. package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
  136. package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
  137. package/src/ai/__tests__/BTNodes.test.ts +263 -0
  138. package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
  139. package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
  140. package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
  141. package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
  142. package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
  143. package/src/ai/__tests__/Blackboard.test.ts +183 -0
  144. package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
  145. package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
  146. package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
  147. package/src/ai/__tests__/GenerationCache.test.ts +171 -0
  148. package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
  149. package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
  150. package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
  151. package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
  152. package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
  153. package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
  154. package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
  155. package/src/ai/__tests__/NavMesh.test.ts +159 -0
  156. package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
  157. package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
  158. package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
  159. package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
  160. package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
  161. package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
  162. package/src/ai/__tests__/StateMachine.test.ts +163 -0
  163. package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
  164. package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
  165. package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
  166. package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
  167. package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
  168. package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
  169. package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
  170. package/src/ai/__tests__/UtilityAI.test.ts +155 -0
  171. package/src/ai/__tests__/adapters.prod.test.ts +263 -0
  172. package/src/ai/__tests__/adapters.test.ts +320 -0
  173. package/src/ai/adapters.ts +1585 -0
  174. package/src/ai/index.ts +130 -0
  175. package/src/behavior/BehaviorPresets.ts +140 -0
  176. package/src/behavior/BehaviorTree.ts +236 -0
  177. package/src/behavior/StateMachine.ts +176 -0
  178. package/src/behavior/StateTrait.ts +67 -0
  179. package/src/behavior/index.ts +8 -0
  180. package/src/behavior.ts +8 -0
  181. package/src/board/audit.ts +284 -0
  182. package/src/board/board-ops.ts +336 -0
  183. package/src/board/board-types.ts +302 -0
  184. package/src/board/index.ts +69 -0
  185. package/src/define-agent.ts +46 -0
  186. package/src/define-team.ts +33 -0
  187. package/src/delegation.ts +265 -0
  188. package/src/distributed-claimer.ts +228 -0
  189. package/src/economy/AgentBudgetEnforcer.ts +464 -0
  190. package/src/economy/BountyManager.ts +185 -0
  191. package/src/economy/CreatorRevenueAggregator.ts +460 -0
  192. package/src/economy/InvisibleWallet.ts +82 -0
  193. package/src/economy/KnowledgeMarketplace.ts +193 -0
  194. package/src/economy/PaymentWebhookService.ts +512 -0
  195. package/src/economy/RevenueSplitter.ts +156 -0
  196. package/src/economy/SubscriptionManager.ts +546 -0
  197. package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
  198. package/src/economy/UsageMeter.ts +440 -0
  199. package/src/economy/_core-stubs.ts +219 -0
  200. package/src/economy/index.ts +100 -0
  201. package/src/economy/x402-facilitator.ts +1978 -0
  202. package/src/index.ts +348 -0
  203. package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
  204. package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
  205. package/src/knowledge/brain.ts +167 -0
  206. package/src/knowledge/consolidation.ts +581 -0
  207. package/src/knowledge/knowledge-consolidator.ts +510 -0
  208. package/src/knowledge/knowledge-store.ts +616 -0
  209. package/src/learning/MemoryConsolidator.ts +102 -0
  210. package/src/learning/MemoryScorer.ts +69 -0
  211. package/src/learning/ProceduralCompiler.ts +45 -0
  212. package/src/learning/SemanticClusterer.ts +66 -0
  213. package/src/learning/index.ts +8 -0
  214. package/src/llm/llm-adapter.ts +159 -0
  215. package/src/mesh/index.ts +309 -0
  216. package/src/negotiation/NegotiationProtocol.ts +694 -0
  217. package/src/negotiation/NegotiationTypes.ts +473 -0
  218. package/src/negotiation/VotingMechanisms.ts +691 -0
  219. package/src/negotiation/index.ts +49 -0
  220. package/src/protocol/goal-synthesizer.ts +317 -0
  221. package/src/protocol/implementations.ts +474 -0
  222. package/src/protocol/micro-phase-decomposer.ts +299 -0
  223. package/src/protocol/micro-step-decomposer.test.ts +306 -0
  224. package/src/protocol-agent.test.ts +353 -0
  225. package/src/protocol-agent.ts +670 -0
  226. package/src/self-improve/absorb-scanner.ts +252 -0
  227. package/src/self-improve/evolution-engine.ts +149 -0
  228. package/src/self-improve/framework-absorber.ts +214 -0
  229. package/src/self-improve/index.ts +50 -0
  230. package/src/self-improve/prompt-optimizer.ts +212 -0
  231. package/src/self-improve/test-generator.ts +175 -0
  232. package/src/skill-router.ts +186 -0
  233. package/src/skills/index.ts +5 -0
  234. package/src/skills/skill-md-bridge.ts +1699 -0
  235. package/src/swarm/ACOEngine.ts +261 -0
  236. package/src/swarm/CollectiveIntelligence.ts +383 -0
  237. package/src/swarm/ContributionSynthesizer.ts +481 -0
  238. package/src/swarm/LeaderElection.ts +393 -0
  239. package/src/swarm/PSOEngine.ts +206 -0
  240. package/src/swarm/QuorumPolicy.ts +173 -0
  241. package/src/swarm/SwarmCoordinator.ts +335 -0
  242. package/src/swarm/SwarmManager.ts +442 -0
  243. package/src/swarm/SwarmMembership.ts +456 -0
  244. package/src/swarm/VotingRound.ts +255 -0
  245. package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
  246. package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
  247. package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
  248. package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
  249. package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
  250. package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
  251. package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
  252. package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
  253. package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
  254. package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
  255. package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
  256. package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
  257. package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
  258. package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
  259. package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
  260. package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
  261. package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
  262. package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
  263. package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
  264. package/src/swarm/__tests__/VotingRound.test.ts +174 -0
  265. package/src/swarm/analytics/SwarmInspector.ts +476 -0
  266. package/src/swarm/analytics/SwarmMetrics.ts +449 -0
  267. package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
  268. package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
  269. package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
  270. package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
  271. package/src/swarm/analytics/index.ts +7 -0
  272. package/src/swarm/index.ts +69 -0
  273. package/src/swarm/messaging/BroadcastChannel.ts +509 -0
  274. package/src/swarm/messaging/GossipProtocol.ts +565 -0
  275. package/src/swarm/messaging/SwarmEventBus.ts +443 -0
  276. package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
  277. package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
  278. package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
  279. package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
  280. package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
  281. package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
  282. package/src/swarm/messaging/index.ts +8 -0
  283. package/src/swarm/spatial/FlockingBehavior.ts +462 -0
  284. package/src/swarm/spatial/FormationController.ts +500 -0
  285. package/src/swarm/spatial/Vector3.ts +170 -0
  286. package/src/swarm/spatial/ZoneClaiming.ts +509 -0
  287. package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
  288. package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
  289. package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
  290. package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
  291. package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
  292. package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
  293. package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
  294. package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
  295. package/src/swarm/spatial/index.ts +28 -0
  296. package/src/team.ts +1245 -0
  297. package/src/training/LRScheduler.ts +377 -0
  298. package/src/training/QualityScoringPipeline.ts +139 -0
  299. package/src/training/SoftDedup.ts +461 -0
  300. package/src/training/SparsityMonitor.ts +685 -0
  301. package/src/training/SparsityMonitorTypes.ts +209 -0
  302. package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
  303. package/src/training/SpatialTrainingDataTypes.ts +216 -0
  304. package/src/training/TrainingPipelineConfig.ts +215 -0
  305. package/src/training/constants.ts +94 -0
  306. package/src/training/index.ts +138 -0
  307. package/src/training/schema.ts +147 -0
  308. package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
  309. package/src/training/scripts/generate-spatial-dataset.ts +521 -0
  310. package/src/training/training/data/novel-use-cases.jsonl +153 -0
  311. package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
  312. package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
  313. package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
  314. package/src/training/trainingmonkey/index.ts +26 -0
  315. package/src/training/trait-mappings.ts +157 -0
  316. package/src/types/core-stubs.d.ts +113 -0
  317. package/src/types.ts +304 -0
  318. package/test-output.txt +0 -0
  319. package/test-result.json +1 -0
  320. package/tsc-errors.txt +4 -0
  321. package/tsc_output.txt +0 -0
  322. package/tsconfig.json +14 -0
  323. package/tsup-learning-esm.config.ts +12 -0
  324. package/tsup.config.ts +21 -0
  325. package/typescript-errors-2.txt +0 -0
  326. package/typescript-errors.txt +22 -0
  327. package/vitest-log-utf8.txt +268 -0
  328. package/vitest-log.txt +0 -0
  329. package/vitest.config.ts +8 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * @fileoverview Tests for CulturalMemory — Dual Memory Architecture
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { CulturalMemory } from '../CulturalMemory';
7
+
8
+ describe('CulturalMemory', () => {
9
+ // ── Episodic Memory ────────────────────────────────────────────────────
10
+
11
+ describe('Episodic Memory', () => {
12
+ it('records and recalls memories', () => {
13
+ const mem = new CulturalMemory();
14
+ mem.record('agent1', 'Met agent2 at market', {
15
+ participants: ['agent2'],
16
+ valence: 0.8,
17
+ normId: 'fair_trade',
18
+ tags: ['trade'],
19
+ });
20
+ const recalled = mem.recall('agent1');
21
+ expect(recalled).toHaveLength(1);
22
+ expect(recalled[0].event).toBe('Met agent2 at market');
23
+ expect(recalled[0].valence).toBe(0.8);
24
+ });
25
+
26
+ it('filters by normId', () => {
27
+ const mem = new CulturalMemory();
28
+ mem.record('agent1', 'Traded fairly', { normId: 'fair_trade' });
29
+ mem.record('agent1', 'Greeted neighbor', { normId: 'greeting_convention' });
30
+ const filtered = mem.recall('agent1', { normId: 'fair_trade' });
31
+ expect(filtered).toHaveLength(1);
32
+ expect(filtered[0].normId).toBe('fair_trade');
33
+ });
34
+
35
+ it('filters by tags', () => {
36
+ const mem = new CulturalMemory();
37
+ mem.record('agent1', 'Found resource', { tags: ['resource', 'discovery'] });
38
+ mem.record('agent1', 'Had a fight', { tags: ['conflict'] });
39
+ const filtered = mem.recall('agent1', { tags: ['resource'] });
40
+ expect(filtered).toHaveLength(1);
41
+ });
42
+
43
+ it('evicts oldest when over capacity', () => {
44
+ const mem = new CulturalMemory({ episodicCapacity: 3 });
45
+ for (let i = 0; i < 5; i++) {
46
+ mem.record('agent1', `Event ${i}`, { importance: i * 0.2 });
47
+ }
48
+ expect(mem.memoryCount('agent1')).toBe(3);
49
+ });
50
+
51
+ it('decays memory strength over ticks', () => {
52
+ const mem = new CulturalMemory({ episodicDecayRate: 0.1 });
53
+ mem.record('agent1', 'Old event');
54
+ const before = mem.recall('agent1')[0].strength;
55
+ mem.tick();
56
+ const after = mem.recall('agent1')[0].strength;
57
+ expect(after).toBeLessThan(before);
58
+ });
59
+
60
+ it('prunes memories below threshold', () => {
61
+ const mem = new CulturalMemory({ episodicDecayRate: 0.99 }); // Extreme decay
62
+ mem.record('agent1', 'Fragile memory');
63
+ for (let i = 0; i < 10; i++) mem.tick(); // Decay to near-zero
64
+ expect(mem.memoryCount('agent1')).toBe(0);
65
+ });
66
+ });
67
+
68
+ // ── Stigmergic Traces ────────────────────────────────────────────────────
69
+
70
+ describe('Stigmergic Traces', () => {
71
+ it('leaves and perceives traces', () => {
72
+ const mem = new CulturalMemory();
73
+ mem.leaveTrace('agent1', 'zone_a', 'danger', { x: 10, y: 0, z: 10 });
74
+ const perceived = mem.perceiveTraces('zone_a', { x: 12, y: 0, z: 10 });
75
+ expect(perceived).toHaveLength(1);
76
+ expect(perceived[0].label).toBe('danger');
77
+ });
78
+
79
+ it('does not perceive out-of-range traces', () => {
80
+ const mem = new CulturalMemory();
81
+ mem.leaveTrace('agent1', 'zone_a', 'far away', { x: 0, y: 0, z: 0 }, { radius: 5 });
82
+ const perceived = mem.perceiveTraces('zone_a', { x: 100, y: 0, z: 100 });
83
+ expect(perceived).toHaveLength(0);
84
+ });
85
+
86
+ it('reinforces traces', () => {
87
+ const mem = new CulturalMemory();
88
+ const trace = mem.leaveTrace('agent1', 'zone_a', 'food here', { x: 5, y: 0, z: 5 });
89
+ const initialIntensity = trace.intensity;
90
+ mem.reinforceTrace(trace.id, 'zone_a');
91
+ const reinforced = mem.zoneTraces('zone_a').find((t) => t.id === trace.id);
92
+ expect(reinforced!.intensity).toBeGreaterThan(initialIntensity);
93
+ expect(reinforced!.reinforcements).toBe(1);
94
+ });
95
+
96
+ it('traces decay over ticks', () => {
97
+ const mem = new CulturalMemory({ traceDecayRate: 0.1 });
98
+ const trace = mem.leaveTrace(
99
+ 'agent1',
100
+ 'zone_a',
101
+ 'temp',
102
+ { x: 0, y: 0, z: 0 },
103
+ { decayRate: 0.1 }
104
+ );
105
+ const before = trace.intensity;
106
+ mem.tick();
107
+ const after = mem.zoneTraces('zone_a').find((t) => t.id === trace.id);
108
+ expect(after!.intensity).toBeLessThan(before);
109
+ });
110
+
111
+ it('evaporated traces are pruned', () => {
112
+ const mem = new CulturalMemory();
113
+ mem.leaveTrace('agent1', 'zone_a', 'ephemeral', { x: 0, y: 0, z: 0 }, { decayRate: 1.0 });
114
+ const result = mem.tick();
115
+ expect(result.evaporatedTraces).toBe(1);
116
+ expect(mem.zoneTraces('zone_a')).toHaveLength(0);
117
+ });
118
+ });
119
+
120
+ // ── SOP Consolidation ────────────────────────────────────────────────────
121
+
122
+ describe('SOP Consolidation', () => {
123
+ it('forms SOP when threshold reached', () => {
124
+ const mem = new CulturalMemory({ consolidationThreshold: 3 });
125
+ for (let i = 0; i < 5; i++) {
126
+ mem.record('agent1', `Traded fairly ${i}`, { normId: 'fair_trade', valence: 0.8 });
127
+ }
128
+ const sops = mem.consolidate('agent1');
129
+ expect(sops).toHaveLength(1);
130
+ expect(sops[0].normId).toBe('fair_trade');
131
+ expect(sops[0].actions).toContain('comply');
132
+ });
133
+
134
+ it('does not form SOP below threshold', () => {
135
+ const mem = new CulturalMemory({ consolidationThreshold: 10 });
136
+ for (let i = 0; i < 3; i++) {
137
+ mem.record('agent1', `Event ${i}`, { normId: 'rare_norm' });
138
+ }
139
+ const sops = mem.consolidate('agent1');
140
+ expect(sops).toHaveLength(0);
141
+ });
142
+
143
+ it('forms avoidance SOP for negative experiences', () => {
144
+ const mem = new CulturalMemory({ consolidationThreshold: 3 });
145
+ for (let i = 0; i < 5; i++) {
146
+ mem.record('agent1', `Got griefed ${i}`, { normId: 'no_griefing', valence: -0.9 });
147
+ }
148
+ const sops = mem.consolidate('agent1');
149
+ expect(sops[0].actions).toContain('avoid');
150
+ });
151
+
152
+ it('retrieves SOPs by agent', () => {
153
+ const mem = new CulturalMemory({ consolidationThreshold: 2 });
154
+ for (let i = 0; i < 3; i++) {
155
+ mem.record('agent1', 'Trade', { normId: 'fair_trade' });
156
+ mem.record('agent2', 'Greet', { normId: 'greeting_convention' });
157
+ }
158
+ mem.consolidate('agent1');
159
+ mem.consolidate('agent2');
160
+ expect(mem.getSOPs('agent1')).toHaveLength(1);
161
+ expect(mem.getSOPs('agent2')).toHaveLength(1);
162
+ });
163
+ });
164
+
165
+ // ── State Export/Import ──────────────────────────────────────────────────
166
+
167
+ describe('State Persistence', () => {
168
+ it('exports and imports state', () => {
169
+ const mem = new CulturalMemory({ consolidationThreshold: 2 });
170
+ mem.record('agent1', 'Event A', { normId: 'test_norm', tags: ['a'] });
171
+ mem.record('agent1', 'Event B', { normId: 'test_norm', tags: ['b'] });
172
+ mem.leaveTrace('agent1', 'zone_a', 'marker', { x: 1, y: 2, z: 3 });
173
+ mem.consolidate('agent1');
174
+
175
+ const state = mem.exportState();
176
+ const mem2 = new CulturalMemory();
177
+ mem2.importState(state);
178
+
179
+ expect(mem2.memoryCount('agent1')).toBe(2);
180
+ expect(mem2.zoneTraces('zone_a')).toHaveLength(1);
181
+ expect(mem2.getSOPs('agent1')).toHaveLength(1);
182
+ });
183
+ });
184
+
185
+ // ── Stats ────────────────────────────────────────────────────────────────
186
+
187
+ describe('Stats', () => {
188
+ it('reports correct stats', () => {
189
+ const mem = new CulturalMemory();
190
+ mem.record('agent1', 'A');
191
+ mem.record('agent2', 'B');
192
+ mem.leaveTrace('agent1', 'zone_a', 'x', { x: 0, y: 0, z: 0 });
193
+ const s = mem.stats();
194
+ expect(s.agents).toBe(2);
195
+ expect(s.totalMemories).toBe(2);
196
+ expect(s.totalTraces).toBe(1);
197
+ expect(s.zones).toBe(1);
198
+ });
199
+ });
200
+ });
@@ -0,0 +1,409 @@
1
+ /**
2
+ * FederatedRegistryAdapter Tests
3
+ *
4
+ * Tests cross-composition agent discovery via remote A2A Agent Card fetching.
5
+ * Part of HoloScript v5.5 "Agents as Universal Orchestrators".
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
9
+ import {
10
+ FederatedRegistryAdapter,
11
+ type FederatedRegistryConfig,
12
+ type A2AAgentCard,
13
+ } from '../FederatedRegistryAdapter';
14
+ import { AgentRegistry, resetDefaultRegistry } from '../AgentRegistry';
15
+
16
+ // =============================================================================
17
+ // TEST FIXTURES
18
+ // =============================================================================
19
+
20
+ function makeAgentCard(overrides: Partial<A2AAgentCard> = {}): A2AAgentCard {
21
+ return {
22
+ id: 'remote-agent-1',
23
+ name: 'Remote Agent',
24
+ description: 'A remote agent for testing',
25
+ endpoint: 'https://remote.example.com/a2a',
26
+ version: '1.0.0',
27
+ provider: { organization: 'TestOrg', url: 'https://example.com' },
28
+ capabilities: { streaming: false, pushNotifications: false, stateTransitionHistory: false },
29
+ skills: [
30
+ {
31
+ id: 'parse_hs',
32
+ name: 'Parse HoloScript',
33
+ description: 'Parses HoloScript source code',
34
+ tags: ['parsing', 'spatial'],
35
+ inputModes: ['application/json'],
36
+ outputModes: ['application/json'],
37
+ },
38
+ {
39
+ id: 'compile_hs',
40
+ name: 'Compile HoloScript',
41
+ description: 'Compiles HoloScript to target',
42
+ tags: ['compilation', 'spatial'],
43
+ inputModes: ['application/json'],
44
+ outputModes: ['application/json'],
45
+ },
46
+ ],
47
+ ...overrides,
48
+ };
49
+ }
50
+
51
+ function makeMockFetch(
52
+ cards: Record<string, A2AAgentCard | null>
53
+ ): (url: string, init?: RequestInit) => Promise<Response> {
54
+ return async (url: string) => {
55
+ const card = cards[url];
56
+ if (card === null || card === undefined) {
57
+ return { ok: false, status: 404, json: async () => ({}) } as Response;
58
+ }
59
+ return {
60
+ ok: true,
61
+ status: 200,
62
+ json: async () => card,
63
+ } as Response;
64
+ };
65
+ }
66
+
67
+ // =============================================================================
68
+ // TESTS
69
+ // =============================================================================
70
+
71
+ describe('FederatedRegistryAdapter', () => {
72
+ let registry: AgentRegistry;
73
+
74
+ beforeEach(() => {
75
+ resetDefaultRegistry();
76
+ registry = new AgentRegistry();
77
+ });
78
+
79
+ afterEach(() => {
80
+ registry.stop();
81
+ registry.clear();
82
+ });
83
+
84
+ describe('a2aCardToManifest', () => {
85
+ it('converts an A2A AgentCard to an AgentManifest', () => {
86
+ const adapter = new FederatedRegistryAdapter(registry);
87
+ const card = makeAgentCard();
88
+ const manifest = adapter.a2aCardToManifest(
89
+ card,
90
+ 'https://remote.example.com/.well-known/agent-card.json'
91
+ );
92
+
93
+ expect(manifest.id).toBe('remote-agent-1');
94
+ expect(manifest.name).toBe('Remote Agent');
95
+ expect(manifest.version).toBe('1.0.0');
96
+ expect(manifest.trustLevel).toBe('external');
97
+ expect(manifest.tags).toContain('remote');
98
+ expect(manifest.tags).toContain('a2a');
99
+ expect(manifest.tags).toContain('TestOrg');
100
+ expect(manifest.endpoints).toHaveLength(1);
101
+ expect(manifest.endpoints[0].protocol).toBe('https');
102
+ expect(manifest.endpoints[0].address).toBe('https://remote.example.com/a2a');
103
+ expect(manifest.capabilities.length).toBeGreaterThan(0);
104
+ expect(manifest.metadata?.sourceUrl).toBe(
105
+ 'https://remote.example.com/.well-known/agent-card.json'
106
+ );
107
+ });
108
+
109
+ it('extracts capability type from skill tags', () => {
110
+ const adapter = new FederatedRegistryAdapter(registry);
111
+ const card = makeAgentCard({
112
+ skills: [
113
+ {
114
+ id: 'skill-1',
115
+ name: 'Analyzer',
116
+ tags: ['analysis', 'nlp'],
117
+ inputModes: [],
118
+ outputModes: [],
119
+ },
120
+ ],
121
+ });
122
+ const manifest = adapter.a2aCardToManifest(card, 'https://example.com');
123
+
124
+ expect(manifest.capabilities[0].type).toBe('analyze');
125
+ expect(manifest.capabilities[0].domain).toBe('nlp');
126
+ });
127
+
128
+ it('deduplicates capabilities by type+domain', () => {
129
+ const adapter = new FederatedRegistryAdapter(registry);
130
+ const card = makeAgentCard({
131
+ skills: [
132
+ {
133
+ id: 's1',
134
+ name: 'Parse 1',
135
+ tags: ['parsing', 'spatial'],
136
+ inputModes: [],
137
+ outputModes: [],
138
+ },
139
+ {
140
+ id: 's2',
141
+ name: 'Parse 2',
142
+ tags: ['parsing', 'spatial'],
143
+ inputModes: [],
144
+ outputModes: [],
145
+ },
146
+ {
147
+ id: 's3',
148
+ name: 'Compile',
149
+ tags: ['compilation', 'spatial'],
150
+ inputModes: [],
151
+ outputModes: [],
152
+ },
153
+ ],
154
+ });
155
+ const manifest = adapter.a2aCardToManifest(card, 'https://example.com');
156
+
157
+ // Should have 2 unique type+domain pairs: analyze:spatial and transform:spatial
158
+ expect(manifest.capabilities).toHaveLength(2);
159
+ });
160
+
161
+ it('handles cards with no skills', () => {
162
+ const adapter = new FederatedRegistryAdapter(registry);
163
+ const card = makeAgentCard({ skills: [] });
164
+ const manifest = adapter.a2aCardToManifest(card, 'https://example.com');
165
+
166
+ expect(manifest.capabilities).toHaveLength(1);
167
+ expect(manifest.capabilities[0].type).toBe('custom');
168
+ expect(manifest.capabilities[0].domain).toBe('general');
169
+ });
170
+
171
+ it('respects custom trustRemoteAs config', () => {
172
+ const adapter = new FederatedRegistryAdapter(registry, { trustRemoteAs: 'known' });
173
+ const card = makeAgentCard();
174
+ const manifest = adapter.a2aCardToManifest(card, 'https://example.com');
175
+
176
+ expect(manifest.trustLevel).toBe('known');
177
+ });
178
+ });
179
+
180
+ describe('fetchAndRegister', () => {
181
+ it('fetches a remote agent card and registers into registry', async () => {
182
+ const card = makeAgentCard();
183
+ const adapter = new FederatedRegistryAdapter(registry, {
184
+ fetchFn: makeMockFetch({
185
+ 'https://remote.example.com/.well-known/agent-card.json': card,
186
+ }),
187
+ });
188
+
189
+ const manifest = await adapter.fetchAndRegister(
190
+ 'https://remote.example.com/.well-known/agent-card.json'
191
+ );
192
+
193
+ expect(manifest).not.toBeNull();
194
+ expect(manifest!.id).toBe('remote-agent-1');
195
+ expect(registry.has('remote-agent-1')).toBe(true);
196
+ expect(adapter.remoteAgentCount).toBe(1);
197
+ });
198
+
199
+ it('returns null for failed HTTP requests', async () => {
200
+ const adapter = new FederatedRegistryAdapter(registry, {
201
+ fetchFn: makeMockFetch({ 'https://fail.example.com': null }),
202
+ });
203
+
204
+ const manifest = await adapter.fetchAndRegister('https://fail.example.com');
205
+
206
+ expect(manifest).toBeNull();
207
+ expect(adapter.remoteAgentCount).toBe(0);
208
+ });
209
+
210
+ it('returns null when card is missing required fields', async () => {
211
+ const adapter = new FederatedRegistryAdapter(registry, {
212
+ fetchFn: async () => ({ ok: true, json: async () => ({ version: '1.0.0' }) }) as Response,
213
+ });
214
+
215
+ const manifest = await adapter.fetchAndRegister('https://bad.example.com');
216
+ expect(manifest).toBeNull();
217
+ });
218
+
219
+ it('enforces maxRemoteAgents capacity', async () => {
220
+ const adapter = new FederatedRegistryAdapter(registry, {
221
+ maxRemoteAgents: 1,
222
+ fetchFn: makeMockFetch({
223
+ 'https://agent1.com': makeAgentCard({ id: 'agent-1', name: 'Agent 1' }),
224
+ 'https://agent2.com': makeAgentCard({ id: 'agent-2', name: 'Agent 2' }),
225
+ }),
226
+ });
227
+
228
+ const m1 = await adapter.fetchAndRegister('https://agent1.com');
229
+ const m2 = await adapter.fetchAndRegister('https://agent2.com');
230
+
231
+ expect(m1).not.toBeNull();
232
+ expect(m2).toBeNull(); // Capacity reached
233
+ expect(adapter.remoteAgentCount).toBe(1);
234
+ });
235
+
236
+ it('allows re-registering an existing remote agent (update)', async () => {
237
+ const card = makeAgentCard();
238
+ const adapter = new FederatedRegistryAdapter(registry, {
239
+ maxRemoteAgents: 1,
240
+ fetchFn: makeMockFetch({
241
+ 'https://agent1.com': card,
242
+ }),
243
+ });
244
+
245
+ await adapter.fetchAndRegister('https://agent1.com');
246
+ const m2 = await adapter.fetchAndRegister('https://agent1.com');
247
+
248
+ expect(m2).not.toBeNull(); // Same ID, should update, not be blocked by capacity
249
+ expect(adapter.remoteAgentCount).toBe(1);
250
+ });
251
+ });
252
+
253
+ describe('pollAll', () => {
254
+ it('polls all seed URLs and returns summary', async () => {
255
+ const adapter = new FederatedRegistryAdapter(registry, {
256
+ seedUrls: [
257
+ 'https://agent1.com/.well-known/agent-card.json',
258
+ 'https://agent2.com/.well-known/agent-card.json',
259
+ 'https://fail.com/.well-known/agent-card.json',
260
+ ],
261
+ fetchFn: makeMockFetch({
262
+ 'https://agent1.com/.well-known/agent-card.json': makeAgentCard({
263
+ id: 'agent-1',
264
+ name: 'Agent 1',
265
+ }),
266
+ 'https://agent2.com/.well-known/agent-card.json': makeAgentCard({
267
+ id: 'agent-2',
268
+ name: 'Agent 2',
269
+ }),
270
+ }),
271
+ });
272
+
273
+ const result = await adapter.pollAll();
274
+
275
+ expect(result.added).toBe(2);
276
+ expect(result.failed).toHaveLength(1);
277
+ expect(result.failed[0]).toBe('https://fail.com/.well-known/agent-card.json');
278
+ expect(registry.size).toBe(2);
279
+ });
280
+
281
+ it('reports updated on subsequent polls', async () => {
282
+ const adapter = new FederatedRegistryAdapter(registry, {
283
+ seedUrls: ['https://agent1.com'],
284
+ fetchFn: makeMockFetch({
285
+ 'https://agent1.com': makeAgentCard({ id: 'agent-1', name: 'Agent 1' }),
286
+ }),
287
+ });
288
+
289
+ const first = await adapter.pollAll();
290
+ expect(first.added).toBe(1);
291
+ expect(first.updated).toBe(0);
292
+
293
+ const second = await adapter.pollAll();
294
+ expect(second.added).toBe(0);
295
+ expect(second.updated).toBe(1);
296
+ });
297
+ });
298
+
299
+ describe('polling lifecycle', () => {
300
+ it('starts and stops polling', () => {
301
+ const adapter = new FederatedRegistryAdapter(registry, { pollIntervalMs: 100_000 });
302
+
303
+ expect(adapter.isPolling).toBe(false);
304
+ adapter.startPolling();
305
+ expect(adapter.isPolling).toBe(true);
306
+ adapter.stopPolling();
307
+ expect(adapter.isPolling).toBe(false);
308
+ });
309
+
310
+ it('does not start duplicate polling timers', () => {
311
+ const adapter = new FederatedRegistryAdapter(registry, { pollIntervalMs: 100_000 });
312
+
313
+ adapter.startPolling();
314
+ adapter.startPolling(); // Should not create a second timer
315
+ expect(adapter.isPolling).toBe(true);
316
+ adapter.stopPolling();
317
+ expect(adapter.isPolling).toBe(false);
318
+ });
319
+ });
320
+
321
+ describe('discoverFederated', () => {
322
+ it('discovers agents across local and remote registries', async () => {
323
+ // Register a local agent
324
+ await registry.register({
325
+ id: 'local-agent',
326
+ name: 'Local Agent',
327
+ version: '1.0.0',
328
+ capabilities: [{ type: 'analyze', domain: 'spatial' }],
329
+ endpoints: [{ protocol: 'local', address: 'local://agent' }],
330
+ trustLevel: 'local',
331
+ });
332
+
333
+ // Set up adapter with a remote agent
334
+ const adapter = new FederatedRegistryAdapter(registry, {
335
+ seedUrls: ['https://remote.com/.well-known/agent-card.json'],
336
+ fetchFn: makeMockFetch({
337
+ 'https://remote.com/.well-known/agent-card.json': makeAgentCard({
338
+ id: 'remote-1',
339
+ name: 'Remote 1',
340
+ skills: [
341
+ {
342
+ id: 's1',
343
+ name: 'Analyze',
344
+ tags: ['analysis', 'spatial'],
345
+ inputModes: [],
346
+ outputModes: [],
347
+ },
348
+ ],
349
+ }),
350
+ }),
351
+ });
352
+
353
+ const matches = await adapter.discoverFederated({
354
+ type: 'analyze',
355
+ domain: 'spatial',
356
+ includeOffline: true,
357
+ });
358
+
359
+ expect(matches.length).toBe(2);
360
+ const ids = matches.map((m) => m.manifest.id);
361
+ expect(ids).toContain('local-agent');
362
+ expect(ids).toContain('remote-1');
363
+ });
364
+ });
365
+
366
+ describe('seed URL management', () => {
367
+ it('addSeedUrl adds a new URL', () => {
368
+ const adapter = new FederatedRegistryAdapter(registry, { seedUrls: ['https://a.com'] });
369
+ adapter.addSeedUrl('https://b.com');
370
+ adapter.addSeedUrl('https://a.com'); // Duplicate, should not add
371
+
372
+ expect(adapter.getRemoteAgentIds()).toHaveLength(0); // No agents yet
373
+ });
374
+
375
+ it('removeSeedUrl deregisters the associated agent', async () => {
376
+ const adapter = new FederatedRegistryAdapter(registry, {
377
+ seedUrls: ['https://agent1.com'],
378
+ fetchFn: makeMockFetch({
379
+ 'https://agent1.com': makeAgentCard({ id: 'agent-1', name: 'Agent 1' }),
380
+ }),
381
+ });
382
+
383
+ await adapter.fetchAndRegister('https://agent1.com');
384
+ expect(registry.has('agent-1')).toBe(true);
385
+
386
+ await adapter.removeSeedUrl('https://agent1.com');
387
+ expect(registry.has('agent-1')).toBe(false);
388
+ });
389
+ });
390
+
391
+ describe('getPollResult', () => {
392
+ it('tracks poll results per URL', async () => {
393
+ const adapter = new FederatedRegistryAdapter(registry, {
394
+ fetchFn: makeMockFetch({
395
+ 'https://ok.com': makeAgentCard(),
396
+ }),
397
+ });
398
+
399
+ await adapter.fetchAndRegister('https://ok.com');
400
+ await adapter.fetchAndRegister('https://fail.com');
401
+
402
+ const okResult = adapter.getPollResult('https://ok.com');
403
+ expect(okResult?.success).toBe(true);
404
+
405
+ const failResult = adapter.getPollResult('https://fail.com');
406
+ expect(failResult?.success).toBe(false);
407
+ });
408
+ });
409
+ });