@codespar/cli 0.16.0 → 0.18.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 (486) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/mandate-verify.js +98 -19
  3. package/dist/commands/mandate-verify.js.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/mandate-codec.js +31 -20
  7. package/dist/mandate-codec.js.map +1 -1
  8. package/package.json +1 -1
  9. package/templates/bills-agent/README.md +1 -1
  10. package/templates/bills-agent/agents/bills-agent/AGENTS.md +1 -1
  11. package/templates/bills-agent/agents/bills-agent/CLAUDE.md +1 -1
  12. package/templates/bills-agent/agents/bills-agent/README.md +6 -5
  13. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +5 -4
  14. package/templates/bills-agent/packages/agent-core/README.md +14 -1
  15. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  16. package/templates/bills-agent/packages/agent-core/src/agent.ts +39 -1
  17. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  18. package/templates/bills-agent/packages/agent-core/src/api/client.ts +28 -5
  19. package/templates/bills-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  20. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +62 -26
  21. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  22. package/templates/bills-agent/packages/agent-core/src/approval.ts +14 -2
  23. package/templates/bills-agent/packages/agent-core/src/bundle.ts +35 -3
  24. package/templates/bills-agent/packages/agent-core/src/channels.ts +49 -3
  25. package/templates/bills-agent/packages/agent-core/src/check.ts +25 -2
  26. package/templates/bills-agent/packages/agent-core/src/engine.ts +235 -46
  27. package/templates/bills-agent/packages/agent-core/src/hash.ts +57 -1
  28. package/templates/bills-agent/packages/agent-core/src/index.ts +2 -0
  29. package/templates/bills-agent/packages/agent-core/src/quote.ts +50 -0
  30. package/templates/bills-agent/packages/agent-core/src/rail.ts +89 -4
  31. package/templates/bills-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  32. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  33. package/templates/bills-agent/packages/agent-core/src/revocation.ts +1 -1
  34. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +10 -1
  35. package/templates/bills-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  36. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  37. package/templates/bills-agent/packages/agent-core/src/tools.ts +17 -6
  38. package/templates/bills-agent/packages/agent-core/src/types.ts +54 -1
  39. package/templates/bills-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  40. package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  41. package/templates/bills-agent/packages/agent-core/test/composition.test.ts +204 -0
  42. package/templates/bills-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  43. package/templates/bills-agent/packages/agent-core/test/helpers.ts +4 -1
  44. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  45. package/templates/bills-agent/packages/agent-core/test/quote.test.ts +198 -0
  46. package/templates/bills-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  47. package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  48. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +103 -3
  49. package/templates/bills-agent/packages/agent-runtime/README.md +12 -0
  50. package/templates/bills-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  51. package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  52. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  53. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  54. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  55. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  56. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  57. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  58. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  59. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  60. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  61. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  62. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  63. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  64. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  65. package/templates/bills-agent/packages/agent-runtime/src/index.ts +1 -0
  66. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +5 -1
  67. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +25 -2
  68. package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  69. package/templates/bills-agent/packages/agent-runtime/src/setup.ts +13 -3
  70. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +127 -18
  71. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  72. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  73. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  74. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  75. package/templates/checkout-agent/LICENSE +21 -0
  76. package/templates/checkout-agent/README.md +28 -0
  77. package/templates/checkout-agent/_gitignore +10 -0
  78. package/templates/checkout-agent/agents/checkout-agent/.env.example +5 -0
  79. package/templates/checkout-agent/agents/checkout-agent/AGENTS.md +20 -0
  80. package/templates/checkout-agent/agents/checkout-agent/CLAUDE.md +20 -0
  81. package/templates/checkout-agent/agents/checkout-agent/README.md +94 -0
  82. package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +36 -0
  83. package/templates/checkout-agent/agents/checkout-agent/agent.yaml +30 -0
  84. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +28 -0
  85. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-beatriz.json +11 -0
  86. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina-retomada.json +10 -0
  87. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina.json +11 -0
  88. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +49 -0
  89. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +12 -0
  90. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +11 -0
  91. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +5 -0
  92. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +13 -0
  93. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.transcript.jsonl +4 -0
  94. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.json +26 -0
  95. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
  96. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.json +11 -0
  97. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.transcript.jsonl +5 -0
  98. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.json +12 -0
  99. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +5 -0
  100. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.json +13 -0
  101. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.transcript.jsonl +5 -0
  102. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +15 -0
  103. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +7 -0
  104. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +12 -0
  105. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.transcript.jsonl +5 -0
  106. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.json +13 -0
  107. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +4 -0
  108. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.json +16 -0
  109. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.transcript.jsonl +9 -0
  110. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.json +15 -0
  111. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +8 -0
  112. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/webhook-replay.json +11 -0
  113. package/templates/checkout-agent/agents/checkout-agent/evals/eval.yaml +11 -0
  114. package/templates/checkout-agent/agents/checkout-agent/guardrails.json +25 -0
  115. package/templates/checkout-agent/agents/checkout-agent/mandate.example.json +28 -0
  116. package/templates/checkout-agent/agents/checkout-agent/package.json +33 -0
  117. package/templates/checkout-agent/agents/checkout-agent/runbook.md +19 -0
  118. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.json +42 -0
  119. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +4 -0
  120. package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.json +32 -0
  121. package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.transcript.jsonl +4 -0
  122. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.json +61 -0
  123. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +9 -0
  124. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +61 -0
  125. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +9 -0
  126. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +36 -0
  127. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +6 -0
  128. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.json +23 -0
  129. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +4 -0
  130. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.json +72 -0
  131. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +9 -0
  132. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.json +15 -0
  133. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +6 -0
  134. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.json +23 -0
  135. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +3 -0
  136. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.json +42 -0
  137. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +12 -0
  138. package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.json +14 -0
  139. package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.transcript.jsonl +9 -0
  140. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +34 -0
  141. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +7 -0
  142. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.json +33 -0
  143. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +4 -0
  144. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.json +32 -0
  145. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +4 -0
  146. package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +92 -0
  147. package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +338 -0
  148. package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +179 -0
  149. package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +374 -0
  150. package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +220 -0
  151. package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +297 -0
  152. package/templates/checkout-agent/agents/checkout-agent/test/adversarial.test.ts +117 -0
  153. package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +67 -0
  154. package/templates/checkout-agent/agents/checkout-agent/test/cli.test.ts +169 -0
  155. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +5 -0
  156. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +6 -0
  157. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +2 -0
  158. package/templates/checkout-agent/agents/checkout-agent/test/nfse.test.ts +170 -0
  159. package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +138 -0
  160. package/templates/checkout-agent/agents/checkout-agent/test/scenarios.test.ts +113 -0
  161. package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +171 -0
  162. package/templates/checkout-agent/agents/checkout-agent/tools.json +68 -0
  163. package/templates/checkout-agent/agents/checkout-agent/tsconfig.json +10 -0
  164. package/templates/checkout-agent/package.json +38 -0
  165. package/templates/checkout-agent/packages/agent-core/README.md +34 -0
  166. package/templates/checkout-agent/packages/agent-core/package.json +24 -0
  167. package/templates/checkout-agent/packages/agent-core/src/agent.ts +163 -0
  168. package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +195 -0
  169. package/templates/checkout-agent/packages/agent-core/src/api/client.ts +76 -0
  170. package/templates/checkout-agent/packages/agent-core/src/api/mandate-status.ts +74 -0
  171. package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +153 -0
  172. package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +43 -0
  173. package/templates/checkout-agent/packages/agent-core/src/approval.ts +135 -0
  174. package/templates/checkout-agent/packages/agent-core/src/bundle.ts +191 -0
  175. package/templates/checkout-agent/packages/agent-core/src/channels.ts +186 -0
  176. package/templates/checkout-agent/packages/agent-core/src/check.ts +276 -0
  177. package/templates/checkout-agent/packages/agent-core/src/clock.ts +42 -0
  178. package/templates/checkout-agent/packages/agent-core/src/engine.ts +1074 -0
  179. package/templates/checkout-agent/packages/agent-core/src/escalate.ts +85 -0
  180. package/templates/checkout-agent/packages/agent-core/src/events.ts +40 -0
  181. package/templates/checkout-agent/packages/agent-core/src/guardrails.ts +45 -0
  182. package/templates/checkout-agent/packages/agent-core/src/hash.ts +118 -0
  183. package/templates/checkout-agent/packages/agent-core/src/ids.ts +10 -0
  184. package/templates/checkout-agent/packages/agent-core/src/index.ts +34 -0
  185. package/templates/checkout-agent/packages/agent-core/src/mandate.ts +100 -0
  186. package/templates/checkout-agent/packages/agent-core/src/manifest.ts +76 -0
  187. package/templates/checkout-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  188. package/templates/checkout-agent/packages/agent-core/src/providers/replay.ts +63 -0
  189. package/templates/checkout-agent/packages/agent-core/src/providers/types.ts +39 -0
  190. package/templates/checkout-agent/packages/agent-core/src/quote.ts +50 -0
  191. package/templates/checkout-agent/packages/agent-core/src/rail.ts +186 -0
  192. package/templates/checkout-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  193. package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +577 -0
  194. package/templates/checkout-agent/packages/agent-core/src/revocation.ts +30 -0
  195. package/templates/checkout-agent/packages/agent-core/src/secrets.ts +30 -0
  196. package/templates/checkout-agent/packages/agent-core/src/state/store.ts +307 -0
  197. package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +157 -0
  198. package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
  199. package/templates/checkout-agent/packages/agent-core/src/stubs/mandate-status.ts +58 -0
  200. package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +209 -0
  201. package/templates/checkout-agent/packages/agent-core/src/tools.ts +66 -0
  202. package/templates/checkout-agent/packages/agent-core/src/types.ts +187 -0
  203. package/templates/checkout-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  204. package/templates/checkout-agent/packages/agent-core/test/approval.test.ts +117 -0
  205. package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  206. package/templates/checkout-agent/packages/agent-core/test/bundle.test.ts +85 -0
  207. package/templates/checkout-agent/packages/agent-core/test/clock.test.ts +25 -0
  208. package/templates/checkout-agent/packages/agent-core/test/composition.test.ts +204 -0
  209. package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +596 -0
  210. package/templates/checkout-agent/packages/agent-core/test/escalate.test.ts +42 -0
  211. package/templates/checkout-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  212. package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  213. package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  214. package/templates/checkout-agent/packages/agent-core/test/helpers.ts +142 -0
  215. package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +229 -0
  216. package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +45 -0
  217. package/templates/checkout-agent/packages/agent-core/test/quote.test.ts +198 -0
  218. package/templates/checkout-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  219. package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  220. package/templates/checkout-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  221. package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +416 -0
  222. package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +28 -0
  223. package/templates/checkout-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  224. package/templates/checkout-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  225. package/templates/checkout-agent/packages/agent-core/tsconfig.json +10 -0
  226. package/templates/checkout-agent/packages/agent-runtime/README.md +80 -0
  227. package/templates/checkout-agent/packages/agent-runtime/bin.mjs +32 -0
  228. package/templates/checkout-agent/packages/agent-runtime/package.json +23 -0
  229. package/templates/checkout-agent/packages/agent-runtime/src/adversarial.ts +199 -0
  230. package/templates/checkout-agent/packages/agent-runtime/src/agent.ts +68 -0
  231. package/templates/checkout-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  232. package/templates/checkout-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  233. package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  234. package/templates/checkout-agent/packages/agent-runtime/src/channels/types.ts +173 -0
  235. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +459 -0
  236. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +216 -0
  237. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  238. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +350 -0
  239. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +180 -0
  240. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  241. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +120 -0
  242. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +127 -0
  243. package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +98 -0
  244. package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  245. package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  246. package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  247. package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  248. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +367 -0
  249. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +145 -0
  250. package/templates/checkout-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  251. package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  252. package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +49 -0
  253. package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +134 -0
  254. package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +248 -0
  255. package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +330 -0
  256. package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +40 -0
  257. package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  258. package/templates/checkout-agent/packages/agent-runtime/src/index.ts +13 -0
  259. package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +801 -0
  260. package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +229 -0
  261. package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +105 -0
  262. package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +274 -0
  263. package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +239 -0
  264. package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +263 -0
  265. package/templates/checkout-agent/packages/agent-runtime/src/webhook.ts +131 -0
  266. package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  267. package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +329 -0
  268. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +277 -0
  269. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  270. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  271. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +167 -0
  272. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  273. package/templates/checkout-agent/packages/agent-runtime/tsconfig.json +9 -0
  274. package/templates/checkout-agent/scripts/whatsapp-emulator.mjs +84 -0
  275. package/templates/checkout-agent/tsconfig.base.json +16 -0
  276. package/templates/checkout-agent/vitest.config.ts +12 -0
  277. package/templates/collections-agent/README.md +6 -1
  278. package/templates/collections-agent/agents/collections-agent/README.md +12 -8
  279. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +8 -0
  280. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042-retomada.json +10 -0
  281. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +27 -1
  282. package/templates/collections-agent/agents/collections-agent/src/kit.ts +2 -0
  283. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +12 -2
  284. package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +55 -0
  285. package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +2 -0
  286. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +12 -6
  287. package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +148 -0
  288. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +5 -0
  289. package/templates/collections-agent/package.json +1 -0
  290. package/templates/collections-agent/packages/agent-core/README.md +14 -1
  291. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  292. package/templates/collections-agent/packages/agent-core/src/agent.ts +39 -1
  293. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  294. package/templates/collections-agent/packages/agent-core/src/api/client.ts +28 -5
  295. package/templates/collections-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  296. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +62 -26
  297. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  298. package/templates/collections-agent/packages/agent-core/src/approval.ts +14 -2
  299. package/templates/collections-agent/packages/agent-core/src/bundle.ts +35 -3
  300. package/templates/collections-agent/packages/agent-core/src/channels.ts +49 -3
  301. package/templates/collections-agent/packages/agent-core/src/check.ts +25 -2
  302. package/templates/collections-agent/packages/agent-core/src/engine.ts +235 -46
  303. package/templates/collections-agent/packages/agent-core/src/hash.ts +57 -1
  304. package/templates/collections-agent/packages/agent-core/src/index.ts +2 -0
  305. package/templates/collections-agent/packages/agent-core/src/quote.ts +50 -0
  306. package/templates/collections-agent/packages/agent-core/src/rail.ts +89 -4
  307. package/templates/collections-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  308. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  309. package/templates/collections-agent/packages/agent-core/src/revocation.ts +1 -1
  310. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +10 -1
  311. package/templates/collections-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  312. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  313. package/templates/collections-agent/packages/agent-core/src/tools.ts +17 -6
  314. package/templates/collections-agent/packages/agent-core/src/types.ts +54 -1
  315. package/templates/collections-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  316. package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  317. package/templates/collections-agent/packages/agent-core/test/composition.test.ts +204 -0
  318. package/templates/collections-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  319. package/templates/collections-agent/packages/agent-core/test/helpers.ts +4 -1
  320. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  321. package/templates/collections-agent/packages/agent-core/test/quote.test.ts +198 -0
  322. package/templates/collections-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  323. package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  324. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +103 -3
  325. package/templates/collections-agent/packages/agent-runtime/README.md +12 -0
  326. package/templates/collections-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  327. package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  328. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  329. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  330. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  331. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  332. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  333. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  334. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  335. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  336. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  337. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  338. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  339. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  340. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  341. package/templates/collections-agent/packages/agent-runtime/src/index.ts +1 -0
  342. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +5 -1
  343. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +25 -2
  344. package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  345. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +13 -3
  346. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +127 -18
  347. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  348. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  349. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  350. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  351. package/templates/collections-agent/scripts/whatsapp-emulator.mjs +84 -0
  352. package/templates/hello-agent/README.md +1 -1
  353. package/templates/hello-agent/packages/agent-core/README.md +14 -1
  354. package/templates/hello-agent/packages/agent-core/package.json +1 -1
  355. package/templates/hello-agent/packages/agent-core/src/agent.ts +39 -1
  356. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  357. package/templates/hello-agent/packages/agent-core/src/api/client.ts +28 -5
  358. package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  359. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +62 -26
  360. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  361. package/templates/hello-agent/packages/agent-core/src/approval.ts +14 -2
  362. package/templates/hello-agent/packages/agent-core/src/bundle.ts +35 -3
  363. package/templates/hello-agent/packages/agent-core/src/channels.ts +49 -3
  364. package/templates/hello-agent/packages/agent-core/src/check.ts +25 -2
  365. package/templates/hello-agent/packages/agent-core/src/engine.ts +235 -46
  366. package/templates/hello-agent/packages/agent-core/src/hash.ts +57 -1
  367. package/templates/hello-agent/packages/agent-core/src/index.ts +2 -0
  368. package/templates/hello-agent/packages/agent-core/src/quote.ts +50 -0
  369. package/templates/hello-agent/packages/agent-core/src/rail.ts +89 -4
  370. package/templates/hello-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  371. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  372. package/templates/hello-agent/packages/agent-core/src/revocation.ts +1 -1
  373. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +10 -1
  374. package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  375. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  376. package/templates/hello-agent/packages/agent-core/src/tools.ts +17 -6
  377. package/templates/hello-agent/packages/agent-core/src/types.ts +54 -1
  378. package/templates/hello-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  379. package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  380. package/templates/hello-agent/packages/agent-core/test/composition.test.ts +204 -0
  381. package/templates/hello-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  382. package/templates/hello-agent/packages/agent-core/test/helpers.ts +4 -1
  383. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  384. package/templates/hello-agent/packages/agent-core/test/quote.test.ts +198 -0
  385. package/templates/hello-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  386. package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  387. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +103 -3
  388. package/templates/hello-agent/packages/agent-runtime/README.md +12 -0
  389. package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  390. package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  391. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  392. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  393. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  394. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  395. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  396. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  397. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  398. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  399. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  400. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  401. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  402. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  403. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  404. package/templates/hello-agent/packages/agent-runtime/src/index.ts +1 -0
  405. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +5 -1
  406. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +25 -2
  407. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  408. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +13 -3
  409. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +127 -18
  410. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  411. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  412. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  413. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  414. package/templates/kits.lock.json +29 -6
  415. package/templates/supplier-payments-agent/README.md +1 -1
  416. package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +1 -1
  417. package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +1 -1
  418. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +11 -9
  419. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +1 -1
  420. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +67 -20
  421. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +504 -5
  422. package/templates/supplier-payments-agent/packages/agent-core/README.md +14 -1
  423. package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
  424. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +39 -1
  425. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  426. package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +28 -5
  427. package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  428. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +62 -26
  429. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  430. package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +14 -2
  431. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +35 -3
  432. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +49 -3
  433. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -2
  434. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +235 -46
  435. package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +57 -1
  436. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +2 -0
  437. package/templates/supplier-payments-agent/packages/agent-core/src/quote.ts +50 -0
  438. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +89 -4
  439. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  440. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  441. package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +1 -1
  442. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +10 -1
  443. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  444. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  445. package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +17 -6
  446. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +54 -1
  447. package/templates/supplier-payments-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  448. package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  449. package/templates/supplier-payments-agent/packages/agent-core/test/composition.test.ts +204 -0
  450. package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  451. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +4 -1
  452. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  453. package/templates/supplier-payments-agent/packages/agent-core/test/quote.test.ts +198 -0
  454. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  455. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  456. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +103 -3
  457. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +12 -0
  458. package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  459. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  460. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  461. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  462. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  463. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  464. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  465. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  466. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  467. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  468. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  469. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  470. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  471. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  472. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  473. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +1 -0
  474. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +5 -1
  475. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +25 -2
  476. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  477. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +13 -3
  478. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +127 -18
  479. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  480. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  481. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  482. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  483. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  484. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  485. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  486. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Section 4.4: `escalate_above` only tightens. Each trigger sends a
3
+ * `mandate` execution to `awaiting_approval`; none of them raises a cap or
4
+ * adds a payee. The first trigger that fires is the one the artifact records.
5
+ */
6
+ import type { Guardrails } from "./guardrails.js";
7
+ import type { EscalateAbove } from "./manifest.js";
8
+ import type { EscalationTrigger, ExecutionItem } from "./types.js";
9
+
10
+ export interface EscalationContext {
11
+ now: Date;
12
+ timezone: string;
13
+ /** Payees this agent has already settled a payment to, under this mandate. */
14
+ knownPayees: ReadonlySet<string>;
15
+ /** Minor units already executed (settled or in flight) per payee inside the velocity window. */
16
+ recentByPayee: ReadonlyMap<string, number>;
17
+ }
18
+
19
+ export interface Escalation {
20
+ trigger: EscalationTrigger;
21
+ detail: string;
22
+ }
23
+
24
+ export function evaluateEscalation(
25
+ rule: EscalateAbove | undefined,
26
+ guardrails: Guardrails,
27
+ items: readonly ExecutionItem[],
28
+ ctx: EscalationContext,
29
+ ): Escalation | undefined {
30
+ if (!rule) return undefined;
31
+
32
+ if (rule.amount !== undefined) {
33
+ const total = items.reduce((sum, i) => sum + i.amount, 0);
34
+ if (total > rule.amount) {
35
+ return { trigger: "amount", detail: `total ${total} is above the escalation threshold ${rule.amount}` };
36
+ }
37
+ // Fractioning (section 9): the same payee, several parts inside the window, adds up.
38
+ if (guardrails.velocity) {
39
+ const perPayee = new Map<string, number>();
40
+ for (const item of items) perPayee.set(item.payee, (perPayee.get(item.payee) ?? 0) + item.amount);
41
+ for (const [payee, amount] of perPayee) {
42
+ const recent = ctx.recentByPayee.get(payee) ?? 0;
43
+ if (recent + amount > rule.amount) {
44
+ return {
45
+ trigger: "amount",
46
+ detail: `payments to ${payee} inside the last ${guardrails.velocity.window_hours}h add up to ${recent + amount}, above the escalation threshold ${rule.amount}`,
47
+ };
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ if (rule.new_beneficiary) {
54
+ const fresh = items.find((i) => !ctx.knownPayees.has(i.payee));
55
+ if (fresh) {
56
+ return { trigger: "new_beneficiary", detail: `first payment to ${fresh.beneficiary} (${fresh.payee}) under this mandate` };
57
+ }
58
+ }
59
+
60
+ if (rule.outside_hours && isOutsideHours(rule.outside_hours, ctx.now, ctx.timezone)) {
61
+ return { trigger: "outside_hours", detail: `requested at ${localClock(ctx.now, ctx.timezone)}, inside the ${rule.outside_hours} window` };
62
+ }
63
+
64
+ return undefined;
65
+ }
66
+
67
+ export function localClock(now: Date, timezone: string): string {
68
+ const parts = new Intl.DateTimeFormat("en-GB", { timeZone: timezone, hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).formatToParts(now);
69
+ const hour = parts.find((p) => p.type === "hour")?.value ?? "00";
70
+ const minute = parts.find((p) => p.type === "minute")?.value ?? "00";
71
+ return `${hour}:${minute}`;
72
+ }
73
+
74
+ /** `"22:00-07:00"` is the CLOSED window: inside it, the trigger fires. Crosses midnight when start > end. */
75
+ export function isOutsideHours(window: string, now: Date, timezone: string): boolean {
76
+ const [start, end] = window.split("-") as [string, string];
77
+ const minutes = (hhmm: string): number => {
78
+ const [h, m] = hhmm.split(":").map(Number) as [number, number];
79
+ return h * 60 + m;
80
+ };
81
+ const current = minutes(localClock(now, timezone));
82
+ const s = minutes(start);
83
+ const e = minutes(end);
84
+ return s <= e ? current >= s && current < e : current >= s || current < e;
85
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The events the CodeSpar API publishes, as an agent may declare them under
3
+ * `events:` in `agent.yaml`. The list is the one place the kits keep it;
4
+ * `npm run check` refuses a manifest entry outside it.
5
+ *
6
+ * Source: codespar-enterprise `packages/api/src` (the publishers behind
7
+ * `/v1/triggers`), measured 2026-09-23. Update it against that tree, never
8
+ * from memory.
9
+ */
10
+ export const PUBLISHED_EVENTS = [
11
+ "commerce.payment.succeeded",
12
+ "commerce.payment.failed",
13
+ "commerce.payment.pending",
14
+ "commerce.payment.refunded",
15
+ "commerce.payment.updated",
16
+ "commerce.pix_out.succeeded",
17
+ "commerce.pix_out.failed",
18
+ "commerce.charge.created",
19
+ "commerce.charge.paid",
20
+ "commerce.charge.expired",
21
+ "commerce.charge.cancelled",
22
+ "commerce.mandate.granted",
23
+ "commerce.mandate.paused",
24
+ "commerce.mandate.resumed",
25
+ "commerce.mandate.revoked",
26
+ ] as const;
27
+
28
+ export type PublishedEvent = (typeof PUBLISHED_EVENTS)[number];
29
+
30
+ /** The rail's answer to one attempt, as the core records it locally and as the API publishes it. */
31
+ export const PAYMENT_SUCCEEDED: PublishedEvent = "commerce.payment.succeeded";
32
+ export const PAYMENT_FAILED: PublishedEvent = "commerce.payment.failed";
33
+ /** The payer's answer to a receivable, as the API publishes it: paid settles, expired and cancelled fail. */
34
+ export const CHARGE_PAID: PublishedEvent = "commerce.charge.paid";
35
+ export const CHARGE_EXPIRED: PublishedEvent = "commerce.charge.expired";
36
+ export const CHARGE_CANCELLED: PublishedEvent = "commerce.charge.cancelled";
37
+
38
+ export function isPublishedEvent(name: string): name is PublishedEvent {
39
+ return (PUBLISHED_EVENTS as readonly string[]).includes(name);
40
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `guardrails.json`: what the agent applies on its own, before the mandate.
3
+ * Everything here can only tighten the mandate; nothing here widens it.
4
+ */
5
+ import { readFileSync } from "node:fs";
6
+ import { z } from "zod";
7
+ import { EscalateAboveSchema } from "./manifest.js";
8
+
9
+ export const GuardrailsSchema = z
10
+ .object({
11
+ approval: z.enum(["human", "mandate"]),
12
+ /** Must equal the manifest's `escalate_above`; `npm run check` compares them. */
13
+ escalate_above: EscalateAboveSchema.optional(),
14
+ /** Section 9, fractioning: the window over which amounts to one payee add up towards `escalate_above.amount`. */
15
+ velocity: z
16
+ .object({
17
+ window_hours: z.number().int().positive(),
18
+ /** Optional hard ceiling on the number of executions to one payee in the window. */
19
+ max_per_payee: z.number().int().positive().optional(),
20
+ })
21
+ .strict()
22
+ .optional(),
23
+ /** When an `outside_hours` trigger fires: ask a human now, or refuse and let the person retry inside the window. */
24
+ outside_hours_action: z.enum(["escalate", "refuse"]).default("escalate"),
25
+ /** When the model's stated total differs from the core's: execute the core's number, or refuse. Never the model's. */
26
+ model_total_mismatch: z.enum(["use_core", "refuse"]).default("use_core"),
27
+ /** Minutes an approval artifact stays valid. */
28
+ approval_ttl_minutes: z.number().int().positive().default(15),
29
+ /** IANA zone the `outside_hours` window is read in. */
30
+ timezone: z.string().default("America/Sao_Paulo"),
31
+ /**
32
+ * The agent-specific envelope the kit's own deterministic policy reads
33
+ * (a collections agent: discount ceiling, instalments, due-date window).
34
+ * The core carries it and runs the kit's `policyExtension` at every gate;
35
+ * it does not interpret the keys.
36
+ */
37
+ envelope: z.record(z.string(), z.unknown()).optional(),
38
+ })
39
+ .strict();
40
+
41
+ export type Guardrails = z.infer<typeof GuardrailsSchema>;
42
+
43
+ export function loadGuardrails(path: string): Guardrails {
44
+ return GuardrailsSchema.parse(JSON.parse(readFileSync(path, "utf8")));
45
+ }
@@ -0,0 +1,118 @@
1
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
2
+ import type { CompositionLine, ExecutionBatch, ExecutionItem } from "./types.js";
3
+
4
+ /** JSON with keys sorted at every level, so the same value always hashes the same. */
5
+ export function canonicalJson(value: unknown): string {
6
+ return JSON.stringify(sortKeys(value));
7
+ }
8
+
9
+ function sortKeys(value: unknown): unknown {
10
+ if (Array.isArray(value)) return value.map(sortKeys);
11
+ if (value && typeof value === "object") {
12
+ const out: Record<string, unknown> = {};
13
+ for (const key of Object.keys(value as Record<string, unknown>).sort()) {
14
+ const v = (value as Record<string, unknown>)[key];
15
+ if (v !== undefined) out[key] = sortKeys(v);
16
+ }
17
+ return out;
18
+ }
19
+ return value;
20
+ }
21
+
22
+ export function sha256Hex(input: string | Buffer): string {
23
+ return createHash("sha256").update(input).digest("hex");
24
+ }
25
+
26
+ /**
27
+ * Section 4.2: the hash of the canonical list. Only the fields that decide
28
+ * where money goes take part: payee, amount, currency, and the due date of a
29
+ * receivable when it has one. Aliases, names and descriptions are
30
+ * presentation and may differ without changing the hash.
31
+ */
32
+ export function itemsHash(items: readonly ExecutionItem[]): string {
33
+ const canonical = items.map((item) => ({
34
+ payee: item.payee,
35
+ amount: item.amount,
36
+ currency: item.currency,
37
+ ...(item.due_date ? { due_date: item.due_date } : {}),
38
+ }));
39
+ return `sha256:${sha256Hex(canonicalJson(canonical))}`;
40
+ }
41
+
42
+ /**
43
+ * The hash of a batch's ordered lines, bound into every artifact of that
44
+ * batch. It IS `itemsHash` over the whole list and deliberately not a second
45
+ * canonicalisation: the same fields decide the set that decide the line, so a
46
+ * reader who concatenates the batch's lines in order and hashes them gets the
47
+ * batch's hash back, and any line moved, re-priced, added or dropped changes
48
+ * it. Order is part of it — `index` names a position, and a position only
49
+ * means something in a list whose order is fixed.
50
+ */
51
+ export function batchHash(lines: readonly ExecutionItem[]): string {
52
+ return itemsHash(lines);
53
+ }
54
+
55
+ /**
56
+ * The hash of what an execution's amount is composed of (a cart's resolved
57
+ * lines, in order). The same canonicalisation as `itemsHash` — sorted-key
58
+ * JSON, SHA-256, the `sha256:` prefix — over the fields that decide a
59
+ * composition, and deliberately not `itemsHash` itself: its fields are the
60
+ * ones that decide where money goes (payee, amount, currency, due date), and
61
+ * none of them sees a quantity or a unit price. Ten units at a 10% discount
62
+ * and nine at list price are the same line amount; they are not the same
63
+ * sale. Order is part of it, like a batch.
64
+ */
65
+ export function compositionHash(lines: readonly CompositionLine[]): string {
66
+ const canonical = lines.map((line) => ({
67
+ ref: line.ref,
68
+ quantity: line.quantity,
69
+ unit_amount: line.unit_amount,
70
+ amount: line.amount,
71
+ currency: line.currency,
72
+ }));
73
+ return `sha256:${sha256Hex(canonicalJson(canonical))}`;
74
+ }
75
+
76
+ /**
77
+ * The `attempt_id` of an item of a batch line, derived from WHAT is being
78
+ * paid rather than from the execution that happens to pay it:
79
+ *
80
+ * ska_ + hex(sha256(mandate_id | batch_hash | line index | item index))
81
+ *
82
+ * An execution's own attempt ids come from its `idempotency_key`, which comes
83
+ * from a random execution id, so a second run of the same batch on a machine
84
+ * that has lost `.codespar/state.db` (or never had it) would present fresh ids
85
+ * and the API would take each line as a new payment (OPEN_QUESTIONS §39c).
86
+ * Derived this way, the same line of the same list under the same mandate is
87
+ * the same attempt on any machine, and the API answers a repeat of it from its
88
+ * record of that attempt (ent#1671): the original body when it settled, a 409
89
+ * while it is in flight or pinned, never a second dispatch.
90
+ *
91
+ * Every input decides the payment: the mandate is whose money, the hash is the
92
+ * exact ordered list (payee, amount, currency of every line), the index is
93
+ * which line of it. A list that changes in any line is a different hash and so
94
+ * different ids. `ska_` names the namespace (starter-kit attempt) and 68
95
+ * characters sit inside the API's 128.
96
+ *
97
+ * `generation` exists because the API never runs an attempt id twice: once an
98
+ * attempt FAILED and moved no money, a repeat of it answers
99
+ * `psp_attempt_conflict` for good. A line whose payment the provider refused
100
+ * must still be payable by a later run of the same list, so it moves to the
101
+ * next generation, and only on that answer: the server saying the id is
102
+ * spent is the one fact every machine reads the same way, so every machine
103
+ * walks the same sequence and none of them finds a "free" id past one that
104
+ * paid. Generation 0 hashes exactly as above.
105
+ */
106
+ export function batchAttemptId(mandateId: string, batch: Pick<ExecutionBatch, "batch_hash" | "index">, item: number, generation = 0): string {
107
+ const base = `${mandateId}|${batch.batch_hash}|${batch.index}|${item}`;
108
+ return `ska_${sha256Hex(generation === 0 ? base : `${base}|${generation}`)}`;
109
+ }
110
+
111
+ export function hmacSha256Hex(key: Buffer, payload: string): string {
112
+ return createHmac("sha256", key).update(payload).digest("hex");
113
+ }
114
+
115
+ export function hexEqual(a: string, b: string): boolean {
116
+ if (a.length !== b.length) return false;
117
+ return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
118
+ }
@@ -0,0 +1,10 @@
1
+ import { randomBytes } from "node:crypto";
2
+
3
+ export function newId(prefix: string, bytes = 8): string {
4
+ return `${prefix}_${randomBytes(bytes).toString("hex")}`;
5
+ }
6
+
7
+ export function newRunId(label?: string): string {
8
+ const stamp = new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
9
+ return label ? `run_${stamp}_${label}_${randomBytes(3).toString("hex")}` : `run_${stamp}_${randomBytes(3).toString("hex")}`;
10
+ }
@@ -0,0 +1,34 @@
1
+ export * from "./types.js";
2
+ export * from "./state-machine.js";
3
+ export * from "./hash.js";
4
+ export * from "./ids.js";
5
+ export * from "./approval.js";
6
+ export * from "./manifest.js";
7
+ export * from "./guardrails.js";
8
+ export * from "./channels.js";
9
+ export * from "./mandate.js";
10
+ export * from "./escalate.js";
11
+ export * from "./clock.js";
12
+ export * from "./secrets.js";
13
+ export * from "./revocation.js";
14
+ export * from "./rail.js";
15
+ export * from "./quote.js";
16
+ export * from "./receipt-verification.js";
17
+ export * from "./receipt-chain.js";
18
+ export * from "./tools.js";
19
+ export * from "./bundle.js";
20
+ export * from "./engine.js";
21
+ export * from "./agent.js";
22
+ export * from "./check.js";
23
+ export * from "./events.js";
24
+ export * from "./state/store.js";
25
+ export * from "./stubs/mandate-status.js";
26
+ export * from "./stubs/rail.js";
27
+ export * from "./stubs/charge-rail.js";
28
+ export * from "./api/client.js";
29
+ export * from "./api/rail.js";
30
+ export * from "./api/mandate-status.js";
31
+ export * from "./api/charge-rail.js";
32
+ export * from "./api/sandbox-payer.js";
33
+ export * from "./providers/types.js";
34
+ export * from "./providers/replay.js";
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The local view of a consumer mandate: the fields the core checks before
3
+ * anything reaches the API, plus the named payees the kit presents to the
4
+ * person. The API re-verifies all of it server-side on every spend; the
5
+ * local checks exist so a refusal is readable and happens before any call.
6
+ */
7
+ import { readFileSync } from "node:fs";
8
+ import { z } from "zod";
9
+
10
+ export const BeneficiarySchema = z
11
+ .object({
12
+ /** Short handle the model may use: `escola`, `mercado`. */
13
+ alias: z.string().regex(/^[a-z0-9_-]+$/),
14
+ name: z.string().min(1),
15
+ /** The pinned payee key. Must appear in `merchant_allowlist`. */
16
+ payee: z.string().min(1),
17
+ })
18
+ .strict();
19
+
20
+ export const MandateSchema = z
21
+ .object({
22
+ id: z.string().min(1),
23
+ /** Local version counter for the approval artifact; bumps when the mandate is re-signed. */
24
+ version: z.number().int().positive(),
25
+ consumer_id: z.string().min(1),
26
+ agent_id: z.string().min(1),
27
+ purpose: z.string().min(1),
28
+ currency: z.string().min(1),
29
+ /** Section 4.3: total over the window, in minor units. */
30
+ cap_minor: z.number().int().positive(),
31
+ per_tx_cap_minor: z.number().int().positive(),
32
+ periodic_cap: z.object({ window: z.enum(["day", "month"]), cap_minor: z.number().int().positive() }).strict().optional(),
33
+ /** `document` is the receivable side: the list names the debtors (CPF/CNPJ) with an open agreement, and a charge may only be issued against one of them. */
34
+ merchant_pin_kind: z.enum(["pix-key", "merchant-id", "mcc", "document"]),
35
+ /** Concrete keys. The kit never treats `"*"` as authorizing a payee. */
36
+ merchant_allowlist: z.array(z.string().min(1)).nonempty(),
37
+ beneficiaries: z.array(BeneficiarySchema),
38
+ status: z.enum(["active", "paused", "revoked", "expired"]),
39
+ /** ISO 8601. */
40
+ expires_at: z.string().datetime(),
41
+ /** The signature the API returned at consent, when the mandate is a real one. Never required locally. */
42
+ signature: z.string().regex(/^[0-9a-f]{64}$/).optional(),
43
+ /** The canonical mandate the API returned, presented on `/v1/consumer-payments/execute`. */
44
+ canonical: z.record(z.string(), z.unknown()).optional(),
45
+ /** Where this mandate came from. */
46
+ source: z.enum(["example", "consent"]).default("example"),
47
+ })
48
+ .strict()
49
+ .superRefine((m, ctx) => {
50
+ if (m.per_tx_cap_minor > m.cap_minor) {
51
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["per_tx_cap_minor"], message: "per_tx_cap_minor cannot exceed cap_minor" });
52
+ }
53
+ // The API's own rule (`periodic_cap_never_binds`): the window cap must sit below the lifetime cap, or it is a limit the consumer was shown and never enforced.
54
+ if (m.periodic_cap && m.periodic_cap.cap_minor >= m.cap_minor) {
55
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["periodic_cap", "cap_minor"], message: "periodic_cap.cap_minor must be below cap_minor (the lifetime cap)" });
56
+ }
57
+ for (const [i, b] of m.beneficiaries.entries()) {
58
+ if (!m.merchant_allowlist.includes(b.payee)) {
59
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["beneficiaries", i, "payee"], message: `payee ${b.payee} is not in merchant_allowlist` });
60
+ }
61
+ }
62
+ });
63
+
64
+ export type Mandate = z.infer<typeof MandateSchema>;
65
+ export type Beneficiary = z.infer<typeof BeneficiarySchema>;
66
+
67
+ export function loadMandate(path: string): Mandate {
68
+ return MandateSchema.parse(JSON.parse(readFileSync(path, "utf8")));
69
+ }
70
+
71
+ /** The window the monthly cap is counted over. */
72
+ export function windowStart(mandate: Mandate, now: Date): Date {
73
+ const window = mandate.periodic_cap?.window ?? "month";
74
+ const d = new Date(now);
75
+ if (window === "day") {
76
+ d.setUTCHours(0, 0, 0, 0);
77
+ } else {
78
+ d.setUTCDate(1);
79
+ d.setUTCHours(0, 0, 0, 0);
80
+ }
81
+ return d;
82
+ }
83
+
84
+ export function windowCap(mandate: Mandate): number {
85
+ return mandate.periodic_cap?.cap_minor ?? mandate.cap_minor;
86
+ }
87
+
88
+ /** A payee is allowed only when the SIGNED list names it. A wildcard names nobody here. */
89
+ export function payeeAllowed(mandate: Mandate, payee: string): boolean {
90
+ return mandate.merchant_allowlist.some((entry) => entry !== "*" && entry === payee);
91
+ }
92
+
93
+ export function resolveBeneficiary(mandate: Mandate, aliasOrPayee: string): Beneficiary | undefined {
94
+ const needle = aliasOrPayee.trim().toLowerCase();
95
+ return mandate.beneficiaries.find((b) => b.alias === needle || b.payee.toLowerCase() === needle || b.name.toLowerCase() === needle);
96
+ }
97
+
98
+ export function mandateExpired(mandate: Mandate, now: Date): boolean {
99
+ return new Date(mandate.expires_at).getTime() <= now.getTime();
100
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Section 4.3: the `agent.yaml` manifest, `schema: 1`.
3
+ *
4
+ * The schema promises stability from now on: a field is removed or changes
5
+ * meaning only under a new `schema` number.
6
+ */
7
+ import { readFileSync } from "node:fs";
8
+ import { dirname, resolve } from "node:path";
9
+ import { parse as parseYaml } from "yaml";
10
+ import { z } from "zod";
11
+
12
+ const PINNED_PACKAGE = /^@codespar\/(mcp|cli)@\d+\.\d+\.\d+$/;
13
+ const HOURS_WINDOW = /^([01]\d|2[0-3]):[0-5]\d-([01]\d|2[0-3]):[0-5]\d$/;
14
+
15
+ export const MaturitySchema = z.enum(["live", "sandbox", "blocked"]);
16
+
17
+ export const EscalateAboveSchema = z
18
+ .object({
19
+ /** Minor units. A payment above this, still inside the mandate cap, asks a human. */
20
+ amount: z.number().int().positive().optional(),
21
+ /** The first payment to a payee that is already on the allowlist asks a human. */
22
+ new_beneficiary: z.boolean().optional(),
23
+ /** "HH:MM-HH:MM", may cross midnight. Execution requested inside it asks a human. */
24
+ outside_hours: z.string().regex(HOURS_WINDOW, 'expected "HH:MM-HH:MM"').optional(),
25
+ })
26
+ .strict();
27
+
28
+ export const ManifestSchema = z
29
+ .object({
30
+ schema: z.literal(1),
31
+ name: z.string().regex(/^[a-z0-9-]+$/),
32
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
33
+ approval: z.array(z.enum(["human", "mandate"])).nonempty(),
34
+ default_approval: z.enum(["human", "mandate"]),
35
+ escalate_above: EscalateAboveSchema.optional(),
36
+ mcp: z.string().regex(PINNED_PACKAGE, "mcp must pin an exact version, e.g. @codespar/mcp@0.5.8"),
37
+ cli: z.string().regex(PINNED_PACKAGE, "cli must pin an exact version, e.g. @codespar/cli@0.14.0"),
38
+ tools: z.string(),
39
+ guardrails: z.string(),
40
+ mandate_schema: z.string(),
41
+ events: z.array(z.string().regex(/^commerce\.[a-z_.]+$/)),
42
+ channels: z.array(z.enum(["terminal", "whatsapp"])).nonempty(),
43
+ maturity: z.record(z.string(), MaturitySchema),
44
+ scenarios: z.string(),
45
+ evals: z.string(),
46
+ agents_md: z.string(),
47
+ })
48
+ .strict()
49
+ .superRefine((m, ctx) => {
50
+ if (!m.approval.includes(m.default_approval)) {
51
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["default_approval"], message: "default_approval must be one of approval" });
52
+ }
53
+ });
54
+
55
+ export type Manifest = z.infer<typeof ManifestSchema>;
56
+ export type EscalateAbove = z.infer<typeof EscalateAboveSchema>;
57
+
58
+ export interface LoadedManifest {
59
+ manifest: Manifest;
60
+ /** Absolute path of the manifest file. */
61
+ path: string;
62
+ /** Directory the relative paths in the manifest resolve against. */
63
+ dir: string;
64
+ resolvePath(relative: string): string;
65
+ }
66
+
67
+ export function parseManifest(text: string): Manifest {
68
+ return ManifestSchema.parse(parseYaml(text));
69
+ }
70
+
71
+ export function loadManifest(path: string): LoadedManifest {
72
+ const absolute = resolve(path);
73
+ const manifest = parseManifest(readFileSync(absolute, "utf8"));
74
+ const dir = dirname(absolute);
75
+ return { manifest, path: absolute, dir, resolvePath: (relative) => resolve(dir, relative) };
76
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The reference harness: a tool-use loop on `@anthropic-ai/sdk`. It only
3
+ * turns messages into a request and the response into tool calls or a
4
+ * reply; it never decides anything about money.
5
+ */
6
+ import Anthropic from "@anthropic-ai/sdk";
7
+ import type { ContentBlockParam, MessageParam, Tool as AnthropicTool } from "@anthropic-ai/sdk/resources/messages";
8
+ import type { AgentRuntime, ConversationMessage, Reply, ToolCall, ToolSpec, Turn } from "./types.js";
9
+
10
+ export const DEFAULT_MODEL = "claude-sonnet-5";
11
+
12
+ export interface AnthropicRuntimeOptions {
13
+ apiKey?: string | undefined;
14
+ model?: string;
15
+ maxTokens?: number;
16
+ }
17
+
18
+ export class AnthropicRuntime implements AgentRuntime {
19
+ readonly name = "anthropic";
20
+ private readonly client: Anthropic;
21
+ private readonly model: string;
22
+ private readonly maxTokens: number;
23
+
24
+ constructor(options: AnthropicRuntimeOptions = {}) {
25
+ const apiKey = options.apiKey ?? process.env["ANTHROPIC_API_KEY"];
26
+ if (!apiKey) throw new Error("ANTHROPIC_API_KEY is not set; use the replay provider for runs without a model");
27
+ this.client = new Anthropic({ apiKey });
28
+ this.model = options.model ?? process.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODEL;
29
+ this.maxTokens = options.maxTokens ?? 1024;
30
+ }
31
+
32
+ async step(input: Turn, tools: ToolSpec[]): Promise<ToolCall[] | Reply> {
33
+ const response = await this.client.messages.create({
34
+ model: this.model,
35
+ max_tokens: this.maxTokens,
36
+ system: input.system,
37
+ tools: tools.map(toAnthropicTool),
38
+ messages: toAnthropicMessages(input.messages),
39
+ });
40
+ const calls: ToolCall[] = [];
41
+ const text: string[] = [];
42
+ for (const block of response.content) {
43
+ if (block.type === "tool_use") calls.push({ id: block.id, name: block.name, input: (block.input ?? {}) as Record<string, unknown> });
44
+ else if (block.type === "text") text.push(block.text);
45
+ }
46
+ if (calls.length > 0) return calls;
47
+ return { text: text.join("\n").trim() };
48
+ }
49
+ }
50
+
51
+ function toAnthropicTool(tool: ToolSpec): AnthropicTool {
52
+ return { name: tool.name, description: tool.description, input_schema: tool.input_schema as AnthropicTool["input_schema"] };
53
+ }
54
+
55
+ function toAnthropicMessages(messages: ConversationMessage[]): MessageParam[] {
56
+ const out: MessageParam[] = [];
57
+ for (const m of messages) {
58
+ if (m.role === "user") {
59
+ out.push({ role: "user", content: m.content });
60
+ } else if (m.role === "assistant") {
61
+ const content: ContentBlockParam[] = [];
62
+ if (m.content) content.push({ type: "text", text: m.content });
63
+ for (const call of m.tool_calls ?? []) content.push({ type: "tool_use", id: call.id, name: call.name, input: call.input });
64
+ out.push({ role: "assistant", content });
65
+ } else {
66
+ const last = out[out.length - 1];
67
+ const block = { type: "tool_result" as const, tool_use_id: m.tool_call_id, content: m.content, ...(m.is_error ? { is_error: true } : {}) };
68
+ if (last && last.role === "user" && Array.isArray(last.content) && last.content.every((b) => (b as { type: string }).type === "tool_result")) {
69
+ (last.content as Array<typeof block>).push(block);
70
+ } else {
71
+ out.push({ role: "user", content: [block] });
72
+ }
73
+ }
74
+ }
75
+ return out;
76
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The deterministic provider. It reads the `assistant_step` lines of a
3
+ * recorded transcript and answers them in order, so the CI, the scenarios
4
+ * and `npm run rerun` run with no model and no network. The recorded lines
5
+ * are the MODEL's outputs only; everything the core decided is recomputed
6
+ * live, which is what makes a rerun a test rather than a printout.
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ import type { AgentRuntime, Reply, ToolCall, ToolSpec, Turn } from "./types.js";
10
+
11
+ export interface RecordedStep {
12
+ kind: "assistant_step";
13
+ tool_calls?: ToolCall[];
14
+ reply?: string;
15
+ }
16
+
17
+ export class ReplayExhaustedError extends Error {
18
+ constructor(consumed: number) {
19
+ super(`replay transcript exhausted after ${consumed} step(s); the run asked the model more than the recording holds`);
20
+ this.name = "ReplayExhaustedError";
21
+ }
22
+ }
23
+
24
+ export class ReplayRuntime implements AgentRuntime {
25
+ readonly name = "replay";
26
+ private cursor = 0;
27
+
28
+ constructor(private readonly steps: RecordedStep[]) {}
29
+
30
+ static fromFile(path: string): ReplayRuntime {
31
+ return new ReplayRuntime(parseTranscript(readFileSync(path, "utf8")));
32
+ }
33
+
34
+ static fromLines(lines: Array<Record<string, unknown>>): ReplayRuntime {
35
+ return new ReplayRuntime(lines.filter((l) => l["kind"] === "assistant_step") as unknown as RecordedStep[]);
36
+ }
37
+
38
+ get consumed(): number {
39
+ return this.cursor;
40
+ }
41
+
42
+ get remaining(): number {
43
+ return this.steps.length - this.cursor;
44
+ }
45
+
46
+ async step(_input: Turn, _tools: ToolSpec[]): Promise<ToolCall[] | Reply> {
47
+ const next = this.steps[this.cursor];
48
+ if (!next) throw new ReplayExhaustedError(this.cursor);
49
+ this.cursor += 1;
50
+ if (next.tool_calls && next.tool_calls.length > 0) {
51
+ return next.tool_calls.map((c, i) => ({ id: c.id ?? `tc_${this.cursor}_${i}`, name: c.name, input: c.input ?? {} }));
52
+ }
53
+ return { text: next.reply ?? "" };
54
+ }
55
+ }
56
+
57
+ export function parseTranscript(text: string): RecordedStep[] {
58
+ return text
59
+ .split("\n")
60
+ .filter((l) => l.trim().length > 0)
61
+ .map((l) => JSON.parse(l) as Record<string, unknown>)
62
+ .filter((l) => l["kind"] === "assistant_step") as unknown as RecordedStep[];
63
+ }