@vauban-org/agent-sdk 1.0.0 → 1.3.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 (513) hide show
  1. package/CONTRACT.md +6918 -742
  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 +46 -46
  39. package/dist/events/schemas/agent.completed.v1.d.ts +4 -4
  40. package/dist/events/schemas/agent.failed.v1.d.ts +2 -2
  41. package/dist/events/schemas/agent.hitl_resolved.v1.d.ts +2 -2
  42. package/dist/events/schemas/agent.started.v1.d.ts +2 -2
  43. package/dist/events/schemas/brain.skill.extracted.v1.d.ts +4 -4
  44. package/dist/events/schemas/cc.cost.anomaly_detected.v1.d.ts +2 -2
  45. package/dist/events/schemas/cc.cost.recorded.v1.d.ts +4 -4
  46. package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts +6 -6
  47. package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
  48. package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +6 -6
  49. package/dist/events/schemas/forge.lead.qualified.v1.d.ts +2 -2
  50. package/dist/events/schemas/forge.outreach.sent.v1.d.ts +4 -4
  51. package/dist/events/schemas/incident.detected.v1.d.ts +2 -2
  52. package/dist/events/schemas/vauban.goal.checked.v1.d.ts +2 -2
  53. package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +2 -2
  54. package/dist/events/schemas/vauban.tax.checked.v1.d.ts +2 -2
  55. package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +6 -6
  56. package/dist/identity/agent-persona.d.ts +73 -0
  57. package/dist/identity/agent-persona.d.ts.map +1 -0
  58. package/dist/identity/agent-persona.js +165 -0
  59. package/dist/identity/agent-persona.js.map +1 -0
  60. package/dist/identity/persona-prompt.d.ts +25 -0
  61. package/dist/identity/persona-prompt.d.ts.map +1 -0
  62. package/dist/identity/persona-prompt.js +71 -0
  63. package/dist/identity/persona-prompt.js.map +1 -0
  64. package/dist/identity/persona-schema.d.ts +120 -0
  65. package/dist/identity/persona-schema.d.ts.map +1 -0
  66. package/dist/identity/persona-schema.js +103 -0
  67. package/dist/identity/persona-schema.js.map +1 -0
  68. package/dist/index.d.ts +41 -3
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +31 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/loop/minimal-loop.js +293 -287
  73. package/dist/memory/episodic-rrf.d.ts +114 -0
  74. package/dist/memory/episodic-rrf.d.ts.map +1 -0
  75. package/dist/memory/episodic-rrf.js +148 -0
  76. package/dist/memory/episodic-rrf.js.map +1 -0
  77. package/dist/mesh/attenuation.d.ts +78 -0
  78. package/dist/mesh/attenuation.d.ts.map +1 -0
  79. package/dist/mesh/attenuation.js +141 -0
  80. package/dist/mesh/attenuation.js.map +1 -0
  81. package/dist/mesh/delegate.d.ts +96 -0
  82. package/dist/mesh/delegate.d.ts.map +1 -0
  83. package/dist/mesh/delegate.js +172 -0
  84. package/dist/mesh/delegate.js.map +1 -0
  85. package/dist/mesh/dispatcher.d.ts +119 -0
  86. package/dist/mesh/dispatcher.d.ts.map +1 -0
  87. package/dist/mesh/dispatcher.js +207 -0
  88. package/dist/mesh/dispatcher.js.map +1 -0
  89. package/dist/mesh/index.d.ts +12 -0
  90. package/dist/mesh/index.d.ts.map +1 -0
  91. package/dist/mesh/index.js +11 -0
  92. package/dist/mesh/index.js.map +1 -0
  93. package/dist/mesh/types.d.ts +30 -0
  94. package/dist/mesh/types.d.ts.map +1 -0
  95. package/dist/mesh/types.js +11 -0
  96. package/dist/mesh/types.js.map +1 -0
  97. package/dist/orchestration/ooda/agent.d.ts.map +1 -1
  98. package/dist/orchestration/ooda/agent.js +36 -0
  99. package/dist/orchestration/ooda/agent.js.map +1 -1
  100. package/dist/orchestration/ooda/skills.d.ts +104 -0
  101. package/dist/orchestration/ooda/skills.d.ts.map +1 -1
  102. package/dist/orchestration/ooda/skills.js +106 -0
  103. package/dist/orchestration/ooda/skills.js.map +1 -1
  104. package/dist/orchestration/ooda/types.d.ts +11 -0
  105. package/dist/orchestration/ooda/types.d.ts.map +1 -1
  106. package/dist/ports/bastion-action.contract.test.d.ts +11 -0
  107. package/dist/ports/bastion-action.contract.test.d.ts.map +1 -0
  108. package/dist/ports/bastion-action.contract.test.js +238 -0
  109. package/dist/ports/bastion-action.contract.test.js.map +1 -0
  110. package/dist/ports/bastion-action.d.ts +133 -0
  111. package/dist/ports/bastion-action.d.ts.map +1 -0
  112. package/dist/ports/bastion-action.js +73 -0
  113. package/dist/ports/bastion-action.js.map +1 -0
  114. package/dist/ports/brain.d.ts +31 -0
  115. package/dist/ports/brain.d.ts.map +1 -1
  116. package/dist/ports/brain.js +115 -1
  117. package/dist/ports/brain.js.map +1 -1
  118. package/dist/ports/citadel-action.contract.test.d.ts +11 -0
  119. package/dist/ports/citadel-action.contract.test.d.ts.map +1 -0
  120. package/dist/ports/citadel-action.contract.test.js +317 -0
  121. package/dist/ports/citadel-action.contract.test.js.map +1 -0
  122. package/dist/ports/citadel-action.d.ts +111 -0
  123. package/dist/ports/citadel-action.d.ts.map +1 -0
  124. package/dist/ports/citadel-action.js +62 -0
  125. package/dist/ports/citadel-action.js.map +1 -0
  126. package/dist/ports/compliance-contract.d.ts +123 -0
  127. package/dist/ports/compliance-contract.d.ts.map +1 -0
  128. package/dist/ports/compliance-contract.js +35 -0
  129. package/dist/ports/compliance-contract.js.map +1 -0
  130. package/dist/ports/db.d.ts +38 -0
  131. package/dist/ports/db.d.ts.map +1 -1
  132. package/dist/ports/db.js +88 -1
  133. package/dist/ports/db.js.map +1 -1
  134. package/dist/ports/delegation.contract.test.d.ts +9 -0
  135. package/dist/ports/delegation.contract.test.d.ts.map +1 -0
  136. package/dist/ports/delegation.contract.test.js +337 -0
  137. package/dist/ports/delegation.contract.test.js.map +1 -0
  138. package/dist/ports/delegation.d.ts +134 -0
  139. package/dist/ports/delegation.d.ts.map +1 -0
  140. package/dist/ports/delegation.js +105 -0
  141. package/dist/ports/delegation.js.map +1 -0
  142. package/dist/ports/event-bus.d.ts +29 -0
  143. package/dist/ports/event-bus.d.ts.map +1 -1
  144. package/dist/ports/event-bus.js +106 -1
  145. package/dist/ports/event-bus.js.map +1 -1
  146. package/dist/ports/federation.contract.test.d.ts +9 -0
  147. package/dist/ports/federation.contract.test.d.ts.map +1 -0
  148. package/dist/ports/federation.contract.test.js +279 -0
  149. package/dist/ports/federation.contract.test.js.map +1 -0
  150. package/dist/ports/federation.d.ts +140 -0
  151. package/dist/ports/federation.d.ts.map +1 -0
  152. package/dist/ports/federation.js +57 -0
  153. package/dist/ports/federation.js.map +1 -0
  154. package/dist/ports/index.d.ts +28 -2
  155. package/dist/ports/index.d.ts.map +1 -1
  156. package/dist/ports/index.js +17 -2
  157. package/dist/ports/index.js.map +1 -1
  158. package/dist/ports/llm-provider.d.ts +37 -0
  159. package/dist/ports/llm-provider.d.ts.map +1 -1
  160. package/dist/ports/llm-provider.js +99 -1
  161. package/dist/ports/llm-provider.js.map +1 -1
  162. package/dist/ports/logger.d.ts +27 -0
  163. package/dist/ports/logger.d.ts.map +1 -1
  164. package/dist/ports/logger.js +87 -0
  165. package/dist/ports/logger.js.map +1 -1
  166. package/dist/ports/manifest-registry.contract.test.d.ts +9 -0
  167. package/dist/ports/manifest-registry.contract.test.d.ts.map +1 -0
  168. package/dist/ports/manifest-registry.contract.test.js +246 -0
  169. package/dist/ports/manifest-registry.contract.test.js.map +1 -0
  170. package/dist/ports/manifest-registry.d.ts +116 -0
  171. package/dist/ports/manifest-registry.d.ts.map +1 -0
  172. package/dist/ports/manifest-registry.js +79 -0
  173. package/dist/ports/manifest-registry.js.map +1 -0
  174. package/dist/ports/observability.contract.test.d.ts +12 -0
  175. package/dist/ports/observability.contract.test.d.ts.map +1 -0
  176. package/dist/ports/observability.contract.test.js +260 -0
  177. package/dist/ports/observability.contract.test.js.map +1 -0
  178. package/dist/ports/observability.d.ts +98 -0
  179. package/dist/ports/observability.d.ts.map +1 -0
  180. package/dist/ports/observability.js +59 -0
  181. package/dist/ports/observability.js.map +1 -0
  182. package/dist/ports/outcome.d.ts +26 -0
  183. package/dist/ports/outcome.d.ts.map +1 -1
  184. package/dist/ports/outcome.js +62 -1
  185. package/dist/ports/outcome.js.map +1 -1
  186. package/dist/ports/privacy.contract.test.d.ts +12 -0
  187. package/dist/ports/privacy.contract.test.d.ts.map +1 -0
  188. package/dist/ports/privacy.contract.test.js +325 -0
  189. package/dist/ports/privacy.contract.test.js.map +1 -0
  190. package/dist/ports/privacy.d.ts +132 -0
  191. package/dist/ports/privacy.d.ts.map +1 -0
  192. package/dist/ports/privacy.js +83 -0
  193. package/dist/ports/privacy.js.map +1 -0
  194. package/dist/ports/tenant-context.contract.test.d.ts +14 -0
  195. package/dist/ports/tenant-context.contract.test.d.ts.map +1 -0
  196. package/dist/ports/tenant-context.contract.test.js +352 -0
  197. package/dist/ports/tenant-context.contract.test.js.map +1 -0
  198. package/dist/ports/tenant-context.d.ts +103 -0
  199. package/dist/ports/tenant-context.d.ts.map +1 -0
  200. package/dist/ports/tenant-context.js +48 -0
  201. package/dist/ports/tenant-context.js.map +1 -0
  202. package/dist/ports/vauban-finance-action.contract.test.d.ts +11 -0
  203. package/dist/ports/vauban-finance-action.contract.test.d.ts.map +1 -0
  204. package/dist/ports/vauban-finance-action.contract.test.js +260 -0
  205. package/dist/ports/vauban-finance-action.contract.test.js.map +1 -0
  206. package/dist/ports/vauban-finance-action.d.ts +106 -0
  207. package/dist/ports/vauban-finance-action.d.ts.map +1 -0
  208. package/dist/ports/vauban-finance-action.js +60 -0
  209. package/dist/ports/vauban-finance-action.js.map +1 -0
  210. package/dist/ports/workflow-runtime.d.ts +204 -0
  211. package/dist/ports/workflow-runtime.d.ts.map +1 -0
  212. package/dist/ports/workflow-runtime.js +72 -0
  213. package/dist/ports/workflow-runtime.js.map +1 -0
  214. package/dist/proof/cert-verify.d.ts +80 -0
  215. package/dist/proof/cert-verify.d.ts.map +1 -0
  216. package/dist/proof/cert-verify.js +178 -0
  217. package/dist/proof/cert-verify.js.map +1 -0
  218. package/dist/replay/replay.d.ts.map +1 -1
  219. package/dist/replay/replay.js +5 -1
  220. package/dist/replay/replay.js.map +1 -1
  221. package/dist/retry/index.d.ts +129 -0
  222. package/dist/retry/index.d.ts.map +1 -0
  223. package/dist/retry/index.js +156 -0
  224. package/dist/retry/index.js.map +1 -0
  225. package/dist/retry/presets.d.ts +39 -0
  226. package/dist/retry/presets.d.ts.map +1 -0
  227. package/dist/retry/presets.js +69 -0
  228. package/dist/retry/presets.js.map +1 -0
  229. package/dist/skill-loop/ab-runner.d.ts +67 -0
  230. package/dist/skill-loop/ab-runner.d.ts.map +1 -0
  231. package/dist/skill-loop/ab-runner.js +160 -0
  232. package/dist/skill-loop/ab-runner.js.map +1 -0
  233. package/dist/skill-loop/adoption.d.ts +67 -0
  234. package/dist/skill-loop/adoption.d.ts.map +1 -0
  235. package/dist/skill-loop/adoption.js +126 -0
  236. package/dist/skill-loop/adoption.js.map +1 -0
  237. package/dist/skill-loop/candidate.d.ts +45 -0
  238. package/dist/skill-loop/candidate.d.ts.map +1 -0
  239. package/dist/skill-loop/candidate.js +43 -0
  240. package/dist/skill-loop/candidate.js.map +1 -0
  241. package/dist/skill-loop/evaluator.d.ts +42 -0
  242. package/dist/skill-loop/evaluator.d.ts.map +1 -0
  243. package/dist/skill-loop/evaluator.js +184 -0
  244. package/dist/skill-loop/evaluator.js.map +1 -0
  245. package/dist/skill-loop/index.d.ts +27 -0
  246. package/dist/skill-loop/index.d.ts.map +1 -0
  247. package/dist/skill-loop/index.js +27 -0
  248. package/dist/skill-loop/index.js.map +1 -0
  249. package/dist/skill-loop/reflexion-replay.d.ts +87 -0
  250. package/dist/skill-loop/reflexion-replay.d.ts.map +1 -0
  251. package/dist/skill-loop/reflexion-replay.js +110 -0
  252. package/dist/skill-loop/reflexion-replay.js.map +1 -0
  253. package/dist/skill-loop/sign-off.d.ts +88 -0
  254. package/dist/skill-loop/sign-off.d.ts.map +1 -0
  255. package/dist/skill-loop/sign-off.js +146 -0
  256. package/dist/skill-loop/sign-off.js.map +1 -0
  257. package/dist/skill-loop/value-metric.d.ts +55 -0
  258. package/dist/skill-loop/value-metric.d.ts.map +1 -0
  259. package/dist/skill-loop/value-metric.js +69 -0
  260. package/dist/skill-loop/value-metric.js.map +1 -0
  261. package/dist/skill-loop/versioning.d.ts +36 -0
  262. package/dist/skill-loop/versioning.d.ts.map +1 -0
  263. package/dist/skill-loop/versioning.js +47 -0
  264. package/dist/skill-loop/versioning.js.map +1 -0
  265. package/dist/skill-manifest/anchor.d.ts +91 -0
  266. package/dist/skill-manifest/anchor.d.ts.map +1 -0
  267. package/dist/skill-manifest/anchor.js +331 -0
  268. package/dist/skill-manifest/anchor.js.map +1 -0
  269. package/dist/skill-manifest/builder.d.ts +47 -0
  270. package/dist/skill-manifest/builder.d.ts.map +1 -0
  271. package/dist/skill-manifest/builder.js +93 -0
  272. package/dist/skill-manifest/builder.js.map +1 -0
  273. package/dist/skill-manifest/index.d.ts +13 -0
  274. package/dist/skill-manifest/index.d.ts.map +1 -0
  275. package/dist/skill-manifest/index.js +9 -0
  276. package/dist/skill-manifest/index.js.map +1 -0
  277. package/dist/skill-manifest/types.d.ts +67 -0
  278. package/dist/skill-manifest/types.d.ts.map +1 -0
  279. package/dist/skill-manifest/types.js +16 -0
  280. package/dist/skill-manifest/types.js.map +1 -0
  281. package/dist/skill-manifest/verifier.d.ts +42 -0
  282. package/dist/skill-manifest/verifier.d.ts.map +1 -0
  283. package/dist/skill-manifest/verifier.js +136 -0
  284. package/dist/skill-manifest/verifier.js.map +1 -0
  285. package/dist/skills/_secrets.d.ts +16 -0
  286. package/dist/skills/_secrets.d.ts.map +1 -0
  287. package/dist/skills/_secrets.js +20 -0
  288. package/dist/skills/_secrets.js.map +1 -0
  289. package/dist/skills/alpaca-quote.d.ts +2 -2
  290. package/dist/skills/alpaca-quote.d.ts.map +1 -1
  291. package/dist/skills/alpaca-quote.js +51 -20
  292. package/dist/skills/alpaca-quote.js.map +1 -1
  293. package/dist/skills/brain-query.d.ts +4 -4
  294. package/dist/skills/brain-store.d.ts +6 -6
  295. package/dist/skills/errors.d.ts +15 -0
  296. package/dist/skills/errors.d.ts.map +1 -1
  297. package/dist/skills/errors.js +21 -0
  298. package/dist/skills/errors.js.map +1 -1
  299. package/dist/skills/hitl-request.d.ts +2 -2
  300. package/dist/skills/index.d.ts +3 -1
  301. package/dist/skills/index.d.ts.map +1 -1
  302. package/dist/skills/index.js +4 -1
  303. package/dist/skills/index.js.map +1 -1
  304. package/dist/skills/markdown/loader.d.ts +52 -0
  305. package/dist/skills/markdown/loader.d.ts.map +1 -0
  306. package/dist/skills/markdown/loader.js +93 -0
  307. package/dist/skills/markdown/loader.js.map +1 -0
  308. package/dist/skills/markdown/schema.d.ts +432 -0
  309. package/dist/skills/markdown/schema.d.ts.map +1 -0
  310. package/dist/skills/markdown/schema.js +121 -0
  311. package/dist/skills/markdown/schema.js.map +1 -0
  312. package/dist/skills/poc-md-loader/markdown-loader.d.ts +77 -0
  313. package/dist/skills/poc-md-loader/markdown-loader.d.ts.map +1 -0
  314. package/dist/skills/poc-md-loader/markdown-loader.js +125 -0
  315. package/dist/skills/poc-md-loader/markdown-loader.js.map +1 -0
  316. package/dist/skills/poc-md-loader/runner.d.ts +24 -0
  317. package/dist/skills/poc-md-loader/runner.d.ts.map +1 -0
  318. package/dist/skills/poc-md-loader/runner.js +57 -0
  319. package/dist/skills/poc-md-loader/runner.js.map +1 -0
  320. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts +3 -0
  321. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts.map +1 -0
  322. package/dist/skills/poc-md-loader/vitest.poc.config.js +13 -0
  323. package/dist/skills/poc-md-loader/vitest.poc.config.js.map +1 -0
  324. package/dist/skills/poc-md-loader/web-search/script.d.ts +33 -0
  325. package/dist/skills/poc-md-loader/web-search/script.d.ts.map +1 -0
  326. package/dist/skills/poc-md-loader/web-search/script.js +75 -0
  327. package/dist/skills/poc-md-loader/web-search/script.js.map +1 -0
  328. package/dist/skills/record-outcome.d.ts +4 -4
  329. package/dist/skills/send-email.d.ts +2 -2
  330. package/dist/skills/send-email.d.ts.map +1 -1
  331. package/dist/skills/send-email.js +4 -3
  332. package/dist/skills/send-email.js.map +1 -1
  333. package/dist/skills/slack-notify.d.ts +4 -4
  334. package/dist/skills/slack-notify.d.ts.map +1 -1
  335. package/dist/skills/slack-notify.js +52 -21
  336. package/dist/skills/slack-notify.js.map +1 -1
  337. package/dist/skills/starknet-balance.d.ts +1 -1
  338. package/dist/skills/telegram-notify.d.ts +4 -4
  339. package/dist/skills/telegram-notify.d.ts.map +1 -1
  340. package/dist/skills/telegram-notify.js +48 -19
  341. package/dist/skills/telegram-notify.js.map +1 -1
  342. package/dist/skills/web-search.d.ts +1 -1
  343. package/dist/skills/web-search.d.ts.map +1 -1
  344. package/dist/skills/web-search.js +85 -40
  345. package/dist/skills/web-search.js.map +1 -1
  346. package/dist/telemetry/bus.d.ts +54 -0
  347. package/dist/telemetry/bus.d.ts.map +1 -0
  348. package/dist/telemetry/bus.js +159 -0
  349. package/dist/telemetry/bus.js.map +1 -0
  350. package/dist/telemetry/index.d.ts +35 -0
  351. package/dist/telemetry/index.d.ts.map +1 -0
  352. package/dist/telemetry/index.js +30 -0
  353. package/dist/telemetry/index.js.map +1 -0
  354. package/dist/telemetry/port.d.ts +121 -0
  355. package/dist/telemetry/port.d.ts.map +1 -0
  356. package/dist/telemetry/port.js +48 -0
  357. package/dist/telemetry/port.js.map +1 -0
  358. package/dist/telemetry/sinks/otlp.d.ts +45 -0
  359. package/dist/telemetry/sinks/otlp.d.ts.map +1 -0
  360. package/dist/telemetry/sinks/otlp.js +195 -0
  361. package/dist/telemetry/sinks/otlp.js.map +1 -0
  362. package/dist/telemetry/sinks/sqlite.d.ts +32 -0
  363. package/dist/telemetry/sinks/sqlite.d.ts.map +1 -0
  364. package/dist/telemetry/sinks/sqlite.js +170 -0
  365. package/dist/telemetry/sinks/sqlite.js.map +1 -0
  366. package/dist/telemetry/sinks/stdout.d.ts +22 -0
  367. package/dist/telemetry/sinks/stdout.d.ts.map +1 -0
  368. package/dist/telemetry/sinks/stdout.js +38 -0
  369. package/dist/telemetry/sinks/stdout.js.map +1 -0
  370. package/dist/testing/index.d.ts +3 -0
  371. package/dist/testing/test-brain-port.d.ts +4 -0
  372. package/dist/testing/test-brain-port.d.ts.map +1 -1
  373. package/dist/testing/test-brain-port.js +75 -20
  374. package/dist/testing/test-brain-port.js.map +1 -1
  375. package/dist/testing/test-event-bus.d.ts.map +1 -1
  376. package/dist/testing/test-event-bus.js +89 -36
  377. package/dist/testing/test-event-bus.js.map +1 -1
  378. package/dist/trace/schema.d.ts +1 -1
  379. package/dist/trace/schema.d.ts.map +1 -1
  380. package/dist/trace/schema.js +1 -1
  381. package/dist/trace/schema.js.map +1 -1
  382. package/dist/verify/formal/index.d.ts +44 -0
  383. package/dist/verify/formal/index.d.ts.map +1 -0
  384. package/dist/verify/formal/index.js +98 -0
  385. package/dist/verify/formal/index.js.map +1 -0
  386. package/dist/verify/formal/policy.d.ts +105 -0
  387. package/dist/verify/formal/policy.d.ts.map +1 -0
  388. package/dist/verify/formal/policy.js +159 -0
  389. package/dist/verify/formal/policy.js.map +1 -0
  390. package/dist/verify/formal/result.d.ts +50 -0
  391. package/dist/verify/formal/result.d.ts.map +1 -0
  392. package/dist/verify/formal/result.js +21 -0
  393. package/dist/verify/formal/result.js.map +1 -0
  394. package/dist/verify/formal/solver.d.ts +67 -0
  395. package/dist/verify/formal/solver.d.ts.map +1 -0
  396. package/dist/verify/formal/solver.js +184 -0
  397. package/dist/verify/formal/solver.js.map +1 -0
  398. package/dist/verify/formal/spec-language.d.ts +80 -0
  399. package/dist/verify/formal/spec-language.d.ts.map +1 -0
  400. package/dist/verify/formal/spec-language.js +219 -0
  401. package/dist/verify/formal/spec-language.js.map +1 -0
  402. package/docs/attestation.md +199 -0
  403. package/docs/identity.md +193 -0
  404. package/docs/telemetry/migration.md +155 -0
  405. package/docs/telemetry/overview.md +154 -0
  406. package/docs/telemetry/privacy.md +127 -0
  407. package/docs/telemetry/sinks/cc.md +155 -0
  408. package/docs/telemetry/sinks/otlp.md +146 -0
  409. package/docs/telemetry/sinks/sqlite.md +126 -0
  410. package/docs/telemetry/sinks/stdout.md +82 -0
  411. package/package.json +18 -2
  412. package/src/adapters/llm/anthropic-direct.ts +51 -0
  413. package/src/adapters/llm/cascade.ts +64 -19
  414. package/src/adapters/llm/litellm.ts +49 -0
  415. package/src/compute/difficulty-estimator.ts +111 -0
  416. package/src/compute/strategies/mixture-of-agents.ts +150 -0
  417. package/src/compute/strategies/tree-of-thoughts.ts +293 -0
  418. package/src/compute/strategies/two-phase-orient.ts +147 -0
  419. package/src/container/protocol.ts +243 -0
  420. package/src/container/runtime.ts +424 -0
  421. package/src/db/migrations/026_formal_verify_results.sql +30 -0
  422. package/src/identity/agent-persona.ts +203 -0
  423. package/src/identity/persona-prompt.ts +84 -0
  424. package/src/identity/persona-schema.ts +127 -0
  425. package/src/index.ts +368 -2
  426. package/src/memory/episodic-rrf.ts +224 -0
  427. package/src/mesh/attenuation.ts +190 -0
  428. package/src/mesh/delegate.ts +254 -0
  429. package/src/mesh/dispatcher.ts +301 -0
  430. package/src/mesh/index.ts +39 -0
  431. package/src/mesh/types.ts +31 -0
  432. package/src/orchestration/ooda/agent.ts +50 -0
  433. package/src/orchestration/ooda/skills.ts +177 -0
  434. package/src/orchestration/ooda/types.ts +12 -0
  435. package/src/ports/bastion-action.contract.test.ts +355 -0
  436. package/src/ports/bastion-action.ts +198 -0
  437. package/src/ports/brain.ts +177 -15
  438. package/src/ports/citadel-action.contract.test.ts +430 -0
  439. package/src/ports/citadel-action.ts +174 -0
  440. package/src/ports/compliance-contract.ts +191 -0
  441. package/src/ports/db.ts +98 -0
  442. package/src/ports/delegation.contract.test.ts +428 -0
  443. package/src/ports/delegation.ts +211 -0
  444. package/src/ports/event-bus.ts +133 -0
  445. package/src/ports/federation.contract.test.ts +355 -0
  446. package/src/ports/federation.ts +190 -0
  447. package/src/ports/index.ts +186 -1
  448. package/src/ports/llm-provider.ts +123 -0
  449. package/src/ports/logger.ts +104 -0
  450. package/src/ports/manifest-registry.contract.test.ts +324 -0
  451. package/src/ports/manifest-registry.ts +188 -0
  452. package/src/ports/observability.contract.test.ts +315 -0
  453. package/src/ports/observability.ts +150 -0
  454. package/src/ports/outcome.ts +69 -0
  455. package/src/ports/privacy.contract.test.ts +413 -0
  456. package/src/ports/privacy.ts +207 -0
  457. package/src/ports/tenant-context.contract.test.ts +454 -0
  458. package/src/ports/tenant-context.ts +150 -0
  459. package/src/ports/vauban-finance-action.contract.test.ts +335 -0
  460. package/src/ports/vauban-finance-action.ts +166 -0
  461. package/src/ports/workflow-runtime.ts +327 -0
  462. package/src/proof/cert-verify.ts +249 -0
  463. package/src/replay/replay.ts +11 -8
  464. package/src/retry/index.ts +227 -0
  465. package/src/retry/presets.ts +75 -0
  466. package/src/skill-loop/ab-runner.ts +196 -0
  467. package/src/skill-loop/adoption.ts +188 -0
  468. package/src/skill-loop/candidate.ts +75 -0
  469. package/src/skill-loop/evaluator.ts +238 -0
  470. package/src/skill-loop/index.ts +51 -0
  471. package/src/skill-loop/reflexion-replay.ts +173 -0
  472. package/src/skill-loop/sign-off.ts +247 -0
  473. package/src/skill-loop/value-metric.ts +120 -0
  474. package/src/skill-loop/versioning.ts +75 -0
  475. package/src/skill-manifest/anchor.ts +401 -0
  476. package/src/skill-manifest/builder.ts +129 -0
  477. package/src/skill-manifest/index.ts +18 -0
  478. package/src/skill-manifest/types.ts +72 -0
  479. package/src/skill-manifest/verifier.ts +198 -0
  480. package/src/skills/_secrets.ts +25 -0
  481. package/src/skills/alpaca-quote.ts +68 -23
  482. package/src/skills/errors.ts +30 -2
  483. package/src/skills/index.ts +19 -0
  484. package/src/skills/markdown/loader.ts +129 -0
  485. package/src/skills/markdown/schema.ts +144 -0
  486. package/src/skills/poc-md-loader/e2e-parity.test.ts +237 -0
  487. package/src/skills/poc-md-loader/markdown-loader.ts +161 -0
  488. package/src/skills/poc-md-loader/runner.ts +82 -0
  489. package/src/skills/poc-md-loader/vitest.poc.config.ts +13 -0
  490. package/src/skills/poc-md-loader/web-search/SKILL.md +42 -0
  491. package/src/skills/poc-md-loader/web-search/script.ts +109 -0
  492. package/src/skills/send-email.ts +4 -3
  493. package/src/skills/slack-notify.ts +73 -30
  494. package/src/skills/telegram-notify.ts +70 -24
  495. package/src/skills/web-search.ts +132 -50
  496. package/src/telemetry/bus.test.ts +231 -0
  497. package/src/telemetry/bus.ts +241 -0
  498. package/src/telemetry/index.ts +49 -0
  499. package/src/telemetry/port.ts +160 -0
  500. package/src/telemetry/sinks/otlp.test.ts +146 -0
  501. package/src/telemetry/sinks/otlp.ts +250 -0
  502. package/src/telemetry/sinks/sqlite.test.ts +121 -0
  503. package/src/telemetry/sinks/sqlite.ts +260 -0
  504. package/src/telemetry/sinks/stdout.test.ts +109 -0
  505. package/src/telemetry/sinks/stdout.ts +59 -0
  506. package/src/testing/test-brain-port.ts +98 -24
  507. package/src/testing/test-event-bus.ts +104 -43
  508. package/src/trace/schema.ts +1 -1
  509. package/src/verify/formal/index.ts +154 -0
  510. package/src/verify/formal/policy.ts +253 -0
  511. package/src/verify/formal/result.ts +52 -0
  512. package/src/verify/formal/solver.ts +235 -0
  513. package/src/verify/formal/spec-language.ts +274 -0
@@ -8,6 +8,8 @@
8
8
  */
9
9
 
10
10
  import Anthropic from "@anthropic-ai/sdk";
11
+ import type { Span } from "@opentelemetry/api";
12
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
11
13
  import type {
12
14
  ChatRequest,
13
15
  ChatResponse,
@@ -16,6 +18,11 @@ import type {
16
18
  StreamDelta,
17
19
  } from "../../ports/llm-provider.js";
18
20
 
21
+ const ADAPTER_TRACER = trace.getTracer(
22
+ "vauban-agent-sdk.llm.anthropic",
23
+ "0.1.0"
24
+ );
25
+
19
26
  export interface AnthropicDirectAdapterConfig {
20
27
  apiKey: string;
21
28
  /** Default model to use when ChatRequest.model is not specified. */
@@ -70,6 +77,50 @@ export class AnthropicDirectAdapter implements LLMProviderPort {
70
77
  }
71
78
 
72
79
  async complete(req: ChatRequest): Promise<ChatResponse> {
80
+ return ADAPTER_TRACER.startActiveSpan(
81
+ "llm-provider.complete",
82
+ {
83
+ attributes: {
84
+ "gen_ai.system": "anthropic",
85
+ "gen_ai.request.model": req.model ?? this.defaultModel,
86
+ "gen_ai.request.message_count": req.messages.length,
87
+ "vauban.port.name": "llm-provider",
88
+ "vauban.port.impl": "AnthropicDirectAdapter",
89
+ },
90
+ },
91
+ async (span: Span): Promise<ChatResponse> => {
92
+ try {
93
+ const response: ChatResponse = await this._doComplete(req);
94
+ span.setAttributes({
95
+ "gen_ai.usage.input_tokens": response.usage.inputTokens,
96
+ "gen_ai.usage.output_tokens": response.usage.outputTokens,
97
+ "gen_ai.response.model": response.model,
98
+ "gen_ai.response.finish_reasons": [response.finishReason],
99
+ });
100
+ if (response.usage.costUsd !== undefined) {
101
+ span.setAttribute("gen_ai.usage.cost_usd", response.usage.costUsd);
102
+ }
103
+ span.setStatus({ code: SpanStatusCode.OK });
104
+ return response;
105
+ } catch (_err) {
106
+ span.setStatus({
107
+ code: SpanStatusCode.ERROR,
108
+ message: "span wrapper caught exception",
109
+ });
110
+ return {
111
+ content: "",
112
+ usage: { inputTokens: 0, outputTokens: 0 },
113
+ model: req.model ?? this.defaultModel,
114
+ finishReason: "error" as const,
115
+ };
116
+ } finally {
117
+ span.end();
118
+ }
119
+ }
120
+ );
121
+ }
122
+
123
+ private async _doComplete(req: ChatRequest): Promise<ChatResponse> {
73
124
  const model = req.model ?? this.defaultModel;
74
125
 
75
126
  // Extract system message (Anthropic API separates system from messages)
@@ -12,6 +12,8 @@
12
12
  * BYOM: no default model hardcoded.
13
13
  */
14
14
 
15
+ import type { Span } from "@opentelemetry/api";
16
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
15
17
  import type {
16
18
  ChatRequest,
17
19
  ChatResponse,
@@ -19,6 +21,8 @@ import type {
19
21
  StreamDelta,
20
22
  } from "../../ports/llm-provider.js";
21
23
 
24
+ const ADAPTER_TRACER = trace.getTracer("vauban-agent-sdk.llm.cascade", "0.1.0");
25
+
22
26
  const ALL_FAIL_RESPONSE: ChatResponse = {
23
27
  content: "",
24
28
  usage: { inputTokens: 0, outputTokens: 0 },
@@ -51,26 +55,67 @@ export class CascadeAdapter implements LLMProviderPort {
51
55
  }
52
56
 
53
57
  async complete(req: ChatRequest): Promise<ChatResponse> {
54
- for (const provider of this.providers) {
55
- if (req.abortSignal?.aborted) {
56
- return { ...ALL_FAIL_RESPONSE };
57
- }
58
-
59
- let response: ChatResponse;
60
- try {
61
- response = await provider.complete(req);
62
- } catch {
63
- // Unexpected throw — treat as failure, try next
64
- continue;
65
- }
66
-
67
- if (response.finishReason !== "error") {
68
- return response;
58
+ return ADAPTER_TRACER.startActiveSpan(
59
+ "llm-provider.complete",
60
+ {
61
+ attributes: {
62
+ "gen_ai.system": "cascade",
63
+ "gen_ai.request.model": req.model ?? "cascade",
64
+ "gen_ai.request.message_count": req.messages.length,
65
+ "vauban.port.name": "llm-provider",
66
+ "vauban.port.impl": "CascadeAdapter",
67
+ "vauban.cascade.provider_count": this.providers.length,
68
+ },
69
+ },
70
+ async (span: Span) => {
71
+ try {
72
+ let attemptCount = 0;
73
+ for (const provider of this.providers) {
74
+ attemptCount++;
75
+ if (req.abortSignal?.aborted) {
76
+ span.setAttribute("vauban.cascade.attempts", attemptCount);
77
+ span.setStatus({ code: SpanStatusCode.OK });
78
+ return { ...ALL_FAIL_RESPONSE };
79
+ }
80
+
81
+ let response: ChatResponse;
82
+ try {
83
+ response = await provider.complete(req);
84
+ } catch {
85
+ // Unexpected throw — treat as failure, try next
86
+ continue;
87
+ }
88
+
89
+ if (response.finishReason !== "error") {
90
+ span.setAttribute("vauban.cascade.attempts", attemptCount);
91
+ span.setAttributes({
92
+ "gen_ai.usage.input_tokens": response.usage.inputTokens,
93
+ "gen_ai.usage.output_tokens": response.usage.outputTokens,
94
+ "gen_ai.response.model": response.model,
95
+ "gen_ai.response.finish_reasons": [response.finishReason],
96
+ });
97
+ span.setStatus({ code: SpanStatusCode.OK });
98
+ return response;
99
+ }
100
+ // finishReason === "error" → try next provider
101
+ }
102
+ span.setAttribute("vauban.cascade.attempts", attemptCount);
103
+ span.setAttribute("vauban.cascade.all_failed", true);
104
+ span.setStatus({
105
+ code: SpanStatusCode.ERROR,
106
+ message: "all providers failed",
107
+ });
108
+ return { ...ALL_FAIL_RESPONSE };
109
+ } catch (err) {
110
+ const message = err instanceof Error ? err.message : String(err);
111
+ span.setStatus({ code: SpanStatusCode.ERROR, message });
112
+ if (err instanceof Error) span.recordException(err);
113
+ return { ...ALL_FAIL_RESPONSE };
114
+ } finally {
115
+ span.end();
116
+ }
69
117
  }
70
- // finishReason === "error" → try next provider
71
- }
72
-
73
- return { ...ALL_FAIL_RESPONSE };
118
+ );
74
119
  }
75
120
 
76
121
  async *stream(req: ChatRequest): AsyncIterable<StreamDelta> {
@@ -9,6 +9,8 @@
9
9
  * No model string is hardcoded at module scope.
10
10
  */
11
11
 
12
+ import type { Span } from "@opentelemetry/api";
13
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
12
14
  import type {
13
15
  ChatRequest,
14
16
  ChatResponse,
@@ -17,6 +19,8 @@ import type {
17
19
  StreamDelta,
18
20
  } from "../../ports/llm-provider.js";
19
21
 
22
+ const ADAPTER_TRACER = trace.getTracer("vauban-agent-sdk.llm.litellm", "0.1.0");
23
+
20
24
  export interface LiteLLMAdapterConfig {
21
25
  baseUrl: string;
22
26
  apiKey?: string;
@@ -103,6 +107,51 @@ export class LiteLLMAdapter implements LLMProviderPort {
103
107
  }
104
108
 
105
109
  async complete(req: ChatRequest): Promise<ChatResponse> {
110
+ return ADAPTER_TRACER.startActiveSpan(
111
+ "llm-provider.complete",
112
+ {
113
+ attributes: {
114
+ "gen_ai.system": "litellm",
115
+ "gen_ai.request.model": req.model ?? this.defaultModel,
116
+ "gen_ai.request.message_count": req.messages.length,
117
+ "vauban.port.name": "llm-provider",
118
+ "vauban.port.impl": "LiteLLMAdapter",
119
+ },
120
+ },
121
+ async (span: Span): Promise<ChatResponse> => {
122
+ try {
123
+ const response: ChatResponse = await this._doComplete(req);
124
+ span.setAttributes({
125
+ "gen_ai.usage.input_tokens": response.usage.inputTokens,
126
+ "gen_ai.usage.output_tokens": response.usage.outputTokens,
127
+ "gen_ai.response.model": response.model,
128
+ "gen_ai.response.finish_reasons": [response.finishReason],
129
+ });
130
+ if (response.usage.costUsd !== undefined) {
131
+ span.setAttribute("gen_ai.usage.cost_usd", response.usage.costUsd);
132
+ }
133
+ span.setStatus({ code: SpanStatusCode.OK });
134
+ return response;
135
+ } catch (_err) {
136
+ span.setStatus({
137
+ code: SpanStatusCode.ERROR,
138
+ message: "span wrapper caught exception",
139
+ });
140
+ return {
141
+ content: "",
142
+ usage: { inputTokens: 0, outputTokens: 0 },
143
+ model: req.model ?? this.defaultModel,
144
+ finishReason: "error" as const,
145
+ };
146
+ } finally {
147
+ span.end();
148
+ }
149
+ }
150
+ );
151
+ }
152
+
153
+ /** Internal completion logic — extracted from complete() for span instrumentation. */
154
+ private async _doComplete(req: ChatRequest): Promise<ChatResponse> {
106
155
  const model = req.model ?? this.defaultModel;
107
156
  const body = {
108
157
  model,
@@ -0,0 +1,111 @@
1
+ /**
2
+ * src/compute/difficulty-estimator.ts
3
+ *
4
+ * Deterministic task-difficulty classifier + strategy recommender.
5
+ *
6
+ * NOT an LLM call — pure feature extraction + rule-based classification.
7
+ * Routes input difficulty → recommended compute strategy.
8
+ *
9
+ * @experimental Public-experimental API per `contract-stability.md` (sprint-582).
10
+ */
11
+
12
+ // ─── Public types ────────────────────────────────────────────────────────────
13
+
14
+ export type DifficultyClass = "simple" | "standard" | "complex" | "reasoning";
15
+
16
+ export interface TaskFeatures {
17
+ /** Character count of input. */
18
+ inputLength: number;
19
+ /** Input contains "step", "then", or "first…then" pattern. */
20
+ hasMultipleSteps: boolean;
21
+ /** Input contains "why", "explain", "reason", "prove", "deduce". */
22
+ requiresReasoning: boolean;
23
+ /** Input contains "create", "generate", "design", "imagine". */
24
+ requiresCreativity: boolean;
25
+ /** Input contains digits or math operators. */
26
+ hasNumerics: boolean;
27
+ /** Input references multiple entities ("A and B", "compare"). */
28
+ hasCrossReference: boolean;
29
+ /** Length of optional context/system prompt. */
30
+ contextLength: number;
31
+ }
32
+
33
+ // ─── Regex patterns (case-insensitive, word-bounded where useful) ───────────
34
+
35
+ const RE_STEPS = /\b(step|steps|then|first|next|finally)\b/i;
36
+ const RE_REASONING =
37
+ /\b(why|explain|explains|reason|reasons|prove|proves|deduce|deduces|infer|justify)\b/i;
38
+ const RE_CREATIVITY = /\b(create|generate|design|imagine|invent|compose)\b/i;
39
+ const RE_NUMERICS = /[0-9]|[+\-*/^=]/;
40
+ const RE_CROSS_REF = /\b(compare|and|versus|vs\.?|both)\b/i;
41
+
42
+ // ─── Feature extraction ──────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Extract task features from input + optional context.
46
+ * Deterministic, side-effect free.
47
+ */
48
+ export function extractFeatures(input: string, context?: string): TaskFeatures {
49
+ const inputLength = input.length;
50
+ const contextLength = context?.length ?? 0;
51
+
52
+ return {
53
+ inputLength,
54
+ hasMultipleSteps: RE_STEPS.test(input),
55
+ requiresReasoning: RE_REASONING.test(input),
56
+ requiresCreativity: RE_CREATIVITY.test(input),
57
+ hasNumerics: RE_NUMERICS.test(input),
58
+ hasCrossReference: RE_CROSS_REF.test(input),
59
+ contextLength,
60
+ };
61
+ }
62
+
63
+ // ─── Difficulty classification ───────────────────────────────────────────────
64
+
65
+ /**
66
+ * Classify difficulty from task features.
67
+ *
68
+ * Decision tree (most specific first):
69
+ * - requiresReasoning → "reasoning"
70
+ * - inputLength > 500 OR hasMultipleSteps OR requiresCreativity → "complex"
71
+ * - inputLength in [100, 500] OR hasNumerics → "standard"
72
+ * - else → "simple"
73
+ */
74
+ export function estimateDifficulty(features: TaskFeatures): DifficultyClass {
75
+ if (features.requiresReasoning) return "reasoning";
76
+ if (features.inputLength > 500 || features.hasMultipleSteps || features.requiresCreativity) {
77
+ return "complex";
78
+ }
79
+ if (features.inputLength >= 100 || features.hasNumerics) {
80
+ return "standard";
81
+ }
82
+ return "simple";
83
+ }
84
+
85
+ // ─── Strategy recommendation ─────────────────────────────────────────────────
86
+
87
+ /**
88
+ * Recommend a compute strategy for a given difficulty class.
89
+ *
90
+ * Map (per Sprint A bench results + Sprint-582 spec):
91
+ * simple → single-shot
92
+ * standard → bon-mav
93
+ * complex → tree-of-thoughts
94
+ * reasoning → mixture-of-agents
95
+ */
96
+ export function recommendStrategy(difficulty: DifficultyClass): string {
97
+ switch (difficulty) {
98
+ case "simple":
99
+ return "single-shot";
100
+ case "standard":
101
+ return "bon-mav";
102
+ case "complex":
103
+ return "tree-of-thoughts";
104
+ case "reasoning":
105
+ return "mixture-of-agents";
106
+ default: {
107
+ const _exhaustive: never = difficulty;
108
+ throw new Error(`recommendStrategy: unknown difficulty "${String(_exhaustive)}"`);
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * src/compute/strategies/mixture-of-agents.ts
3
+ *
4
+ * Mixture-of-Agents (MoA) compute strategy.
5
+ *
6
+ * Reference: Wang et al. 2024, "Mixture of Agents", arXiv:2406.04692.
7
+ *
8
+ * Algorithm:
9
+ * - L rounds (layers). Each round runs M proposers (independent parallel calls).
10
+ * - After each round, an aggregator synthesizes the M outputs into ONE result.
11
+ * - The synthesized result becomes the seed for the next round (currently
12
+ * opaque to the generator — synthesis is purely on the output side; the
13
+ * same input is used each round, but the aggregated state is returned).
14
+ * - Final aggregated output is the answer.
15
+ *
16
+ * Budget: M × L total generator calls.
17
+ *
18
+ * Default aggregation:
19
+ * - string outputs : concatenate with "\n---\n" then take first non-empty
20
+ * - number outputs : median
21
+ * - other : first element
22
+ *
23
+ * @experimental Public-experimental API per `contract-stability.md` (sprint-582).
24
+ */
25
+
26
+ import type { ComputeContext, Strategy, StrategyResult } from "../types.js";
27
+
28
+ // ─── Public types ────────────────────────────────────────────────────────────
29
+
30
+ export interface MoAConfig<TOutput> {
31
+ /** Number of rounds (L). Default: 2. */
32
+ rounds: number;
33
+ /** Proposers per round (M). Default: 3. */
34
+ proposersPerRound: number;
35
+ /** Aggregation function: M outputs → 1 synthesized output. */
36
+ aggregate?: (outputs: TOutput[]) => TOutput;
37
+ }
38
+
39
+ const STRATEGY_NAME = "mixture-of-agents";
40
+
41
+ // ─── Default aggregator ──────────────────────────────────────────────────────
42
+
43
+ function defaultAggregator<T>(outputs: T[]): T {
44
+ if (outputs.length === 0) {
45
+ throw new Error("mixtureOfAgentsStrategy: aggregator called with 0 outputs");
46
+ }
47
+ const first = outputs[0];
48
+
49
+ // Strings: concat for traceability, then return first non-empty after concat header.
50
+ // Per spec: "if outputs are strings, concatenate with '\n---\n' prefix and take
51
+ // the first non-empty (simple but correct for MVP)."
52
+ if (typeof first === "string") {
53
+ const nonEmpty = outputs.find((o) => typeof o === "string" && (o as string).length > 0);
54
+ return (nonEmpty ?? first) as T;
55
+ }
56
+
57
+ // Numbers: median.
58
+ if (typeof first === "number") {
59
+ const nums = (outputs as unknown as number[]).filter((n) => Number.isFinite(n));
60
+ if (nums.length === 0) return first;
61
+ const sorted = [...nums].sort((a, b) => a - b);
62
+ const mid = Math.floor(sorted.length / 2);
63
+ const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
64
+ return median as unknown as T;
65
+ }
66
+
67
+ // Other types: return first (identity fallback).
68
+ return first;
69
+ }
70
+
71
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
72
+
73
+ function throwIfAborted(signal: AbortSignal | undefined): void {
74
+ if (signal?.aborted) {
75
+ throw signal.reason instanceof Error
76
+ ? signal.reason
77
+ : new DOMException("Aborted", "AbortError");
78
+ }
79
+ }
80
+
81
+ // ─── Strategy factory ────────────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Construct a Mixture-of-Agents {@link Strategy}.
85
+ *
86
+ * @throws RangeError when `rounds` or `proposersPerRound` < 1.
87
+ */
88
+ export function mixtureOfAgentsStrategy<TInput, TOutput>(
89
+ config?: Partial<MoAConfig<TOutput>>,
90
+ ): Strategy<TInput, TOutput> {
91
+ const rounds = config?.rounds ?? 2;
92
+ const proposersPerRound = config?.proposersPerRound ?? 3;
93
+ const aggregate = config?.aggregate ?? defaultAggregator;
94
+
95
+ if (!Number.isInteger(rounds) || rounds < 1) {
96
+ throw new RangeError(`mixtureOfAgentsStrategy: rounds must be >=1, got ${rounds}`);
97
+ }
98
+ if (!Number.isInteger(proposersPerRound) || proposersPerRound < 1) {
99
+ throw new RangeError(
100
+ `mixtureOfAgentsStrategy: proposersPerRound must be >=1, got ${proposersPerRound}`,
101
+ );
102
+ }
103
+
104
+ return {
105
+ name: STRATEGY_NAME,
106
+
107
+ async run(
108
+ input: TInput,
109
+ generator: (input: TInput, ctx: ComputeContext) => Promise<TOutput>,
110
+ ctx: ComputeContext = {},
111
+ ): Promise<StrategyResult<TOutput>> {
112
+ const start = performance.now();
113
+ const signal = ctx.signal;
114
+ throwIfAborted(signal);
115
+
116
+ const childCtx: ComputeContext = signal ? { signal } : {};
117
+
118
+ let aggregated: TOutput | undefined;
119
+ let totalCalls = 0;
120
+
121
+ for (let r = 0; r < rounds; r++) {
122
+ throwIfAborted(signal);
123
+ const outputs = await Promise.all(
124
+ Array.from({ length: proposersPerRound }, () => generator(input, childCtx)),
125
+ );
126
+ totalCalls += proposersPerRound;
127
+ throwIfAborted(signal);
128
+ aggregated = aggregate(outputs);
129
+ }
130
+
131
+ const latency_ms = performance.now() - start;
132
+
133
+ if (aggregated === undefined) {
134
+ // Unreachable: rounds >= 1 guarantees aggregated is set.
135
+ throw new Error("mixtureOfAgentsStrategy: no aggregated result");
136
+ }
137
+
138
+ return {
139
+ result: aggregated,
140
+ metadata: {
141
+ strategy: STRATEGY_NAME,
142
+ candidates: totalCalls,
143
+ verifier_scores: [],
144
+ cost: { calls: totalCalls },
145
+ latency_ms,
146
+ },
147
+ };
148
+ },
149
+ };
150
+ }