@vauban-org/agent-sdk 0.17.4 → 1.2.0

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 (506) hide show
  1. package/CONTRACT.md +6401 -813
  2. package/dist/adapters/llm/anthropic-direct.d.ts +1 -0
  3. package/dist/adapters/llm/anthropic-direct.d.ts.map +1 -1
  4. package/dist/adapters/llm/anthropic-direct.js +43 -0
  5. package/dist/adapters/llm/anthropic-direct.js.map +1 -1
  6. package/dist/adapters/llm/cascade.d.ts.map +1 -1
  7. package/dist/adapters/llm/cascade.js +57 -14
  8. package/dist/adapters/llm/cascade.js.map +1 -1
  9. package/dist/adapters/llm/litellm.d.ts +2 -0
  10. package/dist/adapters/llm/litellm.d.ts.map +1 -1
  11. package/dist/adapters/llm/litellm.js +44 -0
  12. package/dist/adapters/llm/litellm.js.map +1 -1
  13. package/dist/compute/difficulty-estimator.d.ts +53 -0
  14. package/dist/compute/difficulty-estimator.d.ts.map +1 -0
  15. package/dist/compute/difficulty-estimator.js +82 -0
  16. package/dist/compute/difficulty-estimator.js.map +1 -0
  17. package/dist/compute/strategies/mixture-of-agents.d.ts +40 -0
  18. package/dist/compute/strategies/mixture-of-agents.d.ts.map +1 -0
  19. package/dist/compute/strategies/mixture-of-agents.js +110 -0
  20. package/dist/compute/strategies/mixture-of-agents.js.map +1 -0
  21. package/dist/compute/strategies/tree-of-thoughts.d.ts +48 -0
  22. package/dist/compute/strategies/tree-of-thoughts.d.ts.map +1 -0
  23. package/dist/compute/strategies/tree-of-thoughts.js +242 -0
  24. package/dist/compute/strategies/tree-of-thoughts.js.map +1 -0
  25. package/dist/compute/strategies/two-phase-orient.d.ts +72 -0
  26. package/dist/compute/strategies/two-phase-orient.d.ts.map +1 -0
  27. package/dist/compute/strategies/two-phase-orient.js +85 -0
  28. package/dist/compute/strategies/two-phase-orient.js.map +1 -0
  29. package/dist/constitution/types.d.ts +10 -10
  30. package/dist/container/protocol.d.ts +134 -0
  31. package/dist/container/protocol.d.ts.map +1 -0
  32. package/dist/container/protocol.js +157 -0
  33. package/dist/container/protocol.js.map +1 -0
  34. package/dist/container/runtime.d.ts +140 -0
  35. package/dist/container/runtime.d.ts.map +1 -0
  36. package/dist/container/runtime.js +256 -0
  37. package/dist/container/runtime.js.map +1 -0
  38. package/dist/events/catalogue.d.ts +327 -30
  39. package/dist/events/catalogue.d.ts.map +1 -1
  40. package/dist/events/catalogue.js +18 -0
  41. package/dist/events/catalogue.js.map +1 -1
  42. package/dist/events/index.d.ts +9 -0
  43. package/dist/events/index.d.ts.map +1 -1
  44. package/dist/events/index.js +9 -0
  45. package/dist/events/index.js.map +1 -1
  46. package/dist/events/schemas/agent.completed.v1.d.ts +4 -4
  47. package/dist/events/schemas/agent.failed.v1.d.ts +2 -2
  48. package/dist/events/schemas/agent.hitl_resolved.v1.d.ts +2 -2
  49. package/dist/events/schemas/agent.started.v1.d.ts +2 -2
  50. package/dist/events/schemas/brain.skill.extracted.v1.d.ts +4 -4
  51. package/dist/events/schemas/cc.cost.anomaly_detected.v1.d.ts +2 -2
  52. package/dist/events/schemas/cc.cost.recorded.v1.d.ts +4 -4
  53. package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts +55 -0
  54. package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts.map +1 -0
  55. package/dist/events/schemas/citadel.sprint.analyzed.v1.js +22 -0
  56. package/dist/events/schemas/citadel.sprint.analyzed.v1.js.map +1 -0
  57. package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
  58. package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +33 -0
  59. package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts.map +1 -0
  60. package/dist/events/schemas/forge.inbox.reply_classified.v1.js +15 -0
  61. package/dist/events/schemas/forge.inbox.reply_classified.v1.js.map +1 -0
  62. package/dist/events/schemas/forge.lead.qualified.v1.d.ts +2 -2
  63. package/dist/events/schemas/forge.outreach.sent.v1.d.ts +4 -4
  64. package/dist/events/schemas/incident.detected.v1.d.ts +2 -2
  65. package/dist/events/schemas/vauban-finance.forecast.generated.v1.d.ts +21 -0
  66. package/dist/events/schemas/vauban-finance.forecast.generated.v1.d.ts.map +1 -0
  67. package/dist/events/schemas/vauban-finance.forecast.generated.v1.js +11 -0
  68. package/dist/events/schemas/vauban-finance.forecast.generated.v1.js.map +1 -0
  69. package/dist/events/schemas/vauban-finance.trade.executed.v1.d.ts +24 -0
  70. package/dist/events/schemas/vauban-finance.trade.executed.v1.d.ts.map +1 -0
  71. package/dist/events/schemas/vauban-finance.trade.executed.v1.js +12 -0
  72. package/dist/events/schemas/vauban-finance.trade.executed.v1.js.map +1 -0
  73. package/dist/events/schemas/vauban.goal.checked.v1.d.ts +21 -0
  74. package/dist/events/schemas/vauban.goal.checked.v1.d.ts.map +1 -0
  75. package/dist/events/schemas/vauban.goal.checked.v1.js +11 -0
  76. package/dist/events/schemas/vauban.goal.checked.v1.js.map +1 -0
  77. package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +21 -0
  78. package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts.map +1 -0
  79. package/dist/events/schemas/vauban.rebalancing.checked.v1.js +11 -0
  80. package/dist/events/schemas/vauban.rebalancing.checked.v1.js.map +1 -0
  81. package/dist/events/schemas/vauban.tax.checked.v1.d.ts +21 -0
  82. package/dist/events/schemas/vauban.tax.checked.v1.d.ts.map +1 -0
  83. package/dist/events/schemas/vauban.tax.checked.v1.js +11 -0
  84. package/dist/events/schemas/vauban.tax.checked.v1.js.map +1 -0
  85. package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +59 -0
  86. package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts.map +1 -0
  87. package/dist/events/schemas/vauban.vault.analyzed.v1.js +19 -0
  88. package/dist/events/schemas/vauban.vault.analyzed.v1.js.map +1 -0
  89. package/dist/events/schemas/vauban.vault.compounded.v1.d.ts +24 -0
  90. package/dist/events/schemas/vauban.vault.compounded.v1.d.ts.map +1 -0
  91. package/dist/events/schemas/vauban.vault.compounded.v1.js +12 -0
  92. package/dist/events/schemas/vauban.vault.compounded.v1.js.map +1 -0
  93. package/dist/identity/agent-persona.d.ts +73 -0
  94. package/dist/identity/agent-persona.d.ts.map +1 -0
  95. package/dist/identity/agent-persona.js +165 -0
  96. package/dist/identity/agent-persona.js.map +1 -0
  97. package/dist/identity/persona-prompt.d.ts +25 -0
  98. package/dist/identity/persona-prompt.d.ts.map +1 -0
  99. package/dist/identity/persona-prompt.js +71 -0
  100. package/dist/identity/persona-prompt.js.map +1 -0
  101. package/dist/identity/persona-schema.d.ts +120 -0
  102. package/dist/identity/persona-schema.d.ts.map +1 -0
  103. package/dist/identity/persona-schema.js +103 -0
  104. package/dist/identity/persona-schema.js.map +1 -0
  105. package/dist/index.d.ts +37 -2
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +29 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/loop/index.d.ts +1 -1
  110. package/dist/loop/index.d.ts.map +1 -1
  111. package/dist/loop/index.js.map +1 -1
  112. package/dist/loop/minimal-loop.js +293 -287
  113. package/dist/loop/sdk-loop.d.ts +1 -3
  114. package/dist/loop/sdk-loop.d.ts.map +1 -1
  115. package/dist/loop/sdk-loop.js +1 -1
  116. package/dist/loop/sdk-loop.js.map +1 -1
  117. package/dist/memory/episodic-rrf.d.ts +114 -0
  118. package/dist/memory/episodic-rrf.d.ts.map +1 -0
  119. package/dist/memory/episodic-rrf.js +148 -0
  120. package/dist/memory/episodic-rrf.js.map +1 -0
  121. package/dist/mesh/attenuation.d.ts +78 -0
  122. package/dist/mesh/attenuation.d.ts.map +1 -0
  123. package/dist/mesh/attenuation.js +141 -0
  124. package/dist/mesh/attenuation.js.map +1 -0
  125. package/dist/mesh/delegate.d.ts +96 -0
  126. package/dist/mesh/delegate.d.ts.map +1 -0
  127. package/dist/mesh/delegate.js +172 -0
  128. package/dist/mesh/delegate.js.map +1 -0
  129. package/dist/mesh/dispatcher.d.ts +119 -0
  130. package/dist/mesh/dispatcher.d.ts.map +1 -0
  131. package/dist/mesh/dispatcher.js +207 -0
  132. package/dist/mesh/dispatcher.js.map +1 -0
  133. package/dist/mesh/index.d.ts +12 -0
  134. package/dist/mesh/index.d.ts.map +1 -0
  135. package/dist/mesh/index.js +11 -0
  136. package/dist/mesh/index.js.map +1 -0
  137. package/dist/mesh/types.d.ts +30 -0
  138. package/dist/mesh/types.d.ts.map +1 -0
  139. package/dist/mesh/types.js +11 -0
  140. package/dist/mesh/types.js.map +1 -0
  141. package/dist/orchestration/ooda/skills.d.ts +104 -0
  142. package/dist/orchestration/ooda/skills.d.ts.map +1 -1
  143. package/dist/orchestration/ooda/skills.js +106 -0
  144. package/dist/orchestration/ooda/skills.js.map +1 -1
  145. package/dist/orchestration/ooda/types.d.ts +3 -8
  146. package/dist/orchestration/ooda/types.d.ts.map +1 -1
  147. package/dist/ports/bastion-action.contract.test.d.ts +11 -0
  148. package/dist/ports/bastion-action.contract.test.d.ts.map +1 -0
  149. package/dist/ports/bastion-action.contract.test.js +238 -0
  150. package/dist/ports/bastion-action.contract.test.js.map +1 -0
  151. package/dist/ports/bastion-action.d.ts +133 -0
  152. package/dist/ports/bastion-action.d.ts.map +1 -0
  153. package/dist/ports/bastion-action.js +73 -0
  154. package/dist/ports/bastion-action.js.map +1 -0
  155. package/dist/ports/brain.d.ts +31 -0
  156. package/dist/ports/brain.d.ts.map +1 -1
  157. package/dist/ports/brain.js +115 -1
  158. package/dist/ports/brain.js.map +1 -1
  159. package/dist/ports/citadel-action.contract.test.d.ts +11 -0
  160. package/dist/ports/citadel-action.contract.test.d.ts.map +1 -0
  161. package/dist/ports/citadel-action.contract.test.js +317 -0
  162. package/dist/ports/citadel-action.contract.test.js.map +1 -0
  163. package/dist/ports/citadel-action.d.ts +111 -0
  164. package/dist/ports/citadel-action.d.ts.map +1 -0
  165. package/dist/ports/citadel-action.js +62 -0
  166. package/dist/ports/citadel-action.js.map +1 -0
  167. package/dist/ports/compliance-contract.d.ts +123 -0
  168. package/dist/ports/compliance-contract.d.ts.map +1 -0
  169. package/dist/ports/compliance-contract.js +35 -0
  170. package/dist/ports/compliance-contract.js.map +1 -0
  171. package/dist/ports/db.d.ts +38 -0
  172. package/dist/ports/db.d.ts.map +1 -1
  173. package/dist/ports/db.js +88 -1
  174. package/dist/ports/db.js.map +1 -1
  175. package/dist/ports/delegation.contract.test.d.ts +9 -0
  176. package/dist/ports/delegation.contract.test.d.ts.map +1 -0
  177. package/dist/ports/delegation.contract.test.js +337 -0
  178. package/dist/ports/delegation.contract.test.js.map +1 -0
  179. package/dist/ports/delegation.d.ts +134 -0
  180. package/dist/ports/delegation.d.ts.map +1 -0
  181. package/dist/ports/delegation.js +105 -0
  182. package/dist/ports/delegation.js.map +1 -0
  183. package/dist/ports/event-bus.d.ts +29 -13
  184. package/dist/ports/event-bus.d.ts.map +1 -1
  185. package/dist/ports/event-bus.js +106 -1
  186. package/dist/ports/event-bus.js.map +1 -1
  187. package/dist/ports/federation.contract.test.d.ts +9 -0
  188. package/dist/ports/federation.contract.test.d.ts.map +1 -0
  189. package/dist/ports/federation.contract.test.js +279 -0
  190. package/dist/ports/federation.contract.test.js.map +1 -0
  191. package/dist/ports/federation.d.ts +140 -0
  192. package/dist/ports/federation.d.ts.map +1 -0
  193. package/dist/ports/federation.js +57 -0
  194. package/dist/ports/federation.js.map +1 -0
  195. package/dist/ports/index.d.ts +28 -2
  196. package/dist/ports/index.d.ts.map +1 -1
  197. package/dist/ports/index.js +17 -2
  198. package/dist/ports/index.js.map +1 -1
  199. package/dist/ports/llm-provider.d.ts +37 -0
  200. package/dist/ports/llm-provider.d.ts.map +1 -1
  201. package/dist/ports/llm-provider.js +99 -1
  202. package/dist/ports/llm-provider.js.map +1 -1
  203. package/dist/ports/logger.d.ts +27 -0
  204. package/dist/ports/logger.d.ts.map +1 -1
  205. package/dist/ports/logger.js +87 -0
  206. package/dist/ports/logger.js.map +1 -1
  207. package/dist/ports/manifest-registry.contract.test.d.ts +9 -0
  208. package/dist/ports/manifest-registry.contract.test.d.ts.map +1 -0
  209. package/dist/ports/manifest-registry.contract.test.js +246 -0
  210. package/dist/ports/manifest-registry.contract.test.js.map +1 -0
  211. package/dist/ports/manifest-registry.d.ts +116 -0
  212. package/dist/ports/manifest-registry.d.ts.map +1 -0
  213. package/dist/ports/manifest-registry.js +79 -0
  214. package/dist/ports/manifest-registry.js.map +1 -0
  215. package/dist/ports/observability.contract.test.d.ts +12 -0
  216. package/dist/ports/observability.contract.test.d.ts.map +1 -0
  217. package/dist/ports/observability.contract.test.js +260 -0
  218. package/dist/ports/observability.contract.test.js.map +1 -0
  219. package/dist/ports/observability.d.ts +98 -0
  220. package/dist/ports/observability.d.ts.map +1 -0
  221. package/dist/ports/observability.js +59 -0
  222. package/dist/ports/observability.js.map +1 -0
  223. package/dist/ports/outcome.d.ts +26 -0
  224. package/dist/ports/outcome.d.ts.map +1 -1
  225. package/dist/ports/outcome.js +62 -1
  226. package/dist/ports/outcome.js.map +1 -1
  227. package/dist/ports/privacy.contract.test.d.ts +12 -0
  228. package/dist/ports/privacy.contract.test.d.ts.map +1 -0
  229. package/dist/ports/privacy.contract.test.js +325 -0
  230. package/dist/ports/privacy.contract.test.js.map +1 -0
  231. package/dist/ports/privacy.d.ts +132 -0
  232. package/dist/ports/privacy.d.ts.map +1 -0
  233. package/dist/ports/privacy.js +83 -0
  234. package/dist/ports/privacy.js.map +1 -0
  235. package/dist/ports/tenant-context.contract.test.d.ts +14 -0
  236. package/dist/ports/tenant-context.contract.test.d.ts.map +1 -0
  237. package/dist/ports/tenant-context.contract.test.js +352 -0
  238. package/dist/ports/tenant-context.contract.test.js.map +1 -0
  239. package/dist/ports/tenant-context.d.ts +103 -0
  240. package/dist/ports/tenant-context.d.ts.map +1 -0
  241. package/dist/ports/tenant-context.js +48 -0
  242. package/dist/ports/tenant-context.js.map +1 -0
  243. package/dist/ports/vauban-finance-action.contract.test.d.ts +11 -0
  244. package/dist/ports/vauban-finance-action.contract.test.d.ts.map +1 -0
  245. package/dist/ports/vauban-finance-action.contract.test.js +260 -0
  246. package/dist/ports/vauban-finance-action.contract.test.js.map +1 -0
  247. package/dist/ports/vauban-finance-action.d.ts +106 -0
  248. package/dist/ports/vauban-finance-action.d.ts.map +1 -0
  249. package/dist/ports/vauban-finance-action.js +60 -0
  250. package/dist/ports/vauban-finance-action.js.map +1 -0
  251. package/dist/ports/workflow-runtime.d.ts +204 -0
  252. package/dist/ports/workflow-runtime.d.ts.map +1 -0
  253. package/dist/ports/workflow-runtime.js +72 -0
  254. package/dist/ports/workflow-runtime.js.map +1 -0
  255. package/dist/proof/cert-verify.d.ts +80 -0
  256. package/dist/proof/cert-verify.d.ts.map +1 -0
  257. package/dist/proof/cert-verify.js +178 -0
  258. package/dist/proof/cert-verify.js.map +1 -0
  259. package/dist/replay/replay.d.ts.map +1 -1
  260. package/dist/replay/replay.js +5 -1
  261. package/dist/replay/replay.js.map +1 -1
  262. package/dist/retry/index.d.ts +129 -0
  263. package/dist/retry/index.d.ts.map +1 -0
  264. package/dist/retry/index.js +156 -0
  265. package/dist/retry/index.js.map +1 -0
  266. package/dist/retry/presets.d.ts +39 -0
  267. package/dist/retry/presets.d.ts.map +1 -0
  268. package/dist/retry/presets.js +69 -0
  269. package/dist/retry/presets.js.map +1 -0
  270. package/dist/skill-loop/ab-runner.d.ts +67 -0
  271. package/dist/skill-loop/ab-runner.d.ts.map +1 -0
  272. package/dist/skill-loop/ab-runner.js +160 -0
  273. package/dist/skill-loop/ab-runner.js.map +1 -0
  274. package/dist/skill-loop/adoption.d.ts +67 -0
  275. package/dist/skill-loop/adoption.d.ts.map +1 -0
  276. package/dist/skill-loop/adoption.js +126 -0
  277. package/dist/skill-loop/adoption.js.map +1 -0
  278. package/dist/skill-loop/candidate.d.ts +45 -0
  279. package/dist/skill-loop/candidate.d.ts.map +1 -0
  280. package/dist/skill-loop/candidate.js +43 -0
  281. package/dist/skill-loop/candidate.js.map +1 -0
  282. package/dist/skill-loop/evaluator.d.ts +42 -0
  283. package/dist/skill-loop/evaluator.d.ts.map +1 -0
  284. package/dist/skill-loop/evaluator.js +184 -0
  285. package/dist/skill-loop/evaluator.js.map +1 -0
  286. package/dist/skill-loop/index.d.ts +27 -0
  287. package/dist/skill-loop/index.d.ts.map +1 -0
  288. package/dist/skill-loop/index.js +27 -0
  289. package/dist/skill-loop/index.js.map +1 -0
  290. package/dist/skill-loop/reflexion-replay.d.ts +87 -0
  291. package/dist/skill-loop/reflexion-replay.d.ts.map +1 -0
  292. package/dist/skill-loop/reflexion-replay.js +110 -0
  293. package/dist/skill-loop/reflexion-replay.js.map +1 -0
  294. package/dist/skill-loop/sign-off.d.ts +88 -0
  295. package/dist/skill-loop/sign-off.d.ts.map +1 -0
  296. package/dist/skill-loop/sign-off.js +146 -0
  297. package/dist/skill-loop/sign-off.js.map +1 -0
  298. package/dist/skill-loop/value-metric.d.ts +55 -0
  299. package/dist/skill-loop/value-metric.d.ts.map +1 -0
  300. package/dist/skill-loop/value-metric.js +69 -0
  301. package/dist/skill-loop/value-metric.js.map +1 -0
  302. package/dist/skill-loop/versioning.d.ts +36 -0
  303. package/dist/skill-loop/versioning.d.ts.map +1 -0
  304. package/dist/skill-loop/versioning.js +47 -0
  305. package/dist/skill-loop/versioning.js.map +1 -0
  306. package/dist/skill-manifest/anchor.d.ts +91 -0
  307. package/dist/skill-manifest/anchor.d.ts.map +1 -0
  308. package/dist/skill-manifest/anchor.js +331 -0
  309. package/dist/skill-manifest/anchor.js.map +1 -0
  310. package/dist/skill-manifest/builder.d.ts +47 -0
  311. package/dist/skill-manifest/builder.d.ts.map +1 -0
  312. package/dist/skill-manifest/builder.js +93 -0
  313. package/dist/skill-manifest/builder.js.map +1 -0
  314. package/dist/skill-manifest/index.d.ts +13 -0
  315. package/dist/skill-manifest/index.d.ts.map +1 -0
  316. package/dist/skill-manifest/index.js +9 -0
  317. package/dist/skill-manifest/index.js.map +1 -0
  318. package/dist/skill-manifest/types.d.ts +67 -0
  319. package/dist/skill-manifest/types.d.ts.map +1 -0
  320. package/dist/skill-manifest/types.js +16 -0
  321. package/dist/skill-manifest/types.js.map +1 -0
  322. package/dist/skill-manifest/verifier.d.ts +42 -0
  323. package/dist/skill-manifest/verifier.d.ts.map +1 -0
  324. package/dist/skill-manifest/verifier.js +136 -0
  325. package/dist/skill-manifest/verifier.js.map +1 -0
  326. package/dist/skills/brain-query.d.ts +4 -4
  327. package/dist/skills/brain-store.d.ts +6 -6
  328. package/dist/skills/errors.d.ts +15 -0
  329. package/dist/skills/errors.d.ts.map +1 -1
  330. package/dist/skills/errors.js +21 -0
  331. package/dist/skills/errors.js.map +1 -1
  332. package/dist/skills/hitl-request.d.ts +2 -2
  333. package/dist/skills/index.d.ts +3 -1
  334. package/dist/skills/index.d.ts.map +1 -1
  335. package/dist/skills/index.js +4 -1
  336. package/dist/skills/index.js.map +1 -1
  337. package/dist/skills/markdown/loader.d.ts +52 -0
  338. package/dist/skills/markdown/loader.d.ts.map +1 -0
  339. package/dist/skills/markdown/loader.js +93 -0
  340. package/dist/skills/markdown/loader.js.map +1 -0
  341. package/dist/skills/markdown/schema.d.ts +432 -0
  342. package/dist/skills/markdown/schema.d.ts.map +1 -0
  343. package/dist/skills/markdown/schema.js +121 -0
  344. package/dist/skills/markdown/schema.js.map +1 -0
  345. package/dist/skills/poc-md-loader/markdown-loader.d.ts +77 -0
  346. package/dist/skills/poc-md-loader/markdown-loader.d.ts.map +1 -0
  347. package/dist/skills/poc-md-loader/markdown-loader.js +125 -0
  348. package/dist/skills/poc-md-loader/markdown-loader.js.map +1 -0
  349. package/dist/skills/poc-md-loader/runner.d.ts +24 -0
  350. package/dist/skills/poc-md-loader/runner.d.ts.map +1 -0
  351. package/dist/skills/poc-md-loader/runner.js +57 -0
  352. package/dist/skills/poc-md-loader/runner.js.map +1 -0
  353. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts +3 -0
  354. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts.map +1 -0
  355. package/dist/skills/poc-md-loader/vitest.poc.config.js +13 -0
  356. package/dist/skills/poc-md-loader/vitest.poc.config.js.map +1 -0
  357. package/dist/skills/poc-md-loader/web-search/script.d.ts +33 -0
  358. package/dist/skills/poc-md-loader/web-search/script.d.ts.map +1 -0
  359. package/dist/skills/poc-md-loader/web-search/script.js +75 -0
  360. package/dist/skills/poc-md-loader/web-search/script.js.map +1 -0
  361. package/dist/skills/record-outcome.d.ts +4 -4
  362. package/dist/skills/send-email.d.ts.map +1 -1
  363. package/dist/skills/send-email.js +15 -3
  364. package/dist/skills/send-email.js.map +1 -1
  365. package/dist/skills/slack-notify.d.ts +4 -4
  366. package/dist/skills/starknet-balance.d.ts +1 -1
  367. package/dist/skills/telegram-notify.d.ts +4 -4
  368. package/dist/skills/web-search.d.ts +1 -1
  369. package/dist/testing/contracts/event-bus.contract.d.ts.map +1 -1
  370. package/dist/testing/contracts/event-bus.contract.js +14 -12
  371. package/dist/testing/contracts/event-bus.contract.js.map +1 -1
  372. package/dist/testing/index.d.ts +3 -0
  373. package/dist/testing/test-brain-port.d.ts +4 -0
  374. package/dist/testing/test-brain-port.d.ts.map +1 -1
  375. package/dist/testing/test-brain-port.js +75 -20
  376. package/dist/testing/test-brain-port.js.map +1 -1
  377. package/dist/testing/test-event-bus.d.ts.map +1 -1
  378. package/dist/testing/test-event-bus.js +89 -36
  379. package/dist/testing/test-event-bus.js.map +1 -1
  380. package/dist/trace/schema.d.ts +1 -1
  381. package/dist/trace/schema.d.ts.map +1 -1
  382. package/dist/trace/schema.js +1 -1
  383. package/dist/trace/schema.js.map +1 -1
  384. package/dist/verify/formal/index.d.ts +44 -0
  385. package/dist/verify/formal/index.d.ts.map +1 -0
  386. package/dist/verify/formal/index.js +98 -0
  387. package/dist/verify/formal/index.js.map +1 -0
  388. package/dist/verify/formal/policy.d.ts +105 -0
  389. package/dist/verify/formal/policy.d.ts.map +1 -0
  390. package/dist/verify/formal/policy.js +159 -0
  391. package/dist/verify/formal/policy.js.map +1 -0
  392. package/dist/verify/formal/result.d.ts +50 -0
  393. package/dist/verify/formal/result.d.ts.map +1 -0
  394. package/dist/verify/formal/result.js +21 -0
  395. package/dist/verify/formal/result.js.map +1 -0
  396. package/dist/verify/formal/solver.d.ts +67 -0
  397. package/dist/verify/formal/solver.d.ts.map +1 -0
  398. package/dist/verify/formal/solver.js +184 -0
  399. package/dist/verify/formal/solver.js.map +1 -0
  400. package/dist/verify/formal/spec-language.d.ts +80 -0
  401. package/dist/verify/formal/spec-language.d.ts.map +1 -0
  402. package/dist/verify/formal/spec-language.js +219 -0
  403. package/dist/verify/formal/spec-language.js.map +1 -0
  404. package/docs/attestation.md +199 -0
  405. package/docs/identity.md +193 -0
  406. package/package.json +22 -1
  407. package/src/adapters/llm/anthropic-direct.ts +51 -0
  408. package/src/adapters/llm/cascade.ts +64 -19
  409. package/src/adapters/llm/litellm.ts +49 -0
  410. package/src/compute/difficulty-estimator.ts +111 -0
  411. package/src/compute/strategies/mixture-of-agents.ts +150 -0
  412. package/src/compute/strategies/tree-of-thoughts.ts +293 -0
  413. package/src/compute/strategies/two-phase-orient.ts +147 -0
  414. package/src/container/protocol.ts +243 -0
  415. package/src/container/runtime.ts +424 -0
  416. package/src/db/migrations/026_formal_verify_results.sql +30 -0
  417. package/src/events/catalogue.ts +54 -0
  418. package/src/events/index.ts +9 -0
  419. package/src/events/schemas/citadel.sprint.analyzed.v1.ts +23 -0
  420. package/src/events/schemas/forge.inbox.reply_classified.v1.ts +15 -0
  421. package/src/events/schemas/vauban-finance.forecast.generated.v1.ts +11 -0
  422. package/src/events/schemas/vauban-finance.trade.executed.v1.ts +12 -0
  423. package/src/events/schemas/vauban.goal.checked.v1.ts +11 -0
  424. package/src/events/schemas/vauban.rebalancing.checked.v1.ts +11 -0
  425. package/src/events/schemas/vauban.tax.checked.v1.ts +11 -0
  426. package/src/events/schemas/vauban.vault.analyzed.v1.ts +21 -0
  427. package/src/events/schemas/vauban.vault.compounded.v1.ts +12 -0
  428. package/src/identity/agent-persona.ts +203 -0
  429. package/src/identity/persona-prompt.ts +84 -0
  430. package/src/identity/persona-schema.ts +127 -0
  431. package/src/index.ts +338 -1
  432. package/src/loop/index.ts +0 -1
  433. package/src/loop/sdk-loop.ts +5 -8
  434. package/src/memory/episodic-rrf.ts +224 -0
  435. package/src/mesh/attenuation.ts +190 -0
  436. package/src/mesh/delegate.ts +254 -0
  437. package/src/mesh/dispatcher.ts +301 -0
  438. package/src/mesh/index.ts +39 -0
  439. package/src/mesh/types.ts +31 -0
  440. package/src/orchestration/ooda/skills.ts +177 -0
  441. package/src/orchestration/ooda/types.ts +3 -9
  442. package/src/ports/bastion-action.contract.test.ts +355 -0
  443. package/src/ports/bastion-action.ts +198 -0
  444. package/src/ports/brain.ts +177 -15
  445. package/src/ports/citadel-action.contract.test.ts +430 -0
  446. package/src/ports/citadel-action.ts +174 -0
  447. package/src/ports/compliance-contract.ts +191 -0
  448. package/src/ports/db.ts +98 -0
  449. package/src/ports/delegation.contract.test.ts +428 -0
  450. package/src/ports/delegation.ts +211 -0
  451. package/src/ports/event-bus.ts +133 -18
  452. package/src/ports/federation.contract.test.ts +355 -0
  453. package/src/ports/federation.ts +190 -0
  454. package/src/ports/index.ts +186 -1
  455. package/src/ports/llm-provider.ts +123 -0
  456. package/src/ports/logger.ts +104 -0
  457. package/src/ports/manifest-registry.contract.test.ts +324 -0
  458. package/src/ports/manifest-registry.ts +188 -0
  459. package/src/ports/observability.contract.test.ts +315 -0
  460. package/src/ports/observability.ts +150 -0
  461. package/src/ports/outcome.ts +69 -0
  462. package/src/ports/privacy.contract.test.ts +413 -0
  463. package/src/ports/privacy.ts +207 -0
  464. package/src/ports/tenant-context.contract.test.ts +454 -0
  465. package/src/ports/tenant-context.ts +150 -0
  466. package/src/ports/vauban-finance-action.contract.test.ts +335 -0
  467. package/src/ports/vauban-finance-action.ts +166 -0
  468. package/src/ports/workflow-runtime.ts +327 -0
  469. package/src/proof/cert-verify.ts +249 -0
  470. package/src/replay/replay.ts +11 -8
  471. package/src/retry/index.ts +227 -0
  472. package/src/retry/presets.ts +75 -0
  473. package/src/skill-loop/ab-runner.ts +196 -0
  474. package/src/skill-loop/adoption.ts +188 -0
  475. package/src/skill-loop/candidate.ts +75 -0
  476. package/src/skill-loop/evaluator.ts +238 -0
  477. package/src/skill-loop/index.ts +51 -0
  478. package/src/skill-loop/reflexion-replay.ts +173 -0
  479. package/src/skill-loop/sign-off.ts +247 -0
  480. package/src/skill-loop/value-metric.ts +120 -0
  481. package/src/skill-loop/versioning.ts +75 -0
  482. package/src/skill-manifest/anchor.ts +401 -0
  483. package/src/skill-manifest/builder.ts +129 -0
  484. package/src/skill-manifest/index.ts +18 -0
  485. package/src/skill-manifest/types.ts +72 -0
  486. package/src/skill-manifest/verifier.ts +198 -0
  487. package/src/skills/errors.ts +30 -2
  488. package/src/skills/index.ts +19 -0
  489. package/src/skills/markdown/loader.ts +129 -0
  490. package/src/skills/markdown/schema.ts +144 -0
  491. package/src/skills/poc-md-loader/e2e-parity.test.ts +237 -0
  492. package/src/skills/poc-md-loader/markdown-loader.ts +161 -0
  493. package/src/skills/poc-md-loader/runner.ts +82 -0
  494. package/src/skills/poc-md-loader/vitest.poc.config.ts +13 -0
  495. package/src/skills/poc-md-loader/web-search/SKILL.md +42 -0
  496. package/src/skills/poc-md-loader/web-search/script.ts +109 -0
  497. package/src/skills/send-email.ts +15 -3
  498. package/src/testing/contracts/event-bus.contract.ts +16 -14
  499. package/src/testing/test-brain-port.ts +98 -24
  500. package/src/testing/test-event-bus.ts +104 -43
  501. package/src/trace/schema.ts +1 -1
  502. package/src/verify/formal/index.ts +154 -0
  503. package/src/verify/formal/policy.ts +253 -0
  504. package/src/verify/formal/result.ts +52 -0
  505. package/src/verify/formal/solver.ts +235 -0
  506. package/src/verify/formal/spec-language.ts +274 -0
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Episodic memory recall — weighted score combination (cosine + recency + importance).
3
+ *
4
+ * Despite the file name (RRF — Reciprocal Rank Fusion), the algorithm used
5
+ * for CC v3.1 is a **linear combination of normalized components**:
6
+ *
7
+ * score(e) = α · cosine_sim(q, e.embedding)
8
+ * + β · exp(-Δt / τ) // recency decay
9
+ * + γ · importance(e) // [0,1]
10
+ *
11
+ * defaults: α=0.5, β=0.3, γ=0.2, τ=14 days
12
+ *
13
+ * This shape was chosen over pure RRF because the three signals are
14
+ * heterogeneous (similarity, time, salience) and combining them via rank
15
+ * fusion would erase the magnitude information that callers care about
16
+ * (e.g. "near-perfect cosine match" vs "loosely related").
17
+ *
18
+ * Pluggable scorers — callers provide functions mapping an entry to each
19
+ * component so the algorithm is decoupled from storage details (embedding
20
+ * column, importance field name, etc.).
21
+ *
22
+ * @see ../ports/brain.ts — EpisodicMemoryEntry
23
+ * @see ADR-ECO-034 §"AgentPersona via Brain Tier 3 semantic" (companion)
24
+ * @public
25
+ */
26
+
27
+ import type { EpisodicMemoryEntry } from "../ports/brain.js";
28
+
29
+ /** Default weights — sum to 1.0. */
30
+ export const DEFAULT_RRF_WEIGHTS = {
31
+ cosine: 0.5,
32
+ recency: 0.3,
33
+ importance: 0.2,
34
+ } as const;
35
+
36
+ /** Default recency half-life (14 days in ms). */
37
+ export const DEFAULT_RECENCY_HALFLIFE_MS = 14 * 24 * 60 * 60 * 1000;
38
+
39
+ export interface RrfWeights {
40
+ cosine: number;
41
+ recency: number;
42
+ importance: number;
43
+ }
44
+
45
+ export interface RrfOptions {
46
+ weights?: Partial<RrfWeights>;
47
+ /** Half-life for recency decay (default: 14 days). */
48
+ recencyHalflifeMs?: number;
49
+ /** Cap on returned entries (default: unbounded). */
50
+ topK?: number;
51
+ /** Override "now" for deterministic tests. */
52
+ now?: () => number;
53
+ }
54
+
55
+ export interface ScoreComponents {
56
+ cosine: number;
57
+ recency: number;
58
+ importance: number;
59
+ }
60
+
61
+ export interface ScoredEntry<T> {
62
+ entry: T;
63
+ score: number;
64
+ components: ScoreComponents;
65
+ }
66
+
67
+ export interface RrfScorers<T> {
68
+ /** Cosine similarity ∈ [-1, 1] — non-finite values clamped to 0. */
69
+ cosine: (entry: T) => number;
70
+ /** Timestamp (ms epoch) used for recency decay. Negative → drop the entry. */
71
+ timestamp: (entry: T) => number;
72
+ /** Salience ∈ [0, 1]. Out-of-range values clamped. */
73
+ importance: (entry: T) => number;
74
+ }
75
+
76
+ // ─── Pure helpers ─────────────────────────────────────────────────────────────
77
+
78
+ /**
79
+ * Cosine similarity between two equal-length numeric vectors.
80
+ *
81
+ * Returns 0 if either vector is empty / zero-norm / mismatched length —
82
+ * never throws. This makes the function safe to compose into scorers that
83
+ * may receive partial entries.
84
+ */
85
+ export function cosineSimilarity(a: number[], b: number[]): number {
86
+ if (a.length === 0 || a.length !== b.length) return 0;
87
+ let dot = 0;
88
+ let na = 0;
89
+ let nb = 0;
90
+ for (let i = 0; i < a.length; i++) {
91
+ const ai = a[i]!;
92
+ const bi = b[i]!;
93
+ dot += ai * bi;
94
+ na += ai * ai;
95
+ nb += bi * bi;
96
+ }
97
+ if (na === 0 || nb === 0) return 0;
98
+ return dot / (Math.sqrt(na) * Math.sqrt(nb));
99
+ }
100
+
101
+ /**
102
+ * Recency score in [0, 1]: exp(-ln(2) · Δt / halflife).
103
+ * - 1.0 at Δt = 0
104
+ * - 0.5 at Δt = halflife
105
+ * - approaches 0 as Δt → ∞
106
+ *
107
+ * `nowMs` and `timestampMs` are epoch ms. Future timestamps (Δt < 0) clamp
108
+ * to 1.0 (treated as "right now").
109
+ */
110
+ export function recencyScore(
111
+ nowMs: number,
112
+ timestampMs: number,
113
+ halflifeMs: number
114
+ ): number {
115
+ if (halflifeMs <= 0) return 0;
116
+ const dt = Math.max(0, nowMs - timestampMs);
117
+ return Math.exp((-Math.LN2 * dt) / halflifeMs);
118
+ }
119
+
120
+ /** Clamp to [0, 1]; NaN / non-finite → 0. */
121
+ function clamp01(value: number): number {
122
+ if (!Number.isFinite(value)) return 0;
123
+ if (value < 0) return 0;
124
+ if (value > 1) return 1;
125
+ return value;
126
+ }
127
+
128
+ /** Clamp cosine output (−1..1) to ≥0 to avoid negative contributions. */
129
+ function clampCosineToPos(value: number): number {
130
+ if (!Number.isFinite(value)) return 0;
131
+ return value < 0 ? 0 : value;
132
+ }
133
+
134
+ // ─── Generic scorer ───────────────────────────────────────────────────────────
135
+
136
+ /**
137
+ * Score a batch of entries via the weighted combination. The result is sorted
138
+ * by descending score and trimmed to `topK` when set.
139
+ *
140
+ * Negative timestamps (per `scorers.timestamp`) cause the entry to be dropped
141
+ * entirely — this is the cheap way for a scorer to signal "skip" (e.g. row
142
+ * lacks the field).
143
+ */
144
+ export function scoreEntries<T>(
145
+ entries: T[],
146
+ scorers: RrfScorers<T>,
147
+ opts: RrfOptions = {}
148
+ ): ScoredEntry<T>[] {
149
+ const weights: RrfWeights = {
150
+ cosine: opts.weights?.cosine ?? DEFAULT_RRF_WEIGHTS.cosine,
151
+ recency: opts.weights?.recency ?? DEFAULT_RRF_WEIGHTS.recency,
152
+ importance: opts.weights?.importance ?? DEFAULT_RRF_WEIGHTS.importance,
153
+ };
154
+ const halflifeMs = opts.recencyHalflifeMs ?? DEFAULT_RECENCY_HALFLIFE_MS;
155
+ const nowMs = (opts.now ?? Date.now)();
156
+
157
+ const scored: ScoredEntry<T>[] = [];
158
+ for (const entry of entries) {
159
+ const ts = scorers.timestamp(entry);
160
+ if (ts < 0) continue;
161
+ const cosine = clampCosineToPos(scorers.cosine(entry));
162
+ const recency = recencyScore(nowMs, ts, halflifeMs);
163
+ const importance = clamp01(scorers.importance(entry));
164
+ const score =
165
+ weights.cosine * cosine +
166
+ weights.recency * recency +
167
+ weights.importance * importance;
168
+ scored.push({
169
+ entry,
170
+ score,
171
+ components: { cosine, recency, importance },
172
+ });
173
+ }
174
+ scored.sort((a, b) => b.score - a.score);
175
+ if (opts.topK !== undefined && opts.topK >= 0) {
176
+ return scored.slice(0, opts.topK);
177
+ }
178
+ return scored;
179
+ }
180
+
181
+ // ─── Concrete recall over EpisodicMemoryEntry ────────────────────────────────
182
+
183
+ /**
184
+ * The agent-sdk EpisodicMemoryEntry does NOT carry an embedding column —
185
+ * embeddings live in the storage layer (Postgres pgvector). To enable
186
+ * pluggable cosine scoring, the caller may attach an embedding via the
187
+ * `embedding` field on `metadata`, or supply a custom resolver.
188
+ */
189
+ export type EpisodicCosineFn = (entry: EpisodicMemoryEntry) => number;
190
+
191
+ /** Default cosine: 0 (no embedding available — relies on recency + importance only). */
192
+ const ZERO_COSINE: EpisodicCosineFn = () => 0;
193
+
194
+ export interface RecallRrfOptions extends RrfOptions {
195
+ /**
196
+ * Cosine scorer — defaults to 0 (no embedding). Provide when you have a
197
+ * pre-computed (entry × query) similarity for each entry.
198
+ */
199
+ cosine?: EpisodicCosineFn;
200
+ }
201
+
202
+ /**
203
+ * Rank EpisodicMemoryEntry[] by weighted score. Convenience over scoreEntries
204
+ * with the standard projection (timestamp = entry.timestamp,
205
+ * importance = metadata.importance ?? 0.5).
206
+ */
207
+ export function recallEpisodicRrf(
208
+ entries: EpisodicMemoryEntry[],
209
+ opts: RecallRrfOptions = {}
210
+ ): ScoredEntry<EpisodicMemoryEntry>[] {
211
+ const cosineFn = opts.cosine ?? ZERO_COSINE;
212
+ return scoreEntries(
213
+ entries,
214
+ {
215
+ cosine: cosineFn,
216
+ timestamp: (e) => e.timestamp,
217
+ importance: (e) => {
218
+ const raw = (e.metadata?.importance as unknown) ?? 0.5;
219
+ return typeof raw === "number" ? raw : 0.5;
220
+ },
221
+ },
222
+ opts
223
+ );
224
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * src/mesh/attenuation.ts
3
+ *
4
+ * Biscuit-style capability attenuation for mesh.delegate().
5
+ *
6
+ * @experimental — sprint-585. Public API may change before v1.x freeze.
7
+ *
8
+ * Implements capability INTERSECTION (child ⊆ parent) without the actual
9
+ * Biscuit token format — keeps the SDK dependency-free. Production deployments
10
+ * should swap `buildToken` / `parseToken` for a real Biscuit issuer in CC.
11
+ *
12
+ * Invariants:
13
+ * - Child actions = INTERSECTION(parent.actions, requested.actions)
14
+ * - Child budget = MIN(parent.budgetEur, requested.budgetEur)
15
+ * - Child expiry = MIN(parent.expiresAt, requested.expiresAt) when both present
16
+ * - Wildcard support: "*" or "ns:*" in parent grants any matching action.
17
+ *
18
+ * No `any` — strict types per craft-standards.
19
+ */
20
+
21
+ // ─── Types ────────────────────────────────────────────────────────────────────
22
+
23
+ /**
24
+ * MeshCapabilityScope — bounded capability declaration for mesh dispatch.
25
+ *
26
+ * Renamed from `CapabilityScope` to avoid clash with `ports/delegation.ts`
27
+ * which models a different (DelegationClaim) shape.
28
+ */
29
+ export interface MeshCapabilityScope {
30
+ /** Actions permitted, e.g. ["brain:read", "vault:read", "hitl:trigger"]. */
31
+ readonly actions: ReadonlyArray<string>;
32
+ /** Max EUR the holder may spend under this scope. */
33
+ readonly budgetEur: number;
34
+ /** Hard expiry — past this date, scope MUST be rejected by callers. */
35
+ readonly expiresAt?: Date;
36
+ }
37
+
38
+ /** Backwards-compatible alias for the spec name `CapabilityScope`. */
39
+ export type CapabilityScope = MeshCapabilityScope;
40
+
41
+ /**
42
+ * AttenuatedToken — opaque transport for a scope across an agent boundary.
43
+ *
44
+ * Phase MVP : plain object (no signature). Phase 2+ : swap with Biscuit token
45
+ * (the encoded `token` field becomes the Biscuit hex / base64 form).
46
+ */
47
+ export interface AttenuatedToken {
48
+ /** Allowed actions (post-attenuation). */
49
+ readonly scope: ReadonlyArray<string>;
50
+ /** Remaining EUR allowance. */
51
+ readonly budgetEur: number;
52
+ /** Parent agent identifier — caller of the delegation step. */
53
+ readonly parentId: string;
54
+ /** Optional expiry, ISO 8601 — propagated from MeshCapabilityScope.expiresAt. */
55
+ readonly expiresAt?: string;
56
+ }
57
+
58
+ // ─── Wildcard match ──────────────────────────────────────────────────────────
59
+
60
+ /**
61
+ * Match an action against a parent permission entry.
62
+ *
63
+ * - Exact match (case-sensitive).
64
+ * - `"*"` grants everything.
65
+ * - `"ns:*"` grants any action whose namespace prefix matches `ns:`.
66
+ */
67
+ function permissionMatches(parentPerm: string, requested: string): boolean {
68
+ if (parentPerm === "*" || parentPerm === requested) return true;
69
+ if (parentPerm.endsWith(":*")) {
70
+ const prefix = parentPerm.slice(0, -1); // keep trailing colon
71
+ return requested.startsWith(prefix);
72
+ }
73
+ return false;
74
+ }
75
+
76
+ /**
77
+ * Intersect a parent action set with a requested set.
78
+ * Output: only requested actions that the parent allows (preserving order).
79
+ */
80
+ function intersectActions(
81
+ parent: ReadonlyArray<string>,
82
+ requested: ReadonlyArray<string>,
83
+ ): string[] {
84
+ const out: string[] = [];
85
+ const seen = new Set<string>();
86
+ for (const req of requested) {
87
+ if (seen.has(req)) continue;
88
+ for (const p of parent) {
89
+ if (permissionMatches(p, req)) {
90
+ out.push(req);
91
+ seen.add(req);
92
+ break;
93
+ }
94
+ }
95
+ }
96
+ return out;
97
+ }
98
+
99
+ // ─── Public API ──────────────────────────────────────────────────────────────
100
+
101
+ /**
102
+ * Attenuate a parent scope by a requested scope.
103
+ *
104
+ * Returns a NEW scope (immutable input semantics).
105
+ * Guarantees `child ⊆ parent` (capability intersection invariant).
106
+ */
107
+ export function attenuateScope(
108
+ parent: MeshCapabilityScope,
109
+ requested: MeshCapabilityScope,
110
+ ): MeshCapabilityScope {
111
+ if (!Number.isFinite(parent.budgetEur) || parent.budgetEur < 0) {
112
+ throw new RangeError(`attenuateScope: parent.budgetEur must be ≥ 0, got ${parent.budgetEur}`);
113
+ }
114
+ if (!Number.isFinite(requested.budgetEur) || requested.budgetEur < 0) {
115
+ throw new RangeError(
116
+ `attenuateScope: requested.budgetEur must be ≥ 0, got ${requested.budgetEur}`,
117
+ );
118
+ }
119
+
120
+ const childActions = intersectActions(parent.actions, requested.actions);
121
+ const childBudget = Math.min(parent.budgetEur, requested.budgetEur);
122
+
123
+ let childExpiresAt: Date | undefined;
124
+ if (parent.expiresAt && requested.expiresAt) {
125
+ childExpiresAt = new Date(Math.min(parent.expiresAt.getTime(), requested.expiresAt.getTime()));
126
+ } else if (parent.expiresAt) {
127
+ childExpiresAt = new Date(parent.expiresAt.getTime());
128
+ } else if (requested.expiresAt) {
129
+ childExpiresAt = new Date(requested.expiresAt.getTime());
130
+ }
131
+
132
+ const out: MeshCapabilityScope = childExpiresAt
133
+ ? {
134
+ actions: childActions,
135
+ budgetEur: childBudget,
136
+ expiresAt: childExpiresAt,
137
+ }
138
+ : { actions: childActions, budgetEur: childBudget };
139
+ return out;
140
+ }
141
+
142
+ /**
143
+ * Check whether a scope permits a specific action.
144
+ * Supports wildcards (`"*"`, `"ns:*"`). Returns false if scope is expired.
145
+ */
146
+ export function scopeAllows(scope: MeshCapabilityScope, action: string): boolean {
147
+ if (scope.expiresAt && scope.expiresAt.getTime() <= Date.now()) return false;
148
+ for (const perm of scope.actions) {
149
+ if (permissionMatches(perm, action)) return true;
150
+ }
151
+ return false;
152
+ }
153
+
154
+ /**
155
+ * Encode a scope as an opaque token bound to a parent identifier.
156
+ *
157
+ * Phase MVP : plain structural copy. Phase 2+ : replace with Biscuit-signed token
158
+ * (the `parentId` becomes the issuer public key, `scope`/`budgetEur` become
159
+ * Biscuit facts, `expiresAt` becomes a Biscuit check).
160
+ */
161
+ export function buildToken(scope: MeshCapabilityScope, parentId: string): AttenuatedToken {
162
+ if (!parentId || typeof parentId !== "string") {
163
+ throw new TypeError("buildToken: parentId must be a non-empty string");
164
+ }
165
+ const out: AttenuatedToken = scope.expiresAt
166
+ ? {
167
+ scope: [...scope.actions],
168
+ budgetEur: scope.budgetEur,
169
+ parentId,
170
+ expiresAt: scope.expiresAt.toISOString(),
171
+ }
172
+ : { scope: [...scope.actions], budgetEur: scope.budgetEur, parentId };
173
+ return out;
174
+ }
175
+
176
+ /**
177
+ * Decode a token back to a MeshCapabilityScope.
178
+ *
179
+ * Inverse of `buildToken` modulo identity loss (parentId not part of scope).
180
+ */
181
+ export function parseToken(token: AttenuatedToken): MeshCapabilityScope {
182
+ const out: MeshCapabilityScope = token.expiresAt
183
+ ? {
184
+ actions: [...token.scope],
185
+ budgetEur: token.budgetEur,
186
+ expiresAt: new Date(token.expiresAt),
187
+ }
188
+ : { actions: [...token.scope], budgetEur: token.budgetEur };
189
+ return out;
190
+ }
@@ -0,0 +1,254 @@
1
+ /**
2
+ * src/mesh/delegate.ts
3
+ *
4
+ * `mesh.delegate()` — intent-based dispatch to the best available agent.
5
+ *
6
+ * @experimental — sprint-585. Public API may change before v1.x freeze.
7
+ *
8
+ * Replaces manual `withCompute()` boilerplate with a one-liner:
9
+ *
10
+ * const r = await meshDelegate({ need: "summarize the spec" }, dispatcher);
11
+ *
12
+ * Responsibilities:
13
+ * 1. Classify need → AgentKind (via dispatcher.classify or injected hint).
14
+ * 2. Apply capability attenuation if a parent token is present.
15
+ * 3. Forward to dispatcher with budget/deadline guards.
16
+ * 4. Build a delegation chain link for audit.
17
+ *
18
+ * Streaming (`onChunk`) is a best-effort surface — the dispatcher must opt-in
19
+ * by exposing a `dispatchStream` (not part of base contract). When unavailable,
20
+ * the final result is delivered as a single chunk after completion.
21
+ */
22
+
23
+ import {
24
+ type AttenuatedToken,
25
+ type MeshCapabilityScope,
26
+ attenuateScope,
27
+ buildToken,
28
+ } from "./attenuation.js";
29
+ import { DefaultMeshDispatcher, type DispatchIntent, type MeshDispatcher } from "./dispatcher.js";
30
+ import type { DelegationLink, MeshAgentKind } from "./types.js";
31
+
32
+ // ─── Public types ────────────────────────────────────────────────────────────
33
+
34
+ export interface DelegateChunk {
35
+ readonly text: string;
36
+ readonly done: boolean;
37
+ readonly agentKind?: MeshAgentKind;
38
+ }
39
+
40
+ export interface DelegateOptions {
41
+ /** Natural language description of the need. */
42
+ readonly need: string;
43
+ /** Optional structured or free-form context. Serialized to JSON if object. */
44
+ readonly context?: string | Record<string, unknown>;
45
+ /** Caller-requested capabilities (subject to attenuation if parentToken present). */
46
+ readonly capabilities?: ReadonlyArray<string>;
47
+ /** Wall-clock budget in ms. Default 30 000. */
48
+ readonly deadline_ms?: number;
49
+ /** Cost cap in EUR. Default 0.01. */
50
+ readonly max_cost_eur?: number;
51
+ /** Parent token — when present, child scope = parent ∩ requested capabilities. */
52
+ readonly parentToken?: AttenuatedToken;
53
+ /** Optional streaming callback. */
54
+ readonly onChunk?: (chunk: DelegateChunk) => void;
55
+ /** Optional pre-resolved kind — skips classifier. */
56
+ readonly kind?: MeshAgentKind;
57
+ /** Stable child agent identifier (for delegation chain audit). Default: random. */
58
+ readonly childId?: string;
59
+ /** MCP tool name (only when kind === "mcp-tool"). */
60
+ readonly toolName?: string;
61
+ /** MCP tool args (only when kind === "mcp-tool"). */
62
+ readonly toolArgs?: unknown;
63
+ }
64
+
65
+ export interface DelegateResult<T = string> {
66
+ readonly output: T;
67
+ readonly agentKind: MeshAgentKind;
68
+ readonly delegationChain: ReadonlyArray<DelegationLink>;
69
+ readonly costEur: number;
70
+ readonly durationMs: number;
71
+ readonly truncated: boolean;
72
+ /** Token issued to the child — empty when no parentToken given. */
73
+ readonly childToken?: AttenuatedToken;
74
+ }
75
+
76
+ // ─── Defaults ────────────────────────────────────────────────────────────────
77
+
78
+ const DEFAULT_DEADLINE_MS = 30_000;
79
+ const DEFAULT_MAX_COST_EUR = 0.01;
80
+ const SELF_ID = "mesh:caller";
81
+
82
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
83
+
84
+ function stringifyContext(ctx?: string | Record<string, unknown>): string | undefined {
85
+ if (ctx === undefined) return undefined;
86
+ if (typeof ctx === "string") return ctx;
87
+ try {
88
+ return JSON.stringify(ctx);
89
+ } catch {
90
+ return String(ctx);
91
+ }
92
+ }
93
+
94
+ function isDispatcherWithClassify(
95
+ d: MeshDispatcher,
96
+ ): d is MeshDispatcher & { classify(need: string): MeshAgentKind } {
97
+ return typeof (d as { classify?: unknown }).classify === "function";
98
+ }
99
+
100
+ function generateChildId(): string {
101
+ // Tiny non-cryptographic id — child-id is for audit, not auth.
102
+ // Production: replace with ULID/UUID from caller env.
103
+ return `mesh-child-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e6).toString(36)}`;
104
+ }
105
+
106
+ /**
107
+ * Compute child scope from parent token + caller-requested capabilities.
108
+ * Returns the issued child token (parented to caller's parentId) and the
109
+ * effective MeshCapabilityScope (post-intersection).
110
+ */
111
+ function issueChildToken(
112
+ parentToken: AttenuatedToken,
113
+ requestedCapabilities: ReadonlyArray<string> | undefined,
114
+ requestedBudgetEur: number,
115
+ childId: string,
116
+ ): { token: AttenuatedToken; scope: MeshCapabilityScope } {
117
+ const parentScope: MeshCapabilityScope = {
118
+ actions: parentToken.scope,
119
+ budgetEur: parentToken.budgetEur,
120
+ expiresAt: parentToken.expiresAt ? new Date(parentToken.expiresAt) : undefined,
121
+ };
122
+ const requestedScope: MeshCapabilityScope = {
123
+ actions: requestedCapabilities ?? parentToken.scope,
124
+ budgetEur: requestedBudgetEur,
125
+ };
126
+ const childScope = attenuateScope(parentScope, requestedScope);
127
+ const token = buildToken(childScope, childId);
128
+ return { token, scope: childScope };
129
+ }
130
+
131
+ // ─── Errors ──────────────────────────────────────────────────────────────────
132
+
133
+ export class DelegateAttenuationError extends Error {
134
+ override readonly name = "DelegateAttenuationError";
135
+ }
136
+
137
+ // ─── Public API ──────────────────────────────────────────────────────────────
138
+
139
+ /**
140
+ * Delegate a need to the best available agent.
141
+ *
142
+ * Routing priority (when `kind` not pre-set):
143
+ * 1. Dispatcher's `classify(need)` hook if present.
144
+ * 2. Heuristic — see `defaultClassifier`.
145
+ *
146
+ * Capability attenuation:
147
+ * - If `parentToken` is provided, child scope = parent ∩ requested.
148
+ * - Empty intersection raises {@link DelegateAttenuationError}.
149
+ *
150
+ * Budget guards:
151
+ * - When `parentToken.budgetEur < max_cost_eur`, the effective max is parent's.
152
+ * - Negative budget or deadline → RangeError.
153
+ */
154
+ export async function meshDelegate<T = string>(
155
+ options: DelegateOptions,
156
+ dispatcher: MeshDispatcher,
157
+ ): Promise<DelegateResult<T>> {
158
+ if (!options || typeof options.need !== "string" || options.need.length === 0) {
159
+ throw new TypeError("meshDelegate: `need` is required and must be a non-empty string");
160
+ }
161
+ if (!dispatcher || typeof dispatcher.dispatch !== "function") {
162
+ throw new TypeError("meshDelegate: `dispatcher` must implement MeshDispatcher");
163
+ }
164
+
165
+ const deadlineMs = options.deadline_ms ?? DEFAULT_DEADLINE_MS;
166
+ if (!Number.isFinite(deadlineMs) || deadlineMs <= 0) {
167
+ throw new RangeError(`meshDelegate: deadline_ms must be > 0, got ${deadlineMs}`);
168
+ }
169
+ let maxCostEur = options.max_cost_eur ?? DEFAULT_MAX_COST_EUR;
170
+ if (!Number.isFinite(maxCostEur) || maxCostEur < 0) {
171
+ throw new RangeError(`meshDelegate: max_cost_eur must be ≥ 0, got ${maxCostEur}`);
172
+ }
173
+
174
+ // ── 1. Classify ──────────────────────────────────────────────────────────
175
+ const kind: MeshAgentKind =
176
+ options.kind ??
177
+ (isDispatcherWithClassify(dispatcher) ? dispatcher.classify(options.need) : "llm-router");
178
+
179
+ // ── 2. Attenuation (if parent token given) ───────────────────────────────
180
+ const childId = options.childId ?? generateChildId();
181
+ let childToken: AttenuatedToken | undefined;
182
+ let effectiveScope: ReadonlyArray<string> | undefined;
183
+ if (options.parentToken) {
184
+ const issued = issueChildToken(options.parentToken, options.capabilities, maxCostEur, childId);
185
+ if (issued.scope.actions.length === 0 && (options.capabilities?.length ?? 0) > 0) {
186
+ throw new DelegateAttenuationError(
187
+ "meshDelegate: requested capabilities are not granted by parent scope",
188
+ );
189
+ }
190
+ childToken = issued.token;
191
+ effectiveScope = issued.scope.actions;
192
+ // Enforce parent budget cap.
193
+ maxCostEur = Math.min(maxCostEur, issued.scope.budgetEur);
194
+ } else if (options.capabilities) {
195
+ effectiveScope = options.capabilities;
196
+ }
197
+
198
+ // ── 3. Dispatch ──────────────────────────────────────────────────────────
199
+ const intent: DispatchIntent = {
200
+ kind,
201
+ need: options.need,
202
+ context: stringifyContext(options.context),
203
+ deadline_ms: deadlineMs,
204
+ max_cost_eur: maxCostEur,
205
+ toolName: options.toolName,
206
+ toolArgs: options.toolArgs,
207
+ };
208
+
209
+ const dispatched = await dispatcher.dispatch(intent);
210
+
211
+ // ── 4. Audit chain ───────────────────────────────────────────────────────
212
+ const parentIdForLink = options.parentToken?.parentId ?? SELF_ID;
213
+ const link: DelegationLink = {
214
+ from: parentIdForLink,
215
+ to: childId,
216
+ scope: effectiveScope ?? [],
217
+ budget: maxCostEur,
218
+ };
219
+
220
+ // ── 5. Stream (best-effort, single-shot when streaming not supported) ────
221
+ if (options.onChunk) {
222
+ options.onChunk({ text: dispatched.output, done: true, agentKind: kind });
223
+ }
224
+
225
+ const result: DelegateResult<T> = {
226
+ output: dispatched.output as unknown as T,
227
+ agentKind: kind,
228
+ delegationChain: [link],
229
+ costEur: dispatched.costEur,
230
+ durationMs: dispatched.durationMs,
231
+ truncated: dispatched.truncated,
232
+ childToken,
233
+ };
234
+ return result;
235
+ }
236
+
237
+ /**
238
+ * Factory variant — binds a dispatcher so callers can call `delegate(opts)`
239
+ * without re-passing the dispatcher every time.
240
+ *
241
+ * Useful for DI in long-lived services.
242
+ */
243
+ export function createMeshDelegate(
244
+ dispatcher: MeshDispatcher,
245
+ ): <T = string>(options: DelegateOptions) => Promise<DelegateResult<T>> {
246
+ return <T = string>(options: DelegateOptions) => meshDelegate<T>(options, dispatcher);
247
+ }
248
+
249
+ /**
250
+ * Re-export DefaultMeshDispatcher as a convenience so callers can do:
251
+ *
252
+ * import { meshDelegate, DefaultMeshDispatcher } from "@vauban-org/agent-sdk";
253
+ */
254
+ export { DefaultMeshDispatcher };