@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,464 @@
1
+ /**
2
+ * AgentBudgetEnforcer — Per-agent budget caps with enforcement
3
+ *
4
+ * Tracks spending per agent with configurable enforcement modes
5
+ * (warn, soft, hard) and budget periods. Includes circuit breaker
6
+ * for consecutive failures or overspend.
7
+ *
8
+ * Part of HoloScript v5.8 "Live Economy".
9
+ *
10
+ * @version 1.0.0
11
+ */
12
+
13
+ import type { TelemetryCollector } from './_core-stubs';
14
+
15
+ // =============================================================================
16
+ // TYPES
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Enforcement mode for budget limits.
21
+ */
22
+ export type EnforcementMode = 'warn' | 'soft' | 'hard';
23
+
24
+ /**
25
+ * Budget period type.
26
+ */
27
+ export type BudgetPeriod = 'per-request' | 'per-session' | 'daily' | 'monthly';
28
+
29
+ /**
30
+ * Budget configuration for an agent.
31
+ */
32
+ export interface AgentBudget {
33
+ /** Agent ID */
34
+ agentId: string;
35
+ /** Maximum spend per period (USDC base units, 6 decimals) */
36
+ maxSpend: number;
37
+ /** Budget period */
38
+ period: BudgetPeriod;
39
+ /** Enforcement mode */
40
+ mode: EnforcementMode;
41
+ /** Warning threshold (fraction 0-1, e.g. 0.8 = warn at 80%) */
42
+ warnThreshold?: number;
43
+ /** Circuit breaker: max consecutive failures before tripping */
44
+ circuitBreakerThreshold?: number;
45
+ }
46
+
47
+ /**
48
+ * Current budget state for an agent.
49
+ */
50
+ export interface BudgetState {
51
+ /** Agent ID */
52
+ agentId: string;
53
+ /** Amount spent in current period (USDC base units) */
54
+ spent: number;
55
+ /** Budget limit (USDC base units) */
56
+ limit: number;
57
+ /** Budget remaining (USDC base units) */
58
+ remaining: number;
59
+ /** Whether budget is exhausted */
60
+ exhausted: boolean;
61
+ /** Whether warning threshold is reached */
62
+ warning: boolean;
63
+ /** Current enforcement mode */
64
+ mode: EnforcementMode;
65
+ /** Current period */
66
+ period: BudgetPeriod;
67
+ /** Period start (ISO 8601) */
68
+ periodStart: string;
69
+ /** Number of requests in this period */
70
+ requestCount: number;
71
+ /** Circuit breaker state */
72
+ circuitBreaker: CircuitBreakerState;
73
+ }
74
+
75
+ /**
76
+ * Circuit breaker state.
77
+ */
78
+ export interface CircuitBreakerState {
79
+ /** Whether the circuit breaker is open (tripped) */
80
+ isOpen: boolean;
81
+ /** Consecutive failure count */
82
+ consecutiveFailures: number;
83
+ /** Maximum consecutive failures */
84
+ threshold: number;
85
+ /** When the circuit breaker was tripped (ISO 8601, null if not tripped) */
86
+ trippedAt: string | null;
87
+ /** When the circuit breaker will reset (ISO 8601, null if not tripped) */
88
+ resetAt: string | null;
89
+ }
90
+
91
+ /**
92
+ * Result of a spend authorization check.
93
+ */
94
+ export interface SpendAuthorizationResult {
95
+ /** Whether the spend is authorized */
96
+ authorized: boolean;
97
+ /** Reason for denial */
98
+ reason?: string;
99
+ /** Current budget state */
100
+ state: BudgetState;
101
+ /** Whether this is a warning (authorized but near limit) */
102
+ warning?: boolean;
103
+ /** Warning message */
104
+ warningMessage?: string;
105
+ }
106
+
107
+ /**
108
+ * AgentBudgetEnforcer configuration.
109
+ */
110
+ export interface BudgetEnforcerConfig {
111
+ /** Default budget for agents without explicit config */
112
+ defaultBudget?: Partial<AgentBudget>;
113
+ /** Circuit breaker reset timeout (ms, default: 60s) */
114
+ circuitBreakerResetMs?: number;
115
+ /** Telemetry collector */
116
+ telemetry?: TelemetryCollector;
117
+ }
118
+
119
+ // =============================================================================
120
+ // INTERNAL TRACKING
121
+ // =============================================================================
122
+
123
+ interface AgentTracker {
124
+ budget: AgentBudget;
125
+ spent: number;
126
+ requestCount: number;
127
+ periodStart: number;
128
+ consecutiveFailures: number;
129
+ circuitBreakerTrippedAt: number | null;
130
+ sessionId: string;
131
+ }
132
+
133
+ // =============================================================================
134
+ // AGENT BUDGET ENFORCER
135
+ // =============================================================================
136
+
137
+ export class AgentBudgetEnforcer {
138
+ private trackers: Map<string, AgentTracker> = new Map();
139
+ private config: Required<Omit<BudgetEnforcerConfig, 'telemetry' | 'defaultBudget'>> & {
140
+ telemetry?: TelemetryCollector;
141
+ defaultBudget: AgentBudget;
142
+ };
143
+ private sessionCounter = 0;
144
+
145
+ constructor(config?: BudgetEnforcerConfig) {
146
+ this.config = {
147
+ defaultBudget: {
148
+ agentId: '',
149
+ maxSpend: 10_000_000, // $10.00 default
150
+ period: 'daily',
151
+ mode: 'soft',
152
+ warnThreshold: 0.8,
153
+ circuitBreakerThreshold: 5,
154
+ ...config?.defaultBudget,
155
+ } as AgentBudget,
156
+ circuitBreakerResetMs: config?.circuitBreakerResetMs ?? 60_000,
157
+ telemetry: config?.telemetry,
158
+ };
159
+ }
160
+
161
+ // ===========================================================================
162
+ // BUDGET MANAGEMENT
163
+ // ===========================================================================
164
+
165
+ /**
166
+ * Set budget for an agent.
167
+ */
168
+ setBudget(budget: AgentBudget): void {
169
+ const existing = this.trackers.get(budget.agentId);
170
+ if (existing) {
171
+ existing.budget = { ...budget };
172
+ } else {
173
+ this.trackers.set(budget.agentId, {
174
+ budget: { ...budget },
175
+ spent: 0,
176
+ requestCount: 0,
177
+ periodStart: Date.now(),
178
+ consecutiveFailures: 0,
179
+ circuitBreakerTrippedAt: null,
180
+ sessionId: `session-${++this.sessionCounter}`,
181
+ });
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Get budget configuration for an agent.
187
+ */
188
+ getBudget(agentId: string): AgentBudget | undefined {
189
+ return this.trackers.get(agentId)?.budget;
190
+ }
191
+
192
+ /**
193
+ * Remove budget for an agent.
194
+ */
195
+ removeBudget(agentId: string): boolean {
196
+ return this.trackers.delete(agentId);
197
+ }
198
+
199
+ // ===========================================================================
200
+ // AUTHORIZATION
201
+ // ===========================================================================
202
+
203
+ /**
204
+ * Check if an agent is authorized to spend a given amount.
205
+ */
206
+ authorize(agentId: string, amount: number): SpendAuthorizationResult {
207
+ const tracker = this.getOrCreateTracker(agentId);
208
+ this.checkPeriodReset(tracker);
209
+
210
+ const state = this.buildState(tracker);
211
+
212
+ // Check circuit breaker first
213
+ if (state.circuitBreaker.isOpen) {
214
+ // Check if reset time has passed
215
+ if (tracker.circuitBreakerTrippedAt) {
216
+ const elapsed = Date.now() - tracker.circuitBreakerTrippedAt;
217
+ if (elapsed >= this.config.circuitBreakerResetMs) {
218
+ // Reset circuit breaker
219
+ tracker.consecutiveFailures = 0;
220
+ tracker.circuitBreakerTrippedAt = null;
221
+ } else {
222
+ this.emitTelemetry('budget_circuit_breaker_blocked', { agentId, amount });
223
+ return {
224
+ authorized: false,
225
+ reason: `Circuit breaker open: ${tracker.consecutiveFailures} consecutive failures. Resets in ${Math.ceil((this.config.circuitBreakerResetMs - elapsed) / 1000)}s`,
226
+ state: this.buildState(tracker),
227
+ };
228
+ }
229
+ }
230
+ }
231
+
232
+ // Check budget
233
+ const wouldExceed = tracker.spent + amount > tracker.budget.maxSpend;
234
+ const warnThreshold = tracker.budget.warnThreshold ?? 0.8;
235
+ const atWarningLevel = (tracker.spent + amount) / tracker.budget.maxSpend >= warnThreshold;
236
+
237
+ if (wouldExceed) {
238
+ switch (tracker.budget.mode) {
239
+ case 'hard':
240
+ this.emitTelemetry('budget_hard_denied', {
241
+ agentId,
242
+ amount,
243
+ spent: tracker.spent,
244
+ limit: tracker.budget.maxSpend,
245
+ });
246
+ return {
247
+ authorized: false,
248
+ reason: `Budget exhausted (hard limit): spent ${tracker.spent} + ${amount} > limit ${tracker.budget.maxSpend}`,
249
+ state: this.buildState(tracker),
250
+ };
251
+
252
+ case 'soft':
253
+ this.emitTelemetry('budget_soft_denied', { agentId, amount, spent: tracker.spent });
254
+ return {
255
+ authorized: false,
256
+ reason: `Budget exhausted (soft limit): spent ${tracker.spent} + ${amount} > limit ${tracker.budget.maxSpend}`,
257
+ state: this.buildState(tracker),
258
+ };
259
+
260
+ case 'warn':
261
+ // Allow but warn
262
+ this.emitTelemetry('budget_warn_overspend', { agentId, amount });
263
+ return {
264
+ authorized: true,
265
+ state: this.buildState(tracker),
266
+ warning: true,
267
+ warningMessage: `Budget exceeded: spent ${tracker.spent} + ${amount} > limit ${tracker.budget.maxSpend}`,
268
+ };
269
+ }
270
+ }
271
+
272
+ // Check warning level
273
+ if (atWarningLevel && !wouldExceed) {
274
+ return {
275
+ authorized: true,
276
+ state: this.buildState(tracker),
277
+ warning: true,
278
+ warningMessage: `Approaching budget limit: ${Math.round(((tracker.spent + amount) / tracker.budget.maxSpend) * 100)}% used`,
279
+ };
280
+ }
281
+
282
+ return {
283
+ authorized: true,
284
+ state: this.buildState(tracker),
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Record a spend. Call after a successful tool execution.
290
+ */
291
+ recordSpend(agentId: string, amount: number): void {
292
+ const tracker = this.getOrCreateTracker(agentId);
293
+ this.checkPeriodReset(tracker);
294
+ tracker.spent += amount;
295
+ tracker.requestCount++;
296
+ tracker.consecutiveFailures = 0; // Reset on success
297
+
298
+ this.emitTelemetry('budget_spend_recorded', { agentId, amount, totalSpent: tracker.spent });
299
+ }
300
+
301
+ /**
302
+ * Record a failure. Increments circuit breaker counter.
303
+ */
304
+ recordFailure(agentId: string): void {
305
+ const tracker = this.getOrCreateTracker(agentId);
306
+ tracker.consecutiveFailures++;
307
+
308
+ const threshold = tracker.budget.circuitBreakerThreshold ?? 5;
309
+ if (tracker.consecutiveFailures >= threshold && !tracker.circuitBreakerTrippedAt) {
310
+ tracker.circuitBreakerTrippedAt = Date.now();
311
+ this.emitTelemetry('budget_circuit_breaker_tripped', {
312
+ agentId,
313
+ failures: tracker.consecutiveFailures,
314
+ threshold,
315
+ });
316
+ }
317
+ }
318
+
319
+ // ===========================================================================
320
+ // QUERIES
321
+ // ===========================================================================
322
+
323
+ /**
324
+ * Get current budget state for an agent.
325
+ */
326
+ getState(agentId: string): BudgetState | undefined {
327
+ const tracker = this.trackers.get(agentId);
328
+ if (!tracker) return undefined;
329
+ this.checkPeriodReset(tracker);
330
+ return this.buildState(tracker);
331
+ }
332
+
333
+ /**
334
+ * Get all agent budget states.
335
+ */
336
+ getAllStates(): BudgetState[] {
337
+ return [...this.trackers.keys()].map((id) => this.getState(id)!).filter(Boolean);
338
+ }
339
+
340
+ /**
341
+ * Get agents that are over budget.
342
+ */
343
+ getOverBudgetAgents(): BudgetState[] {
344
+ return this.getAllStates().filter((s) => s.exhausted || s.circuitBreaker.isOpen);
345
+ }
346
+
347
+ /**
348
+ * Reset an agent's period spending.
349
+ */
350
+ resetSpending(agentId: string): void {
351
+ const tracker = this.trackers.get(agentId);
352
+ if (tracker) {
353
+ tracker.spent = 0;
354
+ tracker.requestCount = 0;
355
+ tracker.periodStart = Date.now();
356
+ tracker.consecutiveFailures = 0;
357
+ tracker.circuitBreakerTrippedAt = null;
358
+ tracker.sessionId = `session-${++this.sessionCounter}`;
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Reset circuit breaker for an agent.
364
+ */
365
+ resetCircuitBreaker(agentId: string): void {
366
+ const tracker = this.trackers.get(agentId);
367
+ if (tracker) {
368
+ tracker.consecutiveFailures = 0;
369
+ tracker.circuitBreakerTrippedAt = null;
370
+ }
371
+ }
372
+
373
+ // ===========================================================================
374
+ // INTERNALS
375
+ // ===========================================================================
376
+
377
+ private getOrCreateTracker(agentId: string): AgentTracker {
378
+ let tracker = this.trackers.get(agentId);
379
+ if (!tracker) {
380
+ tracker = {
381
+ budget: { ...this.config.defaultBudget, agentId },
382
+ spent: 0,
383
+ requestCount: 0,
384
+ periodStart: Date.now(),
385
+ consecutiveFailures: 0,
386
+ circuitBreakerTrippedAt: null,
387
+ sessionId: `session-${++this.sessionCounter}`,
388
+ };
389
+ this.trackers.set(agentId, tracker);
390
+ }
391
+ return tracker;
392
+ }
393
+
394
+ private checkPeriodReset(tracker: AgentTracker): void {
395
+ const now = Date.now();
396
+ const elapsed = now - tracker.periodStart;
397
+
398
+ let shouldReset = false;
399
+ switch (tracker.budget.period) {
400
+ case 'per-request':
401
+ shouldReset = tracker.requestCount > 0;
402
+ break;
403
+ case 'per-session':
404
+ // Sessions don't auto-reset — must call resetSpending()
405
+ break;
406
+ case 'daily':
407
+ shouldReset = elapsed >= 86400_000;
408
+ break;
409
+ case 'monthly':
410
+ shouldReset = elapsed >= 30 * 86400_000;
411
+ break;
412
+ }
413
+
414
+ if (shouldReset) {
415
+ tracker.spent = 0;
416
+ tracker.requestCount = 0;
417
+ tracker.periodStart = now;
418
+ tracker.sessionId = `session-${++this.sessionCounter}`;
419
+ }
420
+ }
421
+
422
+ private buildState(tracker: AgentTracker): BudgetState {
423
+ const remaining = Math.max(0, tracker.budget.maxSpend - tracker.spent);
424
+ const warnThreshold = tracker.budget.warnThreshold ?? 0.8;
425
+ const cbThreshold = tracker.budget.circuitBreakerThreshold ?? 5;
426
+
427
+ return {
428
+ agentId: tracker.budget.agentId,
429
+ spent: tracker.spent,
430
+ limit: tracker.budget.maxSpend,
431
+ remaining,
432
+ exhausted: remaining === 0,
433
+ warning: tracker.spent / tracker.budget.maxSpend >= warnThreshold,
434
+ mode: tracker.budget.mode,
435
+ period: tracker.budget.period,
436
+ periodStart: new Date(tracker.periodStart).toISOString(),
437
+ requestCount: tracker.requestCount,
438
+ circuitBreaker: {
439
+ isOpen:
440
+ tracker.circuitBreakerTrippedAt !== null &&
441
+ Date.now() - tracker.circuitBreakerTrippedAt < this.config.circuitBreakerResetMs,
442
+ consecutiveFailures: tracker.consecutiveFailures,
443
+ threshold: cbThreshold,
444
+ trippedAt: tracker.circuitBreakerTrippedAt
445
+ ? new Date(tracker.circuitBreakerTrippedAt).toISOString()
446
+ : null,
447
+ resetAt: tracker.circuitBreakerTrippedAt
448
+ ? new Date(
449
+ tracker.circuitBreakerTrippedAt + this.config.circuitBreakerResetMs
450
+ ).toISOString()
451
+ : null,
452
+ },
453
+ };
454
+ }
455
+
456
+ private emitTelemetry(type: string, data?: Record<string, unknown>): void {
457
+ this.config.telemetry?.record({
458
+ type,
459
+ severity: type.includes('denied') || type.includes('tripped') ? 'warning' : 'info',
460
+ agentId: (data?.agentId as string) || 'budget-enforcer',
461
+ data,
462
+ });
463
+ }
464
+ }
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Bounty Manager — Task-based incentive system for agent teams.
3
+ *
4
+ * Creates, claims, and settles bounties tied to board tasks.
5
+ * Integrates with X402Facilitator for on-chain or in-memory payouts.
6
+ *
7
+ * FW-0.6
8
+ */
9
+
10
+ import type { X402Facilitator, MicroPaymentLedger } from './x402-facilitator';
11
+
12
+ // ── Types ──
13
+
14
+ export type BountyCurrency = 'USDC' | 'credits';
15
+ export type BountyStatus = 'open' | 'claimed' | 'completed' | 'expired' | 'disputed';
16
+
17
+ export interface BountyReward {
18
+ amount: number;
19
+ currency: BountyCurrency;
20
+ }
21
+
22
+ export interface Bounty {
23
+ id: string;
24
+ taskId: string;
25
+ reward: BountyReward;
26
+ status: BountyStatus;
27
+ createdBy: string;
28
+ claimedBy?: string;
29
+ completedAt?: string;
30
+ deadline?: number;
31
+ createdAt: string;
32
+ }
33
+
34
+ export interface ClaimResult {
35
+ success: boolean;
36
+ bountyId: string;
37
+ error?: string;
38
+ }
39
+
40
+ export interface CompletionProof {
41
+ commitHash?: string;
42
+ summary: string;
43
+ /** Arbitrary evidence (test output, URLs, etc.) */
44
+ evidence?: string[];
45
+ }
46
+
47
+ export interface PayoutResult {
48
+ success: boolean;
49
+ bountyId: string;
50
+ amount: number;
51
+ currency: BountyCurrency;
52
+ /** Settlement method used (ledger for credits/micro, on-chain for larger USDC) */
53
+ settlement: 'ledger' | 'on_chain';
54
+ error?: string;
55
+ }
56
+
57
+ export interface BountyManagerConfig {
58
+ /** Optional X402Facilitator for USDC payouts. Without it, only credits work. */
59
+ facilitator?: X402Facilitator;
60
+ /** Optional MicroPaymentLedger for credit-based or micro USDC payouts. */
61
+ ledger?: MicroPaymentLedger;
62
+ /** Default deadline in ms from creation (default: 7 days). */
63
+ defaultDeadlineMs?: number;
64
+ }
65
+
66
+ // ── Manager ──
67
+
68
+ export class BountyManager {
69
+ private bounties: Map<string, Bounty> = new Map();
70
+ private nextId = 1;
71
+ private config: BountyManagerConfig;
72
+
73
+ constructor(config: BountyManagerConfig = {}) {
74
+ this.config = config;
75
+ }
76
+
77
+ /** Create a bounty for a board task. */
78
+ createBounty(
79
+ taskId: string,
80
+ reward: BountyReward,
81
+ createdBy: string,
82
+ deadline?: number,
83
+ ): Bounty {
84
+ if (reward.amount <= 0) throw new Error('Bounty reward must be positive');
85
+
86
+ const id = `bounty_${String(this.nextId++).padStart(4, '0')}`;
87
+ const now = Date.now();
88
+
89
+ const bounty: Bounty = {
90
+ id,
91
+ taskId,
92
+ reward,
93
+ status: 'open',
94
+ createdBy,
95
+ createdAt: new Date().toISOString(),
96
+ deadline: deadline ?? (this.config.defaultDeadlineMs
97
+ ? now + this.config.defaultDeadlineMs
98
+ : undefined),
99
+ };
100
+
101
+ this.bounties.set(id, bounty);
102
+ return bounty;
103
+ }
104
+
105
+ /** Claim an open bounty. */
106
+ claimBounty(bountyId: string, agentId: string): ClaimResult {
107
+ const bounty = this.bounties.get(bountyId);
108
+ if (!bounty) return { success: false, bountyId, error: 'Bounty not found' };
109
+ if (bounty.status !== 'open') return { success: false, bountyId, error: `Bounty is ${bounty.status}, not open` };
110
+
111
+ // Check deadline
112
+ if (bounty.deadline && Date.now() > bounty.deadline) {
113
+ bounty.status = 'expired';
114
+ return { success: false, bountyId, error: 'Bounty has expired' };
115
+ }
116
+
117
+ bounty.status = 'claimed';
118
+ bounty.claimedBy = agentId;
119
+ return { success: true, bountyId };
120
+ }
121
+
122
+ /** Complete a bounty with proof of work and trigger payout. */
123
+ completeBounty(bountyId: string, proof: CompletionProof): PayoutResult {
124
+ const bounty = this.bounties.get(bountyId);
125
+ if (!bounty) return { success: false, bountyId, amount: 0, currency: 'credits', settlement: 'ledger', error: 'Bounty not found' };
126
+ if (bounty.status !== 'claimed') return { success: false, bountyId, amount: 0, currency: bounty.reward.currency, settlement: 'ledger', error: `Bounty is ${bounty.status}, not claimed` };
127
+
128
+ if (!proof.summary || proof.summary.trim().length === 0) {
129
+ return { success: false, bountyId, amount: 0, currency: bounty.reward.currency, settlement: 'ledger', error: 'Completion proof requires a summary' };
130
+ }
131
+
132
+ bounty.status = 'completed';
133
+ bounty.completedAt = new Date().toISOString();
134
+
135
+ // Determine settlement method
136
+ const settlement: 'ledger' | 'on_chain' =
137
+ bounty.reward.currency === 'credits' ? 'ledger' :
138
+ bounty.reward.amount < 0.10 ? 'ledger' : 'on_chain';
139
+
140
+ return {
141
+ success: true,
142
+ bountyId,
143
+ amount: bounty.reward.amount,
144
+ currency: bounty.reward.currency,
145
+ settlement,
146
+ };
147
+ }
148
+
149
+ /** Get a bounty by ID. */
150
+ getBounty(bountyId: string): Bounty | undefined {
151
+ return this.bounties.get(bountyId);
152
+ }
153
+
154
+ /** List bounties, optionally filtered by status. */
155
+ list(status?: BountyStatus): Bounty[] {
156
+ const all = Array.from(this.bounties.values());
157
+ if (!status) return all;
158
+ return all.filter(b => b.status === status);
159
+ }
160
+
161
+ /** List bounties for a specific task. */
162
+ byTask(taskId: string): Bounty[] {
163
+ return Array.from(this.bounties.values()).filter(b => b.taskId === taskId);
164
+ }
165
+
166
+ /** Expire bounties past their deadline. Returns count expired. */
167
+ expireStale(): number {
168
+ const now = Date.now();
169
+ let count = 0;
170
+ for (const bounty of this.bounties.values()) {
171
+ if (bounty.deadline && now > bounty.deadline && bounty.status === 'open') {
172
+ bounty.status = 'expired';
173
+ count++;
174
+ }
175
+ }
176
+ return count;
177
+ }
178
+
179
+ /** Total open bounty value in a given currency. */
180
+ totalOpen(currency?: BountyCurrency): number {
181
+ return this.list('open')
182
+ .filter(b => !currency || b.reward.currency === currency)
183
+ .reduce((sum, b) => sum + b.reward.amount, 0);
184
+ }
185
+ }