@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
@@ -0,0 +1,293 @@
1
+ /**
2
+ * src/compute/strategies/tree-of-thoughts.ts
3
+ *
4
+ * Tree-of-Thoughts (ToT) compute strategy.
5
+ *
6
+ * Reference: Yao et al. 2023, "Tree of Thoughts: Deliberate Problem Solving
7
+ * with Large Language Models", arXiv:2305.10601.
8
+ *
9
+ * Algorithm (paper §3):
10
+ * 1. Build a tree of partial-solution states, root = empty/initial state.
11
+ * 2. Expand each node into up to `branchFactor` children via the generator.
12
+ * 3. Evaluate each state with a lightweight heuristic (no extra LLM call).
13
+ * 4. BFS expands level-by-level; DFS goes depth-first with backtracking
14
+ * when score < pruning threshold.
15
+ * 5. Bound total expansions by `maxCalls` (== generator-call budget).
16
+ * 6. Return the highest-scoring leaf output.
17
+ *
18
+ * Default state-evaluator (no LLM):
19
+ * - string outputs : monotone progress score based on length (caps at 200)
20
+ * - number outputs : closeness to plausible-answer band [0, 100]
21
+ * - other : 0.5 (neutral)
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 type ToTSearchPolicy = "bfs" | "dfs";
31
+
32
+ export interface ToTConfig {
33
+ /** BFS or DFS. Default: "bfs". */
34
+ searchPolicy: ToTSearchPolicy;
35
+ /** Max tree depth (steps). Default: 3. */
36
+ maxDepth: number;
37
+ /** Max branching factor (children per node). Default: 3. */
38
+ branchFactor: number;
39
+ /** Hard cap on total generator calls. Default: maxDepth * branchFactor. */
40
+ maxCalls: number;
41
+ /** State evaluator → score in [0,1]. Default: heuristic on output shape. */
42
+ evaluateState?: (state: unknown) => number;
43
+ /** Prune any node whose evaluator score is below this. Default: 0.2. */
44
+ pruneThreshold: number;
45
+ }
46
+
47
+ const STRATEGY_NAME = "tree-of-thoughts";
48
+
49
+ const VALID_POLICIES: ReadonlySet<string> = new Set(["bfs", "dfs"]);
50
+
51
+ // ─── Default evaluator ───────────────────────────────────────────────────────
52
+
53
+ function defaultEvaluator(state: unknown): number {
54
+ if (typeof state === "string") {
55
+ const len = state.length;
56
+ if (len === 0) return 0;
57
+ // Monotone, saturates at 200 chars → 1.0
58
+ return Math.min(1, len / 200);
59
+ }
60
+ if (typeof state === "number" && Number.isFinite(state)) {
61
+ if (state < 0 || state > 200) return 0.1;
62
+ // Centered around 50 for plausibility (synthetic-task heuristic)
63
+ return 0.5 + 0.5 * (1 / (1 + Math.abs(state - 50)));
64
+ }
65
+ return 0.5;
66
+ }
67
+
68
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
69
+
70
+ function throwIfAborted(signal: AbortSignal | undefined): void {
71
+ if (signal?.aborted) {
72
+ throw signal.reason instanceof Error
73
+ ? signal.reason
74
+ : new DOMException("Aborted", "AbortError");
75
+ }
76
+ }
77
+
78
+ interface TreeNode<O> {
79
+ state: O;
80
+ depth: number;
81
+ score: number;
82
+ }
83
+
84
+ // ─── Strategy factory ────────────────────────────────────────────────────────
85
+
86
+ /**
87
+ * Construct a Tree-of-Thoughts {@link Strategy}.
88
+ *
89
+ * @throws RangeError when `maxDepth`, `branchFactor`, or `maxCalls` is < 1.
90
+ * @throws Error when `searchPolicy` is not "bfs" or "dfs".
91
+ */
92
+ export function treeOfThoughtsStrategy<TInput, TOutput>(
93
+ config?: Partial<ToTConfig>,
94
+ ): Strategy<TInput, TOutput> {
95
+ const searchPolicy: ToTSearchPolicy = config?.searchPolicy ?? "bfs";
96
+ const maxDepth = config?.maxDepth ?? 3;
97
+ const branchFactor = config?.branchFactor ?? 3;
98
+ const maxCalls = config?.maxCalls ?? maxDepth * branchFactor;
99
+ const pruneThreshold = config?.pruneThreshold ?? 0.2;
100
+ const evaluateState = config?.evaluateState ?? defaultEvaluator;
101
+
102
+ if (!Number.isInteger(maxDepth) || maxDepth < 1) {
103
+ throw new RangeError(`treeOfThoughtsStrategy: maxDepth must be >=1, got ${maxDepth}`);
104
+ }
105
+ if (!Number.isInteger(branchFactor) || branchFactor < 1) {
106
+ throw new RangeError(`treeOfThoughtsStrategy: branchFactor must be >=1, got ${branchFactor}`);
107
+ }
108
+ if (!Number.isInteger(maxCalls) || maxCalls < 1) {
109
+ throw new RangeError(`treeOfThoughtsStrategy: maxCalls must be >=1, got ${maxCalls}`);
110
+ }
111
+ if (!VALID_POLICIES.has(searchPolicy)) {
112
+ throw new Error(
113
+ `treeOfThoughtsStrategy: searchPolicy must be "bfs" or "dfs", got "${searchPolicy}"`,
114
+ );
115
+ }
116
+
117
+ const strategyLabel = `${STRATEGY_NAME}-${searchPolicy}`;
118
+
119
+ return {
120
+ name: strategyLabel,
121
+
122
+ async run(
123
+ input: TInput,
124
+ generator: (input: TInput, ctx: ComputeContext) => Promise<TOutput>,
125
+ ctx: ComputeContext = {},
126
+ ): Promise<StrategyResult<TOutput>> {
127
+ const start = performance.now();
128
+ const signal = ctx.signal;
129
+ throwIfAborted(signal);
130
+
131
+ const childCtx: ComputeContext = signal ? { signal } : {};
132
+
133
+ let callsUsed = 0;
134
+ const allLeaves: TreeNode<TOutput>[] = [];
135
+ const allScores: number[] = [];
136
+
137
+ // Helper: expand one parent into up to branchFactor children.
138
+ // Each child = 1 generator call.
139
+ const expandNode = async (
140
+ _parent: TreeNode<TOutput> | null,
141
+ depth: number,
142
+ ): Promise<TreeNode<TOutput>[]> => {
143
+ const childrenToMake = Math.min(branchFactor, maxCalls - callsUsed);
144
+ if (childrenToMake <= 0) return [];
145
+
146
+ // Parallel sampling at this level.
147
+ throwIfAborted(signal);
148
+ const samples = await Promise.all(
149
+ Array.from({ length: childrenToMake }, () => generator(input, childCtx)),
150
+ );
151
+ callsUsed += childrenToMake;
152
+
153
+ const nodes: TreeNode<TOutput>[] = samples.map((state) => {
154
+ const score = clamp01(evaluateState(state));
155
+ return { state, depth, score };
156
+ });
157
+
158
+ for (const n of nodes) allScores.push(n.score);
159
+
160
+ // Pruned nodes are still recorded as leaves (score known) but not expanded.
161
+ return nodes;
162
+ };
163
+
164
+ if (searchPolicy === "bfs") {
165
+ // ── BFS ───────────────────────────────────────────────────────────
166
+ let frontier: TreeNode<TOutput>[] = [];
167
+
168
+ // Depth-1 children from root.
169
+ const initial = await expandNode(null, 1);
170
+ frontier = initial;
171
+ // Leaves at maxDepth or pruned go into allLeaves.
172
+ for (const n of initial) {
173
+ if (n.depth >= maxDepth || n.score < pruneThreshold) {
174
+ allLeaves.push(n);
175
+ }
176
+ }
177
+
178
+ while (frontier.length > 0 && callsUsed < maxCalls) {
179
+ // Filter out pruned/leaf nodes — only expand survivors.
180
+ const survivors = frontier.filter((n) => n.score >= pruneThreshold && n.depth < maxDepth);
181
+ if (survivors.length === 0) break;
182
+
183
+ const nextFrontier: TreeNode<TOutput>[] = [];
184
+ for (const parent of survivors) {
185
+ if (callsUsed >= maxCalls) break;
186
+ const children = await expandNode(parent, parent.depth + 1);
187
+ for (const c of children) {
188
+ if (c.depth >= maxDepth || c.score < pruneThreshold) {
189
+ allLeaves.push(c);
190
+ } else {
191
+ nextFrontier.push(c);
192
+ }
193
+ }
194
+ }
195
+
196
+ // If BFS terminates with un-expanded frontier (budget hit), those are leaves too.
197
+ if (callsUsed >= maxCalls) {
198
+ for (const n of nextFrontier) allLeaves.push(n);
199
+ break;
200
+ }
201
+ frontier = nextFrontier;
202
+ }
203
+ // Any remaining frontier nodes at end-of-budget = leaves.
204
+ for (const n of frontier) {
205
+ if (!allLeaves.includes(n)) allLeaves.push(n);
206
+ }
207
+ } else {
208
+ // ── DFS with backtracking ─────────────────────────────────────────
209
+ const stack: TreeNode<TOutput>[] = [];
210
+ const initial = await expandNode(null, 1);
211
+ // Push so highest score is explored first.
212
+ const sortedInitial = [...initial].sort((a, b) => b.score - a.score);
213
+ stack.push(...sortedInitial.reverse()); // reverse so highest pops first
214
+
215
+ for (const n of initial) {
216
+ if (n.depth >= maxDepth || n.score < pruneThreshold) {
217
+ allLeaves.push(n);
218
+ }
219
+ }
220
+
221
+ while (stack.length > 0 && callsUsed < maxCalls) {
222
+ const node = stack.pop();
223
+ if (!node) break;
224
+ // Backtrack if pruned or terminal.
225
+ if (node.score < pruneThreshold || node.depth >= maxDepth) {
226
+ // Already recorded as leaf above (or will be).
227
+ if (!allLeaves.includes(node)) allLeaves.push(node);
228
+ continue;
229
+ }
230
+ // Expand survivor.
231
+ const children = await expandNode(node, node.depth + 1);
232
+ const sortedChildren = [...children].sort((a, b) => b.score - a.score);
233
+ for (const c of sortedChildren.reverse()) {
234
+ if (c.depth >= maxDepth || c.score < pruneThreshold) {
235
+ allLeaves.push(c);
236
+ } else {
237
+ stack.push(c);
238
+ }
239
+ }
240
+ }
241
+ // Any unexplored stack nodes = leaves (budget-bound).
242
+ for (const n of stack) {
243
+ if (!allLeaves.includes(n)) allLeaves.push(n);
244
+ }
245
+ }
246
+
247
+ // ── Pick highest-scoring leaf ─────────────────────────────────────
248
+ if (allLeaves.length === 0) {
249
+ // Should never happen: root expansion always produces ≥1 leaf
250
+ // unless maxCalls=0 (which we reject). Defensive fallback.
251
+ const fallback = await generator(input, childCtx);
252
+ callsUsed++;
253
+ allScores.push(clamp01(evaluateState(fallback)));
254
+ const latency_ms = performance.now() - start;
255
+ return {
256
+ result: fallback,
257
+ metadata: {
258
+ strategy: strategyLabel,
259
+ candidates: 1,
260
+ verifier_scores: allScores,
261
+ cost: { calls: callsUsed },
262
+ latency_ms,
263
+ },
264
+ };
265
+ }
266
+
267
+ let best = allLeaves[0];
268
+ for (let i = 1; i < allLeaves.length; i++) {
269
+ const n = allLeaves[i] as TreeNode<TOutput>;
270
+ if (n.score > best.score) best = n;
271
+ }
272
+
273
+ const latency_ms = performance.now() - start;
274
+ return {
275
+ result: best.state,
276
+ metadata: {
277
+ strategy: strategyLabel,
278
+ candidates: callsUsed,
279
+ verifier_scores: allScores,
280
+ cost: { calls: callsUsed },
281
+ latency_ms,
282
+ },
283
+ };
284
+ },
285
+ };
286
+ }
287
+
288
+ function clamp01(x: number): number {
289
+ if (!Number.isFinite(x)) return 0;
290
+ if (x < 0) return 0;
291
+ if (x > 1) return 1;
292
+ return x;
293
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * src/compute/strategies/two-phase-orient.ts
3
+ *
4
+ * Two-Phase Orient pattern.
5
+ *
6
+ * Phase 1 — Orient: read-only context gathering, produces an orientation state.
7
+ * Phase 2 — Act: state-mutating execution driven by the orientation.
8
+ *
9
+ * The separation enforces a hard OODA discipline:
10
+ * - Phase 1 has no side effects; it may be retried cheaply on failure.
11
+ * - Phase 2 consumes the orientation and may be retried up to `maxActRetries`.
12
+ *
13
+ * Error semantics:
14
+ * - `TwoPhaseOrientError` (phase: "orient") — Phase 1 threw; Phase 2 is never reached.
15
+ * - `TwoPhaseOrientError` (phase: "act") — Phase 2 exhausted all retries.
16
+ * - Each Phase 2 retry attempt is tracked in `retriesUsed` (0 = first attempt succeeded).
17
+ */
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Error
21
+ // ---------------------------------------------------------------------------
22
+
23
+ export class TwoPhaseOrientError extends Error {
24
+ readonly phase: "orient" | "act";
25
+ readonly cause: unknown;
26
+ readonly retriesUsed: number;
27
+
28
+ constructor(
29
+ phase: "orient" | "act",
30
+ cause: unknown,
31
+ retriesUsed: number,
32
+ message: string
33
+ ) {
34
+ super(message);
35
+ this.name = "TwoPhaseOrientError";
36
+ this.phase = phase;
37
+ this.cause = cause;
38
+ this.retriesUsed = retriesUsed;
39
+ // Restore prototype chain (tsc targets < ES2022)
40
+ Object.setPrototypeOf(this, TwoPhaseOrientError.prototype);
41
+ }
42
+ }
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // Config + return type
46
+ // ---------------------------------------------------------------------------
47
+
48
+ export interface TwoPhaseOrientConfig<C, O, R> {
49
+ /**
50
+ * Phase 1: orientation (read-only, observe + analyse).
51
+ * Receives the raw context and returns an orientation state.
52
+ * Must not produce observable side effects.
53
+ */
54
+ orient: (context: C) => Promise<O>;
55
+
56
+ /**
57
+ * Phase 2: act on the orientation.
58
+ * Receives both the orientation produced by Phase 1 and the original context.
59
+ * Returns the final result.
60
+ */
61
+ act: (orientation: O, context: C) => Promise<R>;
62
+
63
+ /**
64
+ * Maximum number of times Phase 2 may be retried after a recoverable failure.
65
+ * `maxActRetries = 1` means one initial attempt + one retry = 2 total attempts.
66
+ * Default: 1.
67
+ * Must be a non-negative integer; values < 0 are treated as 0.
68
+ */
69
+ maxActRetries?: number;
70
+ }
71
+
72
+ export interface TwoPhaseOrientResult<O, R> {
73
+ orientation: O;
74
+ result: R;
75
+ /** Number of Phase-2 retries consumed (0 = succeeded on first attempt). */
76
+ retriesUsed: number;
77
+ }
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Implementation
81
+ // ---------------------------------------------------------------------------
82
+
83
+ /**
84
+ * Executes the Two-Phase Orient pattern.
85
+ *
86
+ * @param config Wiring for both phases + optional retry cap.
87
+ * @param context Opaque context forwarded to both `orient` and `act`.
88
+ *
89
+ * @throws {TwoPhaseOrientError} When Phase 1 throws (phase: "orient") or
90
+ * Phase 2 exhausts all retries (phase: "act").
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const { orientation, result, retriesUsed } = await runTwoPhaseOrient(
95
+ * {
96
+ * orient: async (ctx) => await gatherSignals(ctx),
97
+ * act: async (orient, ctx) => await executeDecision(orient, ctx),
98
+ * },
99
+ * requestContext,
100
+ * );
101
+ * ```
102
+ */
103
+ export async function runTwoPhaseOrient<C, O, R>(
104
+ config: TwoPhaseOrientConfig<C, O, R>,
105
+ context: C
106
+ ): Promise<TwoPhaseOrientResult<O, R>> {
107
+ const maxRetries = Math.max(0, Math.floor(config.maxActRetries ?? 1));
108
+
109
+ // ── Phase 1: Orient ───────────────────────────────────────────────────────
110
+ let orientation: O;
111
+ try {
112
+ orientation = await config.orient(context);
113
+ } catch (err) {
114
+ throw new TwoPhaseOrientError(
115
+ "orient",
116
+ err,
117
+ 0,
118
+ `TwoPhaseOrient Phase 1 (orient) failed: ${
119
+ err instanceof Error ? err.message : String(err)
120
+ }`
121
+ );
122
+ }
123
+
124
+ // ── Phase 2: Act (with retries) ───────────────────────────────────────────
125
+ let lastActError: unknown;
126
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
127
+ try {
128
+ const result = await config.act(orientation, context);
129
+ return { orientation, result, retriesUsed: attempt };
130
+ } catch (err) {
131
+ lastActError = err;
132
+ // Continue to next attempt if retries remain.
133
+ }
134
+ }
135
+
136
+ // All attempts exhausted.
137
+ throw new TwoPhaseOrientError(
138
+ "act",
139
+ lastActError,
140
+ maxRetries,
141
+ `TwoPhaseOrient Phase 2 (act) failed after ${maxRetries + 1} attempt(s): ${
142
+ lastActError instanceof Error
143
+ ? lastActError.message
144
+ : String(lastActError)
145
+ }`
146
+ );
147
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Container Execution Protocol — standard contract for running automations
3
+ * inside containers or as local binaries.
4
+ *
5
+ * Contract:
6
+ *
7
+ * Input (via env vars):
8
+ * VAUBAN_EXECUTION_ID — unique execution identifier (UUID)
9
+ * VAUBAN_AUTOMATION_NAME — automation name (kebab-case)
10
+ * VAUBAN_INPUT — JSON-encoded input parameters
11
+ * VAUBAN_TIMEOUT — timeout in seconds
12
+ * VAUBAN_MODE — execution mode (default: "execute")
13
+ *
14
+ * Output (via stdout, last non-empty line, JSON):
15
+ * { "status": "completed", "output": <any> }
16
+ * { "status": "failed", "error": { "code": "...", "message": "...", "details"?: <any> } }
17
+ *
18
+ * Diagnostics (via stderr, optional, one JSON object per line):
19
+ * { "level": "info", "message": "...", "timestamp": "..." }
20
+ * { "progress": 0.5, "message": "..." }
21
+ *
22
+ * @public @since 1.2.0
23
+ */
24
+
25
+ /**
26
+ * Reserved environment variable names. All caller env merged on top must NOT
27
+ * shadow these keys, or the automation's view of its own context becomes
28
+ * undefined.
29
+ *
30
+ * @public
31
+ */
32
+ export const PROTOCOL_ENV = {
33
+ EXECUTION_ID: "VAUBAN_EXECUTION_ID",
34
+ AUTOMATION_NAME: "VAUBAN_AUTOMATION_NAME",
35
+ INPUT: "VAUBAN_INPUT",
36
+ TIMEOUT: "VAUBAN_TIMEOUT",
37
+ MODE: "VAUBAN_MODE",
38
+ } as const;
39
+
40
+ /**
41
+ * Default protocol mode set when caller does not specify one.
42
+ * @public
43
+ */
44
+ export const DEFAULT_PROTOCOL_MODE = "execute";
45
+
46
+ /**
47
+ * Final status reported by a container/binary on stdout.
48
+ * @public
49
+ */
50
+ export type ProtocolStatus = "completed" | "failed";
51
+
52
+ /**
53
+ * Discriminated union of protocol outputs parsed from stdout.
54
+ * @public
55
+ */
56
+ export type ProtocolResult<T = unknown> =
57
+ | { readonly status: "completed"; readonly output: T }
58
+ | {
59
+ readonly status: "failed";
60
+ readonly error: {
61
+ readonly code: string;
62
+ readonly message: string;
63
+ readonly details?: unknown;
64
+ };
65
+ };
66
+
67
+ /**
68
+ * Outcome of an execution attempt, combining protocol result with timing,
69
+ * captured logs, and propagated metadata.
70
+ *
71
+ * @public
72
+ */
73
+ export interface ExecutionResult<T = unknown> {
74
+ readonly executionId: string;
75
+ readonly automationName: string;
76
+ readonly status: "completed" | "failed" | "timeout";
77
+ readonly input: unknown;
78
+ readonly output?: T;
79
+ readonly error?: {
80
+ code: string;
81
+ message: string;
82
+ details?: unknown;
83
+ };
84
+ readonly startedAt: Date;
85
+ readonly completedAt: Date;
86
+ readonly durationMs: number;
87
+ readonly logs: ReadonlyArray<{
88
+ readonly level: string;
89
+ readonly message: string;
90
+ readonly timestamp: string;
91
+ }>;
92
+ }
93
+
94
+ /**
95
+ * Thrown when stdout does not contain a parseable protocol result on its last
96
+ * non-empty line.
97
+ *
98
+ * @public
99
+ */
100
+ export class ProtocolParseError extends Error {
101
+ readonly rawTail: string;
102
+ constructor(reason: string, rawTail: string) {
103
+ super(`container-protocol: ${reason}`);
104
+ this.name = "ProtocolParseError";
105
+ this.rawTail = rawTail;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Build the protocol's environment variables. Caller `extraEnv` is merged
111
+ * AFTER protocol env, so it cannot accidentally override reserved keys.
112
+ *
113
+ * @public
114
+ */
115
+ export function buildProtocolEnv(args: {
116
+ executionId: string;
117
+ automationName: string;
118
+ input: unknown;
119
+ timeoutSeconds: number;
120
+ mode?: string;
121
+ extraEnv?: Readonly<Record<string, string>>;
122
+ }): Record<string, string> {
123
+ const env: Record<string, string> = {};
124
+ if (args.extraEnv) {
125
+ for (const [k, v] of Object.entries(args.extraEnv)) {
126
+ env[k] = v;
127
+ }
128
+ }
129
+ env[PROTOCOL_ENV.EXECUTION_ID] = args.executionId;
130
+ env[PROTOCOL_ENV.AUTOMATION_NAME] = args.automationName;
131
+ env[PROTOCOL_ENV.INPUT] = JSON.stringify(args.input);
132
+ env[PROTOCOL_ENV.TIMEOUT] = String(args.timeoutSeconds);
133
+ env[PROTOCOL_ENV.MODE] = args.mode ?? DEFAULT_PROTOCOL_MODE;
134
+ return env;
135
+ }
136
+
137
+ /**
138
+ * Parse the last non-empty line of stdout as a {@link ProtocolResult}.
139
+ *
140
+ * @throws {@link ProtocolParseError} when stdout is empty, has no JSON tail,
141
+ * or the JSON does not match the protocol shape.
142
+ *
143
+ * @public
144
+ */
145
+ export function parseProtocolOutput<T = unknown>(
146
+ stdout: string
147
+ ): ProtocolResult<T> {
148
+ const trimmed = stdout.trim();
149
+ if (trimmed.length === 0) {
150
+ throw new ProtocolParseError("stdout is empty", "");
151
+ }
152
+ const lines = trimmed.split("\n");
153
+ const lastLine = lines[lines.length - 1]!.trim();
154
+ if (lastLine.length === 0) {
155
+ throw new ProtocolParseError(
156
+ "last stdout line is empty",
157
+ trimmed.slice(-200)
158
+ );
159
+ }
160
+
161
+ let parsed: unknown;
162
+ try {
163
+ parsed = JSON.parse(lastLine);
164
+ } catch {
165
+ throw new ProtocolParseError(
166
+ "last stdout line is not valid JSON",
167
+ lastLine.slice(0, 500)
168
+ );
169
+ }
170
+
171
+ if (typeof parsed !== "object" || parsed === null || !("status" in parsed)) {
172
+ throw new ProtocolParseError(
173
+ "protocol JSON missing 'status' field",
174
+ lastLine.slice(0, 500)
175
+ );
176
+ }
177
+
178
+ const obj = parsed as Record<string, unknown>;
179
+ const status = obj["status"];
180
+
181
+ if (status === "completed") {
182
+ return { status: "completed", output: (obj["output"] ?? null) as T };
183
+ }
184
+
185
+ if (status === "failed") {
186
+ const err = (obj["error"] as Record<string, unknown> | undefined) ?? {};
187
+ const code =
188
+ typeof err["code"] === "string" ? (err["code"] as string) : "UNKNOWN";
189
+ const message =
190
+ typeof err["message"] === "string"
191
+ ? (err["message"] as string)
192
+ : "(no message)";
193
+ const details = err["details"];
194
+ return { status: "failed", error: { code, message, details } };
195
+ }
196
+
197
+ throw new ProtocolParseError(
198
+ `unknown protocol status: ${String(status)}`,
199
+ lastLine.slice(0, 500)
200
+ );
201
+ }
202
+
203
+ /**
204
+ * Parse stderr lines as JSON log entries when possible; fall back to plain
205
+ * text wrapped at level "info". Used by {@link ContainerRuntime} to populate
206
+ * `ExecutionResult.logs`.
207
+ *
208
+ * @public
209
+ */
210
+ export function parseStderrLogs(stderr: string): Array<{
211
+ level: string;
212
+ message: string;
213
+ timestamp: string;
214
+ }> {
215
+ const logs: Array<{ level: string; message: string; timestamp: string }> = [];
216
+ const lines = stderr.split("\n");
217
+ for (const raw of lines) {
218
+ const line = raw.trim();
219
+ if (line.length === 0) continue;
220
+ try {
221
+ const obj = JSON.parse(line) as Record<string, unknown>;
222
+ logs.push({
223
+ level:
224
+ typeof obj["level"] === "string" ? (obj["level"] as string) : "info",
225
+ message:
226
+ typeof obj["message"] === "string"
227
+ ? (obj["message"] as string)
228
+ : line.slice(0, 500),
229
+ timestamp:
230
+ typeof obj["timestamp"] === "string"
231
+ ? (obj["timestamp"] as string)
232
+ : new Date().toISOString(),
233
+ });
234
+ } catch {
235
+ logs.push({
236
+ level: "info",
237
+ message: line.slice(0, 500),
238
+ timestamp: new Date().toISOString(),
239
+ });
240
+ }
241
+ }
242
+ return logs;
243
+ }