@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.
- package/README.md +1 -1
- package/dist/commands/login.js +52 -12
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/payables.js +220 -0
- package/dist/commands/payables.js.map +1 -0
- package/dist/index.js +77 -1
- package/dist/index.js.map +1 -1
- package/dist/surface.js +31 -13
- package/dist/surface.js.map +1 -1
- package/package.json +2 -2
- package/templates/bills-agent/README.md +2 -2
- package/templates/bills-agent/agents/bills-agent/.env.example +2 -2
- package/templates/bills-agent/agents/bills-agent/README.md +25 -18
- package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +13 -3
- package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -1
- package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/mandate.example.json +1 -1
- package/templates/bills-agent/agents/bills-agent/runbook.md +1 -1
- package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.transcript.jsonl +4 -4
- package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.json +1 -1
- package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.transcript.jsonl +4 -4
- package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/src/bills.ts +1 -1
- package/templates/bills-agent/agents/bills-agent/src/kit.ts +15 -28
- package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +42 -15
- package/templates/bills-agent/agents/bills-agent/src/modules/pix-out.ts +21 -3
- package/templates/bills-agent/agents/bills-agent/src/strings.ts +68 -0
- package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +130 -2
- package/templates/bills-agent/agents/bills-agent/test/consent-money.test.ts +25 -0
- package/templates/bills-agent/agents/bills-agent/test/dates-and-approval.test.ts +98 -0
- package/templates/bills-agent/agents/bills-agent/test/eval-runs.test.ts +81 -0
- package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -2
- package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +1 -1
- package/templates/bills-agent/agents/bills-agent/test/locale.test.ts +161 -0
- package/templates/bills-agent/agents/bills-agent/test/mandate-state.test.ts +108 -0
- package/templates/bills-agent/agents/bills-agent/test/refused-before-draft.test.ts +81 -0
- package/templates/bills-agent/agents/bills-agent/test/replay.test.ts +76 -0
- package/templates/bills-agent/agents/bills-agent/test/reply-and-outcome.test.ts +84 -0
- package/templates/bills-agent/agents/bills-agent/test/reply-language.test.ts +95 -0
- package/templates/bills-agent/agents/bills-agent/test/rerun-and-missing-transcript.test.ts +120 -0
- package/templates/bills-agent/agents/bills-agent/test/rerun-world-events.test.ts +55 -0
- package/templates/bills-agent/agents/bills-agent/tools.json +1 -1
- package/templates/bills-agent/packages/agent-core/README.md +21 -2
- package/templates/bills-agent/packages/agent-core/package.json +1 -1
- package/templates/bills-agent/packages/agent-core/src/agent.ts +33 -6
- package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
- package/templates/bills-agent/packages/agent-core/src/api/rail.ts +11 -5
- package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
- package/templates/bills-agent/packages/agent-core/src/bundle.ts +2 -0
- package/templates/bills-agent/packages/agent-core/src/channels.ts +18 -8
- package/templates/bills-agent/packages/agent-core/src/check.ts +25 -3
- package/templates/bills-agent/packages/agent-core/src/engine.ts +90 -9
- package/templates/bills-agent/packages/agent-core/src/escalate.ts +10 -0
- package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/bills-agent/packages/agent-core/src/language.ts +52 -0
- package/templates/bills-agent/packages/agent-core/src/locale.ts +88 -0
- package/templates/bills-agent/packages/agent-core/src/manifest.ts +4 -1
- package/templates/bills-agent/packages/agent-core/src/rail.ts +29 -1
- package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +30 -2
- package/templates/bills-agent/packages/agent-core/src/secrets.ts +53 -8
- package/templates/bills-agent/packages/agent-core/src/state-machine.ts +14 -0
- package/templates/bills-agent/packages/agent-core/src/strings.ts +175 -0
- package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
- package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +7 -4
- package/templates/bills-agent/packages/agent-core/src/types.ts +15 -2
- package/templates/bills-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
- package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
- package/templates/bills-agent/packages/agent-core/test/engine.test.ts +23 -0
- package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/bills-agent/packages/agent-core/test/language.test.ts +40 -0
- package/templates/bills-agent/packages/agent-core/test/locale.test.ts +137 -0
- package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
- package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/bills-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
- package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
- package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +49 -0
- package/templates/bills-agent/packages/agent-core/test/recorded-turns.ts +29 -0
- package/templates/bills-agent/packages/agent-core/test/secrets.test.ts +40 -1
- package/templates/bills-agent/packages/agent-runtime/README.md +31 -4
- package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
- package/templates/bills-agent/packages/agent-runtime/src/cli.ts +30 -4
- package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +18 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
- package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
- package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
- package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
- package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
- package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +48 -17
- package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
- package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
- package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +52 -22
- package/templates/bills-agent/packages/agent-runtime/src/env.ts +64 -0
- package/templates/bills-agent/packages/agent-runtime/src/index.ts +2 -0
- package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +81 -10
- package/templates/bills-agent/packages/agent-runtime/src/kit.ts +34 -12
- package/templates/bills-agent/packages/agent-runtime/src/outcome.ts +118 -0
- package/templates/bills-agent/packages/agent-runtime/src/poll.ts +7 -7
- package/templates/bills-agent/packages/agent-runtime/src/runs.ts +51 -0
- package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +55 -8
- package/templates/bills-agent/packages/agent-runtime/src/setup.ts +75 -5
- package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +71 -33
- package/templates/bills-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
- package/templates/bills-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
- package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
- package/templates/bills-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
- package/templates/bills-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
- package/templates/bills-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
- package/templates/bills-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
- package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
- package/templates/checkout-agent/README.md +2 -2
- package/templates/checkout-agent/agents/checkout-agent/.env.example +6 -4
- package/templates/checkout-agent/agents/checkout-agent/README.md +16 -8
- package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +17 -7
- package/templates/checkout-agent/agents/checkout-agent/agent.yaml +4 -3
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +2 -2
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +48 -4
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/package.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/runbook.md +4 -4
- package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +3 -3
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +7 -7
- package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +47 -43
- package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +20 -12
- package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +4 -4
- package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +9 -6
- package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +44 -41
- package/templates/checkout-agent/agents/checkout-agent/src/strings.ts +179 -0
- package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +4 -1
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +2 -2
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +1 -1
- package/templates/checkout-agent/agents/checkout-agent/test/payable-instrument.test.ts +58 -0
- package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +2 -2
- package/templates/checkout-agent/agents/checkout-agent/test/rerun-unpaid.test.ts +47 -0
- package/templates/checkout-agent/agents/checkout-agent/test/scenario-reach-and-seconds.test.ts +55 -0
- package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +26 -10
- package/templates/checkout-agent/agents/checkout-agent/tools.json +1 -1
- package/templates/checkout-agent/packages/agent-core/README.md +21 -2
- package/templates/checkout-agent/packages/agent-core/package.json +1 -1
- package/templates/checkout-agent/packages/agent-core/src/agent.ts +33 -6
- package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
- package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +11 -5
- package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
- package/templates/checkout-agent/packages/agent-core/src/bundle.ts +2 -0
- package/templates/checkout-agent/packages/agent-core/src/channels.ts +18 -8
- package/templates/checkout-agent/packages/agent-core/src/check.ts +25 -3
- package/templates/checkout-agent/packages/agent-core/src/engine.ts +90 -9
- package/templates/checkout-agent/packages/agent-core/src/escalate.ts +10 -0
- package/templates/checkout-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/checkout-agent/packages/agent-core/src/language.ts +52 -0
- package/templates/checkout-agent/packages/agent-core/src/locale.ts +88 -0
- package/templates/checkout-agent/packages/agent-core/src/manifest.ts +4 -1
- package/templates/checkout-agent/packages/agent-core/src/rail.ts +29 -1
- package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +30 -2
- package/templates/checkout-agent/packages/agent-core/src/secrets.ts +53 -8
- package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +14 -0
- package/templates/checkout-agent/packages/agent-core/src/strings.ts +175 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
- package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +7 -4
- package/templates/checkout-agent/packages/agent-core/src/types.ts +15 -2
- package/templates/checkout-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
- package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
- package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +23 -0
- package/templates/checkout-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/checkout-agent/packages/agent-core/test/language.test.ts +40 -0
- package/templates/checkout-agent/packages/agent-core/test/locale.test.ts +137 -0
- package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
- package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/checkout-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
- package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +49 -0
- package/templates/checkout-agent/packages/agent-core/test/recorded-turns.ts +29 -0
- package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +40 -1
- package/templates/checkout-agent/packages/agent-runtime/README.md +31 -4
- package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
- package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +30 -4
- package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +18 -2
- package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
- package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
- package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
- package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
- package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +48 -17
- package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
- package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
- package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +52 -22
- package/templates/checkout-agent/packages/agent-runtime/src/env.ts +64 -0
- package/templates/checkout-agent/packages/agent-runtime/src/index.ts +2 -0
- package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +81 -10
- package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +34 -12
- package/templates/checkout-agent/packages/agent-runtime/src/outcome.ts +118 -0
- package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +7 -7
- package/templates/checkout-agent/packages/agent-runtime/src/runs.ts +51 -0
- package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +55 -8
- package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +75 -5
- package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +71 -33
- package/templates/checkout-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
- package/templates/checkout-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
- package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
- package/templates/checkout-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
- package/templates/checkout-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
- package/templates/checkout-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
- package/templates/checkout-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
- package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
- package/templates/collections-agent/README.md +2 -2
- package/templates/collections-agent/agents/collections-agent/.env.example +6 -3
- package/templates/collections-agent/agents/collections-agent/README.md +14 -9
- package/templates/collections-agent/agents/collections-agent/SYSTEM_PROMPT.md +16 -5
- package/templates/collections-agent/agents/collections-agent/agent.yaml +4 -3
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +21 -4
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +49 -5
- package/templates/collections-agent/agents/collections-agent/mandate.example.json +1 -1
- package/templates/collections-agent/agents/collections-agent/runbook.md +3 -3
- package/templates/collections-agent/agents/collections-agent/src/agreements.ts +1 -1
- package/templates/collections-agent/agents/collections-agent/src/envelope.ts +15 -13
- package/templates/collections-agent/agents/collections-agent/src/kit.ts +38 -35
- package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +16 -8
- package/templates/collections-agent/agents/collections-agent/src/strings.ts +91 -0
- package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +2 -2
- package/templates/collections-agent/agents/collections-agent/test/check.test.ts +4 -1
- package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +1 -1
- package/templates/collections-agent/agents/collections-agent/test/envelope.test.ts +2 -2
- package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1103.transcript.jsonl +1 -1
- package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +1 -1
- package/templates/collections-agent/agents/collections-agent/test/payable-instrument.test.ts +56 -0
- package/templates/collections-agent/agents/collections-agent/test/rerun-clock.test.ts +54 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +69 -2
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +16 -3
- package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +16 -4
- package/templates/collections-agent/agents/collections-agent/tools.json +2 -2
- package/templates/collections-agent/packages/agent-core/README.md +21 -2
- package/templates/collections-agent/packages/agent-core/package.json +1 -1
- package/templates/collections-agent/packages/agent-core/src/agent.ts +33 -6
- package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
- package/templates/collections-agent/packages/agent-core/src/api/rail.ts +11 -5
- package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
- package/templates/collections-agent/packages/agent-core/src/bundle.ts +2 -0
- package/templates/collections-agent/packages/agent-core/src/channels.ts +18 -8
- package/templates/collections-agent/packages/agent-core/src/check.ts +25 -3
- package/templates/collections-agent/packages/agent-core/src/engine.ts +90 -9
- package/templates/collections-agent/packages/agent-core/src/escalate.ts +10 -0
- package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/collections-agent/packages/agent-core/src/language.ts +52 -0
- package/templates/collections-agent/packages/agent-core/src/locale.ts +88 -0
- package/templates/collections-agent/packages/agent-core/src/manifest.ts +4 -1
- package/templates/collections-agent/packages/agent-core/src/rail.ts +29 -1
- package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +30 -2
- package/templates/collections-agent/packages/agent-core/src/secrets.ts +53 -8
- package/templates/collections-agent/packages/agent-core/src/state-machine.ts +14 -0
- package/templates/collections-agent/packages/agent-core/src/strings.ts +175 -0
- package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
- package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +7 -4
- package/templates/collections-agent/packages/agent-core/src/types.ts +15 -2
- package/templates/collections-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
- package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
- package/templates/collections-agent/packages/agent-core/test/engine.test.ts +23 -0
- package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/collections-agent/packages/agent-core/test/language.test.ts +40 -0
- package/templates/collections-agent/packages/agent-core/test/locale.test.ts +137 -0
- package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
- package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/collections-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
- package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
- package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +49 -0
- package/templates/collections-agent/packages/agent-core/test/recorded-turns.ts +29 -0
- package/templates/collections-agent/packages/agent-core/test/secrets.test.ts +40 -1
- package/templates/collections-agent/packages/agent-runtime/README.md +31 -4
- package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
- package/templates/collections-agent/packages/agent-runtime/src/cli.ts +30 -4
- package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +18 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
- package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
- package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
- package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
- package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
- package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +48 -17
- package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
- package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
- package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +52 -22
- package/templates/collections-agent/packages/agent-runtime/src/env.ts +64 -0
- package/templates/collections-agent/packages/agent-runtime/src/index.ts +2 -0
- package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +81 -10
- package/templates/collections-agent/packages/agent-runtime/src/kit.ts +34 -12
- package/templates/collections-agent/packages/agent-runtime/src/outcome.ts +118 -0
- package/templates/collections-agent/packages/agent-runtime/src/poll.ts +7 -7
- package/templates/collections-agent/packages/agent-runtime/src/runs.ts +51 -0
- package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +55 -8
- package/templates/collections-agent/packages/agent-runtime/src/setup.ts +75 -5
- package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +71 -33
- package/templates/collections-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
- package/templates/collections-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
- package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
- package/templates/collections-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
- package/templates/collections-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
- package/templates/collections-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
- package/templates/collections-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
- package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
- package/templates/hello-agent/README.md +2 -2
- package/templates/hello-agent/agents/hello-agent/README.md +6 -0
- package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +27 -13
- package/templates/hello-agent/agents/hello-agent/agent.yaml +2 -1
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
- package/templates/hello-agent/agents/hello-agent/mandate.example.json +1 -1
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +1 -1
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +1 -1
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +1 -1
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
- package/templates/hello-agent/agents/hello-agent/src/bills.ts +9 -5
- package/templates/hello-agent/agents/hello-agent/src/kit.ts +4 -1
- package/templates/hello-agent/agents/hello-agent/tools.json +1 -1
- package/templates/hello-agent/packages/agent-core/README.md +21 -2
- package/templates/hello-agent/packages/agent-core/package.json +1 -1
- package/templates/hello-agent/packages/agent-core/src/agent.ts +33 -6
- package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
- package/templates/hello-agent/packages/agent-core/src/api/rail.ts +11 -5
- package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
- package/templates/hello-agent/packages/agent-core/src/bundle.ts +2 -0
- package/templates/hello-agent/packages/agent-core/src/channels.ts +18 -8
- package/templates/hello-agent/packages/agent-core/src/check.ts +25 -3
- package/templates/hello-agent/packages/agent-core/src/engine.ts +90 -9
- package/templates/hello-agent/packages/agent-core/src/escalate.ts +10 -0
- package/templates/hello-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/hello-agent/packages/agent-core/src/language.ts +52 -0
- package/templates/hello-agent/packages/agent-core/src/locale.ts +88 -0
- package/templates/hello-agent/packages/agent-core/src/manifest.ts +4 -1
- package/templates/hello-agent/packages/agent-core/src/rail.ts +29 -1
- package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +30 -2
- package/templates/hello-agent/packages/agent-core/src/secrets.ts +53 -8
- package/templates/hello-agent/packages/agent-core/src/state-machine.ts +14 -0
- package/templates/hello-agent/packages/agent-core/src/strings.ts +175 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
- package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +7 -4
- package/templates/hello-agent/packages/agent-core/src/types.ts +15 -2
- package/templates/hello-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
- package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
- package/templates/hello-agent/packages/agent-core/test/engine.test.ts +23 -0
- package/templates/hello-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/hello-agent/packages/agent-core/test/language.test.ts +40 -0
- package/templates/hello-agent/packages/agent-core/test/locale.test.ts +137 -0
- package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
- package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/hello-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
- package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +49 -0
- package/templates/hello-agent/packages/agent-core/test/recorded-turns.ts +29 -0
- package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +40 -1
- package/templates/hello-agent/packages/agent-runtime/README.md +31 -4
- package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
- package/templates/hello-agent/packages/agent-runtime/src/cli.ts +30 -4
- package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +18 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
- package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
- package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
- package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
- package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
- package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +48 -17
- package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
- package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
- package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +52 -22
- package/templates/hello-agent/packages/agent-runtime/src/env.ts +64 -0
- package/templates/hello-agent/packages/agent-runtime/src/index.ts +2 -0
- package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +81 -10
- package/templates/hello-agent/packages/agent-runtime/src/kit.ts +34 -12
- package/templates/hello-agent/packages/agent-runtime/src/outcome.ts +118 -0
- package/templates/hello-agent/packages/agent-runtime/src/poll.ts +7 -7
- package/templates/hello-agent/packages/agent-runtime/src/runs.ts +51 -0
- package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +55 -8
- package/templates/hello-agent/packages/agent-runtime/src/setup.ts +75 -5
- package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +71 -33
- package/templates/hello-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
- package/templates/hello-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
- package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
- package/templates/hello-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
- package/templates/hello-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
- package/templates/hello-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
- package/templates/hello-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
- package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
- package/templates/kits.lock.json +12 -12
- package/templates/supplier-payments-agent/README.md +2 -2
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +2 -2
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +12 -7
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +14 -3
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +2 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +3 -3
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +5 -5
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +5 -5
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +37 -26
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +41 -14
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +12 -3
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +8 -8
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +75 -10
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/locale.test.ts +101 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/run-outcome.test.ts +127 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -2
- package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +33 -6
- package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +11 -5
- package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +2 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +18 -8
- package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +90 -9
- package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +10 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/language.ts +52 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/locale.ts +88 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +4 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +29 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +30 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +53 -8
- package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +14 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/strings.ts +175 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +7 -4
- package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +15 -2
- package/templates/supplier-payments-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
- package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +23 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/test/language.test.ts +40 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/locale.test.ts +137 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
- package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/supplier-payments-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +49 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/recorded-turns.ts +29 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +40 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/README.md +31 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
- package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +30 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +18 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +48 -17
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +52 -22
- package/templates/supplier-payments-agent/packages/agent-runtime/src/env.ts +64 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +2 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +81 -10
- package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +34 -12
- package/templates/supplier-payments-agent/packages/agent-runtime/src/outcome.ts +118 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +7 -7
- package/templates/supplier-payments-agent/packages/agent-runtime/src/runs.ts +51 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +55 -8
- package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +75 -5
- package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +71 -33
- package/templates/supplier-payments-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* `codespar_charge` hands the proposal to the engine and gets an execution in
|
|
4
4
|
* `drafted` (then whatever the core decided); it cannot issue anything.
|
|
5
5
|
* `list_agreements` is a read. The real call (`POST /v1/charges`, one
|
|
6
|
-
*
|
|
6
|
+
* cobrança com vencimento per instalment, `idempotency_key` per attempt) is
|
|
7
7
|
* built by the rail from the execution the core approved.
|
|
8
8
|
*/
|
|
9
|
-
import type { ToolHandler } from "@codespar/agent-core";
|
|
9
|
+
import type { Locale, ToolHandler } from "@codespar/agent-core";
|
|
10
10
|
import { AGREEMENTS, agreementByAlias, formatBRL, formatDate } from "../agreements.js";
|
|
11
11
|
import type { Envelope } from "../envelope.js";
|
|
12
|
+
import { STRINGS } from "../strings.js";
|
|
12
13
|
|
|
13
14
|
interface ChargeInput {
|
|
14
15
|
action?: unknown;
|
|
@@ -18,8 +19,9 @@ interface ChargeInput {
|
|
|
18
19
|
execution_id?: unknown;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export function makeHandlers(envelope: Envelope): Record<string, ToolHandler> {
|
|
22
|
+
export function makeHandlers(envelope: Envelope, locale: () => Locale = () => "pt-BR"): Record<string, ToolHandler> {
|
|
22
23
|
const listAgreements: ToolHandler = async (_input, ctx) => {
|
|
24
|
+
const text = STRINGS[locale()];
|
|
23
25
|
const settled = ctx.engine.list({ state: "settled" });
|
|
24
26
|
const open = ctx.engine.list({ state: "executing" });
|
|
25
27
|
// Issued, then its reference turned ambiguous: the charge exists and may be paid. Not open, and the core refuses another until it is reconciled.
|
|
@@ -28,6 +30,8 @@ export function makeHandlers(envelope: Envelope): Record<string, ToolHandler> {
|
|
|
28
30
|
const settledAliases = new Set(settled.flatMap((e) => e.items.map((i) => i.alias)).filter(Boolean));
|
|
29
31
|
const issuedAliases = new Set(open.flatMap((e) => e.items.map((i) => i.alias)).filter(Boolean));
|
|
30
32
|
return {
|
|
33
|
+
// Due dates are proposed by the model inside `due_date_window_days` of today; it has no calendar but this one.
|
|
34
|
+
today: ctx.engine.today(),
|
|
31
35
|
agreements: AGREEMENTS.map((a) => ({
|
|
32
36
|
alias: a.alias,
|
|
33
37
|
debtor_first_name: a.first_name,
|
|
@@ -36,12 +40,12 @@ export function makeHandlers(envelope: Envelope): Record<string, ToolHandler> {
|
|
|
36
40
|
origin: a.origin,
|
|
37
41
|
opened_at: a.opened_at,
|
|
38
42
|
status: settledAliases.has(a.alias)
|
|
39
|
-
?
|
|
43
|
+
? text.statusSettled
|
|
40
44
|
: issuedAliases.has(a.alias)
|
|
41
|
-
?
|
|
45
|
+
? text.statusIssued
|
|
42
46
|
: unreconciledAliases.has(a.alias)
|
|
43
|
-
?
|
|
44
|
-
:
|
|
47
|
+
? text.statusUnreconciled
|
|
48
|
+
: text.statusOpen,
|
|
45
49
|
})),
|
|
46
50
|
envelope: {
|
|
47
51
|
max_discount_pct: envelope.max_discount_pct,
|
|
@@ -82,7 +86,11 @@ export function makeHandlers(envelope: Envelope): Record<string, ToolHandler> {
|
|
|
82
86
|
const claimed = typeof input.total_minor === "number" ? { claimed_total: input.total_minor } : {};
|
|
83
87
|
|
|
84
88
|
const draft = await ctx.engine.draft({ items, ...claimed });
|
|
85
|
-
if (!draft.ok)
|
|
89
|
+
if (!draft.ok) {
|
|
90
|
+
// Refused before a draft: no execution will ever say so, and the run's count is taken from this.
|
|
91
|
+
ctx.onNotRun?.({ ref: alias, why: "refused", detail: draft.reason });
|
|
92
|
+
return { status: "refused", reason: draft.reason, message: draft.message, issued: false, paid: false };
|
|
93
|
+
}
|
|
86
94
|
const execution = await ctx.onExecution(draft.execution);
|
|
87
95
|
return describe(execution);
|
|
88
96
|
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this agent prints, per locale: the runner's words for it, the lines an
|
|
3
|
+
* execution reads as, the one message per outcome the debtor receives, and the
|
|
4
|
+
* refusal details the envelope writes. Every key exists in both entries (`npm
|
|
5
|
+
* run check`).
|
|
6
|
+
*
|
|
7
|
+
* The envelope's details and the agreement statuses are read by the model too,
|
|
8
|
+
* as tool results; the model explains them in the reply language whatever the
|
|
9
|
+
* locale. The reason CODES next to them (`outside_envelope`, `outside_hours`)
|
|
10
|
+
* are machine words and are the same in every locale.
|
|
11
|
+
*/
|
|
12
|
+
import type { LocaleTable } from "@codespar/agent-core";
|
|
13
|
+
import type { KitStrings } from "@codespar/agent-runtime";
|
|
14
|
+
|
|
15
|
+
const pt = {
|
|
16
|
+
mandateWord: "política",
|
|
17
|
+
receiptWord: "registro",
|
|
18
|
+
intro: 'Você é o pagador. Diga algo ("oi, recebi a mensagem sobre o acordo do pedido 1042"). Ctrl+D ou "sair" encerra.',
|
|
19
|
+
prompt: "pagador> ",
|
|
20
|
+
approveQuestion: " [operador] Aprovar a emissão desta cobrança? [s/N] ",
|
|
21
|
+
uncertainDispatch: " desfecho desconhecido no trilho; rode `npm run resume` para reconciliar (nunca repita a emissão)",
|
|
22
|
+
notAuthorized: "a política não autoriza",
|
|
23
|
+
waitingForPayer: (round: number) => ` aguardando o pagador... (${round} consultas)`,
|
|
24
|
+
|
|
25
|
+
agreementOf: (debtor: string, alias: string) => `acordo de ${debtor} (${alias})`,
|
|
26
|
+
instalmentLine: (instalment: number, count: number, amount: string, due: string) => `parcela ${instalment}/${count}: ${amount}, vence ${due}`,
|
|
27
|
+
chargeLine: (instalment: number) => `cobrança ${instalment}`,
|
|
28
|
+
|
|
29
|
+
toldSettled: (chargeIds: string) => `Recebemos, acordo quitado. Obrigado! (${chargeIds})`,
|
|
30
|
+
toldExpired: "A cobrança venceu sem pagamento. Se quiser, emito uma nova dentro das mesmas condições.",
|
|
31
|
+
toldCancelled: "A cobrança foi cancelada. Nada foi pago.",
|
|
32
|
+
toldAmbiguous: "A cobrança deste acordo já foi emitida e estamos conferindo a situação dela. Não pague de novo; te aviso assim que estiver conferida.",
|
|
33
|
+
toldFailed: (reason: string | undefined) => `Não consegui emitir a cobrança (${reason ?? "falha no trilho"}). Nada foi cobrado.`,
|
|
34
|
+
toldDenied: (reason: string | undefined) => `Não posso emitir nesses termos (${reason ?? "recusado"}).`,
|
|
35
|
+
toldUndecided: (state: string) => `A proposta expirou sem decisão (${state}).`,
|
|
36
|
+
|
|
37
|
+
statusSettled: "quitado",
|
|
38
|
+
statusIssued: "cobrança emitida, aguardando pagamento",
|
|
39
|
+
statusUnreconciled: "cobrança emitida, em conferência: não emitir outra",
|
|
40
|
+
statusOpen: "em aberto",
|
|
41
|
+
|
|
42
|
+
envelopeTooManyInstalments: (count: number, max: number) => `${count} parcelas; o envelope permite até ${max}`,
|
|
43
|
+
envelopeBelowFloor: (total: number, pct: number, principal: number, maxPct: number, floor: number) =>
|
|
44
|
+
`total ${total} é ${pct}% abaixo do principal ${principal}; o desconto máximo é ${maxPct}% (piso ${floor})`,
|
|
45
|
+
envelopeAbovePrincipal: (total: number, principal: number) => `total ${total} acima do principal ${principal}; não se cobra mais do que se deve`,
|
|
46
|
+
envelopeInstalmentTooSmall: (amount: number, min: number) => `parcela de ${amount} abaixo do mínimo ${min}`,
|
|
47
|
+
envelopeNoDueDate: (instalment: number) => `parcela ${instalment} sem vencimento`,
|
|
48
|
+
envelopeDuePassed: (due: string, instalment: number, today: string) => `vencimento ${due} da parcela ${instalment} já passou (hoje é ${today})`,
|
|
49
|
+
envelopeDueOutsideWindow: (due: string, instalment: number, days: number, last: string) => `vencimento ${due} da parcela ${instalment} fora da janela de ${days} dias (até ${last})`,
|
|
50
|
+
envelopeDueOutOfOrder: (instalment: number) => `parcela ${instalment} vence antes da anterior`,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const STRINGS: LocaleTable<typeof pt & KitStrings> = {
|
|
54
|
+
"pt-BR": pt,
|
|
55
|
+
en: {
|
|
56
|
+
mandateWord: "policy",
|
|
57
|
+
receiptWord: "record",
|
|
58
|
+
intro: 'You are the payer. Say something ("hi, I got the message about the agreement for order 1042"). Ctrl+D or "exit" ends.',
|
|
59
|
+
prompt: "payer> ",
|
|
60
|
+
approveQuestion: " [operator] Approve issuing this charge? [y/N] ",
|
|
61
|
+
uncertainDispatch: " outcome unknown on the rail; run `npm run resume` to reconcile (never repeat the issuance)",
|
|
62
|
+
notAuthorized: "the policy does not authorize it",
|
|
63
|
+
waitingForPayer: (round) => ` waiting for the payer... (${round} looks)`,
|
|
64
|
+
|
|
65
|
+
agreementOf: (debtor, alias) => `agreement of ${debtor} (${alias})`,
|
|
66
|
+
instalmentLine: (instalment, count, amount, due) => `instalment ${instalment}/${count}: ${amount}, due ${due}`,
|
|
67
|
+
chargeLine: (instalment) => `charge ${instalment}`,
|
|
68
|
+
|
|
69
|
+
toldSettled: (chargeIds) => `Payment received, the agreement is settled. Thank you! (${chargeIds})`,
|
|
70
|
+
toldExpired: "The charge reached its due date unpaid. If you like, I can issue a new one on the same terms.",
|
|
71
|
+
toldCancelled: "The charge was cancelled. Nothing was paid.",
|
|
72
|
+
toldAmbiguous: "The charge for this agreement was already issued and we are checking where it stands. Do not pay again; I will let you know as soon as it is checked.",
|
|
73
|
+
toldFailed: (reason) => `I could not issue the charge (${reason ?? "rail failure"}). Nothing was charged.`,
|
|
74
|
+
toldDenied: (reason) => `I cannot issue on those terms (${reason ?? "refused"}).`,
|
|
75
|
+
toldUndecided: (state) => `The proposal expired without a decision (${state}).`,
|
|
76
|
+
|
|
77
|
+
statusSettled: "settled",
|
|
78
|
+
statusIssued: "charge issued, awaiting payment",
|
|
79
|
+
statusUnreconciled: "charge issued, under review: do not issue another",
|
|
80
|
+
statusOpen: "open",
|
|
81
|
+
|
|
82
|
+
envelopeTooManyInstalments: (count, max) => `${count} instalments; the envelope allows up to ${max}`,
|
|
83
|
+
envelopeBelowFloor: (total, pct, principal, maxPct, floor) => `total ${total} is ${pct}% below the principal ${principal}; the maximum discount is ${maxPct}% (floor ${floor})`,
|
|
84
|
+
envelopeAbovePrincipal: (total, principal) => `total ${total} above the principal ${principal}; nobody is charged more than they owe`,
|
|
85
|
+
envelopeInstalmentTooSmall: (amount, min) => `instalment of ${amount} below the minimum ${min}`,
|
|
86
|
+
envelopeNoDueDate: (instalment) => `instalment ${instalment} has no due date`,
|
|
87
|
+
envelopeDuePassed: (due, instalment, today) => `due date ${due} of instalment ${instalment} has passed (today is ${today})`,
|
|
88
|
+
envelopeDueOutsideWindow: (due, instalment, days, last) => `due date ${due} of instalment ${instalment} is outside the ${days}-day window (until ${last})`,
|
|
89
|
+
envelopeDueOutOfOrder: (instalment) => `instalment ${instalment} falls due before the previous one`,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -36,7 +36,7 @@ describe("a receivable closed charge_reference_ambiguous: reconcile, never reiss
|
|
|
36
36
|
const handlers = s.kit.handlers(s);
|
|
37
37
|
const ctx = { engine: s.engine, onExecution: async (e: Execution) => e };
|
|
38
38
|
const listed = (await handlers["list_agreements"]!({}, ctx)) as { agreements: Array<{ alias: string; status: string }> };
|
|
39
|
-
expect(listed.agreements.find((a) => a.alias === "acordo-1042")?.status).toBe("
|
|
39
|
+
expect(listed.agreements.find((a) => a.alias === "acordo-1042")?.status).toBe("cobrança emitida, em conferência: não emitir outra");
|
|
40
40
|
|
|
41
41
|
const again = (await handlers["codespar_charge"]!({ action: "create", agreement: "acordo-1042", instalments: [{ amount_minor: 108000, due_date: "2026-10-15" }] }, ctx)) as Record<string, unknown>;
|
|
42
42
|
expect(again).toMatchObject({ status: "denied", reason: "charge_reference_ambiguous", issued: false, charges: [] });
|
|
@@ -46,7 +46,7 @@ describe("a receivable closed charge_reference_ambiguous: reconcile, never reiss
|
|
|
46
46
|
const told: string[] = [];
|
|
47
47
|
announceOutcome(closed, s, (l) => told.push(l));
|
|
48
48
|
expect(told).toHaveLength(1);
|
|
49
|
-
expect(told[0]).toContain("
|
|
49
|
+
expect(told[0]).toContain("já foi emitida");
|
|
50
50
|
expect(told[0]).not.toContain("Nada foi cobrado");
|
|
51
51
|
} finally {
|
|
52
52
|
s.close();
|
|
@@ -28,7 +28,10 @@ describe("npm run check: the manifest is the index", () => {
|
|
|
28
28
|
writeFileSync(join(dir, "tools.json"), JSON.stringify({ ...t, meta_tools: t.meta_tools.filter((x) => x.effect !== "charge") }));
|
|
29
29
|
expect(codes(dir)).toContain("tools_contradict_manifest");
|
|
30
30
|
const again = copyAgent();
|
|
31
|
-
|
|
31
|
+
const manifest = readFileSync(join(again, "agent.yaml"), "utf8");
|
|
32
|
+
const dropped = manifest.replace(/^ bolepix-receivables:.*\n/m, "");
|
|
33
|
+
expect(dropped).not.toBe(manifest);
|
|
34
|
+
writeFileSync(join(again, "agent.yaml"), dropped);
|
|
32
35
|
expect(codes(again)).toContain("tools_contradict_manifest");
|
|
33
36
|
});
|
|
34
37
|
|
|
@@ -72,7 +72,7 @@ describe("npm start -- --input ... --json", () => {
|
|
|
72
72
|
expect(payload.executions).toHaveLength(1);
|
|
73
73
|
expect(payload.executions[0]).toMatchObject({ state: "denied", reason: "outside_hours", charges: [] });
|
|
74
74
|
expect(payload.receipts).toHaveLength(0);
|
|
75
|
-
expect(out.stderr).toContain("agora
|
|
75
|
+
expect(out.stderr).toContain("agora são 20:08");
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it("at 14:00 America/Sao_Paulo the same command settles, whatever the wall clock says", () => {
|
|
@@ -28,11 +28,11 @@ describe("the negotiation envelope is deterministic code", () => {
|
|
|
28
28
|
expect(checkEnvelope(items([{ amount: 101999, due_date: "2026-09-30" }]), envelope, NOW, TZ)?.reason).toBe("outside_envelope");
|
|
29
29
|
expect(checkEnvelope(items([{ amount: 120001, due_date: "2026-09-30" }]), envelope, NOW, TZ)?.detail).toContain("acima do principal");
|
|
30
30
|
expect(checkEnvelope(items([{ amount: 30000, due_date: "2026-09-30" }, { amount: 30000, due_date: "2026-10-30" }, { amount: 30000, due_date: "2026-11-30" }, { amount: 30000, due_date: "2026-12-15" }]), envelope, NOW, TZ)?.detail).toContain("parcelas");
|
|
31
|
-
expect(checkEnvelope(items([{ amount: 118000, due_date: "2026-09-30" }, { amount: 2000, due_date: "2026-10-30" }]), envelope, NOW, TZ)?.detail).toContain("
|
|
31
|
+
expect(checkEnvelope(items([{ amount: 118000, due_date: "2026-09-30" }, { amount: 2000, due_date: "2026-10-30" }]), envelope, NOW, TZ)?.detail).toContain("mínimo");
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it("due dates: in the past, beyond the window, out of order, missing", () => {
|
|
35
|
-
expect(checkEnvelope(items([{ amount: 120000, due_date: "2026-09-22" }]), envelope, NOW, TZ)?.detail).toContain("
|
|
35
|
+
expect(checkEnvelope(items([{ amount: 120000, due_date: "2026-09-22" }]), envelope, NOW, TZ)?.detail).toContain("já passou");
|
|
36
36
|
expect(checkEnvelope(items([{ amount: 120000, due_date: "2026-12-23" }]), envelope, NOW, TZ)?.detail).toContain("fora da janela");
|
|
37
37
|
expect(checkEnvelope(items([{ amount: 120000, due_date: "2026-12-22" }]), envelope, NOW, TZ)).toBeUndefined();
|
|
38
38
|
expect(checkEnvelope(items([{ amount: 60000, due_date: "2026-10-30" }, { amount: 60000, due_date: "2026-09-30" }]), envelope, NOW, TZ)?.detail).toContain("antes da anterior");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{"kind": "assistant_step", "tool_calls": [{"id": "tc_1", "name": "codespar_charge", "input": {"action": "create", "agreement": "acordo-1103", "instalments": [{"amount_minor": 40500, "due_date": "2026-09-25"}], "total_minor": 40500}}]}
|
|
2
|
-
{"kind": "assistant_step", "reply": "A
|
|
2
|
+
{"kind": "assistant_step", "reply": "A cobrança venceu sem pagamento. Se quiser, emito uma nova."}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{"kind": "assistant_step", "tool_calls": [{"id": "tc_1", "name": "codespar_charge", "input": {"action": "create", "agreement": "acordo-1042", "instalments": [{"amount_minor": 108000, "due_date": "2026-09-30"}], "total_minor": 108000}}]}
|
|
2
|
-
{"kind": "assistant_step", "reply": "Pronto, Joana: emiti uma nova
|
|
2
|
+
{"kind": "assistant_step", "reply": "Pronto, Joana: emiti uma nova cobrança de R$ 1.080,00, vencendo em 30/09. O código está acima."}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The false green of OPEN_QUESTIONS §63: on staging (2026-09-27) the issuer
|
|
3
|
+
* ended the bolepix in ERROR, with no QR and no boleto line, and the run still
|
|
4
|
+
* answered `settled` with a cycle time, because the sandbox payer paid what
|
|
5
|
+
* nobody could have paid and the API's test route settled it (ent#1816). The
|
|
6
|
+
* stub scripts both halves here: an issuer that ends in ERROR, and a charge
|
|
7
|
+
* that is settled without ever becoming payable.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdtempSync, readFileSync } from "node:fs";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { describe, expect, it } from "vitest";
|
|
13
|
+
import { checkScenario, loadScenario, runScenario } from "@codespar/agent-runtime";
|
|
14
|
+
import { agent } from "../src/kit.js";
|
|
15
|
+
|
|
16
|
+
const runsDir = mkdtempSync(join(tmpdir(), "collections-payable-"));
|
|
17
|
+
/** The buyer the happy path issues to. */
|
|
18
|
+
const BUYER = "11144477735";
|
|
19
|
+
|
|
20
|
+
function events(bundleDir: string): Array<{ type: string; payload: Record<string, unknown> }> {
|
|
21
|
+
return readFileSync(join(bundleDir, "events.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l) as { type: string; payload: Record<string, unknown> });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("a cycle closes on a payable instrument, or it does not close", () => {
|
|
25
|
+
const scenario = loadScenario(agent, "happy-path");
|
|
26
|
+
|
|
27
|
+
it("an issuer that ends the registration in ERROR fails the order with the issuer's code: never settled, never paid, no cycle to boast of", async () => {
|
|
28
|
+
const run = await runScenario(agent, scenario, { mode: "human", runsDir, stubRail: { issuerErrorPayees: [BUYER] } });
|
|
29
|
+
expect(run.executions.map((e) => [e.state, e.reason])).toEqual([["failed", "charge_issuer_error"]]);
|
|
30
|
+
expect(run.settled_total).toBe(0);
|
|
31
|
+
expect(run.receipts).toBe(0);
|
|
32
|
+
expect(run.payer_calls).toEqual([]);
|
|
33
|
+
expect(run.executions[0]!.payable_seen).toBeNull();
|
|
34
|
+
const told = events(run.bundle_dir).filter((e) => e.type === "message.debtor").map((e) => String(e.payload["text"]));
|
|
35
|
+
expect(told).toEqual([expect.stringContaining("charge_issuer_error")]);
|
|
36
|
+
expect(told[0]).not.toMatch(/Recebemos/);
|
|
37
|
+
expect(checkScenario(scenario, run).ok).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("a charge settled with no payable instrument seen first is refused by the gate as no_payable_instrument, and no cycle is reported", async () => {
|
|
41
|
+
const run = await runScenario(agent, scenario, { mode: "human", runsDir, stubRail: { settlesUnpayablePayees: [BUYER] } });
|
|
42
|
+
expect(run.executions.map((e) => e.state)).toEqual(["settled"]);
|
|
43
|
+
expect(run.executions[0]!.payable_seen).toBe(false);
|
|
44
|
+
expect(run.cycle_seconds).toBeNull();
|
|
45
|
+
const check = checkScenario(scenario, run);
|
|
46
|
+
expect(check.ok).toBe(false);
|
|
47
|
+
expect(check.failures).toEqual([expect.stringMatching(/^no_payable_instrument: /)]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("the ordinary happy path saw its QR before the payment, and reports its cycle", async () => {
|
|
51
|
+
const run = await runScenario(agent, scenario, { mode: "human", runsDir });
|
|
52
|
+
expect(run.executions[0]!.payable_seen).toBe(true);
|
|
53
|
+
expect(run.cycle_seconds).toEqual(expect.any(Number));
|
|
54
|
+
expect(checkScenario(scenario, run).failures).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A rerun replays the run on the run's own clock. The scenario issues an
|
|
3
|
+
* instalment due 2026-09-30 on a run that started 2026-09-23; replayed on
|
|
4
|
+
* today's date the due date has passed, the envelope refuses the agreement,
|
|
5
|
+
* and the rerun reported a run that DIFFERS from one it had every byte of.
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { mkdtempSync } from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join, resolve } from "node:path";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import { ProofBundle } from "@codespar/agent-core";
|
|
13
|
+
import { loadScenario, runScenario } from "@codespar/agent-runtime";
|
|
14
|
+
import { agent } from "../src/kit.js";
|
|
15
|
+
|
|
16
|
+
const AGENT_DIR = resolve(import.meta.dirname, "..");
|
|
17
|
+
const BIN = resolve(AGENT_DIR, "../../packages/agent-runtime/bin.mjs");
|
|
18
|
+
|
|
19
|
+
function rerun(runsDir: string, runId: string, env: Record<string, string> = {}) {
|
|
20
|
+
const result = spawnSync(process.execPath, [BIN, "rerun", runId, "--json"], {
|
|
21
|
+
cwd: AGENT_DIR,
|
|
22
|
+
env: { ...process.env, ANTHROPIC_API_KEY: "", CODESPAR_API_KEY: "", CODESPAR_AGENT_NOW: "", COLLECTIONS_RUNS_DIR: runsDir, COLLECTIONS_STATE_DIR: join(runsDir, "state"), ...env },
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
timeout: 60_000,
|
|
25
|
+
});
|
|
26
|
+
return { code: result.status, stderr: result.stderr, report: JSON.parse(result.stdout.trim()) as { same_states: boolean; original: string[]; rerun: string[]; rerun_id: string } };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("npm run rerun <run-id> on a run from another day", () => {
|
|
30
|
+
it.each(["human", "mandate"] as const)("replays happy-path [%s] to the same states, on the clock the run started on", async (mode) => {
|
|
31
|
+
const runsDir = mkdtempSync(join(tmpdir(), "collections-rerun-clock-"));
|
|
32
|
+
const original = await runScenario(agent, loadScenario(agent, "happy-path"), { mode, rail: "stub", runsDir });
|
|
33
|
+
expect(original.executions.map((e) => e.state)).toEqual(["settled"]);
|
|
34
|
+
// The run is on the scenario's date, which is not today's: what a rerun used to ignore.
|
|
35
|
+
const startedAt = String(ProofBundle.open(runsDir, original.run_id)!.readMeta()!["started_at"]);
|
|
36
|
+
expect(startedAt.slice(0, 10)).toBe("2026-09-23");
|
|
37
|
+
expect(Math.abs(Date.now() - Date.parse(startedAt))).toBeGreaterThan(24 * 3600 * 1000);
|
|
38
|
+
|
|
39
|
+
const out = rerun(runsDir, original.run_id);
|
|
40
|
+
expect(out.stderr).not.toContain("já passou");
|
|
41
|
+
expect(out.report.rerun).toEqual(out.report.original);
|
|
42
|
+
expect(out.report.same_states).toBe(true);
|
|
43
|
+
expect(out.code).toBe(0);
|
|
44
|
+
// The rerun's own bundle says when it ran: where the original did.
|
|
45
|
+
expect(ProofBundle.open(runsDir, out.report.rerun_id)!.readMeta()!["started_at"]).toBe(startedAt);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("the run's clock wins over one the shell pins", async () => {
|
|
49
|
+
const runsDir = mkdtempSync(join(tmpdir(), "collections-rerun-clock-"));
|
|
50
|
+
const original = await runScenario(agent, loadScenario(agent, "happy-path"), { mode: "mandate", rail: "stub", runsDir });
|
|
51
|
+
const out = rerun(runsDir, original.run_id, { CODESPAR_AGENT_NOW: "2027-01-15T12:00:00.000Z" });
|
|
52
|
+
expect(out.report.same_states).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -118,10 +118,21 @@ function poll(env: Record<string, string>, extra: string[] = []) {
|
|
|
118
118
|
return { ...out, payload: JSON.parse(lines[0]!) as PollPayload };
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Every call this file makes to the emulator closes its connection. An agent
|
|
123
|
+
* run here is a `spawnSync`, which blocks this process's event loop for longer
|
|
124
|
+
* than the emulator's keep-alive (`Keep-Alive: timeout=5`), so fetch never gets
|
|
125
|
+
* to expire the socket it pooled; the next call writes to a socket the
|
|
126
|
+
* emulator already closed and dies `fetch failed … ECONNRESET`. A retry would
|
|
127
|
+
* hide that too, but `/_sim/clock` advances and `/_sim/status` marks: a call
|
|
128
|
+
* the emulator did receive, retried, would apply twice.
|
|
129
|
+
*/
|
|
130
|
+
const FRESH_CONNECTION = { connection: "close" } as const;
|
|
131
|
+
|
|
121
132
|
async function advanceConversationClock(hours: number) {
|
|
122
133
|
const response = await fetch(`${EMULATOR}/_sim/clock`, {
|
|
123
134
|
method: "POST",
|
|
124
|
-
headers: { "content-type": "application/json" },
|
|
135
|
+
headers: { "content-type": "application/json", ...FRESH_CONNECTION },
|
|
125
136
|
body: JSON.stringify({ advance_hours: hours }),
|
|
126
137
|
signal: AbortSignal.timeout(5000),
|
|
127
138
|
});
|
|
@@ -145,7 +156,7 @@ function countEvents(env: Record<string, string>, type: string): number {
|
|
|
145
156
|
|
|
146
157
|
const emulatorUp = await (async () => {
|
|
147
158
|
try {
|
|
148
|
-
return (await fetch(`${EMULATOR}/health`, { signal: AbortSignal.timeout(2000) })).ok;
|
|
159
|
+
return (await fetch(`${EMULATOR}/health`, { headers: FRESH_CONNECTION, signal: AbortSignal.timeout(2000) })).ok;
|
|
149
160
|
} catch {
|
|
150
161
|
return false;
|
|
151
162
|
}
|
|
@@ -252,7 +263,63 @@ describe.skipIf(!emulatorUp)("a charge paid after the 24-hour window closed", ()
|
|
|
252
263
|
});
|
|
253
264
|
});
|
|
254
265
|
|
|
266
|
+
/** The `payload` of every `message.debtor` event this state holds: which template, in which language. */
|
|
267
|
+
function debtorMessages(env: Record<string, string>): Array<Record<string, unknown>> {
|
|
268
|
+
const db = new DatabaseSync(join(env["COLLECTIONS_STATE_DIR"]!, "state.db"));
|
|
269
|
+
try {
|
|
270
|
+
return (db.prepare("SELECT payload FROM events WHERE type = 'message.debtor' ORDER BY seq").all() as Array<{ payload: string }>).map((r) => JSON.parse(r.payload) as Record<string, unknown>);
|
|
271
|
+
} finally {
|
|
272
|
+
db.close();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
describe.skipIf(!emulatorUp)("a conversation keeps the locale it started in (#64)", () => {
|
|
277
|
+
it("agreed in English, confirmed days later by the en_US copy of the template, and a --locale that disagrees is refused", async () => {
|
|
278
|
+
const env = scratch("locale-en");
|
|
279
|
+
const agreed = agent(
|
|
280
|
+
["start", "--channel", "whatsapp", "--conversation", "acordo-1042", "--scripted", "--mode", "mandate", "--transcript", AGREED, "--now", TUESDAY, "--locale", "en", "--json"],
|
|
281
|
+
{ ...env, COLLECTIONS_STUB_PAYER: "never" },
|
|
282
|
+
);
|
|
283
|
+
expect(agreed.code).toBe(3);
|
|
284
|
+
const opened = JSON.parse(agreed.stdout.split("\n").filter(Boolean).pop()!) as { channel: { log: string } };
|
|
285
|
+
// The line that introduces the payable code is the code's, so it is English; the QR and the code itself are the rail's.
|
|
286
|
+
const introduced = conversationOf(opened.channel.log).filter((l) => l.direction === "out" && l.kind === "text").map((l) => l.text ?? "");
|
|
287
|
+
expect(introduced.some((t) => /R\$1,080\.00, due 2026-09-30 — charge /.test(t))).toBe(true);
|
|
288
|
+
// The model's own replies are the recorded ones, in Portuguese; what must not be Portuguese is the code's line.
|
|
289
|
+
expect(introduced.some((t) => /, vence 30\/09\/2026 — cobrança /.test(t))).toBe(false);
|
|
290
|
+
|
|
291
|
+
await advanceConversationClock(ADVANCE_HOURS);
|
|
292
|
+
|
|
293
|
+
// Nothing is sent, nothing is paid: the refusal comes before the channel opens.
|
|
294
|
+
const conflicting = agent(["poll", "--channel", "whatsapp", "--conversation", "acordo-1042", "--json", "--simulate-payer", "--now", AFTER_WINDOW, "--locale", "pt-BR"], env);
|
|
295
|
+
expect(conflicting.code).toBe(2);
|
|
296
|
+
expect(conflicting.stderr).toContain("--locale pt-BR");
|
|
297
|
+
expect(debtorMessages(env)).toEqual([]);
|
|
298
|
+
|
|
299
|
+
// No flag: the poll takes the conversation's recorded locale.
|
|
300
|
+
const polled = poll(env, ["--simulate-payer", "--now", AFTER_WINDOW]);
|
|
301
|
+
expect(polled.code).toBe(0);
|
|
302
|
+
expect(polled.payload.polled[0]).toMatchObject({ state: "settled", session_open: false, delivery: { told: true, carrier: "template", template: "acordo_quitado" } });
|
|
303
|
+
expect(debtorMessages(env)).toEqual([expect.objectContaining({ template: "acordo_quitado", language: "en_US", variables: ["acordo-1042"] })]);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("the same conversation in the default locale is confirmed by the pt_BR copy", async () => {
|
|
307
|
+
const env = scratch("locale-pt");
|
|
308
|
+
expect(agree(env).code).toBe(3);
|
|
309
|
+
await advanceConversationClock(ADVANCE_HOURS);
|
|
310
|
+
const polled = poll(env, ["--simulate-payer", "--now", AFTER_WINDOW]);
|
|
311
|
+
expect(polled.payload.polled[0]!.delivery).toMatchObject({ told: true, template: "acordo_quitado" });
|
|
312
|
+
expect(debtorMessages(env)).toEqual([expect.objectContaining({ template: "acordo_quitado", language: "pt_BR" })]);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
255
316
|
describe("what the poll refuses to be asked, with no emulator in sight", () => {
|
|
317
|
+
it("refuses a --locale that is not one of the two", () => {
|
|
318
|
+
const out = agent(["poll", "--channel", "whatsapp", "--conversation", "acordo-1042", "--json", "--locale", "es"], scratch("locale-bad"));
|
|
319
|
+
expect(out.code).toBe(2);
|
|
320
|
+
expect(out.stderr).toContain("--locale must be pt-BR or en");
|
|
321
|
+
});
|
|
322
|
+
|
|
256
323
|
it("nothing waiting for a payer is a clean no-op, not an error: a cron that fails on an empty queue gets turned off", () => {
|
|
257
324
|
const env = scratch("noop");
|
|
258
325
|
const out = poll(env, ["--now", TUESDAY]);
|
package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts
CHANGED
|
@@ -25,9 +25,20 @@ const AFTER_WINDOW = new Date(new Date(TUESDAY).getTime() + 26 * 3600_000).toISO
|
|
|
25
25
|
const AGREED = "test/fixtures/agreed-1042-awaiting-payer.transcript.jsonl";
|
|
26
26
|
const CONTACT = "5511987654321";
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Every call this file makes to the emulator closes its connection. An agent
|
|
30
|
+
* run here is a `spawnSync`, which blocks this process's event loop for longer
|
|
31
|
+
* than the emulator's keep-alive (`Keep-Alive: timeout=5`), so fetch never gets
|
|
32
|
+
* to expire the socket it pooled; the next call writes to a socket the
|
|
33
|
+
* emulator already closed and dies `fetch failed … ECONNRESET`. A retry would
|
|
34
|
+
* hide that too, but `/_sim/clock` advances and `/_sim/status` marks: a call
|
|
35
|
+
* the emulator did receive, retried, would apply twice.
|
|
36
|
+
*/
|
|
37
|
+
const FRESH_CONNECTION = { connection: "close" } as const;
|
|
38
|
+
|
|
28
39
|
const emulatorUp = await (async () => {
|
|
29
40
|
try {
|
|
30
|
-
return (await fetch(`${EMULATOR}/health`, { signal: AbortSignal.timeout(2000) })).ok;
|
|
41
|
+
return (await fetch(`${EMULATOR}/health`, { headers: FRESH_CONNECTION, signal: AbortSignal.timeout(2000) })).ok;
|
|
31
42
|
} catch {
|
|
32
43
|
return false;
|
|
33
44
|
}
|
|
@@ -48,7 +59,7 @@ function run(args: string[], env: Record<string, string>) {
|
|
|
48
59
|
const lastJson = (stdout: string) => JSON.parse(stdout.split("\n").filter(Boolean).pop()!) as Record<string, unknown>;
|
|
49
60
|
|
|
50
61
|
async function sim(path: string, body?: unknown) {
|
|
51
|
-
const r = await fetch(`${EMULATOR}${path}`, body === undefined ? {} : { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
|
|
62
|
+
const r = await fetch(`${EMULATOR}${path}`, body === undefined ? { headers: FRESH_CONNECTION } : { method: "POST", headers: { "content-type": "application/json", ...FRESH_CONNECTION }, body: JSON.stringify(body) });
|
|
52
63
|
return (await r.json()) as Record<string, unknown>;
|
|
53
64
|
}
|
|
54
65
|
|
|
@@ -88,7 +99,9 @@ describe.skipIf(!emulatorUp)("§46 on the collections-agent, against the emulato
|
|
|
88
99
|
if (!template) await new Promise((r) => setTimeout(r, 50));
|
|
89
100
|
}
|
|
90
101
|
expect(template).toBeDefined();
|
|
91
|
-
|
|
102
|
+
// The emulator answers after its webhook did: a 200 here means the poll's receiver heard the failure inside its grace.
|
|
103
|
+
const marked = await sim("/_sim/status", { status: "failed", message_id: template, reason: "not on whatsapp" });
|
|
104
|
+
expect(marked["webhook"]).toMatchObject({ status: 200 });
|
|
92
105
|
|
|
93
106
|
expect(await exit).toBe(1);
|
|
94
107
|
const polled = (lastJson(stdout)["polled"] as Array<{ state: string; delivery: { told: boolean; reason?: string } }>)[0]!;
|
|
@@ -84,10 +84,19 @@ function conversationOf(payload: Payload): ChannelLine[] {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const EMULATOR = process.env["WHATSAPP_SIM_URL"] ?? "http://127.0.0.1:4290";
|
|
87
|
+
/**
|
|
88
|
+
* The probe closes its connection, as every emulator call in these tests does.
|
|
89
|
+
* An agent run here is a `spawnSync`, which blocks this process's event loop
|
|
90
|
+
* for longer than the emulator's keep-alive (`Keep-Alive: timeout=5`), so a
|
|
91
|
+
* pooled socket is never expired by fetch and the next call on it dies
|
|
92
|
+
* `fetch failed … ECONNRESET`. This file makes one call today; the header is
|
|
93
|
+
* here so the next one does not inherit a pooled socket.
|
|
94
|
+
*/
|
|
95
|
+
const FRESH_CONNECTION = { connection: "close" } as const;
|
|
87
96
|
/** Probed at module level: `describe.skipIf` is read when the file is collected, before any hook runs. */
|
|
88
97
|
const emulatorUp = await (async () => {
|
|
89
98
|
try {
|
|
90
|
-
return (await fetch(`${EMULATOR}/health`, { signal: AbortSignal.timeout(2000) })).ok;
|
|
99
|
+
return (await fetch(`${EMULATOR}/health`, { headers: FRESH_CONNECTION, signal: AbortSignal.timeout(2000) })).ok;
|
|
91
100
|
} catch {
|
|
92
101
|
return false;
|
|
93
102
|
}
|
|
@@ -127,7 +136,7 @@ describe.skipIf(!emulatorUp)("the cycle closes over the WhatsApp channel", () =>
|
|
|
127
136
|
const payload = payloadOf(out.stdout);
|
|
128
137
|
expect(payload.executions.map((e) => e.state)).toEqual(["settled"]);
|
|
129
138
|
// The question is the operator's and is on the console; nothing like it is in the conversation.
|
|
130
|
-
for (const line of conversationOf(payload)) expect(line.text ?? "").not.toMatch(/operador|Aprovar a
|
|
139
|
+
for (const line of conversationOf(payload)) expect(line.text ?? "").not.toMatch(/operador|Aprovar a emiss[aã]o/i);
|
|
131
140
|
});
|
|
132
141
|
|
|
133
142
|
it("writes the conversation into the bundle with the contact masked", () => {
|
|
@@ -150,8 +159,11 @@ describe.skipIf(!emulatorUp)("the cycle closes over the WhatsApp channel", () =>
|
|
|
150
159
|
const outbound = conversationOf(payload).filter((l) => l.direction === "out");
|
|
151
160
|
expect(outbound.some((l) => l.kind === "media")).toBe(true);
|
|
152
161
|
// The kit's one-per-outcome message, sent once however many looks carried the event.
|
|
153
|
-
// The model's own reply also says the charge expired, which is the terminal's behaviour too
|
|
154
|
-
|
|
162
|
+
// The model's own reply also says the charge expired, which is the terminal's behaviour too, and since #64 both
|
|
163
|
+
// spell "cobrança"; the kit's message is the one that carries the outcome it tells (`about`).
|
|
164
|
+
const told = outbound.filter((l) => (l as { about?: unknown }).about !== undefined);
|
|
165
|
+
expect(told.filter((l) => String(l.text ?? "").startsWith("A cobrança venceu sem pagamento"))).toHaveLength(1);
|
|
166
|
+
expect(told).toHaveLength(1);
|
|
155
167
|
});
|
|
156
168
|
|
|
157
169
|
it("refuses to say anything at all outside the collection hours, and issues nothing", () => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
{
|
|
4
4
|
"name": "codespar_charge",
|
|
5
5
|
"effect": "charge",
|
|
6
|
-
"description": "Propose the receivable(s) of an agreement the payer accepted: one instalment per bolepix (
|
|
6
|
+
"description": "Propose the receivable(s) of an agreement the payer accepted: one instalment per bolepix (cobrança com vencimento: the payer settles by Pix or by boleto). This does NOT issue anything: it creates an execution in `drafted` that the code checks against the collection policy and the negotiation envelope (discount ceiling, instalment count, due-date window, collection hours) and, depending on the approval mode, asks the operator or issues. The code builds the real call (`POST /v1/charges`, `method: boleto`, the debtor's name and document from the agreement, `idempotency_key` per instalment) and presents the QR and the copy-and-paste; you never see or pass a document. action=status reads back the state of a receivable this run issued.",
|
|
7
7
|
"input_schema": {
|
|
8
8
|
"type": "object",
|
|
9
9
|
"properties": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
{
|
|
34
34
|
"name": "list_agreements",
|
|
35
35
|
"effect": "read",
|
|
36
|
-
"description": "The open agreements this merchant collects: alias, debtor's first name, principal in BRL cents, origin, and the envelope you may negotiate inside (maximum discount, maximum instalments, due-date window). Read-only. Documents are not returned.",
|
|
36
|
+
"description": "The open agreements this merchant collects, with `today` (the date every due date is counted from): alias, debtor's first name, principal in BRL cents, origin, and the envelope you may negotiate inside (maximum discount, maximum instalments, due-date window). Read-only. Documents are not returned.",
|
|
37
37
|
"input_schema": { "type": "object", "properties": {} }
|
|
38
38
|
}
|
|
39
39
|
]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @codespar/agent-core
|
|
2
2
|
|
|
3
|
-
The primitives every CodeSpar starter-kit agent inherits (spec v5.1.1,
|
|
3
|
+
The primitives every CodeSpar starter-kit agent inherits (section 4 of spec v5.1.1, [`docs/spec-v5.1.1.md`](../../docs/spec-v5.1.1.md), the only spec version in this repository; [`docs/OPEN_QUESTIONS.md`](../../docs/OPEN_QUESTIONS.md) says where later parts were built against v5.2 and the checkout spec v0.2): the execution state machine, the approval artifact, the `agent.yaml` manifest, `escalate_above`, `actor`, local state in SQLite, the proof bundle, the rail contract, the conversation loop and the two providers.
|
|
4
4
|
|
|
5
|
-
This package is the decisions. The RUNNER around them — the terminal channel, `codespar-agent start|consent|approve|deny|resume|rerun|reconcile|poll|webhook|check|eval`, the setup that wires this package to an agent directory, and the scenario and adversarial runners — is [`@codespar/agent-runtime`](../agent-runtime), which depends on this one and is what an agent's `package.json` scripts call (#13). Nothing here knows an agent's name.
|
|
5
|
+
This package is the decisions. The RUNNER around them — the terminal channel, `codespar-agent start|consent|approve|deny|resume|rerun|reconcile|poll|webhook|inspect|check|eval|verify`, the setup that wires this package to an agent directory, and the scenario and adversarial runners — is [`@codespar/agent-runtime`](../agent-runtime), which depends on this one and is what an agent's `package.json` scripts call (#13). Nothing here knows an agent's name.
|
|
6
6
|
|
|
7
7
|
## The state machine, and what the types do and do not prove
|
|
8
8
|
|
|
@@ -25,10 +25,29 @@ This package is the decisions. The RUNNER around them — the terminal channel,
|
|
|
25
25
|
|
|
26
26
|
Every spend carries `approval: { items_hash, batch_hash? }`, the artifact's own hashes (`spendApprovalOf`), and the API seals them into the receipt's chain as a link of their own (chain v4, ent#1670). Both rails refuse a spend without them before any call. `composition` is not sent: the API takes the two hashes and nothing else, and only charges carry a composition today. `receipt-chain.ts` recomputes a chain from the receipt read under the `chain_recipe` the key document publishes (RFC 8785 implemented locally, `node:crypto` only), and `verifyReceiptRead` holds the signature, the body and the sealed approval link against the artifact, in that order. It proves WHAT was approved to anybody holding the read; WHO approved stays in the artifact, under the local key. `docs/OPEN_QUESTIONS.md` §3 and §47.
|
|
27
27
|
|
|
28
|
+
## Who acted, on the wire
|
|
29
|
+
|
|
30
|
+
Every spend sends the kit's actor as the SDK's `PaymentActor` (`wireActorOf` in `rail.ts`): an agent is `{ type: "agent", id: "<name>@<version>", on_behalf_of: <the mandate's consumer> }`, a person `{ type: "human", id, channel }`. `agent_id` still goes too; it names the agent the mandate was signed for. The rail reads the actor the API recorded back as `sealed_actor`, the bundle's receipt copy keeps it beside the kit's own `actor`, and one that differs from what was sent, or is missing, is a `receipt.actor_mismatch` event. It does not stop the run: the actor is what the receipt records, not what it proves. It is not in the chain, so a third party checking the Ed25519 signature learns nothing about who triggered the spend, and a charge carries no actor at all. §2.
|
|
31
|
+
|
|
32
|
+
## A settlement this run did not make
|
|
33
|
+
|
|
34
|
+
A spend presented again under the same attempt id is answered with the earlier payment (`idempotent_replay`). Dispatch marks that outcome `replayed: true`, and `isReplayedSettlement(execution)` is true when every settled attempt carries the mark. The money moved, and this execution did not move it. The execution is still `settled`. Only dispatch writes the mark, because dispatch is always this execution's first presentation of an id. Reconcile does not copy it: a lookup presents the attempt again, and the API answers every look at a settled attempt as a replay, this execution's own payment included. The tool results and a one-shot's `--json` read this predicate (`replayed`); `inspect` reads the same mark from the bundle's rail answers. An attempt closed by reconcile is still counted as paid by the execution that looked it up. §39c.
|
|
35
|
+
|
|
28
36
|
## Reconcile never re-dispatches
|
|
29
37
|
|
|
30
38
|
An execution left in `executing` is looked up on the rail, attempt by attempt. A recorded settled or failed outcome closes it; `in_flight`, `uncertain` or unknown leaves it in `executing` with `reason: rail_uncertain` for a human. The single exception is an outbox row still `pending` (the state changed, no call was ever made): those attempts go out once, under the same ids.
|
|
31
39
|
|
|
40
|
+
## The conversation loop
|
|
41
|
+
|
|
42
|
+
`AgentLoop.turn` (`agent.ts`) sends the model the system prompt, the conversation and the tool specs, and hands each tool call to the kit's handler for it; a tool outside `tools.json` is refused `tool_not_allowed`. Only the engine behind the handlers moves money. Two things it adds that no prompt can:
|
|
43
|
+
|
|
44
|
+
- **The reply language.** `detectLanguage` (`language.ts`) reads the language of what the person typed, Brazilian Portuguese or English, from function words; payee names, amounts and Pix keys count for neither. The loop appends a "Reply language for this turn" section naming it to the system prompt of every step of the turn. Tool results do not count: on the Messages API they are user-role messages, and a prompt rule alone lost to their Portuguese data. A turn with no lead either way keeps the previous turn's language, and before any lead the prompt's own default stands. The transcript's user line records `reply_language` (`null` before any lead). §64.
|
|
45
|
+
- **The date.** `ExecutionEngine.today()` is the date in the guardrails' timezone at the engine's clock, so `--now` pins it. `list_bills`, `list_payables` and `list_agreements` return it as `today`, and bills and payables also carry `days_until_due` (`daysUntil`), because the model has no calendar of its own.
|
|
46
|
+
|
|
47
|
+
## What the code prints, per locale
|
|
48
|
+
|
|
49
|
+
`locale.ts` and `strings.ts` (#64). A run has one locale, `pt-BR` or `en`: `--locale`, else the optional `locale:` of `agent.yaml`, else `pt-BR` (`resolveLocale`). `CORE_STRINGS` holds the lines every agent shares (the batch gesture, the waits, how an execution and a payable instrument read, the WhatsApp operator lines) in both locales, and `tableGaps` is what `npm run check` runs over it and over each kit's table: a key one locale lacks, an empty string, or a function whose arity differs is an error. `formatBRL` and `formatDay` format for the locale's reader ("R$ 1.850,00" / "R$1,850.00"; "30/09/2026" / "2026-09-30"). `WHATSAPP_LANGUAGE` maps a locale to the language Meta approves a template in (`pt_BR`, `en_US`); the template registry holds one copy per (name, language), and the check requires every template in the language of every locale. None of it touches what an answer decides, and it is independent of the reply language above.
|
|
50
|
+
|
|
32
51
|
## Stubs
|
|
33
52
|
|
|
34
53
|
`stubs/mandate-status.ts` (the section 4.7 status source for runs without a key: revocation, pause and the organization kill switch, over the local state.db) and `stubs/rail.ts` (the sandbox rail) are stand-ins for the CI, the scenarios and `rerun`, marked as such. With a test key the engine reads the mandate status from the API instead (`api/mandate-status.ts`, `GET /v1/mandates/{id}`), fail-closed: anything but `active` refuses `executing`, `org_paused: true` (the organization kill switch, ent#1648) refuses it whatever `status` says, and a read that does not answer, or answers without `org_paused`, is `mandate_status_unavailable`, never "assume active". The approval artifact is signed with a local development key (`approval.ts`); the API does not sign approval lists.
|