@codespar/cli 0.18.1 → 0.21.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 (560) 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/commands/payables.js +220 -0
  5. package/dist/commands/payables.js.map +1 -0
  6. package/dist/index.js +77 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/surface.js +31 -13
  9. package/dist/surface.js.map +1 -1
  10. package/package.json +2 -2
  11. package/templates/bills-agent/README.md +2 -2
  12. package/templates/bills-agent/agents/bills-agent/.env.example +2 -2
  13. package/templates/bills-agent/agents/bills-agent/README.md +25 -18
  14. package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +13 -3
  15. package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -1
  16. package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  17. package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  18. package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  19. package/templates/bills-agent/agents/bills-agent/mandate.example.json +1 -1
  20. package/templates/bills-agent/agents/bills-agent/runbook.md +1 -1
  21. package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  22. package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  23. package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.transcript.jsonl +4 -4
  24. package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.transcript.jsonl +1 -1
  25. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.json +1 -1
  26. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.transcript.jsonl +4 -4
  27. package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  28. package/templates/bills-agent/agents/bills-agent/src/bills.ts +1 -1
  29. package/templates/bills-agent/agents/bills-agent/src/kit.ts +15 -28
  30. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +42 -15
  31. package/templates/bills-agent/agents/bills-agent/src/modules/pix-out.ts +21 -3
  32. package/templates/bills-agent/agents/bills-agent/src/strings.ts +68 -0
  33. package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +130 -2
  34. package/templates/bills-agent/agents/bills-agent/test/consent-money.test.ts +25 -0
  35. package/templates/bills-agent/agents/bills-agent/test/dates-and-approval.test.ts +98 -0
  36. package/templates/bills-agent/agents/bills-agent/test/eval-runs.test.ts +81 -0
  37. package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -2
  38. package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +1 -1
  39. package/templates/bills-agent/agents/bills-agent/test/locale.test.ts +161 -0
  40. package/templates/bills-agent/agents/bills-agent/test/mandate-state.test.ts +108 -0
  41. package/templates/bills-agent/agents/bills-agent/test/refused-before-draft.test.ts +81 -0
  42. package/templates/bills-agent/agents/bills-agent/test/replay.test.ts +76 -0
  43. package/templates/bills-agent/agents/bills-agent/test/reply-and-outcome.test.ts +84 -0
  44. package/templates/bills-agent/agents/bills-agent/test/reply-language.test.ts +95 -0
  45. package/templates/bills-agent/agents/bills-agent/test/rerun-and-missing-transcript.test.ts +120 -0
  46. package/templates/bills-agent/agents/bills-agent/test/rerun-world-events.test.ts +55 -0
  47. package/templates/bills-agent/agents/bills-agent/tools.json +1 -1
  48. package/templates/bills-agent/packages/agent-core/README.md +21 -2
  49. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  50. package/templates/bills-agent/packages/agent-core/src/agent.ts +33 -6
  51. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  52. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +11 -5
  53. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  54. package/templates/bills-agent/packages/agent-core/src/bundle.ts +2 -0
  55. package/templates/bills-agent/packages/agent-core/src/channels.ts +18 -8
  56. package/templates/bills-agent/packages/agent-core/src/check.ts +25 -3
  57. package/templates/bills-agent/packages/agent-core/src/engine.ts +90 -9
  58. package/templates/bills-agent/packages/agent-core/src/escalate.ts +10 -0
  59. package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
  60. package/templates/bills-agent/packages/agent-core/src/language.ts +52 -0
  61. package/templates/bills-agent/packages/agent-core/src/locale.ts +88 -0
  62. package/templates/bills-agent/packages/agent-core/src/manifest.ts +4 -1
  63. package/templates/bills-agent/packages/agent-core/src/rail.ts +29 -1
  64. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  65. package/templates/bills-agent/packages/agent-core/src/secrets.ts +53 -8
  66. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +14 -0
  67. package/templates/bills-agent/packages/agent-core/src/strings.ts +175 -0
  68. package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  69. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  70. package/templates/bills-agent/packages/agent-core/src/types.ts +15 -2
  71. package/templates/bills-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  72. package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  73. package/templates/bills-agent/packages/agent-core/test/engine.test.ts +23 -0
  74. package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
  75. package/templates/bills-agent/packages/agent-core/test/language.test.ts +40 -0
  76. package/templates/bills-agent/packages/agent-core/test/locale.test.ts +137 -0
  77. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  78. package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
  79. package/templates/bills-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  80. package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  81. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +49 -0
  82. package/templates/bills-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  83. package/templates/bills-agent/packages/agent-core/test/secrets.test.ts +40 -1
  84. package/templates/bills-agent/packages/agent-runtime/README.md +31 -4
  85. package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  86. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  87. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  88. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  89. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  90. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  91. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  92. package/templates/bills-agent/packages/agent-runtime/src/cli.ts +30 -4
  93. package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  94. package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  95. package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  96. package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  97. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  98. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  99. package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  100. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  101. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  102. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  103. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  104. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  105. package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  106. package/templates/bills-agent/packages/agent-runtime/src/env.ts +64 -0
  107. package/templates/bills-agent/packages/agent-runtime/src/index.ts +2 -0
  108. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +81 -10
  109. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +34 -12
  110. package/templates/bills-agent/packages/agent-runtime/src/outcome.ts +118 -0
  111. package/templates/bills-agent/packages/agent-runtime/src/poll.ts +7 -7
  112. package/templates/bills-agent/packages/agent-runtime/src/runs.ts +51 -0
  113. package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  114. package/templates/bills-agent/packages/agent-runtime/src/setup.ts +75 -5
  115. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +71 -33
  116. package/templates/bills-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  117. package/templates/bills-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  118. package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  119. package/templates/bills-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  120. package/templates/bills-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  121. package/templates/bills-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  122. package/templates/bills-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  123. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  124. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  125. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  126. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  127. package/templates/checkout-agent/README.md +2 -2
  128. package/templates/checkout-agent/agents/checkout-agent/.env.example +6 -4
  129. package/templates/checkout-agent/agents/checkout-agent/README.md +16 -8
  130. package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +17 -7
  131. package/templates/checkout-agent/agents/checkout-agent/agent.yaml +4 -3
  132. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +2 -2
  133. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +48 -4
  134. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +1 -1
  135. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +1 -1
  136. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +1 -1
  137. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +1 -1
  138. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  139. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +1 -1
  140. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +1 -1
  141. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +1 -1
  142. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +1 -1
  143. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  144. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +1 -1
  145. package/templates/checkout-agent/agents/checkout-agent/package.json +1 -1
  146. package/templates/checkout-agent/agents/checkout-agent/runbook.md +4 -4
  147. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  148. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +2 -2
  149. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +2 -2
  150. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +2 -2
  151. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +1 -1
  152. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +2 -2
  153. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +1 -1
  154. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +1 -1
  155. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +2 -2
  156. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +1 -1
  157. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +3 -3
  158. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +1 -1
  159. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +2 -2
  160. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +1 -1
  161. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  162. package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +7 -7
  163. package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +47 -43
  164. package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +20 -12
  165. package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +4 -4
  166. package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +9 -6
  167. package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +44 -41
  168. package/templates/checkout-agent/agents/checkout-agent/src/strings.ts +179 -0
  169. package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +4 -1
  170. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +1 -1
  171. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +2 -2
  172. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +1 -1
  173. package/templates/checkout-agent/agents/checkout-agent/test/payable-instrument.test.ts +58 -0
  174. package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +2 -2
  175. package/templates/checkout-agent/agents/checkout-agent/test/rerun-unpaid.test.ts +47 -0
  176. package/templates/checkout-agent/agents/checkout-agent/test/scenario-reach-and-seconds.test.ts +55 -0
  177. package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +26 -10
  178. package/templates/checkout-agent/agents/checkout-agent/tools.json +1 -1
  179. package/templates/checkout-agent/packages/agent-core/README.md +21 -2
  180. package/templates/checkout-agent/packages/agent-core/package.json +1 -1
  181. package/templates/checkout-agent/packages/agent-core/src/agent.ts +33 -6
  182. package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  183. package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +11 -5
  184. package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  185. package/templates/checkout-agent/packages/agent-core/src/bundle.ts +2 -0
  186. package/templates/checkout-agent/packages/agent-core/src/channels.ts +18 -8
  187. package/templates/checkout-agent/packages/agent-core/src/check.ts +25 -3
  188. package/templates/checkout-agent/packages/agent-core/src/engine.ts +90 -9
  189. package/templates/checkout-agent/packages/agent-core/src/escalate.ts +10 -0
  190. package/templates/checkout-agent/packages/agent-core/src/index.ts +3 -0
  191. package/templates/checkout-agent/packages/agent-core/src/language.ts +52 -0
  192. package/templates/checkout-agent/packages/agent-core/src/locale.ts +88 -0
  193. package/templates/checkout-agent/packages/agent-core/src/manifest.ts +4 -1
  194. package/templates/checkout-agent/packages/agent-core/src/rail.ts +29 -1
  195. package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  196. package/templates/checkout-agent/packages/agent-core/src/secrets.ts +53 -8
  197. package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +14 -0
  198. package/templates/checkout-agent/packages/agent-core/src/strings.ts +175 -0
  199. package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  200. package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  201. package/templates/checkout-agent/packages/agent-core/src/types.ts +15 -2
  202. package/templates/checkout-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  203. package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  204. package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +23 -0
  205. package/templates/checkout-agent/packages/agent-core/test/helpers.ts +1 -1
  206. package/templates/checkout-agent/packages/agent-core/test/language.test.ts +40 -0
  207. package/templates/checkout-agent/packages/agent-core/test/locale.test.ts +137 -0
  208. package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  209. package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +2 -2
  210. package/templates/checkout-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  211. package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  212. package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +49 -0
  213. package/templates/checkout-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  214. package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +40 -1
  215. package/templates/checkout-agent/packages/agent-runtime/README.md +31 -4
  216. package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  217. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  218. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  219. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  220. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  221. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  222. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  223. package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +30 -4
  224. package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  225. package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  226. package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  227. package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  228. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  229. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  230. package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  231. package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  232. package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  233. package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  234. package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  235. package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  236. package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  237. package/templates/checkout-agent/packages/agent-runtime/src/env.ts +64 -0
  238. package/templates/checkout-agent/packages/agent-runtime/src/index.ts +2 -0
  239. package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +81 -10
  240. package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +34 -12
  241. package/templates/checkout-agent/packages/agent-runtime/src/outcome.ts +118 -0
  242. package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +7 -7
  243. package/templates/checkout-agent/packages/agent-runtime/src/runs.ts +51 -0
  244. package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  245. package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +75 -5
  246. package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +71 -33
  247. package/templates/checkout-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  248. package/templates/checkout-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  249. package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  250. package/templates/checkout-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  251. package/templates/checkout-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  252. package/templates/checkout-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  253. package/templates/checkout-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  254. package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  255. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  256. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  257. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  258. package/templates/collections-agent/README.md +2 -2
  259. package/templates/collections-agent/agents/collections-agent/.env.example +6 -3
  260. package/templates/collections-agent/agents/collections-agent/README.md +14 -9
  261. package/templates/collections-agent/agents/collections-agent/SYSTEM_PROMPT.md +16 -5
  262. package/templates/collections-agent/agents/collections-agent/agent.yaml +4 -3
  263. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +21 -4
  264. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +49 -5
  265. package/templates/collections-agent/agents/collections-agent/mandate.example.json +1 -1
  266. package/templates/collections-agent/agents/collections-agent/runbook.md +3 -3
  267. package/templates/collections-agent/agents/collections-agent/src/agreements.ts +1 -1
  268. package/templates/collections-agent/agents/collections-agent/src/envelope.ts +15 -13
  269. package/templates/collections-agent/agents/collections-agent/src/kit.ts +38 -35
  270. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +16 -8
  271. package/templates/collections-agent/agents/collections-agent/src/strings.ts +91 -0
  272. package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +2 -2
  273. package/templates/collections-agent/agents/collections-agent/test/check.test.ts +4 -1
  274. package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +1 -1
  275. package/templates/collections-agent/agents/collections-agent/test/envelope.test.ts +2 -2
  276. package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1103.transcript.jsonl +1 -1
  277. package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +1 -1
  278. package/templates/collections-agent/agents/collections-agent/test/payable-instrument.test.ts +56 -0
  279. package/templates/collections-agent/agents/collections-agent/test/rerun-clock.test.ts +54 -0
  280. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +69 -2
  281. package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +16 -3
  282. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +16 -4
  283. package/templates/collections-agent/agents/collections-agent/tools.json +2 -2
  284. package/templates/collections-agent/packages/agent-core/README.md +21 -2
  285. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  286. package/templates/collections-agent/packages/agent-core/src/agent.ts +33 -6
  287. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  288. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +11 -5
  289. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  290. package/templates/collections-agent/packages/agent-core/src/bundle.ts +2 -0
  291. package/templates/collections-agent/packages/agent-core/src/channels.ts +18 -8
  292. package/templates/collections-agent/packages/agent-core/src/check.ts +25 -3
  293. package/templates/collections-agent/packages/agent-core/src/engine.ts +90 -9
  294. package/templates/collections-agent/packages/agent-core/src/escalate.ts +10 -0
  295. package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
  296. package/templates/collections-agent/packages/agent-core/src/language.ts +52 -0
  297. package/templates/collections-agent/packages/agent-core/src/locale.ts +88 -0
  298. package/templates/collections-agent/packages/agent-core/src/manifest.ts +4 -1
  299. package/templates/collections-agent/packages/agent-core/src/rail.ts +29 -1
  300. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  301. package/templates/collections-agent/packages/agent-core/src/secrets.ts +53 -8
  302. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +14 -0
  303. package/templates/collections-agent/packages/agent-core/src/strings.ts +175 -0
  304. package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  305. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  306. package/templates/collections-agent/packages/agent-core/src/types.ts +15 -2
  307. package/templates/collections-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  308. package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  309. package/templates/collections-agent/packages/agent-core/test/engine.test.ts +23 -0
  310. package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
  311. package/templates/collections-agent/packages/agent-core/test/language.test.ts +40 -0
  312. package/templates/collections-agent/packages/agent-core/test/locale.test.ts +137 -0
  313. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  314. package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
  315. package/templates/collections-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  316. package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  317. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +49 -0
  318. package/templates/collections-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  319. package/templates/collections-agent/packages/agent-core/test/secrets.test.ts +40 -1
  320. package/templates/collections-agent/packages/agent-runtime/README.md +31 -4
  321. package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  322. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  323. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  324. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  325. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  326. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  327. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  328. package/templates/collections-agent/packages/agent-runtime/src/cli.ts +30 -4
  329. package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  330. package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  331. package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  332. package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  333. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  334. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  335. package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  336. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  337. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  338. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  339. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  340. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  341. package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  342. package/templates/collections-agent/packages/agent-runtime/src/env.ts +64 -0
  343. package/templates/collections-agent/packages/agent-runtime/src/index.ts +2 -0
  344. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +81 -10
  345. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +34 -12
  346. package/templates/collections-agent/packages/agent-runtime/src/outcome.ts +118 -0
  347. package/templates/collections-agent/packages/agent-runtime/src/poll.ts +7 -7
  348. package/templates/collections-agent/packages/agent-runtime/src/runs.ts +51 -0
  349. package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  350. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +75 -5
  351. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +71 -33
  352. package/templates/collections-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  353. package/templates/collections-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  354. package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  355. package/templates/collections-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  356. package/templates/collections-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  357. package/templates/collections-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  358. package/templates/collections-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  359. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  360. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  361. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  362. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  363. package/templates/hello-agent/README.md +2 -2
  364. package/templates/hello-agent/agents/hello-agent/README.md +6 -0
  365. package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +27 -13
  366. package/templates/hello-agent/agents/hello-agent/agent.yaml +2 -1
  367. package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  368. package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  369. package/templates/hello-agent/agents/hello-agent/mandate.example.json +1 -1
  370. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +1 -1
  371. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +1 -1
  372. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +1 -1
  373. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  374. package/templates/hello-agent/agents/hello-agent/src/bills.ts +9 -5
  375. package/templates/hello-agent/agents/hello-agent/src/kit.ts +4 -1
  376. package/templates/hello-agent/agents/hello-agent/tools.json +1 -1
  377. package/templates/hello-agent/packages/agent-core/README.md +21 -2
  378. package/templates/hello-agent/packages/agent-core/package.json +1 -1
  379. package/templates/hello-agent/packages/agent-core/src/agent.ts +33 -6
  380. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  381. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +11 -5
  382. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  383. package/templates/hello-agent/packages/agent-core/src/bundle.ts +2 -0
  384. package/templates/hello-agent/packages/agent-core/src/channels.ts +18 -8
  385. package/templates/hello-agent/packages/agent-core/src/check.ts +25 -3
  386. package/templates/hello-agent/packages/agent-core/src/engine.ts +90 -9
  387. package/templates/hello-agent/packages/agent-core/src/escalate.ts +10 -0
  388. package/templates/hello-agent/packages/agent-core/src/index.ts +3 -0
  389. package/templates/hello-agent/packages/agent-core/src/language.ts +52 -0
  390. package/templates/hello-agent/packages/agent-core/src/locale.ts +88 -0
  391. package/templates/hello-agent/packages/agent-core/src/manifest.ts +4 -1
  392. package/templates/hello-agent/packages/agent-core/src/rail.ts +29 -1
  393. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  394. package/templates/hello-agent/packages/agent-core/src/secrets.ts +53 -8
  395. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +14 -0
  396. package/templates/hello-agent/packages/agent-core/src/strings.ts +175 -0
  397. package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  398. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  399. package/templates/hello-agent/packages/agent-core/src/types.ts +15 -2
  400. package/templates/hello-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  401. package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  402. package/templates/hello-agent/packages/agent-core/test/engine.test.ts +23 -0
  403. package/templates/hello-agent/packages/agent-core/test/helpers.ts +1 -1
  404. package/templates/hello-agent/packages/agent-core/test/language.test.ts +40 -0
  405. package/templates/hello-agent/packages/agent-core/test/locale.test.ts +137 -0
  406. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  407. package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +2 -2
  408. package/templates/hello-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  409. package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  410. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +49 -0
  411. package/templates/hello-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  412. package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +40 -1
  413. package/templates/hello-agent/packages/agent-runtime/README.md +31 -4
  414. package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  415. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  416. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  417. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  418. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  419. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  420. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  421. package/templates/hello-agent/packages/agent-runtime/src/cli.ts +30 -4
  422. package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  423. package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  424. package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  425. package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  426. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  427. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  428. package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  429. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  430. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  431. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  432. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  433. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  434. package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  435. package/templates/hello-agent/packages/agent-runtime/src/env.ts +64 -0
  436. package/templates/hello-agent/packages/agent-runtime/src/index.ts +2 -0
  437. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +81 -10
  438. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +34 -12
  439. package/templates/hello-agent/packages/agent-runtime/src/outcome.ts +118 -0
  440. package/templates/hello-agent/packages/agent-runtime/src/poll.ts +7 -7
  441. package/templates/hello-agent/packages/agent-runtime/src/runs.ts +51 -0
  442. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  443. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +75 -5
  444. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +71 -33
  445. package/templates/hello-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  446. package/templates/hello-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  447. package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  448. package/templates/hello-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  449. package/templates/hello-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  450. package/templates/hello-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  451. package/templates/hello-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  452. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  453. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  454. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  455. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  456. package/templates/kits.lock.json +12 -12
  457. package/templates/supplier-payments-agent/README.md +2 -2
  458. package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +2 -2
  459. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +12 -7
  460. package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +14 -3
  461. package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +2 -1
  462. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  463. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  464. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  465. package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +3 -3
  466. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  467. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  468. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +5 -5
  469. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +1 -1
  470. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +5 -5
  471. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +1 -1
  472. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +1 -1
  473. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  474. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +37 -26
  475. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +41 -14
  476. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +12 -3
  477. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +8 -8
  478. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +75 -10
  479. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/locale.test.ts +101 -0
  480. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/run-outcome.test.ts +127 -0
  481. package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +1 -1
  482. package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -2
  483. package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
  484. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +33 -6
  485. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  486. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +11 -5
  487. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  488. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +2 -0
  489. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +18 -8
  490. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -3
  491. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +90 -9
  492. package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +10 -0
  493. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +3 -0
  494. package/templates/supplier-payments-agent/packages/agent-core/src/language.ts +52 -0
  495. package/templates/supplier-payments-agent/packages/agent-core/src/locale.ts +88 -0
  496. package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +4 -1
  497. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +29 -1
  498. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  499. package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +53 -8
  500. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +14 -0
  501. package/templates/supplier-payments-agent/packages/agent-core/src/strings.ts +175 -0
  502. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  503. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  504. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +15 -2
  505. package/templates/supplier-payments-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  506. package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  507. package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +23 -0
  508. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +1 -1
  509. package/templates/supplier-payments-agent/packages/agent-core/test/language.test.ts +40 -0
  510. package/templates/supplier-payments-agent/packages/agent-core/test/locale.test.ts +137 -0
  511. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  512. package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +2 -2
  513. package/templates/supplier-payments-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  514. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  515. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +49 -0
  516. package/templates/supplier-payments-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  517. package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +40 -1
  518. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +31 -4
  519. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  520. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  521. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  522. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  523. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  524. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  525. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  526. package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +30 -4
  527. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  528. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  529. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  530. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  531. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  532. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  533. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  534. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  535. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  536. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  537. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  538. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  539. package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  540. package/templates/supplier-payments-agent/packages/agent-runtime/src/env.ts +64 -0
  541. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +2 -0
  542. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +81 -10
  543. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +34 -12
  544. package/templates/supplier-payments-agent/packages/agent-runtime/src/outcome.ts +118 -0
  545. package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +7 -7
  546. package/templates/supplier-payments-agent/packages/agent-runtime/src/runs.ts +51 -0
  547. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  548. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +75 -5
  549. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +71 -33
  550. package/templates/supplier-payments-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  551. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  552. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  553. package/templates/supplier-payments-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  554. package/templates/supplier-payments-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  555. package/templates/supplier-payments-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  556. package/templates/supplier-payments-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  557. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  558. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  559. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  560. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
@@ -18,18 +18,21 @@ import { relative } from "node:path";
18
18
  import qrcode from "qrcode-terminal";
19
19
  import {
20
20
  CodeSparChargeRail,
21
- NotATestKeyError,
22
21
  StubChargeRail,
23
22
  createCodeSparClient,
24
- isTestKey,
23
+ assertTestKey,
25
24
  loadMandate,
26
- paySandboxCharge,
25
+ payIfPayable,
26
+ formatBRL,
27
+ formatDay,
28
+ CORE_STRINGS,
27
29
  type Execution,
28
30
  type StubChargeRailOptions,
31
+ railErrorOf,
29
32
  } from "@codespar/agent-core";
30
33
  import { defineAgent, envName, type AgentKit, type Setup } from "@codespar/agent-runtime";
31
- import { formatBRL, formatDate } from "./catalog.js";
32
34
  import { checkOrder, loadEnvelope, priceCart, localDate } from "./pricing.js";
35
+ import { STRINGS } from "./strings.js";
33
36
  import { claimOrder, CartBook, makeCartHandlers, type Cart } from "./modules/storefront-cart.js";
34
37
  import { followCart, makeChargeHandlers, orderProposal } from "./modules/bolepix-receivables.js";
35
38
  import { CodeSparInvoiceRail, followSale, InvoiceBook, resumeInvoices, StubInvoiceRail, type InvoiceDeps, type InvoiceRail, type StubIssuerBehaviour } from "./modules/nfse-invoice.js";
@@ -68,7 +71,7 @@ function invoiceDeps(s: Setup, say: (line: string) => void): InvoiceDeps {
68
71
  async function placeOrder(s: Setup, customer: string, lines: Array<{ sku: string; quantity: number }>): Promise<Execution> {
69
72
  const book = new CartBook(s.store);
70
73
  const now = s.engine.clock();
71
- const priced = priceCart({ lines }, loadEnvelope(s.guardrails), localDate(now, s.guardrails.timezone));
74
+ const priced = priceCart({ lines }, loadEnvelope(s.guardrails), localDate(now, s.guardrails.timezone), s.locale);
72
75
  const runId = s.runId;
73
76
  const cartId = book.nextId(runId);
74
77
  const cart: Cart = { ...priced, cart_id: cartId, ref: `${runId}/${cartId}`, run_id: runId, version: 1, currency: "BRL", order_discount_pct: 0, updated_at: now.toISOString() };
@@ -87,17 +90,11 @@ const kit: AgentKit = {
87
90
  labels: {
88
91
  defaultUser: "usr_atendente",
89
92
  evalUser: "usr_atendente",
90
- mandateWord: "politica",
91
- receiptWord: "pedido",
92
- intro: 'Voce e o cliente. Diga o que quer ("oi, sou a Marina, quero o pacote de dez aulas e uma avaliacao inicial"). Ctrl+D ou "sair" encerra.',
93
- prompt: "cliente> ",
94
- approveQuestion: " [atendente] Confirmar este pedido? [s/N] ",
95
- uncertainDispatch: " desfecho desconhecido no trilho; rode `npm run resume` para reconciliar (nunca repita a emissao)",
96
93
  missingReceiptKind: "record_missing_locally",
97
94
  missingReceiptDetail: (receiptId, runId) => `paid charge ${receiptId} is not in runs/${runId}/receipts`,
98
95
  stillExecuting: (e) => `${e.id}: still executing (${e.reason}) — ${e.detail}; nothing was re-issued; \`npm run poll\` keeps looking`,
99
- waitingForPayer: (round) => ` aguardando o pagamento... (${round} consultas)`,
100
96
  },
97
+ strings: STRINGS,
101
98
 
102
99
  usage: () => `checkout-agent
103
100
  npm start interactive terminal (you are the customer; the attendant answers the approval question)
@@ -109,12 +106,13 @@ const kit: AgentKit = {
109
106
  npm run poll -- --channel whatsapp --conversation <name> back to a conversation whose payment landed after the run ended
110
107
  options: --mode human|mandate --provider anthropic|replay --transcript <file> --rail stub|api --user <id>
111
108
  --wait <seconds> --simulate-payer --payer pays|expires|never (stub only) --json
112
- --now <ISO 8601> pin the run to that instant (service hours, the due date, timestamps); env CODESPAR_AGENT_NOW is the same thing`,
109
+ --now <ISO 8601> pin the run to that instant (service hours, the due date, timestamps); env CODESPAR_AGENT_NOW is the same thing
110
+ --locale pt-BR|en the language of what the code prints, WhatsApp templates included (the model answers in the language the customer types either way)`,
113
111
 
114
112
  buildRail: (ctx) => {
115
113
  const mandate = ctx.mandate ?? loadMandate(ctx.manifest.resolvePath(ctx.manifest.manifest.mandate_schema));
116
114
  if (ctx.kind === "api") {
117
- if (!isTestKey(ctx.env["CODESPAR_API_KEY"])) throw new NotATestKeyError();
115
+ assertTestKey(ctx.env["CODESPAR_API_KEY"]);
118
116
  const client = createCodeSparClient({ apiKey: ctx.env["CODESPAR_API_KEY"], baseUrl: ctx.env["CODESPAR_API_URL"], projectId: ctx.env["CODESPAR_PROJECT_ID"] });
119
117
  return {
120
118
  rail: new CodeSparChargeRail(client),
@@ -124,8 +122,8 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
124
122
  payer: {
125
123
  kind: "api" as const,
126
124
  async pay(chargeId: string) {
127
- const result = await paySandboxCharge(client, chargeId);
128
- if (!result.ok) return { ok: false as const, detail: `${result.failure.code}: ${result.failure.message}` };
125
+ const result = await payIfPayable(client, chargeId);
126
+ if (!result.ok) return { ok: false as const, detail: "refused" in result ? `${result.refused.code}: ${result.refused.message}` : `${result.failure.code}: ${result.failure.message}` };
129
127
  const s = result.state;
130
128
  return { ok: true as const, detail: `sandbox payer: ${s.charge_id} ${s.status} (${s.payment}, ${s.paid_minor} of ${s.quoted_minor}), simulated=${s.simulated}, settled_against=${s.settled_against}, money_moved=${s.money_moved}${s.idempotent_replay ? ", replay" : ""}` };
131
129
  },
@@ -161,37 +159,40 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
161
159
  const envelope = loadEnvelope(setup.guardrails);
162
160
  const book = new CartBook(setup.store);
163
161
  // On a channel that binds a conversation, the customer is the one it is bound to: read at call time, because the channel binds after setup.
164
- const orderDeps = { book, runId: setup.runId, timezone: setup.guardrails.timezone, clock: setup.engine.clock, boundCustomer: () => setup.conversation?.subject };
162
+ const orderDeps = { book, runId: setup.runId, timezone: setup.guardrails.timezone, clock: setup.engine.clock, boundCustomer: () => setup.conversation?.subject, locale: () => setup.locale };
165
163
  return {
166
164
  ...makeCartHandlers({ ...orderDeps, envelope, onReplaced: (cart, engine) => void followCart(cart, engine, orderDeps) }),
167
165
  ...makeChargeHandlers(orderDeps),
168
166
  };
169
167
  },
170
168
 
171
- policyExtension: ({ guardrails, store }) => {
169
+ policyExtension: ({ guardrails, store, locale }) => {
172
170
  const envelope = loadEnvelope(guardrails);
173
171
  const book = new CartBook(store);
174
- return (execution, ctx) => checkOrder(execution, execution.composition ? book.get(execution.composition.ref) : undefined, envelope, ctx.now, ctx.guardrails.timezone);
172
+ return (execution, ctx) => checkOrder(execution, execution.composition ? book.get(execution.composition.ref) : undefined, envelope, ctx.now, ctx.guardrails.timezone, locale());
175
173
  },
176
174
 
177
175
  describeExecution: (execution, setup) => {
176
+ const text = setup.coreStrings;
177
+ const words = STRINGS[setup.locale];
178
+ const money = (minor: number) => formatBRL(minor, setup.locale);
178
179
  const lines: string[] = [];
179
180
  const cart = cartOf(setup, execution);
180
- lines.push(` pedido ${execution.id}: ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}`);
181
- lines.push(` cliente ${execution.items[0]?.beneficiary ?? "?"}${cart ? `, carrinho ${cart.cart_id} v${cart.version}` : ""}`);
182
- for (const l of cart?.line_items ?? []) lines.push(` - ${l.quantity}x ${l.name}: ${formatBRL(l.totals.find((t) => t.type === "total")!.amount)}${l.discount_pct ? ` (desconto ${l.discount_pct}%)` : ""}`);
183
- for (const d of cart?.order_discounts ?? []) lines.push(` - ${d.kind === "coupon" ? `cupom ${d.ref.replace("coupon:", "")}` : "desconto no pedido"}: ${formatBRL(-d.amount)}`);
184
- lines.push(` total (calculado pelo core): ${formatBRL(execution.total)}${execution.items[0]?.due_date ? `, vence ${formatDate(execution.items[0].due_date)}` : ""}`);
185
- if (execution.composition) lines.push(` cart_hash ${execution.composition.composition_hash.slice(0, 19)}… (${execution.composition.line_count} linha(s))`);
186
- if (execution.escalation) lines.push(` escalado por: ${execution.escalation.trigger} — ${execution.escalation.detail}`);
187
- if (execution.blocking_reasons.length) lines.push(` bloqueado: ${execution.blocking_reasons.join(", ")} — a politica nao autoriza; nao ha o que aprovar`);
181
+ lines.push(` ${words.order} ${execution.id}: ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}`);
182
+ lines.push(` ${words.customerLine(execution.items[0]?.beneficiary ?? "?", cart ? `${cart.cart_id} v${cart.version}` : undefined)}`);
183
+ for (const l of cart?.line_items ?? []) lines.push(` - ${l.quantity}x ${l.name}: ${money(l.totals.find((t) => t.type === "total")!.amount)}${l.discount_pct ? words.lineDiscount(l.discount_pct) : ""}`);
184
+ for (const d of cart?.order_discounts ?? []) lines.push(` - ${d.kind === "coupon" ? words.coupon(d.ref.replace("coupon:", "")) : words.orderDiscount}: ${money(-d.amount)}`);
185
+ lines.push(` ${text.totalByCore}: ${money(execution.total)}${execution.items[0]?.due_date ? text.dueOn(formatDay(execution.items[0].due_date, setup.locale)) : ""}`);
186
+ if (execution.composition) lines.push(` cart_hash ${execution.composition.composition_hash.slice(0, 19)}… (${words.cartLines(execution.composition.line_count)})`);
187
+ if (execution.escalation) lines.push(` ${text.escalatedBy}: ${execution.escalation.trigger} — ${execution.escalation.detail}`);
188
+ if (execution.blocking_reasons.length) lines.push(` ${text.blocked(execution.blocking_reasons.join(", "), words.notAuthorized)}`);
188
189
  if (execution.detail && execution.state !== "awaiting_approval") lines.push(` ${execution.detail}`);
189
190
  for (const outcome of execution.outcomes) {
190
- if (outcome.transaction_id) lines.push(` cobranca: ${outcome.transaction_id} — ${outcome.status}${outcome.code ? ` (${outcome.code})` : ""}`);
191
- if (outcome.receipt_id) lines.push(` pedido pago: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
191
+ if (outcome.transaction_id) lines.push(` ${words.charge}: ${outcome.transaction_id} — ${outcome.status}${outcome.code ? ` (${outcome.code})` : ""}`);
192
+ if (outcome.receipt_id) lines.push(` ${words.paidOrder}: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
192
193
  }
193
194
  const invoice = new InvoiceBook(setup.store).of(execution.id);
194
- if (invoice) lines.push(` NFS-e ${invoice.id}: ${invoice.state}${invoice.reason ? ` (${invoice.reason}, ${invoice.code})` : ""}${invoice.document ? ` — documento ${invoice.document.id}` : ""}`);
195
+ if (invoice) lines.push(` NFS-e ${invoice.id}: ${invoice.state}${invoice.reason ? ` (${invoice.reason}, ${invoice.code})` : ""}${invoice.document ? words.invoiceDocument(invoice.document.id) : ""}`);
195
196
  return lines;
196
197
  },
197
198
 
@@ -214,6 +215,7 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
214
215
  id: e.id,
215
216
  state: e.state,
216
217
  reason: e.reason ?? null,
218
+ rail_error: railErrorOf(e),
217
219
  escalation: e.escalation ?? null,
218
220
  cart_id: cart?.cart_id ?? null,
219
221
  cart_hash: e.composition?.composition_hash ?? null,
@@ -234,18 +236,19 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
234
236
  },
235
237
 
236
238
  /** What the customer reads when the charge is payable: the QR as an image, the copy-and-paste under it, the bank line if any. */
237
- presentInstrument: (execution, _instalment, chargeId, instrument, tell) => {
239
+ presentInstrument: (execution, _instalment, chargeId, instrument, tell, locale) => {
240
+ const text = CORE_STRINGS[locale];
238
241
  tell("");
239
- tell(`Pedido de ${formatBRL(execution.total)}${instrument.due_date ? `, vence ${formatDate(instrument.due_date)}` : ""} — cobranca ${chargeId}`);
242
+ tell(`${STRINGS[locale].orderOf(formatBRL(execution.total, locale))}${instrument.due_date ? text.dueOn(formatDay(instrument.due_date, locale)) : ""}${text.chargeRef(chargeId)}`);
240
243
  if (instrument.pix_copy_paste) {
241
244
  qrcode.generate(instrument.pix_copy_paste, { small: true }, (qr: string) => {
242
245
  for (const line of qr.split("\n")) tell(line);
243
246
  });
244
- tell("Pix copia e cola:");
247
+ tell(text.pixCopyPaste);
245
248
  tell(instrument.pix_copy_paste);
246
249
  }
247
250
  if (instrument.boleto_bank_line) {
248
- tell("Ou pelo boleto, linha digitavel:");
251
+ tell(text.boletoLine);
249
252
  tell(instrument.boleto_bank_line);
250
253
  }
251
254
  tell("");
@@ -255,14 +258,15 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
255
258
  announceOutcome: (execution, setup, tell) => {
256
259
  if (!["settled", "failed", "denied", "expired"].includes(execution.state)) return false;
257
260
  if (!setup.engine.markTold(execution.id, execution.state)) return false;
261
+ const words = STRINGS[setup.locale];
258
262
  let text: string;
259
- if (execution.state === "settled") text = `Recebemos, pedido confirmado! Obrigado. (${execution.outcomes.map((o) => o.transaction_id).filter(Boolean).join(", ")})`;
260
- else if (execution.reason === "charge_expired") text = "A cobranca venceu sem pagamento. Se quiser, emito uma nova para o mesmo pedido.";
261
- else if (execution.reason === "charge_cancelled") text = "A cobranca foi cancelada. Nada foi pago.";
262
- else if (execution.reason === "charge_reference_ambiguous") text = "A cobranca deste pedido ja foi emitida e estamos conferindo a situacao dela. Nao pague de novo; te aviso assim que estiver conferida.";
263
- else if (execution.state === "failed") text = `Nao consegui emitir a cobranca (${execution.reason ?? "falha no trilho"}). Nada foi cobrado.`;
264
- else if (execution.state === "denied") text = `Nao consigo fechar o pedido nesses termos (${execution.reason ?? "recusado"}).`;
265
- else text = `O pedido expirou sem confirmacao (${execution.reason ?? execution.state}).`;
263
+ if (execution.state === "settled") text = words.toldSettled(execution.outcomes.map((o) => o.transaction_id).filter(Boolean).join(", "));
264
+ else if (execution.reason === "charge_expired") text = words.toldExpired;
265
+ else if (execution.reason === "charge_cancelled") text = words.toldCancelled;
266
+ else if (execution.reason === "charge_reference_ambiguous") text = words.toldAmbiguous;
267
+ else if (execution.state === "failed") text = words.toldFailed(execution.reason);
268
+ else if (execution.state === "denied") text = words.toldDenied(execution.reason);
269
+ else text = words.toldUndecided(execution.reason ?? execution.state);
266
270
  tell(text);
267
271
  setup.engine.note("message.debtor", execution.id, { state: execution.state, reason: execution.reason ?? null, text });
268
272
  return true;
@@ -284,8 +288,8 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
284
288
  * is answered inside the turn that produced it, so it has no template, and
285
289
  * the poll reports it rather than sending approximate copy.
286
290
  */
287
- outcomeTemplate: (execution) => {
288
- const total = formatBRL(execution.total);
291
+ outcomeTemplate: (execution, locale) => {
292
+ const total = formatBRL(execution.total, locale);
289
293
  if (execution.state === "settled") return { template: "pedido_confirmado", variables: [total] };
290
294
  if (execution.reason === "charge_expired") return { template: "pedido_cobranca_vencida", variables: [total] };
291
295
  if (execution.reason === "charge_cancelled") return { template: "pedido_cobranca_cancelada", variables: [total] };
@@ -2,7 +2,7 @@
2
2
  * Module `bolepix-receivables`, the sales version: the `codespar_charge`
3
3
  * handler. A copy of the collections-agent's module in its bones (agents do
4
4
  * not import each other's modules, OPEN_QUESTIONS §39f) and different in what
5
- * it charges: an ORDER, one cobranca com vencimento whose amount is the
5
+ * it charges: an ORDER, one cobrança com vencimento whose amount is the
6
6
  * cart's total as the code priced it, due today (checkout decision 1).
7
7
  *
8
8
  * Three actions, because ordering and issuing are two moments of a sale:
@@ -22,10 +22,11 @@
22
22
  * No input carries an amount. `total_minor` is recorded and, with
23
23
  * `model_total_mismatch: refuse`, refuses a total the model got wrong.
24
24
  */
25
- import type { Execution, ExecutionEngine, Proposal, ToolHandler } from "@codespar/agent-core";
25
+ import type { Execution, ExecutionEngine, Locale, Proposal, ToolHandler } from "@codespar/agent-core";
26
26
  import { MERCHANT, formatBRL, formatDate } from "../catalog.js";
27
27
  import { localDate } from "../pricing.js";
28
28
  import { claimOrder, currentCart, orderOf, resolveCart, type Cart, type CartBook } from "./storefront-cart.js";
29
+ import { STRINGS } from "../strings.js";
29
30
 
30
31
  interface ChargeInput {
31
32
  action?: unknown;
@@ -43,6 +44,8 @@ export interface OrderDeps {
43
44
  clock: () => Date;
44
45
  /** The customer a channel's conversation is bound to, when one is: an order in this conversation is theirs. */
45
46
  boundCustomer?: () => string | undefined;
47
+ /** The run's locale, read at call time: an order's status message is worded in it. Default pt-BR. */
48
+ locale?: () => Locale;
46
49
  }
47
50
 
48
51
  const OPEN = new Set(["awaiting_approval", "approved"]);
@@ -74,6 +77,7 @@ export function followCart(cart: Cart, engine: ExecutionEngine, deps: Pick<Order
74
77
  }
75
78
 
76
79
  export function makeChargeHandlers(deps: OrderDeps): Record<string, ToolHandler> {
80
+ const text = () => STRINGS[deps.locale?.() ?? "pt-BR"];
77
81
  const findOrder = (engine: ExecutionEngine, input: ChargeInput): { order: Execution | undefined; cart: Cart | undefined } => {
78
82
  if (typeof input.execution_id === "string" && input.execution_id) {
79
83
  const order = engine.get(input.execution_id);
@@ -91,14 +95,14 @@ export function makeChargeHandlers(deps: OrderDeps): Record<string, ToolHandler>
91
95
 
92
96
  if (action === "status") {
93
97
  const { order, cart } = findOrder(ctx.engine, input);
94
- if (!order) return { found: false, message: cart ? `o carrinho ${cart.cart_id} ainda nao virou pedido` : "nenhum pedido nesta conversa" };
98
+ if (!order) return { found: false, message: cart ? text().noOrderForCart(cart.cart_id) : text().noOrder };
95
99
  return { found: true, ...describe(order, cart) };
96
100
  }
97
101
 
98
102
  if (action === "issue") {
99
103
  const { order, cart } = findOrder(ctx.engine, input);
100
104
  if (!order) throw new Error("codespar_charge: no order to issue; create the order from the cart first (action=create)");
101
- if (order.state !== "approved") return { ...describe(order, cart), message: messageFor(order) };
105
+ if (order.state !== "approved") return { ...describe(order, cart), message: messageFor(order, text()) };
102
106
  // The cart may have moved since the order was approved; the order follows it, and the last gate compares.
103
107
  if (cart) followCart(cart, ctx.engine, deps);
104
108
  const executed = await ctx.engine.execute(order.id);
@@ -123,30 +127,34 @@ export function makeChargeHandlers(deps: OrderDeps): Record<string, ToolHandler>
123
127
  if (existing && (OPEN.has(existing.state) || existing.state === "executing" || existing.state === "settled")) {
124
128
  if (OPEN.has(existing.state)) followCart(cart, ctx.engine, deps);
125
129
  const current = ctx.engine.get(existing.id)!;
126
- return { ...describe(current, cart), message: `este carrinho ja e o pedido ${current.id}; nada novo foi criado` };
130
+ return { ...describe(current, cart), message: text().alreadyOrdered(current.id) };
127
131
  }
128
132
 
129
133
  const claimed = typeof input.total_minor === "number" ? input.total_minor : undefined;
130
134
  const draft = await ctx.engine.draft(orderProposal(cart, customer, deps, claimed));
131
- if (!draft.ok) return { status: "refused", reason: draft.reason, message: draft.message, issued: false, paid: false };
135
+ if (!draft.ok) {
136
+ // Refused before a draft: no execution will ever say so, and the run's count is taken from this.
137
+ ctx.onNotRun?.({ ref: cart.cart_id, why: "refused", detail: draft.reason });
138
+ return { status: "refused", reason: draft.reason, message: draft.message, issued: false, paid: false };
139
+ }
132
140
  claimOrder(ctx.engine, cart, draft.execution.id);
133
141
  const decided = await ctx.onExecution(draft.execution);
134
- return { ...describe(decided, cart), message: messageFor(decided) };
142
+ return { ...describe(decided, cart), message: messageFor(decided, text()) };
135
143
  };
136
144
 
137
145
  return { codespar_charge: codesparCharge };
138
146
  }
139
147
 
140
- function messageFor(order: Execution): string {
148
+ function messageFor(order: Execution, text: (typeof STRINGS)[Locale]): string {
141
149
  switch (order.state) {
142
150
  case "approved":
143
- return "pedido confirmado; a cobranca sai quando o cliente pedir (action=issue)";
151
+ return text.orderApproved;
144
152
  case "awaiting_approval":
145
- return order.reason === "items_hash_mismatch" ? "o carrinho mudou depois da confirmacao; o pedido voltou para o atendente" : "aguardando o atendente confirmar o pedido";
153
+ return order.reason === "items_hash_mismatch" ? text.orderCartChanged : text.orderAwaitingAttendant;
146
154
  case "executing":
147
- return order.reason === "awaiting_settlement" ? "cobranca emitida; aguardando o pagamento" : "desfecho da emissao desconhecido; nada sera reemitido";
155
+ return order.reason === "awaiting_settlement" ? text.orderIssued : text.orderUncertain;
148
156
  case "settled":
149
- return "pago";
157
+ return text.orderPaid;
150
158
  default:
151
159
  return `${order.state}${order.reason ? ` (${order.reason})` : ""}`;
152
160
  }
@@ -178,7 +178,7 @@ export class StubInvoiceRail implements InvoiceRail {
178
178
  return { status: "unsent", code: "no_eligible_providers", message: "stub: routing found no issuer this time; nothing was sent" };
179
179
  }
180
180
  if (behaviour === "refuses" || (behaviour === undefined && !request.recipient.address)) {
181
- return { status: "refused", code: "E0101", message: "stub issuer: tomador sem endereco; a NFS-e exige o endereco do tomador" };
181
+ return { status: "refused", code: "E0101", message: "stub issuer: tomador sem endereço; a NFS-e exige o endereço do tomador" };
182
182
  }
183
183
  // What the issuer did is recorded before the answer is lost, as a real one would have.
184
184
  const documentId = `nfse_stub_${key.slice(-16)}`;
@@ -248,7 +248,7 @@ export function nfseRequest(sale: Execution, cart: Cart, customer: Customer): Nf
248
248
  description: `${MERCHANT.name} - pedido ${cart.cart_id}: ${cart.line_items.map((l) => `${l.quantity}x ${l.name}`).join("; ")}`,
249
249
  // What was PAID, discounts included; the transform would otherwise sum list prices.
250
250
  servicesAmount: sale.total / 100,
251
- additionalInformation: `cobranca ${chargeId}, ${formatBRL(sale.total)}`,
251
+ additionalInformation: `cobrança ${chargeId}, ${formatBRL(sale.total)}`,
252
252
  },
253
253
  };
254
254
  }
@@ -342,8 +342,8 @@ export async function dispatchInvoice(record: InvoiceRecord, deps: InvoiceDeps):
342
342
  function notify(record: InvoiceRecord, deps: InvoiceDeps): InvoiceRecord {
343
343
  const text =
344
344
  record.reason === "invoice_uncertain"
345
- ? `NFS-e do pedido ${record.sale_execution_id} (cobranca ${record.charge_id}) com resultado INCERTO (${record.code}): pode ter sido emitida. Nao reemita; confira no emissor. A venda continua paga.`
346
- : `NFS-e do pedido ${record.sale_execution_id} (cobranca ${record.charge_id}) falhou (${record.reason}, ${record.code}): ${record.detail}. A venda continua paga.`;
345
+ ? `NFS-e do pedido ${record.sale_execution_id} (cobrança ${record.charge_id}) com resultado INCERTO (${record.code}): pode ter sido emitida. Não reemita; confira no emissor. A venda continua paga.`
346
+ : `NFS-e do pedido ${record.sale_execution_id} (cobrança ${record.charge_id}) falhou (${record.reason}, ${record.code}): ${record.detail}. A venda continua paga.`;
347
347
  deps.say(` [atendente] ${text}`);
348
348
  deps.engine.note("message.attendant", record.sale_execution_id, { invoice_id: record.id, state: record.state, reason: record.reason ?? null, code: record.code ?? null, text });
349
349
  return record;
@@ -18,9 +18,10 @@
18
18
  * execution carries (`<run_id>/cart-1`) is unique across runs, so an order
19
19
  * approved from another process (`npm run approve`) finds its cart.
20
20
  */
21
- import type { ExecutionEngine, StateStore, ToolHandler } from "@codespar/agent-core";
21
+ import type { ExecutionEngine, Locale, StateStore, ToolHandler } from "@codespar/agent-core";
22
22
  import { CATALOG, MERCHANT, formatBRL } from "../catalog.js";
23
23
  import { localDate, priceCart, type Envelope, type PricedCart, type ValidationIssue } from "../pricing.js";
24
+ import { STRINGS } from "../strings.js";
24
25
 
25
26
  export interface Cart extends PricedCart {
26
27
  cart_id: string;
@@ -137,6 +138,8 @@ export interface CartDeps {
137
138
  runId: string;
138
139
  timezone: string;
139
140
  clock: () => Date;
141
+ /** The run's locale, read at call time: the cart's issues and totals are worded in it. Default pt-BR. */
142
+ locale?: () => Locale;
140
143
  /** Called after a replacement, with the cart as it is now: an open order follows it (`bolepix-receivables`). */
141
144
  onReplaced(cart: Cart, engine: ExecutionEngine): void;
142
145
  }
@@ -169,16 +172,16 @@ export function makeCartHandlers(deps: CartDeps): Record<string, ToolHandler> {
169
172
  })),
170
173
  policy: {
171
174
  service_hours: deps.envelope.service_hours,
172
- payment: "bolepix (cobranca com vencimento): paga por Pix ou por boleto, vence hoje",
173
- discounts: "so dentro da politica da loja, aplicada pelo codigo; o que estiver fora e recusado. Cupom: so os da tabela da loja, informados pelo cliente.",
174
- prices: "sempre os do catalogo; nenhuma ferramenta aceita preco",
175
+ payment: "bolepix (cobrança com vencimento): paga por Pix ou por boleto, vence hoje",
176
+ discounts: "só dentro da política da loja, aplicada pelo código; o que estiver fora é recusado. Cupom: só os da tabela da loja, informados pelo cliente.",
177
+ prices: "sempre os do catálogo; nenhuma ferramenta aceita preço",
175
178
  },
176
179
  });
177
180
 
178
181
  const cartView: ToolHandler = async (raw, ctx) => {
179
182
  const input = raw as { cart_id?: unknown };
180
183
  const cart = resolveCart(ctx.engine, deps, input.cart_id);
181
- if (!cart) return { cart: null, message: "nenhum carrinho aberto nesta conversa; cart_update abre um" };
184
+ if (!cart) return { cart: null, message: STRINGS[deps.locale?.() ?? "pt-BR"].noCart };
182
185
  return viewOf(ctx.engine, cart);
183
186
  };
184
187
 
@@ -191,7 +194,7 @@ export function makeCartHandlers(deps: CartDeps): Record<string, ToolHandler> {
191
194
  } else target = currentCart(ctx.engine, deps);
192
195
 
193
196
  const now = deps.clock();
194
- const priced = priceCart({ lines: input.lines, coupon: input.coupon, order_discount_pct: input.order_discount_pct }, deps.envelope, localDate(now, deps.timezone));
197
+ const priced = priceCart({ lines: input.lines, coupon: input.coupon, order_discount_pct: input.order_discount_pct }, deps.envelope, localDate(now, deps.timezone), deps.locale?.());
195
198
  const cartId = target?.cart_id ?? deps.book.nextId(deps.runId);
196
199
  const cart: Cart = {
197
200
  ...priced,
@@ -13,8 +13,9 @@
13
13
  * `guardrails.json` under `envelope`, and every rule of it can only refuse.
14
14
  */
15
15
  import { z } from "zod";
16
- import { compositionHash, isOutsideHours, localClock, type CompositionLine, type Execution, type ExecutionReason, type Guardrails } from "@codespar/agent-core";
17
- import { catalogItem, formatBRL } from "./catalog.js";
16
+ import { compositionHash, formatBRL, isOutsideHours, localClock, type CompositionLine, type Execution, type ExecutionReason, type Guardrails, type Locale } from "@codespar/agent-core";
17
+ import { catalogItem } from "./catalog.js";
18
+ import { STRINGS } from "./strings.js";
18
19
 
19
20
  const HOURS = /^([01]\d|2[0-3]):[0-5]\d-([01]\d|2[0-3]):[0-5]\d$/;
20
21
 
@@ -131,7 +132,8 @@ export interface CartInput {
131
132
  * priced from the catalog. A coupon that does not exist, or does not apply,
132
133
  * is named and not applied, and nothing "equivalent" is applied in its place.
133
134
  */
134
- export function priceCart(input: CartInput, envelope: Envelope, today: string): PricedCart {
135
+ export function priceCart(input: CartInput, envelope: Envelope, today: string, locale: Locale = "pt-BR"): PricedCart {
136
+ const text = STRINGS[locale];
135
137
  const issues: ValidationIssue[] = [];
136
138
  const lines: PricedLine[] = [];
137
139
  const raw = Array.isArray(input.lines) ? input.lines : [];
@@ -143,30 +145,30 @@ export function priceCart(input: CartInput, envelope: Envelope, today: string):
143
145
  const line = (entry ?? {}) as Record<string, unknown>;
144
146
  const priced = PRICE_FIELDS.find((f) => f in line);
145
147
  if (priced) {
146
- issues.push({ code: "price_not_caller_input", field: `${field}.${priced}`, message: "o preco vem do catalogo da loja; a linha foi recusada inteira" });
148
+ issues.push({ code: "price_not_caller_input", field: `${field}.${priced}`, message: text.issuePriceNotInput });
147
149
  continue;
148
150
  }
149
151
  const sku = typeof line["sku"] === "string" ? line["sku"].trim().toLowerCase() : "";
150
152
  const item = sku ? catalogItem(sku) : undefined;
151
153
  if (!item) {
152
- issues.push({ code: "sku_unknown", field: `${field}.sku`, message: `nao temos ${sku || "esse item"} no catalogo` });
154
+ issues.push({ code: "sku_unknown", field: `${field}.sku`, message: text.issueSkuUnknown(sku) });
153
155
  continue;
154
156
  }
155
157
  if (!item.available) {
156
- issues.push({ code: "item_unavailable", field: `${field}.sku`, message: `${item.title} esta indisponivel` });
158
+ issues.push({ code: "item_unavailable", field: `${field}.sku`, message: text.issueUnavailable(item.title) });
157
159
  continue;
158
160
  }
159
161
  const quantity = line["quantity"];
160
162
  if (typeof quantity !== "number" || !Number.isInteger(quantity) || quantity <= 0 || quantity > envelope.max_units_per_line) {
161
- issues.push({ code: "quantity_invalid", field: `${field}.quantity`, message: `quantidade deve ser um inteiro de 1 a ${envelope.max_units_per_line}` });
163
+ issues.push({ code: "quantity_invalid", field: `${field}.quantity`, message: text.issueQuantityInvalid(envelope.max_units_per_line) });
162
164
  continue;
163
165
  }
164
166
  if (seen.has(item.sku)) {
165
- issues.push({ code: "quantity_invalid", field: `${field}.sku`, message: `${item.sku} aparece mais de uma vez; uma linha por item, com a quantidade total` });
167
+ issues.push({ code: "quantity_invalid", field: `${field}.sku`, message: text.issueDuplicateSku(item.sku) });
166
168
  continue;
167
169
  }
168
170
  if (item.stock !== undefined && quantity > item.stock) {
169
- issues.push({ code: "quantity_above_stock", field: `${field}.quantity`, message: `so ha ${item.stock} de ${item.title}` });
171
+ issues.push({ code: "quantity_above_stock", field: `${field}.quantity`, message: text.issueAboveStock(item.stock, item.title) });
170
172
  continue;
171
173
  }
172
174
  const discount = line["discount_pct"] ?? 0;
@@ -184,9 +186,9 @@ export function priceCart(input: CartInput, envelope: Envelope, today: string):
184
186
  discount_pct: discount,
185
187
  availability_status: item.stock !== undefined && item.stock - quantity <= 1 ? "low_stock" : "in_stock",
186
188
  totals: [
187
- { type: "items_base_amount", display_text: "Valor", amount: base },
188
- { type: "items_discount", display_text: "Desconto", amount: -off },
189
- { type: "total", display_text: "Total da linha", amount: base - off },
189
+ { type: "items_base_amount", display_text: text.lineValue, amount: base },
190
+ { type: "items_discount", display_text: text.lineDiscountTotal, amount: -off },
191
+ { type: "total", display_text: text.lineTotal, amount: base - off },
190
192
  ],
191
193
  });
192
194
  }
@@ -198,9 +200,9 @@ export function priceCart(input: CartInput, envelope: Envelope, today: string):
198
200
  if (typeof input.coupon !== "string") throw new Error("coupon must be a string");
199
201
  const code = input.coupon.trim().toUpperCase();
200
202
  const found = envelope.coupons.find((c) => c.code === code);
201
- if (!found) issues.push({ code: "coupon_unknown", field: "coupon", message: `o cupom ${code} nao existe nesta loja` });
202
- else if (found.expires_at < today) issues.push({ code: "coupon_not_applicable", field: "coupon", message: `o cupom ${code} expirou` });
203
- else if (subtotal < found.min_order_minor) issues.push({ code: "coupon_not_applicable", field: "coupon", message: `o cupom ${code} vale para pedidos a partir de ${formatBRL(found.min_order_minor)}` });
203
+ if (!found) issues.push({ code: "coupon_unknown", field: "coupon", message: text.issueCouponUnknown(code) });
204
+ else if (found.expires_at < today) issues.push({ code: "coupon_not_applicable", field: "coupon", message: text.issueCouponExpired(code) });
205
+ else if (subtotal < found.min_order_minor) issues.push({ code: "coupon_not_applicable", field: "coupon", message: text.issueCouponMinimum(code, formatBRL(found.min_order_minor, locale)) });
204
206
  else {
205
207
  coupon = code;
206
208
  orderDiscounts.push({ kind: "coupon", ref: `coupon:${code}`, pct: found.discount_pct, amount: Math.round((subtotal * found.discount_pct) / 100) });
@@ -224,11 +226,11 @@ export function priceCart(input: CartInput, envelope: Envelope, today: string):
224
226
  coupon,
225
227
  order_discounts: orderDiscounts,
226
228
  totals: [
227
- { type: "items_base_amount", display_text: "Itens", amount: itemsBase },
228
- { type: "items_discount", display_text: "Descontos nos itens", amount: subtotal - itemsBase },
229
- { type: "subtotal", display_text: "Subtotal", amount: subtotal },
230
- { type: "discount", display_text: "Desconto do pedido", amount: -orderOff },
231
- { type: "total", display_text: "Total", amount: total },
229
+ { type: "items_base_amount", display_text: text.totalItems, amount: itemsBase },
230
+ { type: "items_discount", display_text: text.totalItemsDiscount, amount: subtotal - itemsBase },
231
+ { type: "subtotal", display_text: text.totalSubtotal, amount: subtotal },
232
+ { type: "discount", display_text: text.totalOrderDiscount, amount: -orderOff },
233
+ { type: "total", display_text: text.totalTotal, amount: total },
232
234
  ],
233
235
  total,
234
236
  validation_issues: issues,
@@ -248,46 +250,47 @@ export interface OrderVerdict {
248
250
  * envelope's numbers or a cost: the maximum discount and the margin floor are
249
251
  * negotiation information (checkout §5.6, exfiltration).
250
252
  */
251
- export function checkOrder(execution: Pick<Execution, "items" | "total" | "composition">, cart: PricedCart | undefined, envelope: Envelope, now: Date, timezone: string): OrderVerdict | undefined {
253
+ export function checkOrder(execution: Pick<Execution, "items" | "total" | "composition">, cart: PricedCart | undefined, envelope: Envelope, now: Date, timezone: string, locale: Locale = "pt-BR"): OrderVerdict | undefined {
254
+ const text = STRINGS[locale];
252
255
  const [open, close] = envelope.service_hours.split("-") as [string, string];
253
256
  if (isOutsideHours(`${close}-${open}`, now, timezone)) {
254
- return { reason: "outside_hours", detail: `fora do horario de atendimento (${envelope.service_hours} ${timezone}); agora sao ${localClock(now, timezone)}` };
257
+ return { reason: "outside_hours", detail: text.outsideServiceHours(envelope.service_hours, timezone, localClock(now, timezone)) };
255
258
  }
256
- if (execution.items.length !== 1) return { reason: "outside_envelope", detail: "um pedido e uma cobranca: um item, cujo valor e o total do carrinho" };
257
- if (!execution.composition) return { reason: "outside_envelope", detail: "um pedido nasce de um carrinho; esta execucao nao nomeia nenhum" };
258
- if (!cart) return { reason: "outside_envelope", detail: `o carrinho ${execution.composition.ref} nao existe neste estado` };
259
- if (cart.cart_hash !== execution.composition.composition_hash) return { reason: "outside_envelope", detail: "o pedido nao corresponde ao carrinho atual; o carrinho mudou depois" };
260
- if (cart.line_items.length === 0) return { reason: "outside_envelope", detail: "carrinho vazio" };
261
- if (cart.validation_issues.length > 0) return { reason: "outside_envelope", detail: `o carrinho tem pendencias (${cart.validation_issues.map((i) => i.code).join(", ")})` };
262
- if (execution.total !== cart.total || execution.items[0]!.amount !== cart.total) return { reason: "outside_envelope", detail: `o pedido cobra ${execution.total} e o carrinho soma ${cart.total}` };
259
+ if (execution.items.length !== 1) return { reason: "outside_envelope", detail: text.gateOneItem };
260
+ if (!execution.composition) return { reason: "outside_envelope", detail: text.gateNoCart };
261
+ if (!cart) return { reason: "outside_envelope", detail: text.gateCartMissing(execution.composition.ref) };
262
+ if (cart.cart_hash !== execution.composition.composition_hash) return { reason: "outside_envelope", detail: text.gateCartChanged };
263
+ if (cart.line_items.length === 0) return { reason: "outside_envelope", detail: text.gateCartEmpty };
264
+ if (cart.validation_issues.length > 0) return { reason: "outside_envelope", detail: text.gateCartIssues(cart.validation_issues.map((i) => i.code).join(", ")) };
265
+ if (execution.total !== cart.total || execution.items[0]!.amount !== cart.total) return { reason: "outside_envelope", detail: text.gateTotalMismatch(execution.total, cart.total) };
263
266
 
264
267
  for (const line of cart.line_items) {
265
268
  const item = catalogItem(line.sku);
266
- if (!item || !item.available) return { reason: "outside_envelope", detail: `${line.sku} nao esta a venda` };
267
- if (line.unit_amount !== item.price_minor) return { reason: "outside_envelope", detail: `${line.sku} nao esta pelo preco de tabela` };
268
- if (line.quantity > envelope.max_units_per_line || (item.stock !== undefined && line.quantity > item.stock)) return { reason: "outside_envelope", detail: `quantidade de ${line.sku} fora do permitido` };
269
- if (line.discount_pct > envelope.max_discount_pct) return { reason: "outside_envelope", detail: `desconto em ${line.sku} acima do que a politica da loja permite` };
269
+ if (!item || !item.available) return { reason: "outside_envelope", detail: text.gateNotForSale(line.sku) };
270
+ if (line.unit_amount !== item.price_minor) return { reason: "outside_envelope", detail: text.gateNotListPrice(line.sku) };
271
+ if (line.quantity > envelope.max_units_per_line || (item.stock !== undefined && line.quantity > item.stock)) return { reason: "outside_envelope", detail: text.gateQuantity(line.sku) };
272
+ if (line.discount_pct > envelope.max_discount_pct) return { reason: "outside_envelope", detail: text.gateLineDiscount(line.sku) };
270
273
  const total = lineTotal(line);
271
- if (marginBelow(total, item.cost_minor * line.quantity, envelope.min_margin_pct)) return { reason: "outside_envelope", detail: `${line.sku} ficaria abaixo do piso de margem da loja` };
274
+ if (marginBelow(total, item.cost_minor * line.quantity, envelope.min_margin_pct)) return { reason: "outside_envelope", detail: text.gateLineMargin(line.sku) };
272
275
  }
273
276
  const negotiated = cart.order_discounts.filter((d) => d.kind === "negotiated");
274
277
  const coupons = cart.order_discounts.filter((d) => d.kind === "coupon");
275
- if (negotiated.some((d) => d.pct > envelope.max_order_discount_pct)) return { reason: "outside_envelope", detail: "desconto no pedido acima do que a politica da loja permite" };
276
- if (negotiated.length > 0 && coupons.length > 0) return { reason: "outside_envelope", detail: "cupom e desconto negociado nao se somam" };
278
+ if (negotiated.some((d) => d.pct > envelope.max_order_discount_pct)) return { reason: "outside_envelope", detail: text.gateOrderDiscount };
279
+ if (negotiated.length > 0 && coupons.length > 0) return { reason: "outside_envelope", detail: text.gateCouponAndDiscount };
277
280
  const today = localDate(now, timezone);
278
281
  for (const c of coupons) {
279
282
  const code = c.ref.replace(/^coupon:/, "");
280
283
  const found = envelope.coupons.find((x) => x.code === code);
281
- if (!found || found.expires_at < today || c.pct !== found.discount_pct) return { reason: "outside_envelope", detail: `o cupom ${code} nao vale para este pedido` };
284
+ if (!found || found.expires_at < today || c.pct !== found.discount_pct) return { reason: "outside_envelope", detail: text.gateCouponInvalid(code) };
282
285
  }
283
286
  const cost = cart.line_items.reduce((sum, l) => sum + (catalogItem(l.sku)?.cost_minor ?? 0) * l.quantity, 0);
284
- if (marginBelow(cart.total, cost, envelope.min_margin_pct)) return { reason: "outside_envelope", detail: "o pedido ficaria abaixo do piso de margem da loja" };
285
- if (cart.total > envelope.max_order_minor) return { reason: "outside_envelope", detail: `pedido de ${formatBRL(cart.total)} acima do ticket maximo da loja` };
287
+ if (marginBelow(cart.total, cost, envelope.min_margin_pct)) return { reason: "outside_envelope", detail: text.gateOrderMargin };
288
+ if (cart.total > envelope.max_order_minor) return { reason: "outside_envelope", detail: text.gateTicket(formatBRL(cart.total, locale)) };
286
289
 
287
290
  const due = execution.items[0]!.due_date;
288
- if (!due) return { reason: "outside_envelope", detail: "a cobranca do pedido nao tem vencimento" };
291
+ if (!due) return { reason: "outside_envelope", detail: text.gateNoDueDate };
289
292
  const last = addDays(today, envelope.due_date_window_days);
290
- if (due < today || due > last) return { reason: "outside_envelope", detail: `vencimento ${due} fora da janela da loja (de ${today} ate ${last})` };
293
+ if (due < today || due > last) return { reason: "outside_envelope", detail: text.gateDueOutsideWindow(due, today, last) };
291
294
  return undefined;
292
295
  }
293
296