@codespar/cli 0.18.1 → 0.20.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 (558) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/login.js +52 -12
  3. package/dist/commands/login.js.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/surface.js +31 -13
  7. package/dist/surface.js.map +1 -1
  8. package/package.json +1 -1
  9. package/templates/bills-agent/README.md +2 -2
  10. package/templates/bills-agent/agents/bills-agent/.env.example +2 -2
  11. package/templates/bills-agent/agents/bills-agent/README.md +25 -18
  12. package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +13 -3
  13. package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -1
  14. package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  15. package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  16. package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  17. package/templates/bills-agent/agents/bills-agent/mandate.example.json +1 -1
  18. package/templates/bills-agent/agents/bills-agent/runbook.md +1 -1
  19. package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  20. package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  21. package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.transcript.jsonl +4 -4
  22. package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.transcript.jsonl +1 -1
  23. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.json +1 -1
  24. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.transcript.jsonl +4 -4
  25. package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  26. package/templates/bills-agent/agents/bills-agent/src/bills.ts +1 -1
  27. package/templates/bills-agent/agents/bills-agent/src/kit.ts +15 -28
  28. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +42 -15
  29. package/templates/bills-agent/agents/bills-agent/src/modules/pix-out.ts +21 -3
  30. package/templates/bills-agent/agents/bills-agent/src/strings.ts +68 -0
  31. package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +130 -2
  32. package/templates/bills-agent/agents/bills-agent/test/consent-money.test.ts +25 -0
  33. package/templates/bills-agent/agents/bills-agent/test/dates-and-approval.test.ts +98 -0
  34. package/templates/bills-agent/agents/bills-agent/test/eval-runs.test.ts +81 -0
  35. package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -2
  36. package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +1 -1
  37. package/templates/bills-agent/agents/bills-agent/test/locale.test.ts +161 -0
  38. package/templates/bills-agent/agents/bills-agent/test/mandate-state.test.ts +108 -0
  39. package/templates/bills-agent/agents/bills-agent/test/refused-before-draft.test.ts +81 -0
  40. package/templates/bills-agent/agents/bills-agent/test/replay.test.ts +76 -0
  41. package/templates/bills-agent/agents/bills-agent/test/reply-and-outcome.test.ts +84 -0
  42. package/templates/bills-agent/agents/bills-agent/test/reply-language.test.ts +95 -0
  43. package/templates/bills-agent/agents/bills-agent/test/rerun-and-missing-transcript.test.ts +120 -0
  44. package/templates/bills-agent/agents/bills-agent/test/rerun-world-events.test.ts +55 -0
  45. package/templates/bills-agent/agents/bills-agent/tools.json +1 -1
  46. package/templates/bills-agent/packages/agent-core/README.md +21 -2
  47. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  48. package/templates/bills-agent/packages/agent-core/src/agent.ts +33 -6
  49. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  50. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +11 -5
  51. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  52. package/templates/bills-agent/packages/agent-core/src/bundle.ts +2 -0
  53. package/templates/bills-agent/packages/agent-core/src/channels.ts +18 -8
  54. package/templates/bills-agent/packages/agent-core/src/check.ts +25 -3
  55. package/templates/bills-agent/packages/agent-core/src/engine.ts +90 -9
  56. package/templates/bills-agent/packages/agent-core/src/escalate.ts +10 -0
  57. package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
  58. package/templates/bills-agent/packages/agent-core/src/language.ts +52 -0
  59. package/templates/bills-agent/packages/agent-core/src/locale.ts +88 -0
  60. package/templates/bills-agent/packages/agent-core/src/manifest.ts +4 -1
  61. package/templates/bills-agent/packages/agent-core/src/rail.ts +29 -1
  62. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  63. package/templates/bills-agent/packages/agent-core/src/secrets.ts +53 -8
  64. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +14 -0
  65. package/templates/bills-agent/packages/agent-core/src/strings.ts +175 -0
  66. package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  67. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  68. package/templates/bills-agent/packages/agent-core/src/types.ts +15 -2
  69. package/templates/bills-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  70. package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  71. package/templates/bills-agent/packages/agent-core/test/engine.test.ts +23 -0
  72. package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
  73. package/templates/bills-agent/packages/agent-core/test/language.test.ts +40 -0
  74. package/templates/bills-agent/packages/agent-core/test/locale.test.ts +137 -0
  75. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  76. package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
  77. package/templates/bills-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  78. package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  79. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +49 -0
  80. package/templates/bills-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  81. package/templates/bills-agent/packages/agent-core/test/secrets.test.ts +40 -1
  82. package/templates/bills-agent/packages/agent-runtime/README.md +31 -4
  83. package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  84. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  85. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  86. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  87. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  88. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  89. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  90. package/templates/bills-agent/packages/agent-runtime/src/cli.ts +30 -4
  91. package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  92. package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  93. package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  94. package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  95. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  96. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  97. package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  98. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  99. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  100. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  101. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  102. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  103. package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  104. package/templates/bills-agent/packages/agent-runtime/src/env.ts +64 -0
  105. package/templates/bills-agent/packages/agent-runtime/src/index.ts +2 -0
  106. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +81 -10
  107. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +34 -12
  108. package/templates/bills-agent/packages/agent-runtime/src/outcome.ts +118 -0
  109. package/templates/bills-agent/packages/agent-runtime/src/poll.ts +7 -7
  110. package/templates/bills-agent/packages/agent-runtime/src/runs.ts +51 -0
  111. package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  112. package/templates/bills-agent/packages/agent-runtime/src/setup.ts +75 -5
  113. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +71 -33
  114. package/templates/bills-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  115. package/templates/bills-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  116. package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  117. package/templates/bills-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  118. package/templates/bills-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  119. package/templates/bills-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  120. package/templates/bills-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  121. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  122. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  123. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  124. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  125. package/templates/checkout-agent/README.md +2 -2
  126. package/templates/checkout-agent/agents/checkout-agent/.env.example +6 -4
  127. package/templates/checkout-agent/agents/checkout-agent/README.md +16 -8
  128. package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +17 -7
  129. package/templates/checkout-agent/agents/checkout-agent/agent.yaml +4 -3
  130. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +2 -2
  131. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +48 -4
  132. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +1 -1
  133. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +1 -1
  134. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +1 -1
  135. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +1 -1
  136. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  137. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +1 -1
  138. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +1 -1
  139. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +1 -1
  140. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +1 -1
  141. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  142. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +1 -1
  143. package/templates/checkout-agent/agents/checkout-agent/package.json +1 -1
  144. package/templates/checkout-agent/agents/checkout-agent/runbook.md +4 -4
  145. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  146. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +2 -2
  147. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +2 -2
  148. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +2 -2
  149. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +1 -1
  150. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +2 -2
  151. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +1 -1
  152. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +1 -1
  153. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +2 -2
  154. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +1 -1
  155. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +3 -3
  156. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +1 -1
  157. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +2 -2
  158. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +1 -1
  159. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  160. package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +7 -7
  161. package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +47 -43
  162. package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +20 -12
  163. package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +4 -4
  164. package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +9 -6
  165. package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +44 -41
  166. package/templates/checkout-agent/agents/checkout-agent/src/strings.ts +179 -0
  167. package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +4 -1
  168. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +1 -1
  169. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +2 -2
  170. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +1 -1
  171. package/templates/checkout-agent/agents/checkout-agent/test/payable-instrument.test.ts +58 -0
  172. package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +2 -2
  173. package/templates/checkout-agent/agents/checkout-agent/test/rerun-unpaid.test.ts +47 -0
  174. package/templates/checkout-agent/agents/checkout-agent/test/scenario-reach-and-seconds.test.ts +55 -0
  175. package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +26 -10
  176. package/templates/checkout-agent/agents/checkout-agent/tools.json +1 -1
  177. package/templates/checkout-agent/packages/agent-core/README.md +21 -2
  178. package/templates/checkout-agent/packages/agent-core/package.json +1 -1
  179. package/templates/checkout-agent/packages/agent-core/src/agent.ts +33 -6
  180. package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  181. package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +11 -5
  182. package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  183. package/templates/checkout-agent/packages/agent-core/src/bundle.ts +2 -0
  184. package/templates/checkout-agent/packages/agent-core/src/channels.ts +18 -8
  185. package/templates/checkout-agent/packages/agent-core/src/check.ts +25 -3
  186. package/templates/checkout-agent/packages/agent-core/src/engine.ts +90 -9
  187. package/templates/checkout-agent/packages/agent-core/src/escalate.ts +10 -0
  188. package/templates/checkout-agent/packages/agent-core/src/index.ts +3 -0
  189. package/templates/checkout-agent/packages/agent-core/src/language.ts +52 -0
  190. package/templates/checkout-agent/packages/agent-core/src/locale.ts +88 -0
  191. package/templates/checkout-agent/packages/agent-core/src/manifest.ts +4 -1
  192. package/templates/checkout-agent/packages/agent-core/src/rail.ts +29 -1
  193. package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  194. package/templates/checkout-agent/packages/agent-core/src/secrets.ts +53 -8
  195. package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +14 -0
  196. package/templates/checkout-agent/packages/agent-core/src/strings.ts +175 -0
  197. package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  198. package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  199. package/templates/checkout-agent/packages/agent-core/src/types.ts +15 -2
  200. package/templates/checkout-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  201. package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  202. package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +23 -0
  203. package/templates/checkout-agent/packages/agent-core/test/helpers.ts +1 -1
  204. package/templates/checkout-agent/packages/agent-core/test/language.test.ts +40 -0
  205. package/templates/checkout-agent/packages/agent-core/test/locale.test.ts +137 -0
  206. package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  207. package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +2 -2
  208. package/templates/checkout-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  209. package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  210. package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +49 -0
  211. package/templates/checkout-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  212. package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +40 -1
  213. package/templates/checkout-agent/packages/agent-runtime/README.md +31 -4
  214. package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  215. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  216. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  217. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  218. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  219. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  220. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  221. package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +30 -4
  222. package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  223. package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  224. package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  225. package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  226. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  227. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  228. package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  229. package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  230. package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  231. package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  232. package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  233. package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  234. package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  235. package/templates/checkout-agent/packages/agent-runtime/src/env.ts +64 -0
  236. package/templates/checkout-agent/packages/agent-runtime/src/index.ts +2 -0
  237. package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +81 -10
  238. package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +34 -12
  239. package/templates/checkout-agent/packages/agent-runtime/src/outcome.ts +118 -0
  240. package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +7 -7
  241. package/templates/checkout-agent/packages/agent-runtime/src/runs.ts +51 -0
  242. package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  243. package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +75 -5
  244. package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +71 -33
  245. package/templates/checkout-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  246. package/templates/checkout-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  247. package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  248. package/templates/checkout-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  249. package/templates/checkout-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  250. package/templates/checkout-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  251. package/templates/checkout-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  252. package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  253. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  254. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  255. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  256. package/templates/collections-agent/README.md +2 -2
  257. package/templates/collections-agent/agents/collections-agent/.env.example +6 -3
  258. package/templates/collections-agent/agents/collections-agent/README.md +14 -9
  259. package/templates/collections-agent/agents/collections-agent/SYSTEM_PROMPT.md +16 -5
  260. package/templates/collections-agent/agents/collections-agent/agent.yaml +4 -3
  261. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +21 -4
  262. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +49 -5
  263. package/templates/collections-agent/agents/collections-agent/mandate.example.json +1 -1
  264. package/templates/collections-agent/agents/collections-agent/runbook.md +3 -3
  265. package/templates/collections-agent/agents/collections-agent/src/agreements.ts +1 -1
  266. package/templates/collections-agent/agents/collections-agent/src/envelope.ts +15 -13
  267. package/templates/collections-agent/agents/collections-agent/src/kit.ts +38 -35
  268. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +16 -8
  269. package/templates/collections-agent/agents/collections-agent/src/strings.ts +91 -0
  270. package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +2 -2
  271. package/templates/collections-agent/agents/collections-agent/test/check.test.ts +4 -1
  272. package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +1 -1
  273. package/templates/collections-agent/agents/collections-agent/test/envelope.test.ts +2 -2
  274. package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1103.transcript.jsonl +1 -1
  275. package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +1 -1
  276. package/templates/collections-agent/agents/collections-agent/test/payable-instrument.test.ts +56 -0
  277. package/templates/collections-agent/agents/collections-agent/test/rerun-clock.test.ts +54 -0
  278. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +69 -2
  279. package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +16 -3
  280. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +16 -4
  281. package/templates/collections-agent/agents/collections-agent/tools.json +2 -2
  282. package/templates/collections-agent/packages/agent-core/README.md +21 -2
  283. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  284. package/templates/collections-agent/packages/agent-core/src/agent.ts +33 -6
  285. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  286. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +11 -5
  287. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  288. package/templates/collections-agent/packages/agent-core/src/bundle.ts +2 -0
  289. package/templates/collections-agent/packages/agent-core/src/channels.ts +18 -8
  290. package/templates/collections-agent/packages/agent-core/src/check.ts +25 -3
  291. package/templates/collections-agent/packages/agent-core/src/engine.ts +90 -9
  292. package/templates/collections-agent/packages/agent-core/src/escalate.ts +10 -0
  293. package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
  294. package/templates/collections-agent/packages/agent-core/src/language.ts +52 -0
  295. package/templates/collections-agent/packages/agent-core/src/locale.ts +88 -0
  296. package/templates/collections-agent/packages/agent-core/src/manifest.ts +4 -1
  297. package/templates/collections-agent/packages/agent-core/src/rail.ts +29 -1
  298. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  299. package/templates/collections-agent/packages/agent-core/src/secrets.ts +53 -8
  300. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +14 -0
  301. package/templates/collections-agent/packages/agent-core/src/strings.ts +175 -0
  302. package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  303. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  304. package/templates/collections-agent/packages/agent-core/src/types.ts +15 -2
  305. package/templates/collections-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  306. package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  307. package/templates/collections-agent/packages/agent-core/test/engine.test.ts +23 -0
  308. package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
  309. package/templates/collections-agent/packages/agent-core/test/language.test.ts +40 -0
  310. package/templates/collections-agent/packages/agent-core/test/locale.test.ts +137 -0
  311. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  312. package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
  313. package/templates/collections-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  314. package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  315. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +49 -0
  316. package/templates/collections-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  317. package/templates/collections-agent/packages/agent-core/test/secrets.test.ts +40 -1
  318. package/templates/collections-agent/packages/agent-runtime/README.md +31 -4
  319. package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  320. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  321. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  322. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  323. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  324. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  325. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  326. package/templates/collections-agent/packages/agent-runtime/src/cli.ts +30 -4
  327. package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  328. package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  329. package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  330. package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  331. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  332. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  333. package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  334. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  335. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  336. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  337. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  338. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  339. package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  340. package/templates/collections-agent/packages/agent-runtime/src/env.ts +64 -0
  341. package/templates/collections-agent/packages/agent-runtime/src/index.ts +2 -0
  342. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +81 -10
  343. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +34 -12
  344. package/templates/collections-agent/packages/agent-runtime/src/outcome.ts +118 -0
  345. package/templates/collections-agent/packages/agent-runtime/src/poll.ts +7 -7
  346. package/templates/collections-agent/packages/agent-runtime/src/runs.ts +51 -0
  347. package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  348. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +75 -5
  349. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +71 -33
  350. package/templates/collections-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  351. package/templates/collections-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  352. package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  353. package/templates/collections-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  354. package/templates/collections-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  355. package/templates/collections-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  356. package/templates/collections-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  357. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  358. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  359. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  360. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  361. package/templates/hello-agent/README.md +2 -2
  362. package/templates/hello-agent/agents/hello-agent/README.md +6 -0
  363. package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +27 -13
  364. package/templates/hello-agent/agents/hello-agent/agent.yaml +2 -1
  365. package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  366. package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  367. package/templates/hello-agent/agents/hello-agent/mandate.example.json +1 -1
  368. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +1 -1
  369. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +1 -1
  370. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +1 -1
  371. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  372. package/templates/hello-agent/agents/hello-agent/src/bills.ts +9 -5
  373. package/templates/hello-agent/agents/hello-agent/src/kit.ts +4 -1
  374. package/templates/hello-agent/agents/hello-agent/tools.json +1 -1
  375. package/templates/hello-agent/packages/agent-core/README.md +21 -2
  376. package/templates/hello-agent/packages/agent-core/package.json +1 -1
  377. package/templates/hello-agent/packages/agent-core/src/agent.ts +33 -6
  378. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  379. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +11 -5
  380. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  381. package/templates/hello-agent/packages/agent-core/src/bundle.ts +2 -0
  382. package/templates/hello-agent/packages/agent-core/src/channels.ts +18 -8
  383. package/templates/hello-agent/packages/agent-core/src/check.ts +25 -3
  384. package/templates/hello-agent/packages/agent-core/src/engine.ts +90 -9
  385. package/templates/hello-agent/packages/agent-core/src/escalate.ts +10 -0
  386. package/templates/hello-agent/packages/agent-core/src/index.ts +3 -0
  387. package/templates/hello-agent/packages/agent-core/src/language.ts +52 -0
  388. package/templates/hello-agent/packages/agent-core/src/locale.ts +88 -0
  389. package/templates/hello-agent/packages/agent-core/src/manifest.ts +4 -1
  390. package/templates/hello-agent/packages/agent-core/src/rail.ts +29 -1
  391. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  392. package/templates/hello-agent/packages/agent-core/src/secrets.ts +53 -8
  393. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +14 -0
  394. package/templates/hello-agent/packages/agent-core/src/strings.ts +175 -0
  395. package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  396. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  397. package/templates/hello-agent/packages/agent-core/src/types.ts +15 -2
  398. package/templates/hello-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  399. package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  400. package/templates/hello-agent/packages/agent-core/test/engine.test.ts +23 -0
  401. package/templates/hello-agent/packages/agent-core/test/helpers.ts +1 -1
  402. package/templates/hello-agent/packages/agent-core/test/language.test.ts +40 -0
  403. package/templates/hello-agent/packages/agent-core/test/locale.test.ts +137 -0
  404. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  405. package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +2 -2
  406. package/templates/hello-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  407. package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  408. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +49 -0
  409. package/templates/hello-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  410. package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +40 -1
  411. package/templates/hello-agent/packages/agent-runtime/README.md +31 -4
  412. package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  413. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  414. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  415. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  416. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  417. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  418. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  419. package/templates/hello-agent/packages/agent-runtime/src/cli.ts +30 -4
  420. package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  421. package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  422. package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  423. package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  424. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  425. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  426. package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  427. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  428. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  429. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  430. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  431. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  432. package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  433. package/templates/hello-agent/packages/agent-runtime/src/env.ts +64 -0
  434. package/templates/hello-agent/packages/agent-runtime/src/index.ts +2 -0
  435. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +81 -10
  436. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +34 -12
  437. package/templates/hello-agent/packages/agent-runtime/src/outcome.ts +118 -0
  438. package/templates/hello-agent/packages/agent-runtime/src/poll.ts +7 -7
  439. package/templates/hello-agent/packages/agent-runtime/src/runs.ts +51 -0
  440. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  441. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +75 -5
  442. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +71 -33
  443. package/templates/hello-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  444. package/templates/hello-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  445. package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  446. package/templates/hello-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  447. package/templates/hello-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  448. package/templates/hello-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  449. package/templates/hello-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  450. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  451. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  452. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  453. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  454. package/templates/kits.lock.json +12 -12
  455. package/templates/supplier-payments-agent/README.md +2 -2
  456. package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +2 -2
  457. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +12 -7
  458. package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +14 -3
  459. package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +2 -1
  460. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  461. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  462. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  463. package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +3 -3
  464. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  465. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  466. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +5 -5
  467. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +1 -1
  468. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +5 -5
  469. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +1 -1
  470. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +1 -1
  471. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  472. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +37 -26
  473. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +41 -14
  474. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +12 -3
  475. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +8 -8
  476. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +75 -10
  477. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/locale.test.ts +101 -0
  478. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/run-outcome.test.ts +127 -0
  479. package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +1 -1
  480. package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -2
  481. package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
  482. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +33 -6
  483. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  484. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +11 -5
  485. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  486. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +2 -0
  487. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +18 -8
  488. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -3
  489. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +90 -9
  490. package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +10 -0
  491. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +3 -0
  492. package/templates/supplier-payments-agent/packages/agent-core/src/language.ts +52 -0
  493. package/templates/supplier-payments-agent/packages/agent-core/src/locale.ts +88 -0
  494. package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +4 -1
  495. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +29 -1
  496. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  497. package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +53 -8
  498. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +14 -0
  499. package/templates/supplier-payments-agent/packages/agent-core/src/strings.ts +175 -0
  500. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  501. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  502. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +15 -2
  503. package/templates/supplier-payments-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  504. package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  505. package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +23 -0
  506. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +1 -1
  507. package/templates/supplier-payments-agent/packages/agent-core/test/language.test.ts +40 -0
  508. package/templates/supplier-payments-agent/packages/agent-core/test/locale.test.ts +137 -0
  509. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  510. package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +2 -2
  511. package/templates/supplier-payments-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  512. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  513. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +49 -0
  514. package/templates/supplier-payments-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  515. package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +40 -1
  516. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +31 -4
  517. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  518. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  519. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  520. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  521. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  522. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  523. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  524. package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +30 -4
  525. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  526. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  527. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  528. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  529. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  530. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  531. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  532. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  533. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  534. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  535. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  536. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  537. package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  538. package/templates/supplier-payments-agent/packages/agent-runtime/src/env.ts +64 -0
  539. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +2 -0
  540. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +81 -10
  541. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +34 -12
  542. package/templates/supplier-payments-agent/packages/agent-runtime/src/outcome.ts +118 -0
  543. package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +7 -7
  544. package/templates/supplier-payments-agent/packages/agent-runtime/src/runs.ts +51 -0
  545. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  546. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +75 -5
  547. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +71 -33
  548. package/templates/supplier-payments-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  549. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  550. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  551. package/templates/supplier-payments-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  552. package/templates/supplier-payments-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  553. package/templates/supplier-payments-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  554. package/templates/supplier-payments-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  555. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  556. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  557. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  558. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import { ApiClient, type ApiOperation, type ApiSuccess } from "@codespar/sdk";
16
16
  import type { ApiFailure } from "./client.js";
17
+ import { ISSUER_ERROR_STATUSES, type ChargeView } from "./charge-rail.js";
17
18
  import { createCodeSparClient, describeApiError } from "./client.js";
18
19
 
19
20
  /** What the payer route answers, as the SDK's generated OpenAPI types it. */
@@ -41,3 +42,38 @@ export async function paySandboxCharge(target: ApiClient | SandboxPayerTarget, c
41
42
  return { ok: false, failure: describeApiError(err) };
42
43
  }
43
44
  }
45
+
46
+ /** Why the payer did not call the pay route: there was nothing a payer could have paid. */
47
+ export type PayerRefusal = { code: "no_payable_instrument" | "charge_issuer_error"; message: string };
48
+
49
+ export type GuardedPayResult = SandboxPayResult | { ok: false; refused: PayerRefusal };
50
+
51
+ /**
52
+ * The sandbox payer as a PAYER: it reads the charge first and pays only an
53
+ * instrument a person could have paid, a Pix or a boleto line the read calls
54
+ * `payable`. A charge the issuer ended in error (`ERROR`) is refused as
55
+ * `charge_issuer_error`, anything else unpayable as `no_payable_instrument`,
56
+ * and in both cases the pay route is never called.
57
+ *
58
+ * The route itself settles whatever it is handed: a charge still
59
+ * `PROCESSING`, and on staging on 2026-09-27 a charge the issuer ended in
60
+ * `ERROR`, after which the read answers `CONFIRMED` (ent#1816,
61
+ * OPEN_QUESTIONS §63). A payer that trusted it turned an issuance that failed
62
+ * into a "settled" order no customer could have paid. No live payer can pay a
63
+ * charge with no instrument, so neither does this one.
64
+ */
65
+ export async function payIfPayable(api: ApiClient, chargeRef: string, amountMinor?: number): Promise<GuardedPayResult> {
66
+ let view: ChargeView;
67
+ try {
68
+ view = await api.get("/v1/charges/{chargeId}", { path: { chargeId: chargeRef } });
69
+ } catch (err) {
70
+ return { ok: false, failure: describeApiError(err) };
71
+ }
72
+ if (ISSUER_ERROR_STATUSES.includes(view.status)) {
73
+ return { ok: false, refused: { code: "charge_issuer_error", message: `the issuer ended charge ${chargeRef}'s registration in ${view.status}; there is no instrument to pay, so the pay route was not called` } };
74
+ }
75
+ if (!view.payable) {
76
+ return { ok: false, refused: { code: "no_payable_instrument", message: `charge ${chargeRef} has no payable instrument (status ${view.status}, local ${view.local_status}); the pay route was not called` } };
77
+ }
78
+ return paySandboxCharge(api, chargeRef, amountMinor);
79
+ }
@@ -178,6 +178,8 @@ export function copyDisagreesWithRead(copy: Record<string, unknown>, read: Recor
178
178
  // Written onto the copy since the rail reads them through the SDK's types (0.16.10); a copy from before carries neither, and is not faulted for it.
179
179
  if ("chain_version" in copy) expected.push(["chain_version", copy["chain_version"], read["chain_version"]]);
180
180
  if ("approval" in copy) expected.push(["approval", canonicalJson(copy["approval"] ?? null), canonicalJson(read["approval"] ?? null)]);
181
+ // Written onto the copy since every spend carries the actor (§2); the read calls it `actor`, the copy `sealed_actor` beside its own stamp.
182
+ if ("sealed_actor" in copy) expected.push(["sealed_actor", canonicalJson(copy["sealed_actor"] ?? null), canonicalJson(read["actor"] ?? null)]);
181
183
  return expected.filter(([, a, b]) => a !== b).map(([name]) => name);
182
184
  }
183
185
 
@@ -154,22 +154,32 @@ export const TemplateRegistrySchema = z
154
154
  })
155
155
  .strict()
156
156
  .superRefine((registry, ctx) => {
157
+ // Meta approves a template per (name, language): the same name in two languages is two templates, the same pair twice is one declared twice.
157
158
  const seen = new Set<string>();
158
159
  const replyIds = new Set<string>();
160
+ const replyOwner = new Map<string, string>();
159
161
  for (const [i, template] of registry.templates.entries()) {
160
- if (seen.has(template.name)) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["templates", i, "name"], message: `${template.name} is declared twice` });
161
- seen.add(template.name);
162
- // A tap is resolved by its id alone, so one id means one intent across the whole registry.
162
+ const pair = `${template.name}/${template.language}`;
163
+ if (seen.has(pair)) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["templates", i, "name"], message: `${template.name} is declared twice in ${template.language}` });
164
+ seen.add(pair);
165
+ // A tap is resolved by its id in the conversation's language, so one id means one intent per language, and one template across languages.
163
166
  for (const [j, button] of (template.buttons ?? []).entries()) {
164
- if (replyIds.has(button.id)) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["templates", i, "buttons", j, "id"], message: `reply id ${button.id} is declared twice` });
165
- replyIds.add(button.id);
167
+ if (replyIds.has(`${button.id}/${template.language}`)) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["templates", i, "buttons", j, "id"], message: `reply id ${button.id} is declared twice in ${template.language}` });
168
+ replyIds.add(`${button.id}/${template.language}`);
169
+ const owner = replyOwner.get(button.id);
170
+ if (owner !== undefined && owner !== template.name) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["templates", i, "buttons", j, "id"], message: `reply id ${button.id} is offered by ${owner} and by ${template.name}` });
171
+ replyOwner.set(button.id, template.name);
166
172
  }
167
173
  }
168
174
  });
169
175
 
170
- /** Every quick reply the registry declares, by id: the only taps that can become a turn. */
171
- export function declaredReplies(templates: readonly WhatsAppTemplate[]): Map<string, QuickReply> {
172
- return new Map(templates.flatMap((t) => t.buttons ?? []).map((b) => [b.id, b]));
176
+ /**
177
+ * Every quick reply the registry declares, by id: the only taps that can
178
+ * become a turn. With a `language`, only the copies declared in it: an English
179
+ * conversation hands the model the English intent of the button it tapped.
180
+ */
181
+ export function declaredReplies(templates: readonly WhatsAppTemplate[], language?: string): Map<string, QuickReply> {
182
+ return new Map(templates.filter((t) => language === undefined || t.language === language).flatMap((t) => t.buttons ?? []).map((b) => [b.id, b]));
173
183
  }
174
184
 
175
185
  export type TemplateRegistry = z.infer<typeof TemplateRegistrySchema>;
@@ -14,6 +14,7 @@ import { loadManifest, ManifestSchema, type LoadedManifest } from "./manifest.js
14
14
  import { MandateSchema } from "./mandate.js";
15
15
  import { ToolsFileSchema } from "./tools.js";
16
16
  import { canonicalJson } from "./hash.js";
17
+ import { LOCALES, WHATSAPP_LANGUAGE } from "./locale.js";
17
18
  import { PUBLISHED_EVENTS, isPublishedEvent } from "./events.js";
18
19
 
19
20
  export interface CheckFinding {
@@ -145,9 +146,30 @@ export function checkAgent(agentDir: string): CheckReport {
145
146
  if (manifest.channels.includes("whatsapp")) {
146
147
  if (!existsSync(registryPath)) error("channels_templates_missing", `agent.yaml declares the whatsapp channel and channels/whatsapp/${TEMPLATE_REGISTRY_FILE} does not exist`);
147
148
  else if (registry) {
148
- const fallbacks = registry.templates.filter((t) => t.fallback);
149
- if (fallbacks.length !== 1) error("channels_templates_fallback", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE} declares ${fallbacks.length} fallback template(s); it must declare exactly one, for an outcome the agent has no template for`);
150
- else if (templateArity(fallbacks[0]!.body) !== 0) error("channels_templates_fallback", `the fallback template ${fallbacks[0]!.name} takes variables; it is sent when nothing specific can be said, so it takes none`);
149
+ const names = [...new Set(registry.templates.filter((t) => t.fallback).map((t) => t.name))];
150
+ if (names.length !== 1) error("channels_templates_fallback", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE} declares ${names.length} fallback template(s); it must declare exactly one, for an outcome the agent has no template for`);
151
+ for (const fallback of registry.templates.filter((t) => t.fallback)) {
152
+ if (templateArity(fallback.body) !== 0) error("channels_templates_fallback", `the fallback template ${fallback.name} (${fallback.language}) takes variables; it is sent when nothing specific can be said, so it takes none`);
153
+ }
154
+ }
155
+ }
156
+ // A conversation speaks the language of its locale, and either locale can be
157
+ // chosen per run (`--locale`), so every template exists in the language of
158
+ // every locale, with the same buttons and the same variables. A template
159
+ // missing in one language is an outcome that locale cannot tell once the
160
+ // 24-hour window shuts.
161
+ if (registry) {
162
+ const languages = LOCALES.map((l) => WHATSAPP_LANGUAGE[l]);
163
+ for (const template of registry.templates) {
164
+ if (!languages.includes(template.language)) error("channels_templates_locale", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE}: ${template.name} is declared in ${template.language}, which no locale sends; the locales send ${languages.join(", ")}`);
165
+ }
166
+ for (const name of [...new Set(registry.templates.map((t) => t.name))]) {
167
+ const copies = registry.templates.filter((t) => t.name === name);
168
+ for (const language of languages) {
169
+ if (!copies.some((t) => t.language === language)) error("channels_templates_locale", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE}: ${name} has no ${language} copy; a conversation in that locale could not send it`);
170
+ }
171
+ const shape = (t: (typeof copies)[number]) => JSON.stringify({ arity: templateArity(t.body), buttons: (t.buttons ?? []).map((b) => b.id), fallback: t.fallback ?? false });
172
+ if (new Set(copies.map(shape)).size > 1) error("channels_templates_locale", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE}: the copies of ${name} differ in variables, buttons or fallback across languages; a translation says the same thing`);
151
173
  }
152
174
  }
153
175
  if (existsSync(registryPath)) {
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { checkApprovalArtifact, createApprovalArtifact, type ApprovalSigner } from "./approval.js";
15
15
  import { maskPayee, type ProofBundle } from "./bundle.js";
16
- import { evaluateEscalation, type Escalation } from "./escalate.js";
16
+ import { evaluateEscalation, localDate, type Escalation } from "./escalate.js";
17
17
  import { CHARGE_CANCELLED, CHARGE_EXPIRED, CHARGE_PAID, PAYMENT_FAILED, PAYMENT_SUCCEEDED, type PublishedEvent } from "./events.js";
18
18
  import type { Guardrails } from "./guardrails.js";
19
19
  import { batchAttemptId, itemsHash, sha256Hex } from "./hash.js";
@@ -21,10 +21,10 @@ import { newId } from "./ids.js";
21
21
  import { mandateExpired, payeeAllowed, resolveBeneficiary, windowCap, windowStart, type Mandate } from "./mandate.js";
22
22
  import type { Manifest } from "./manifest.js";
23
23
  import { checkQuote, quoteFromApproval } from "./quote.js";
24
- import { spendApprovalOf, type PaymentRail, type RailOutcome, type RailPayment, type SealedSpendApproval, type SpendApproval } from "./rail.js";
24
+ import { sameWireActor, spendApprovalOf, wireActorOf, type PaymentRail, type RailOutcome, type RailPayment, type SealedSpendApproval, type SpendApproval } from "./rail.js";
25
25
  import { sameApprovalHash } from "./receipt-chain.js";
26
26
  import type { MandateStatusReport, MandateStatusSource } from "./revocation.js";
27
- import { isTerminal, transition, type Execution, type ExecutionState } from "./state-machine.js";
27
+ import { isTerminal, transition, type Execution, type ExecutionState, type RailAnswer } from "./state-machine.js";
28
28
  import type { StateStore } from "./state/store.js";
29
29
  import type { Actor, ApprovalArtifact, ApprovalMode, ExecutionBatch, ExecutionComposition, ExecutionItem, ExecutionReason, ItemOutcome } from "./types.js";
30
30
 
@@ -131,6 +131,16 @@ export class ExecutionEngine {
131
131
  return this.deps.mandate;
132
132
  }
133
133
 
134
+ /**
135
+ * The day it is for the person, in the guardrails' timezone, at this
136
+ * engine's clock (so `--now` pins it too). A tool that shows a due date
137
+ * shows this next to it: the model has no calendar of its own, and without
138
+ * it a bill due next week reads as one that already fell due.
139
+ */
140
+ today(): string {
141
+ return localDate(this.clock(), this.deps.guardrails.timezone);
142
+ }
143
+
134
144
  // ---- the model's only entry point -------------------------------------
135
145
 
136
146
  async draft(proposal: Proposal): Promise<DraftResult> {
@@ -420,6 +430,7 @@ export class ExecutionEngine {
420
430
  private async dispatch(execution: Execution<"executing">, payments: RailPayment[]): Promise<Execution> {
421
431
  const outcomes: ItemOutcome[] = [...execution.outcomes];
422
432
  const unknown: string[] = [];
433
+ const unknownAnswers: RailAnswer[] = [];
423
434
  const sealMismatches: string[] = [];
424
435
  this.deps.store.updateOutbox(execution.idempotency_key, "sent", undefined, this.clock().toISOString());
425
436
 
@@ -453,10 +464,11 @@ export class ExecutionEngine {
453
464
  // sent: an unknown answer about THIS payee says nothing about the next
454
465
  // one, and the execution stays open until reconciliation settles it.
455
466
  unknown.push(`attempt ${payment.attempt_id}: ${outcome.code} — outcome unknown, kept for reconciliation`);
467
+ unknownAnswers.push({ attempt_id: payment.attempt_id, code: outcome.code, message: outcome.message });
456
468
  continue;
457
469
  }
458
470
  if (outcome.status === "failed") {
459
- outcomes.push({ index, attempt_id: payment.attempt_id, status: "failed", code: outcome.code, error: `${outcome.code}: ${outcome.message}`, ...(outcome.held ? { held: outcome.held } : {}) });
471
+ outcomes.push({ index, attempt_id: payment.attempt_id, status: "failed", code: outcome.code, message: outcome.message, error: `${outcome.code}: ${outcome.message}`, ...(outcome.held ? { held: outcome.held } : {}) });
460
472
  continue;
461
473
  }
462
474
  if (outcome.status === "accepted") {
@@ -469,7 +481,12 @@ export class ExecutionEngine {
469
481
  const mismatch = await this.ingestSettlement(execution, index, payment, outcome.receipt_id, PAYMENT_SUCCEEDED);
470
482
  if (mismatch) sealMismatches.push(mismatch);
471
483
  }
472
- const closed = this.close({ ...execution, outcomes, ...(Object.keys(generations).length > 0 ? { attempt_generations: generations } : {}) }, payments.length, unknown.join("; ") || undefined);
484
+ const answers = [...(execution.uncertain_answers ?? []).filter((a) => !unknownAnswers.some((u) => u.attempt_id === a.attempt_id)), ...unknownAnswers];
485
+ const closed = this.close(
486
+ { ...execution, outcomes, ...(Object.keys(generations).length > 0 ? { attempt_generations: generations } : {}), ...(answers.length > 0 ? { uncertain_answers: answers } : {}) },
487
+ payments.length,
488
+ unknown.join("; ") || undefined,
489
+ );
473
490
  if (sealMismatches.length > 0) throw new ReceiptSealMismatchError(execution.id, sealMismatches);
474
491
  return closed;
475
492
  }
@@ -494,13 +511,12 @@ export class ExecutionEngine {
494
511
  if (execution.outcomes.length < attempts) {
495
512
  return this.leaveUnresolved(updated, unknownDetail ?? `${execution.outcomes.length} of ${attempts} attempt(s) have an outcome`);
496
513
  }
497
- // An ambiguous receivable outranks any other failure: it is the one outcome that must be reconciled rather than issued again.
498
- const failed = execution.outcomes.find((o) => o.status === "failed" && o.code === "charge_reference_ambiguous") ?? execution.outcomes.find((o) => o.status === "failed");
514
+ const failed = decisiveFailure(execution.outcomes);
499
515
  if (failed) {
500
516
  this.deps.store.updateOutbox(execution.idempotency_key, "failed", execution.outcomes, at);
501
517
  // `org_paused` is the API refusing the spend itself: the kill switch was pressed after the gate read the status. Nothing moved.
502
518
  const reason: ExecutionReason =
503
- failed.code === "charge_expired" || failed.code === "charge_cancelled" || failed.code === "org_paused" || failed.code === "charge_reference_ambiguous" ? failed.code : "rail_failed";
519
+ failed.code === "charge_expired" || failed.code === "charge_cancelled" || failed.code === "charge_issuer_error" || failed.code === "org_paused" || failed.code === "charge_reference_ambiguous" ? failed.code : "rail_failed";
504
520
  return this.persist(transition(updated, "failed", { at, actor: this.agentActor, reason, detail: failed.error ?? "rail refused" }));
505
521
  }
506
522
  if (execution.outcomes.filter((o) => o.status === "settled").length === attempts) {
@@ -584,6 +600,11 @@ export class ExecutionEngine {
584
600
  this.record("receipt.seal_mismatch", executionId, { receipt_id: receiptId, attempt_id: payment.attempt_id, sealed_approval: receipt.approval, sent_approval: payment.approval });
585
601
  mismatches.push(`receipt ${receiptId} seals approval ${receipt.approval ? receipt.approval.items_hash : "none"}; attempt ${payment.attempt_id} sent ${payment.approval.items_hash}`);
586
602
  }
603
+ // §2: the actor the spend declared, as the API recorded it. A different one, or none, is an event and not a seal mismatch:
604
+ // the money and its link to the approval are what the receipt proves, and who triggered it is what it RECORDS.
605
+ if (receipt.sealed_actor !== undefined && !sameWireActor(receipt.sealed_actor, wireActorOf(payment.actor))) {
606
+ this.record("receipt.actor_mismatch", executionId, { receipt_id: receiptId, attempt_id: payment.attempt_id, sealed_actor: receipt.sealed_actor, sent_actor: wireActorOf(payment.actor) });
607
+ }
587
608
  return mismatches.length > 0 ? mismatches.join("; ") : undefined;
588
609
  }
589
610
 
@@ -671,7 +692,12 @@ export class ExecutionEngine {
671
692
  replace({ index, attempt_id: payment.attempt_id, status: "failed", code: seen.code, error: `${seen.code}: ${seen.message}`, ...(seen.held ? { held: seen.held } : {}) });
672
693
  continue;
673
694
  }
674
- replace({ index, attempt_id: payment.attempt_id, status: "settled", transaction_id: seen.transaction_id, ...(seen.receipt_id ? { receipt_id: seen.receipt_id } : {}), ...(seen.replayed ? { replayed: true as const } : {}) });
695
+ // No `replayed` here, whatever the rail said. A lookup IS a second
696
+ // presentation of an attempt this execution already sent, so on the API
697
+ // every settled lookup answers `idempotent_replay`, including the one
698
+ // whose payment was this execution's own. The mark would say "someone
699
+ // else paid" about a payment nobody can attribute from here.
700
+ replace({ index, attempt_id: payment.attempt_id, status: "settled", transaction_id: seen.transaction_id, ...(seen.receipt_id ? { receipt_id: seen.receipt_id } : {}) });
675
701
  const mismatch = await this.ingestSettlement(execution, index, payment, seen.receipt_id, prior ? CHARGE_PAID : PAYMENT_SUCCEEDED);
676
702
  if (mismatch) sealMismatches.push(mismatch);
677
703
  }
@@ -1050,6 +1076,61 @@ function railAnswer(outcome: RailOutcome): Record<string, unknown> {
1050
1076
  }
1051
1077
  }
1052
1078
 
1079
+ /** The failed outcome an execution closes on. An ambiguous receivable outranks any other failure: it is the one outcome that must be reconciled rather than issued again. */
1080
+ function decisiveFailure(outcomes: readonly ItemOutcome[]): ItemOutcome | undefined {
1081
+ return outcomes.find((o) => o.status === "failed" && o.code === "charge_reference_ambiguous") ?? outcomes.find((o) => o.status === "failed");
1082
+ }
1083
+
1084
+ /** What the rail answered, verbatim: the code and message the API sent, not only `rail_failed` or `rail_uncertain` (#50). */
1085
+ export interface RailError {
1086
+ /** `failed`: the answer the execution closed on. `uncertain`: an answer that left an attempt's outcome unknown. */
1087
+ outcome: "failed" | "uncertain";
1088
+ attempt_id: string;
1089
+ code: string;
1090
+ message: string | null;
1091
+ }
1092
+
1093
+ /**
1094
+ * The rail's own answer behind a failure, for `--json` and the terminal. The
1095
+ * reason (`rail_failed`) says WHICH gate closed the execution; this says what
1096
+ * the API said, so a first failure explains itself — `insufficient_funds` on
1097
+ * an unfunded test wallet reads as that, not as a generic refusal. `null` when
1098
+ * nothing failed and nothing was left unknown. A 5xx is not a failure — the
1099
+ * money may have moved — so `provider_error` comes back as `uncertain`, with
1100
+ * the API's words, while the execution stays open for reconciliation. An
1101
+ * outcome stored before the message was kept carries only `code: message` in
1102
+ * `error`, and that is what is returned.
1103
+ */
1104
+ export function railErrorOf(execution: Pick<Execution, "outcomes" | "uncertain_answers">): RailError | null {
1105
+ const failed = decisiveFailure(execution.outcomes);
1106
+ if (failed?.code !== undefined) return { outcome: "failed", attempt_id: failed.attempt_id, code: failed.code, message: failed.message ?? failed.error ?? null };
1107
+ const pending = (execution.uncertain_answers ?? []).find((a) => !execution.outcomes.some((o) => o.attempt_id === a.attempt_id));
1108
+ return pending ? { outcome: "uncertain", attempt_id: pending.attempt_id, code: pending.code, message: pending.message } : null;
1109
+ }
1110
+
1111
+ /**
1112
+ * Settled, and every settled attempt was answered from the rail's record of
1113
+ * an earlier presentation this execution never made: the money moved, and
1114
+ * this execution did not move it. `dispatch` is the only writer of the mark,
1115
+ * so a report can say "paid by this run" of everything else it calls settled.
1116
+ */
1117
+ export function isReplayedSettlement(execution: Pick<Execution, "state" | "outcomes">): boolean {
1118
+ const settled = execution.outcomes.filter((o) => o.status === "settled");
1119
+ return execution.state === "settled" && settled.length > 0 && settled.every((o) => o.replayed === true);
1120
+ }
1121
+
1122
+ /**
1123
+ * A reason, or a rail code, that closes a payment without anything having
1124
+ * failed: nobody paid the charge in time, the charge was withdrawn, or the
1125
+ * organization pressed the kill switch. It reads with `denied` and `expired`,
1126
+ * not with a rail failure, in every count and report.
1127
+ */
1128
+ const DECLINED_REASONS: readonly string[] = ["charge_expired", "charge_cancelled", "org_paused"];
1129
+
1130
+ export function isDeclinedReason(reason: string | null | undefined): boolean {
1131
+ return typeof reason === "string" && DECLINED_REASONS.includes(reason);
1132
+ }
1133
+
1053
1134
  /** The approval link a receipt sealed is the one a spend sent: the same hashes, in either spelling of the `sha256:` prefix. */
1054
1135
  function sealsApproval(sealed: SealedSpendApproval | null, sent: SpendApproval): boolean {
1055
1136
  return sealed !== null && sameApprovalHash(sealed.items_hash, sent.items_hash) && sameApprovalHash(sealed.batch_hash, sent.batch_hash ?? null);
@@ -71,6 +71,16 @@ export function localClock(now: Date, timezone: string): string {
71
71
  return `${hour}:${minute}`;
72
72
  }
73
73
 
74
+ /** The calendar day `now` falls on in `timezone`, as `YYYY-MM-DD`. */
75
+ export function localDate(now: Date, timezone: string): string {
76
+ return new Intl.DateTimeFormat("en-CA", { timeZone: timezone, year: "numeric", month: "2-digit", day: "2-digit" }).format(now);
77
+ }
78
+
79
+ /** Whole days from `today` to `date` (both `YYYY-MM-DD`): 0 is today, negative is already past. */
80
+ export function daysUntil(today: string, date: string): number {
81
+ return Math.round((Date.parse(`${date}T00:00:00Z`) - Date.parse(`${today}T00:00:00Z`)) / 86_400_000);
82
+ }
83
+
74
84
  /** `"22:00-07:00"` is the CLOSED window: inside it, the trigger fires. Crosses midnight when start > end. */
75
85
  export function isOutsideHours(window: string, now: Date, timezone: string): boolean {
76
86
  const [start, end] = window.split("-") as [string, string];
@@ -19,6 +19,9 @@ export * from "./tools.js";
19
19
  export * from "./bundle.js";
20
20
  export * from "./engine.js";
21
21
  export * from "./agent.js";
22
+ export * from "./language.js";
23
+ export * from "./locale.js";
24
+ export * from "./strings.js";
22
25
  export * from "./check.js";
23
26
  export * from "./events.js";
24
27
  export * from "./state/store.js";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The language a person wrote in, of the two the kits speak, and the sentence
3
+ * that tells the model to answer in it.
4
+ *
5
+ * A rule in the system prompt ("answer in the language of the person's latest
6
+ * message") was not enough (docs/OPEN_QUESTIONS.md §64): on the Messages API a
7
+ * tool result is a user-role message, so on any turn that used a tool the
8
+ * latest message the model read was Portuguese data, and five English requests
9
+ * out of five were answered in Portuguese. The loop therefore reads the
10
+ * language from what the person TYPED, deterministically, and states it for
11
+ * the whole turn.
12
+ *
13
+ * Function words, not a classifier: payee names, bill descriptions and
14
+ * amounts are the same in both languages and count for neither.
15
+ */
16
+
17
+ export type ReplyLanguage = "pt-BR" | "en";
18
+
19
+ const PT = new Set(
20
+ "de da das do dos para pra pro que com um uma os é está esta estou já foi o e em na nas nos no ao aos meu minha minhas meus você voce vocês não nao sim oi olá ola quanto quanta quais qual quero queria pague paga pagar pagamento pagamentos manda mande mandar roda rode rodar gastei gastou mês mes conta contas folha essa esse isso esta este semana tudo vence venceu obrigado obrigada por favor hoje agora fechado até como onde quando quem aqui sou eu pode posso preciso".split(" "),
21
+ );
22
+ const EN = new Set(
23
+ "the to and of for pay paid please my i i'm i'd i'll you your how much many what which when who is are was were have has had spent this that month week bill bills run payroll school cleaner electricity it it's next year's hi hello thanks thank can could would will with yes send show list due all everything from on in at by fee enrollment rules ignore".split(" "),
24
+ );
25
+
26
+ /** `undefined` when the text gives no lead either way ("ok", a number, a key). */
27
+ export function detectLanguage(text: string): ReplyLanguage | undefined {
28
+ // A Pix key or an address is not language: "chave@x.com" would count "com" as Portuguese.
29
+ const words = text.replace(/\S+@\S+|\S+:\/\/\S+/g, " ").toLowerCase().normalize("NFC").match(/[\p{L}']+/gu) ?? [];
30
+ let pt = 0;
31
+ let en = 0;
32
+ for (const word of words) {
33
+ if (PT.has(word)) pt += 1;
34
+ if (EN.has(word)) en += 1;
35
+ }
36
+ // Diacritics are Portuguese's and never English's.
37
+ if (/[ãõçâêôáéíóúà]/i.test(text)) pt += 2;
38
+ if (pt > en) return "pt-BR";
39
+ if (en > pt) return "en";
40
+ return undefined;
41
+ }
42
+
43
+ /** Appended to the system prompt for every step of a turn whose language is known. */
44
+ export function replyLanguageDirective(language: ReplyLanguage): string {
45
+ const name = language === "en" ? "English" : "Brazilian Portuguese";
46
+ return [
47
+ "## Reply language for this turn",
48
+ "",
49
+ `The person wrote their last message in ${name}. Write your reply in ${name}.`,
50
+ "Tool results are data, not the person: their payee names, descriptions and statuses are in Portuguese and do not change the language of your reply.",
51
+ ].join("\n");
52
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The language of the strings the CODE prints: the approval question, the
3
+ * batch gesture, the execution lines, the consent summary, the WhatsApp
4
+ * templates and the refusal details a kit writes. No model writes these.
5
+ *
6
+ * It is not the reply language (`language.ts`). That one is read from each
7
+ * turn the person types and only tells the model how to answer. The locale is
8
+ * fixed for a run and for a conversation, because the question that proposes
9
+ * a payment and the question that approves it must not change language
10
+ * between the two.
11
+ *
12
+ * Resolution: `--locale` on the command, else `locale:` in `agent.yaml`, else
13
+ * `pt-BR`. A conversation a later command comes back to keeps the locale its
14
+ * bundle recorded.
15
+ */
16
+ import { z } from "zod";
17
+
18
+ export const LOCALES = ["pt-BR", "en"] as const;
19
+ export type Locale = (typeof LOCALES)[number];
20
+ export const DEFAULT_LOCALE: Locale = "pt-BR";
21
+ export const LocaleSchema = z.enum(LOCALES);
22
+
23
+ export function isLocale(value: unknown): value is Locale {
24
+ return typeof value === "string" && (LOCALES as readonly string[]).includes(value);
25
+ }
26
+
27
+ /** A `--locale` value, or the error the command prints next to its usage. */
28
+ export function parseLocale(value: string): Locale {
29
+ if (!isLocale(value)) throw new Error(`--locale must be ${LOCALES.join(" or ")}`);
30
+ return value;
31
+ }
32
+
33
+ export function resolveLocale(flag: Locale | undefined, manifest: { locale?: Locale | undefined }): Locale {
34
+ return flag ?? manifest.locale ?? DEFAULT_LOCALE;
35
+ }
36
+
37
+ /**
38
+ * The language code Meta approves a template in. Meta approves a template per
39
+ * (name, language) pair, so an English conversation sends the `en_US` copy of
40
+ * a template and never the `pt_BR` one.
41
+ */
42
+ export const WHATSAPP_LANGUAGE: { readonly [L in Locale]: string } = { "pt-BR": "pt_BR", en: "en_US" };
43
+
44
+ /** One entry per locale. A table missing a locale does not type-check; a key missing from one entry fails `npm run check`. */
45
+ export type LocaleTable<T> = { readonly [L in Locale]: T };
46
+
47
+ /**
48
+ * What differs between the entries of a string table: a key one locale has and
49
+ * another lacks, a string where the other has a function, or a function that
50
+ * takes a different number of arguments. Empty means every key exists in every
51
+ * locale with the same shape. The check reads this at runtime because a kit is
52
+ * TypeScript that `npm run check` does not compile.
53
+ */
54
+ export function tableGaps(name: string, table: Partial<Record<Locale, object>>): string[] {
55
+ const gaps: string[] = [];
56
+ const entry = (l: Locale) => table[l] as Record<string, unknown> | undefined;
57
+ for (const locale of LOCALES) if (!entry(locale)) gaps.push(`${name} has no ${locale} entry`);
58
+ const keys = new Set(LOCALES.flatMap((l) => Object.keys(entry(l) ?? {})));
59
+ for (const key of [...keys].sort()) {
60
+ const shapes = LOCALES.map((l) => {
61
+ const value = entry(l)?.[key];
62
+ if (value === undefined) return "missing";
63
+ if (typeof value === "function") return `function/${value.length}`;
64
+ return typeof value === "string" && value.length > 0 ? "string" : `empty ${typeof value}`;
65
+ });
66
+ for (const [i, shape] of shapes.entries()) {
67
+ if (shape === "missing" || shape.startsWith("empty")) gaps.push(`${name}.${key} is ${shape} in ${LOCALES[i]}`);
68
+ }
69
+ if (new Set(shapes.filter((s) => s !== "missing")).size > 1) gaps.push(`${name}.${key} differs in shape across locales: ${LOCALES.map((l, i) => `${l} ${shapes[i]}`).join(", ")}`);
70
+ }
71
+ return gaps;
72
+ }
73
+
74
+ /** `185000` -> `R$ 1.850,00` in pt-BR, `R$1,850.00` in English: the two forms the prompts give the model since #62. */
75
+ export function formatBRL(minor: number, locale: Locale): string {
76
+ const sign = minor < 0 ? "-" : "";
77
+ const abs = Math.abs(minor);
78
+ const cents = String(abs % 100).padStart(2, "0");
79
+ if (locale === "en") return `${sign}R$${Math.floor(abs / 100).toLocaleString("en-US")}.${cents}`;
80
+ return `${sign}R$ ${Math.floor(abs / 100).toLocaleString("pt-BR")},${cents}`;
81
+ }
82
+
83
+ /** `2026-09-30` -> `30/09/2026` in pt-BR; English keeps the ISO date, which reads the same on either side of the Atlantic. */
84
+ export function formatDay(iso: string, locale: Locale): string {
85
+ if (locale === "en") return iso;
86
+ const [y, m, d] = iso.split("-");
87
+ return `${d}/${m}/${y}`;
88
+ }
@@ -8,6 +8,7 @@ import { readFileSync } from "node:fs";
8
8
  import { dirname, resolve } from "node:path";
9
9
  import { parse as parseYaml } from "yaml";
10
10
  import { z } from "zod";
11
+ import { LocaleSchema } from "./locale.js";
11
12
 
12
13
  const PINNED_PACKAGE = /^@codespar\/(mcp|cli)@\d+\.\d+\.\d+$/;
13
14
  const HOURS_WINDOW = /^([01]\d|2[0-3]):[0-5]\d-([01]\d|2[0-3]):[0-5]\d$/;
@@ -34,12 +35,14 @@ export const ManifestSchema = z
34
35
  default_approval: z.enum(["human", "mandate"]),
35
36
  escalate_above: EscalateAboveSchema.optional(),
36
37
  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
+ cli: z.string().regex(PINNED_PACKAGE, "cli must pin an exact version, e.g. @codespar/cli@0.18.1"),
38
39
  tools: z.string(),
39
40
  guardrails: z.string(),
40
41
  mandate_schema: z.string(),
41
42
  events: z.array(z.string().regex(/^commerce\.[a-z_.]+$/)),
42
43
  channels: z.array(z.enum(["terminal", "whatsapp"])).nonempty(),
44
+ /** The language of the strings the code prints (not of the model's replies). Optional: absent is `pt-BR`, which is what every agent printed before the field existed. */
45
+ locale: LocaleSchema.optional(),
43
46
  maturity: z.record(z.string(), MaturitySchema),
44
47
  scenarios: z.string(),
45
48
  evals: z.string(),
@@ -75,7 +75,7 @@ export interface RailPayment {
75
75
  * its shape and never its content. A charge rail ignores it.
76
76
  */
77
77
  approval?: SpendApproval;
78
- /** Section 4.5: carried on every call. The API has no wire field for it yet; see OPEN_QUESTIONS. */
78
+ /** Section 4.5: carried on every call, on the wire as `PaymentActor` (`wireActorOf`) since @codespar/sdk 0.16.10; see OPEN_QUESTIONS §2. */
79
79
  actor: Actor;
80
80
  }
81
81
 
@@ -167,9 +167,37 @@ export interface RailReceipt {
167
167
  receipt_sig_kid: string | null;
168
168
  /** Section 4.5: the kit stamps the actor onto the local copy of every receipt. */
169
169
  actor: Actor;
170
+ /**
171
+ * The actor the API RECORDED for the spend and read back (`PaymentActor`,
172
+ * @codespar/sdk 0.16.10): `null` when it recorded none — an API that did not
173
+ * take the field, or a spend that sent none. Absent when the rail cannot
174
+ * say: a charge, which records no actor.
175
+ */
176
+ sealed_actor?: WireActor | null;
170
177
  raw: unknown;
171
178
  }
172
179
 
180
+ /**
181
+ * Who triggered a spend, in the API's own shape (`PaymentActor`,
182
+ * @codespar/sdk 0.16.10): the agent by its identifier and the consumer it acts
183
+ * for, or the person by id and the channel they acted from. The kit's `Actor`
184
+ * names the agent under `agent`; the wire names it under `id`, and that is the
185
+ * only difference.
186
+ */
187
+ export type WireActor = { type: "agent"; id: string; on_behalf_of: string } | { type: "human"; id: string; channel?: string };
188
+
189
+ export function wireActorOf(actor: Actor): WireActor {
190
+ return actor.type === "agent" ? { type: "agent", id: actor.agent, on_behalf_of: actor.on_behalf_of } : { type: "human", id: actor.id, channel: actor.channel };
191
+ }
192
+
193
+ /** The same actor, field for field. A human's channel counts: the same person on WhatsApp and on a dashboard are two events. */
194
+ export function sameWireActor(a: WireActor | null, b: WireActor | null): boolean {
195
+ if (a === null || b === null) return a === b;
196
+ if (a.type === "agent" && b.type === "agent") return a.id === b.id && a.on_behalf_of === b.on_behalf_of;
197
+ if (a.type === "human" && b.type === "human") return a.id === b.id && (a.channel ?? null) === (b.channel ?? null);
198
+ return false;
199
+ }
200
+
173
201
  /** What a reconcile learns: a recorded outcome, "still running", or nothing. Never a new payment. */
174
202
  export type RailLookup = RailOutcome | { status: "in_flight" } | undefined;
175
203