@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
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* The terminal channel: what `codespar-agent start` opens. No account, no
|
|
3
3
|
* server. It shows what the core decided, asks the person when an execution
|
|
4
4
|
* is awaiting approval, and prints where the sealed outcome landed. The
|
|
5
|
-
* words are the agent's (`kit.
|
|
6
|
-
*
|
|
5
|
+
* words are the agent's (`kit.strings`, `kit.describeExecution`) and the
|
|
6
|
+
* shared ones (`CORE_STRINGS`), in the run's locale; the order of the gates
|
|
7
|
+
* is the runner's and is the same for every agent, and so is what an answer
|
|
8
|
+
* decides: the parsers below read both languages whatever the locale.
|
|
7
9
|
*/
|
|
8
10
|
import { createInterface } from "node:readline/promises";
|
|
9
11
|
import { stdin, stderr, stdout } from "node:process";
|
|
10
12
|
import { relative } from "node:path";
|
|
11
|
-
import type
|
|
13
|
+
import { formatBRL, railErrorOf, type AgentRuntime, type BatchGesture, type BatchPresentation, type ChargeInstrument, type Execution, type NotRunLine } from "@codespar/agent-core";
|
|
12
14
|
import { pollUntilClosed, type PollResult } from "./poll.js";
|
|
13
|
-
import
|
|
15
|
+
import { draftRefusals, refusalLine, sayOutcome } from "./outcome.js";
|
|
16
|
+
import { inLocaleOf, type Setup } from "./setup.js";
|
|
14
17
|
|
|
15
18
|
export interface TerminalOptions {
|
|
16
19
|
setup: Setup;
|
|
@@ -69,7 +72,7 @@ export async function followUp(execution: Execution, setup: Setup, say: (line: s
|
|
|
69
72
|
|
|
70
73
|
function receiptLines(execution: Execution, setup: Setup, say: (line: string) => void): void {
|
|
71
74
|
for (const outcome of execution.outcomes) {
|
|
72
|
-
if (outcome.receipt_id) say(` ${setup.
|
|
75
|
+
if (outcome.receipt_id) say(` ${setup.strings.receiptWord}: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -78,7 +81,8 @@ export async function handleExecution(execution: Execution, options: TerminalOpt
|
|
|
78
81
|
const { setup, approver } = options;
|
|
79
82
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
80
83
|
const tell = options.tell ?? ((l: string) => stdout.write(l + "\n"));
|
|
81
|
-
const
|
|
84
|
+
const words = setup.strings;
|
|
85
|
+
const text = setup.coreStrings;
|
|
82
86
|
const engine = setup.engine;
|
|
83
87
|
|
|
84
88
|
for (const line of describeExecution(execution, setup)) say(line);
|
|
@@ -91,42 +95,43 @@ export async function handleExecution(execution: Execution, options: TerminalOpt
|
|
|
91
95
|
} else {
|
|
92
96
|
let decision = options.decision;
|
|
93
97
|
if (!decision) {
|
|
94
|
-
if (current.blocking_reasons.length > 0) say(
|
|
98
|
+
if (current.blocking_reasons.length > 0) say(text.onlyDeny);
|
|
95
99
|
const ask = options.ask ?? defaultAsk;
|
|
96
|
-
|
|
97
|
-
decision = answer === "s" || answer === "sim" || answer === "y" || answer === "yes" ? "approve" : "deny";
|
|
100
|
+
decision = parseApproval(await ask(words.approveQuestion));
|
|
98
101
|
}
|
|
99
102
|
if (decision === "approve") current = engine.approve(current.id, approver);
|
|
100
103
|
else if (decision === "deny") current = engine.deny(current.id, approver);
|
|
101
104
|
else {
|
|
102
|
-
say(
|
|
105
|
+
say(text.leftAwaiting);
|
|
103
106
|
return current;
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
|
-
say(
|
|
109
|
+
say(transitionLine(current));
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
// An agent that issues on request (`executeOnApproval: false`) leaves the approved execution for its own tool to issue.
|
|
110
113
|
if (current.state === "approved" && setup.kit.executeOnApproval !== false) {
|
|
111
114
|
current = await engine.execute(current.id);
|
|
112
|
-
say(
|
|
115
|
+
say(transitionLine(current));
|
|
113
116
|
if (setup.settlement === "immediate") {
|
|
114
117
|
receiptLines(current, setup, say);
|
|
115
|
-
if (current.state === "executing") say(
|
|
118
|
+
if (current.state === "executing") say(words.uncertainDispatch);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
if (setup.settlement === "await-payer") {
|
|
123
|
+
// The counterparty is spoken to in the locale of the run that proposed this execution (`npm run approve` is a later command); the operator's lines stay in this one's.
|
|
124
|
+
const counterparty = inLocaleOf(setup, current);
|
|
120
125
|
if (current.state === "executing" && current.reason === "awaiting_settlement") {
|
|
121
|
-
const result = await waitForPayer(current.id, options);
|
|
126
|
+
const result = await waitForPayer(current.id, { ...options, setup: counterparty });
|
|
122
127
|
current = result.execution;
|
|
123
|
-
say(
|
|
128
|
+
say(`${transitionLine(current)}${text.afterLooks(result.rounds, result.seconds, result.timed_out)}`);
|
|
124
129
|
receiptLines(current, setup, say);
|
|
125
130
|
} else if (current.state === "executing") {
|
|
126
|
-
say(
|
|
131
|
+
say(words.uncertainDispatch);
|
|
127
132
|
}
|
|
128
133
|
const told = current;
|
|
129
|
-
announceOutcome(told,
|
|
134
|
+
announceOutcome(told, counterparty, (line) => tell(line, told));
|
|
130
135
|
await followUp(current, setup, say);
|
|
131
136
|
}
|
|
132
137
|
return current;
|
|
@@ -150,6 +155,16 @@ function decideByGesture(execution: Execution, gesture: BatchGestureRecord, setu
|
|
|
150
155
|
return engine.approve(execution.id, approver);
|
|
151
156
|
}
|
|
152
157
|
|
|
158
|
+
/**
|
|
159
|
+
* What the person answered to the per-line question. Yes is s, sim, y or yes,
|
|
160
|
+
* in any locale; anything else is no, which is the default the `[s/N]` and
|
|
161
|
+
* `[y/N]` prompts show.
|
|
162
|
+
*/
|
|
163
|
+
export function parseApproval(answer: string): "approve" | "deny" {
|
|
164
|
+
const text = answer.trim().toLowerCase();
|
|
165
|
+
return text === "s" || text === "sim" || text === "y" || text === "yes" ? "approve" : "deny";
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
/**
|
|
154
169
|
* What the person answered to a whole list, or `undefined` when the answer
|
|
155
170
|
* cannot be read as one. Lines are numbered from 1, as they were shown.
|
|
@@ -181,28 +196,30 @@ export async function presentBatch(batch: BatchPresentation, options: TerminalOp
|
|
|
181
196
|
const { setup, approver } = options;
|
|
182
197
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
183
198
|
const ask = options.ask ?? defaultAsk;
|
|
184
|
-
|
|
199
|
+
const text = setup.coreStrings;
|
|
200
|
+
// The amounts are formatted here from their minor units, in the run's locale; the presentation's own strings are the model's.
|
|
201
|
+
say(text.batchHeader(batch.ref, batch.label, batch.count, formatBRL(batch.total_minor, setup.locale), batch.batch_hash.slice(0, 19)));
|
|
185
202
|
for (const line of batch.lines) {
|
|
186
203
|
const note =
|
|
187
204
|
line.status === "already_settled"
|
|
188
|
-
?
|
|
205
|
+
? text.batchAlreadySettled
|
|
189
206
|
: line.status === "in_progress"
|
|
190
|
-
?
|
|
207
|
+
? text.batchInProgress
|
|
191
208
|
: line.status === "attempt_id_conflict"
|
|
192
|
-
?
|
|
209
|
+
? text.batchAttemptConflict
|
|
193
210
|
: "";
|
|
194
|
-
say(` ${line.index + 1}. ${line.beneficiary}: ${line.
|
|
211
|
+
say(` ${line.index + 1}. ${line.beneficiary}: ${formatBRL(line.amount_minor, setup.locale)}${note}`);
|
|
195
212
|
}
|
|
196
213
|
let parsed: { vetoed: number[] } | undefined;
|
|
197
214
|
while (!parsed) {
|
|
198
|
-
parsed = parseBatchGesture(await ask(
|
|
199
|
-
if (!parsed) say(
|
|
215
|
+
parsed = parseBatchGesture(await ask(text.batchQuestion), batch.count);
|
|
216
|
+
if (!parsed) say(text.batchUnreadable(batch.count));
|
|
200
217
|
}
|
|
201
218
|
const vetoed = new Set(parsed.vetoed);
|
|
202
219
|
const gesture: BatchGesture = { batch_hash: batch.batch_hash, approved: batch.lines.map((l) => l.index).filter((i) => !vetoed.has(i)), vetoed: parsed.vetoed };
|
|
203
220
|
options.gestures.set(batch.ref, { batch_hash: batch.batch_hash, count: batch.count, vetoed });
|
|
204
221
|
setup.engine.note("batch.gesture", null, { batch_ref: batch.ref, batch_hash: batch.batch_hash, count: batch.count, total_minor: batch.total_minor, approved: gesture.approved, vetoed: gesture.vetoed, approver: { type: "human", id: approver.id, channel: approver.channel } });
|
|
205
|
-
say(
|
|
222
|
+
say(gesture.vetoed.length === 0 ? text.batchApprovedAll : gesture.approved.length === 0 ? text.batchDeniedAll : text.batchApprovedExcept(gesture.vetoed.map((i) => i + 1).join(", ")));
|
|
206
223
|
return gesture;
|
|
207
224
|
}
|
|
208
225
|
|
|
@@ -215,9 +232,9 @@ export async function waitForPayer(executionId: string, options: TerminalOptions
|
|
|
215
232
|
intervalMs: setup.pollIntervalMs,
|
|
216
233
|
timeoutMs: waitSeconds * 1000,
|
|
217
234
|
payer: options.simulatePayer ? setup.payer : undefined,
|
|
218
|
-
onInstrument: (e, n, id, instrument) => (options.presentInstrument ?? setup.kit.presentInstrument)?.(e, n, id, instrument, tell),
|
|
235
|
+
onInstrument: (e, n, id, instrument) => (options.presentInstrument ?? setup.kit.presentInstrument)?.(e, n, id, instrument, tell, setup.locale),
|
|
219
236
|
onWait: (_e, round) => {
|
|
220
|
-
const line = setup.
|
|
237
|
+
const line = setup.strings.waitingForPayer?.(round);
|
|
221
238
|
if (setup.railKind === "api" && line !== undefined && round % 5 === 0) say(line);
|
|
222
239
|
},
|
|
223
240
|
});
|
|
@@ -238,18 +255,20 @@ export function closeTerminal(): void {
|
|
|
238
255
|
export async function interactive(options: TerminalOptions & { runtime: AgentRuntime }): Promise<void> {
|
|
239
256
|
const { setup } = options;
|
|
240
257
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
241
|
-
const
|
|
258
|
+
const words = setup.strings;
|
|
242
259
|
// Interactive only: a person at the keyboard can decide a list in one go. The one-shot and the scenario runner pass one decision to every line and never reach this.
|
|
243
260
|
const gestures: BatchGestures = new Map();
|
|
244
261
|
const withGestures = { ...options, gestures };
|
|
245
262
|
const loop = setup.makeLoop(options.runtime, (execution) => handleExecution(execution, withGestures), (batch) => presentBatch(batch, withGestures));
|
|
246
|
-
say(
|
|
247
|
-
say(
|
|
248
|
-
say(
|
|
263
|
+
say(setup.coreStrings.banner(setup.manifest.manifest.name, setup.manifest.manifest.version, setup.mode, setup.railKind, words.mandateWord, setup.mandate.id));
|
|
264
|
+
say(setup.coreStrings.bundleAt(setup.runId, relative(process.cwd(), setup.bundle.dir)));
|
|
265
|
+
say(words.intro);
|
|
266
|
+
const notRun: NotRunLine[] = [];
|
|
267
|
+
let refusalsSaid = 0;
|
|
249
268
|
for (;;) {
|
|
250
269
|
let text: string;
|
|
251
270
|
try {
|
|
252
|
-
text = await defaultAsk(
|
|
271
|
+
text = await defaultAsk(words.prompt);
|
|
253
272
|
} catch {
|
|
254
273
|
break;
|
|
255
274
|
}
|
|
@@ -257,7 +276,26 @@ export async function interactive(options: TerminalOptions & { runtime: AgentRun
|
|
|
257
276
|
if (!trimmed) continue;
|
|
258
277
|
if (["sair", "exit", "quit"].includes(trimmed.toLowerCase())) break;
|
|
259
278
|
const result = await loop.turn(trimmed);
|
|
260
|
-
stdout.write(result.reply
|
|
279
|
+
stdout.write(`${result.reply}\n`);
|
|
280
|
+
// The line counts the run so far, and is said only after a turn that paid, tried to, or skipped a line: a greeting or a read moved nothing.
|
|
281
|
+
notRun.push(...result.not_run);
|
|
282
|
+
// A request refused before a draft: said with the engine's own reason, once, in the turn that met it.
|
|
283
|
+
const refused = draftRefusals(setup.store, setup.runId).slice(refusalsSaid);
|
|
284
|
+
refusalsSaid += refused.length;
|
|
285
|
+
for (const refusal of refused) say(refusalLine(refusal));
|
|
286
|
+
if (result.executions.length > 0 || result.not_run.length > 0 || refused.length > 0) sayOutcome(setup, notRun, (line) => stdout.write(`${line}\n`));
|
|
261
287
|
}
|
|
262
288
|
closeTerminal();
|
|
263
289
|
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* ` -> failed (rail_failed): insufficient_funds — wallet cannot reserve the requested amount`.
|
|
293
|
+
* The reason says which gate closed the execution; on a failure, or an answer
|
|
294
|
+
* that left an attempt unknown, the rail's own code and message follow it,
|
|
295
|
+
* verbatim, so the first failure explains itself (#50).
|
|
296
|
+
*/
|
|
297
|
+
export function transitionLine(execution: Execution): string {
|
|
298
|
+
const failure = execution.state === "failed" || execution.state === "executing" ? railErrorOf(execution) : null;
|
|
299
|
+
const answer = failure ? `: ${failure.code}${failure.message && failure.message !== failure.code ? ` — ${failure.message}` : ""}` : "";
|
|
300
|
+
return ` -> ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}${answer}`;
|
|
301
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit reads `CODESPAR_API_URL` and `CODESPAR_PROJECT_ID`; the CodeSpar CLI
|
|
3
|
+
* reads `CODESPAR_BASE_URL` and `CODESPAR_PROJECT`. A shell set up for one
|
|
4
|
+
* must not send the other to production in silence: the kit takes the CLI's
|
|
5
|
+
* names as aliases, and refuses to start when the two names disagree.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { EnvNamesDisagreeError, reconcileEnvNames } from "../src/env.js";
|
|
9
|
+
|
|
10
|
+
const STAGING = "https://api.staging.codespar.dev";
|
|
11
|
+
|
|
12
|
+
describe("reconcileEnvNames", () => {
|
|
13
|
+
it("fills the kit's names from the CLI's when only the CLI's are set", () => {
|
|
14
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_BASE_URL: STAGING, CODESPAR_PROJECT: "prj_cli" };
|
|
15
|
+
reconcileEnvNames(env);
|
|
16
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
17
|
+
expect(env["CODESPAR_PROJECT_ID"]).toBe("prj_cli");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("fills the CLI's names from the kit's too, so a .env read later cannot reopen a pair the shell closed", () => {
|
|
21
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_PROJECT_ID: "prj_kit" };
|
|
22
|
+
reconcileEnvNames(env);
|
|
23
|
+
expect(env["CODESPAR_BASE_URL"]).toBe(STAGING);
|
|
24
|
+
expect(env["CODESPAR_PROJECT"]).toBe("prj_kit");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("leaves the kit's names alone when the CLI's are unset or empty", () => {
|
|
28
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_BASE_URL: "", CODESPAR_PROJECT_ID: "prj_kit" };
|
|
29
|
+
reconcileEnvNames(env);
|
|
30
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
31
|
+
expect(env["CODESPAR_PROJECT_ID"]).toBe("prj_kit");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("treats an empty kit name as unset, as the CLI does with its own", () => {
|
|
35
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: "", CODESPAR_BASE_URL: STAGING };
|
|
36
|
+
reconcileEnvNames(env);
|
|
37
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("accepts both names when they say the same thing, a trailing slash aside", () => {
|
|
41
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_BASE_URL: `${STAGING}/`, CODESPAR_PROJECT_ID: "prj_1", CODESPAR_PROJECT: "prj_1" };
|
|
42
|
+
expect(() => reconcileEnvNames(env)).not.toThrow();
|
|
43
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("refuses two URLs that disagree, naming both", () => {
|
|
47
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: "https://api.codespar.dev", CODESPAR_BASE_URL: STAGING };
|
|
48
|
+
expect(() => reconcileEnvNames(env)).toThrow(EnvNamesDisagreeError);
|
|
49
|
+
expect(() => reconcileEnvNames(env)).toThrow(/CODESPAR_API_URL=https:\/\/api\.codespar\.dev.*CODESPAR_BASE_URL=https:\/\/api\.staging\.codespar\.dev/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("refuses two projects that disagree, naming both", () => {
|
|
53
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_PROJECT_ID: "prj_kit", CODESPAR_PROJECT: "prj_cli" };
|
|
54
|
+
expect(() => reconcileEnvNames(env)).toThrow(/CODESPAR_PROJECT_ID=prj_kit.*CODESPAR_PROJECT=prj_cli/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header of `inspect` and the mandate's status. The snapshot in the
|
|
3
|
+
* bundle is the local copy at the start of the run and says `active` for a
|
|
4
|
+
* mandate the API answered was revoked two lines below; the header says what
|
|
5
|
+
* a gate of the run heard, when that is the last word the run has.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
import { ProofBundle } from "@codespar/agent-core";
|
|
12
|
+
import { assembleTimeline, renderHtml, renderText } from "../src/inspect.js";
|
|
13
|
+
|
|
14
|
+
const AGENT = { type: "agent", agent: "bills-agent@0.1.0", on_behalf_of: "usr_demo_titular" };
|
|
15
|
+
const SNAPSHOT = "active in the snapshot at the start of the run";
|
|
16
|
+
|
|
17
|
+
type Step = { execution: string | null; to?: string; reason?: string; detail?: string; at: string };
|
|
18
|
+
|
|
19
|
+
function bundleOf(steps: Step[]): ProofBundle {
|
|
20
|
+
const bundle = new ProofBundle(mkdtempSync(join(tmpdir(), "inspect-mandate-status-")), "run_status_mandate_abc123");
|
|
21
|
+
bundle.meta({ run_id: bundle.runId, agent: "bills-agent@0.1.0", mode: "mandate", rail: "api", mandate_id: "cm_fixture", mandate_version: 1, started_at: "2026-09-23T18:00:00.000Z" });
|
|
22
|
+
writeFileSync(join(bundle.dir, "mandate.snapshot.json"), JSON.stringify({ id: "cm_fixture", version: 1, status: "active", currency: "BRL", cap_minor: 7200000, per_tx_cap_minor: 250000, expires_at: "2027-09-23T00:00:00.000Z", beneficiaries: [] }));
|
|
23
|
+
steps.forEach((step, i) => {
|
|
24
|
+
const payload = { ...(step.to ? { from: "approved", to: step.to, at: step.at, actor: AGENT } : {}), ...(step.reason ? { reason: step.reason } : {}), ...(step.detail ? { detail: step.detail } : {}) };
|
|
25
|
+
bundle.event({ seq: i + 1, run_id: bundle.runId, execution_id: step.execution, type: step.to ? "execution.transition" : "execution.refused_before_draft", payload, at: step.at, actor: AGENT });
|
|
26
|
+
});
|
|
27
|
+
return bundle;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const header = (bundle: ProofBundle) => renderText(assembleTimeline(bundle)).split("\n")[2];
|
|
31
|
+
|
|
32
|
+
describe("inspect: the mandate's status in the header", () => {
|
|
33
|
+
it("is the snapshot's when no gate of the run heard otherwise", () => {
|
|
34
|
+
const bundle = bundleOf([
|
|
35
|
+
{ execution: "exe_a", to: "executing", at: "2026-09-23T18:00:10.000Z" },
|
|
36
|
+
{ execution: "exe_a", to: "settled", at: "2026-09-23T18:00:12.000Z" },
|
|
37
|
+
]);
|
|
38
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
39
|
+
expect(header(bundle)).toMatch(/^ {2}mandate active, expires 2027-09-23T00:00:00.000Z · /);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("is what the API answered at the gate, with the source, the time and what the snapshot had said", () => {
|
|
43
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "denied", reason: "mandate_revoked", detail: "mandate cm_fixture was revoked (source: api)", at: "2026-09-23T18:00:13.000Z" }]);
|
|
44
|
+
const report = assembleTimeline(bundle);
|
|
45
|
+
expect(report.mandate).toMatchObject({ status: "active", status_seen: { status: "revoked", source: "api", at: "2026-09-23T18:00:13.000Z" } });
|
|
46
|
+
expect(header(bundle)).toContain(`mandate revoked (source: api, 18:00:13; ${SNAPSHOT}), expires `);
|
|
47
|
+
expect(header(bundle)).not.toContain("mandate active,");
|
|
48
|
+
// The page says the same thing as the terminal.
|
|
49
|
+
expect(renderHtml(report)).toContain(`mandate revoked (source: api, 18:00:13; ${SNAPSHOT}), expires `);
|
|
50
|
+
expect(renderHtml(report)).not.toContain("mandate active,");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("reads a refusal before a draft the same way, and a paused mandate, and the stub", () => {
|
|
54
|
+
const refused = bundleOf([{ execution: null, reason: "mandate_revoked", detail: "mandate cm_fixture was revoked (source: stub)", at: "2026-09-23T18:02:00.000Z" }]);
|
|
55
|
+
expect(header(refused)).toContain(`mandate revoked (source: stub, 18:02:00; ${SNAPSHOT})`);
|
|
56
|
+
const paused = bundleOf([{ execution: "exe_a", to: "denied", reason: "mandate_paused", detail: "mandate cm_fixture is paused (source: api)", at: "2026-09-23T18:00:13.000Z" }]);
|
|
57
|
+
expect(header(paused)).toContain(`mandate paused (source: api, 18:00:13; ${SNAPSHOT})`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("an expiry the run's own clock found names the clock, not a source that never answered it", () => {
|
|
61
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "expired", reason: "mandate_expired", detail: "mandate cm_fixture expired at 2027-09-23T00:00:00.000Z", at: "2027-09-23T00:00:05.000Z" }]);
|
|
62
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toMatchObject({ status: "expired", source: null });
|
|
63
|
+
expect(header(bundle)).toContain(`mandate expired (by the run's clock, 00:00:05; ${SNAPSHOT})`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("a payment that executed after a pause is the last word: the mandate was resumed, and the header is the snapshot's again", () => {
|
|
67
|
+
const bundle = bundleOf([
|
|
68
|
+
{ execution: "exe_a", to: "denied", reason: "mandate_paused", detail: "mandate cm_fixture is paused (source: api)", at: "2026-09-23T18:00:13.000Z" },
|
|
69
|
+
{ execution: "exe_b", to: "executing", at: "2026-09-23T18:05:00.000Z" },
|
|
70
|
+
{ execution: "exe_b", to: "settled", at: "2026-09-23T18:05:02.000Z" },
|
|
71
|
+
]);
|
|
72
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
73
|
+
expect(header(bundle)).toContain("mandate active, expires ");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("a refusal that is not about the mandate's status leaves the header alone", () => {
|
|
77
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "denied", reason: "cap_exceeded", detail: "300000 is above the cap per payment", at: "2026-09-23T18:00:13.000Z" }]);
|
|
78
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -9,7 +9,7 @@ import { tmpdir } from "node:os";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { describe, expect, it } from "vitest";
|
|
11
11
|
import { ProofBundle } from "@codespar/agent-core";
|
|
12
|
-
import { assembleTimeline, redactorFor, renderHtml, renderText, VERIFY_NOTE } from "../src/inspect.js";
|
|
12
|
+
import { assembleTimeline, redactorFor, renderHtml, renderText, REPLAY_NOTE, VERIFY_NOTE } from "../src/inspect.js";
|
|
13
13
|
|
|
14
14
|
const ESCOLA = "financeiro@escola-aurora.example.com.br";
|
|
15
15
|
const MASKED = "fi***@escola-aurora.example.com.br";
|
|
@@ -150,7 +150,7 @@ describe("the timeline `inspect` assembles from a bundle", () => {
|
|
|
150
150
|
|
|
151
151
|
it("lists the receipts that came back, and the events that belong to no execution", () => {
|
|
152
152
|
const report = assembleTimeline(fixtureBundle());
|
|
153
|
-
expect(report.receipts).toEqual([{ receipt_id: "rcpt_one", file: "receipts/rcpt_one.json", state: "paid", amount_minor: 185000, payee: MASKED, money_moved: false, sandbox: true, at: "2026-09-23T18:00:22.000Z" }]);
|
|
153
|
+
expect(report.receipts).toEqual([{ receipt_id: "rcpt_one", file: "receipts/rcpt_one.json", state: "paid", amount_minor: 185000, payee: MASKED, money_moved: false, sandbox: true, at: "2026-09-23T18:00:22.000Z", replayed: false }]);
|
|
154
154
|
expect(report.executions.find((e) => e.execution_id === "exe_one")!.receipts).toEqual(["rcpt_one"]);
|
|
155
155
|
expect(report.run_events.map((e) => e.type)).toEqual(["execution.refused_before_draft", "tool.refused"]);
|
|
156
156
|
});
|
|
@@ -168,6 +168,67 @@ describe("the timeline `inspect` assembles from a bundle", () => {
|
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Issue #60: the rail answered a dispatch from an earlier presentation of the
|
|
173
|
+
* same attempt. Settled, and paid by somebody else. An attempt closed by a
|
|
174
|
+
* later look is the other case: the look cannot say whose payment it read, so
|
|
175
|
+
* it is never counted as a replay.
|
|
176
|
+
*/
|
|
177
|
+
function withReplays(): ProofBundle {
|
|
178
|
+
const bundle = fixtureBundle();
|
|
179
|
+
const run = "run_fixture_human_abc123";
|
|
180
|
+
for (const event of [
|
|
181
|
+
{ run_id: run, execution_id: "exe_three", type: "execution.drafted", payload: { items: [{ alias: "escola", beneficiary: "Escola Aurora", payee: ESCOLA, amount: 185000, currency: "BRL" }], total: 185000, mode: "mandate", batch: { ref: "folha", batch_hash: "sha256:abc", index: 0, count: 2 } }, at: "2026-09-23T18:03:00.000Z", actor: AGENT },
|
|
182
|
+
{ run_id: run, execution_id: "exe_three", type: "rail.dispatch", payload: { attempt_id: "ska_three", payee: ESCOLA, amount: 185000, rail: "stub", idempotency_key: "idk_three" }, at: "2026-09-23T18:03:01.000Z", actor: AGENT },
|
|
183
|
+
{ run_id: run, execution_id: "exe_three", type: "rail.outcome", payload: { attempt_id: "ska_three", status: "settled", transaction_id: "tx_earlier", receipt_id: "rcpt_earlier", money_moved: false, sandbox: true, idempotent_replay: true }, at: "2026-09-23T18:03:02.000Z", actor: AGENT },
|
|
184
|
+
{ run_id: run, execution_id: "exe_three", type: "execution.transition", payload: { from: "executing", to: "settled", at: "2026-09-23T18:03:03.000Z", actor: AGENT }, at: "2026-09-23T18:03:03.000Z", actor: AGENT },
|
|
185
|
+
{ run_id: run, execution_id: "exe_four", type: "execution.drafted", payload: { items: [{ alias: "escola", beneficiary: "Escola Aurora", payee: ESCOLA, amount: 185000, currency: "BRL" }], total: 185000, mode: "mandate", batch: { ref: "folha", batch_hash: "sha256:abc", index: 1, count: 2 } }, at: "2026-09-23T18:04:00.000Z", actor: AGENT },
|
|
186
|
+
{ run_id: run, execution_id: "exe_four", type: "rail.dispatch", payload: { attempt_id: "ska_four", payee: ESCOLA, amount: 185000, rail: "stub", idempotency_key: "idk_four" }, at: "2026-09-23T18:04:01.000Z", actor: AGENT },
|
|
187
|
+
{ run_id: run, execution_id: "exe_four", type: "rail.outcome", payload: { attempt_id: "ska_four", status: "uncertain", code: "psp_dispatch_uncertain", message: "timeout" }, at: "2026-09-23T18:04:02.000Z", actor: AGENT },
|
|
188
|
+
{ run_id: run, execution_id: "exe_four", type: "rail.reconcile", payload: { attempt_id: "ska_four", found: "settled" }, at: "2026-09-23T18:05:00.000Z", actor: AGENT },
|
|
189
|
+
{ run_id: run, execution_id: "exe_four", type: "execution.transition", payload: { from: "executing", to: "settled", at: "2026-09-23T18:05:01.000Z", actor: AGENT }, at: "2026-09-23T18:05:01.000Z", actor: AGENT },
|
|
190
|
+
]) {
|
|
191
|
+
bundle.event(event as Record<string, unknown>);
|
|
192
|
+
}
|
|
193
|
+
writeFileSync(join(bundle.dir, "receipts", "rcpt_earlier.json"), JSON.stringify({ receipt_id: "rcpt_earlier", state: "paid", payment: { amount_minor: 185000, payee: MASKED, money_moved: false, sandbox: true, at: "2026-09-23T17:00:00.000Z" }, actor: AGENT }));
|
|
194
|
+
return bundle;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
describe("inspect says which settlements this run did not pay (#60)", () => {
|
|
198
|
+
it("a dispatch answered as a replay is settled and replayed; one closed by a later look is settled and not", () => {
|
|
199
|
+
const report = assembleTimeline(withReplays());
|
|
200
|
+
const byId = new Map(report.executions.map((e) => [e.execution_id, e]));
|
|
201
|
+
expect(byId.get("exe_one")!.replayed).toBe(false);
|
|
202
|
+
expect(byId.get("exe_three")).toMatchObject({ final_state: "settled", replayed: true });
|
|
203
|
+
expect(byId.get("exe_three")!.attempts[0]!.answer).toMatchObject({ status: "settled", receipt_id: "rcpt_earlier", idempotent_replay: true });
|
|
204
|
+
expect(byId.get("exe_four")).toMatchObject({ final_state: "settled", replayed: false });
|
|
205
|
+
expect(report.batches[0]!.lines.map((l) => [l.execution_id, l.replayed])).toEqual([
|
|
206
|
+
["exe_three", true],
|
|
207
|
+
["exe_four", false],
|
|
208
|
+
]);
|
|
209
|
+
expect(report.receipts.map((r) => [r.receipt_id, r.replayed])).toEqual([
|
|
210
|
+
["rcpt_earlier", true],
|
|
211
|
+
["rcpt_one", false],
|
|
212
|
+
]);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("the text and the HTML say it where a reader looks: the rail line, the heading, the batch header and the receipt", () => {
|
|
216
|
+
const report = assembleTimeline(withReplays());
|
|
217
|
+
const text = renderText(report);
|
|
218
|
+
expect(text).toContain("execution exe_three — settled (replayed, not paid by this run)");
|
|
219
|
+
expect(text).toContain("rail says settled (replayed)");
|
|
220
|
+
expect(text).toContain(REPLAY_NOTE);
|
|
221
|
+
expect(text).toContain("1 replayed, paid before and not by this run");
|
|
222
|
+
expect(text).toContain("rcpt_earlier paid R$ 1.850,00");
|
|
223
|
+
expect(text).toMatch(/rcpt_earlier .*read back from a replay, not paid by this run/);
|
|
224
|
+
expect(text).not.toMatch(/rcpt_one .*read back from a replay/);
|
|
225
|
+
expect(text).toContain("execution exe_four — settled · folha");
|
|
226
|
+
const html = renderHtml(report);
|
|
227
|
+
expect(html).toContain("replayed, not paid by this run");
|
|
228
|
+
expect(html).toContain(REPLAY_NOTE);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
171
232
|
describe("masking: inspect never un-masks and never leaks a key it read raw", () => {
|
|
172
233
|
it("no raw payee survives into the report, the text or the HTML", () => {
|
|
173
234
|
const report = assembleTimeline(fixtureBundle());
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The count the terminal prints and the one-shot exits by, on the cases a
|
|
3
|
+
* process test cannot stage cheaply: which reasons read as declined, and
|
|
4
|
+
* which exit code wins.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
import { isDeclinedReason, type Execution, type NotRunLine } from "@codespar/agent-core";
|
|
8
|
+
import { outcomeExitCode, runOutcome } from "../src/outcome.js";
|
|
9
|
+
|
|
10
|
+
function execution(state: Execution["state"], over: Partial<Pick<Execution, "reason" | "outcomes">> = {}): Execution {
|
|
11
|
+
return { id: `exec_${Math.random().toString(36).slice(2)}`, state, outcomes: [], ...over } as unknown as Execution;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const outcome = (status: "settled" | "failed" | "accepted", over: Record<string, unknown> = {}) => ({ index: 0, attempt_id: "att", status, ...over }) as Execution["outcomes"][number];
|
|
15
|
+
|
|
16
|
+
describe("isDeclinedReason", () => {
|
|
17
|
+
it("is true of a charge nobody paid, a charge withdrawn and the organization's pause, and of nothing else", () => {
|
|
18
|
+
for (const reason of ["charge_expired", "charge_cancelled", "org_paused"]) expect(isDeclinedReason(reason)).toBe(true);
|
|
19
|
+
for (const reason of ["charge_issuer_error", "rail_failed", "psp_dispatch_failed", undefined, null]) expect(isDeclinedReason(reason)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("runOutcome", () => {
|
|
24
|
+
it("counts a multi-item execution by payment: three paid and one failed", () => {
|
|
25
|
+
const e = execution("failed", { reason: "rail_failed", outcomes: [outcome("settled"), outcome("failed", { code: "psp_dispatch_failed" }), outcome("settled"), outcome("settled")] });
|
|
26
|
+
expect(runOutcome([e], [])).toEqual({ settled: 3, failed: 1, declined: 0, already_paid: 0, open: 0 });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("counts a replayed settlement as already paid, attempt by attempt", () => {
|
|
30
|
+
const e = execution("settled", { outcomes: [outcome("settled", { replayed: true }), outcome("settled")] });
|
|
31
|
+
expect(runOutcome([e], [])).toMatchObject({ settled: 1, already_paid: 1 });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("reads charge_expired, charge_cancelled and org_paused as declined, and charge_issuer_error as failed", () => {
|
|
35
|
+
const declined = ["charge_expired", "charge_cancelled", "org_paused"].map((code) => execution("failed", { reason: code as Execution["reason"], outcomes: [outcome("failed", { code })] }));
|
|
36
|
+
expect(runOutcome(declined, [])).toEqual({ settled: 0, failed: 0, declined: 3, already_paid: 0, open: 0 });
|
|
37
|
+
expect(runOutcome([execution("failed", { reason: "charge_issuer_error", outcomes: [outcome("failed", { code: "charge_issuer_error" })] })], [])).toMatchObject({ failed: 1, declined: 0 });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("reads an execution closed with no attempt by its own reason", () => {
|
|
41
|
+
expect(runOutcome([execution("failed", { reason: "org_paused" }), execution("failed", { reason: "rail_failed" }), execution("denied"), execution("expired")], [])).toEqual({ settled: 0, failed: 1, declined: 3, already_paid: 0, open: 0 });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("counts a line an earlier run holds as open, whatever that run's verdict, and a refused line as failed", () => {
|
|
45
|
+
const notRun: NotRunLine[] = [
|
|
46
|
+
{ ref: "a", why: "in_progress", detail: "attempt_id_conflict" },
|
|
47
|
+
{ ref: "b", why: "in_progress", detail: "in_progress" },
|
|
48
|
+
{ ref: "c", why: "already_settled" },
|
|
49
|
+
{ ref: "d", why: "refused", detail: "unreadable_line" },
|
|
50
|
+
];
|
|
51
|
+
expect(runOutcome([], notRun)).toEqual({ settled: 0, failed: 1, declined: 0, already_paid: 1, open: 2 });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("outcomeExitCode", () => {
|
|
56
|
+
const executing = execution("executing");
|
|
57
|
+
|
|
58
|
+
it("1 wins over 3: something failed and something else was left executing", () => {
|
|
59
|
+
const failed = execution("failed", { reason: "rail_failed", outcomes: [outcome("failed")] });
|
|
60
|
+
const counted = runOutcome([failed, executing], []);
|
|
61
|
+
expect(counted).toMatchObject({ failed: 1, open: 1 });
|
|
62
|
+
expect(outcomeExitCode(counted, [failed, executing])).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("3 when nothing failed and an execution of this run was left executing", () => {
|
|
66
|
+
expect(outcomeExitCode(runOutcome([executing], []), [executing])).toBe(3);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("0 when a line is held by an earlier run and this run left nothing executing", () => {
|
|
70
|
+
expect(outcomeExitCode(runOutcome([], [{ ref: "a", why: "in_progress" }]), [])).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sandbox payer in the poll pays a receivable only once it is payable.
|
|
3
|
+
* It used to also pay "after a few looks", whatever it found, and on staging
|
|
4
|
+
* that paid a charge the issuer had ended in ERROR: the order read `settled`
|
|
5
|
+
* with no QR ever shown (OPEN_QUESTIONS §63, ent#1816). These drive the poll
|
|
6
|
+
* with a rail that stays unpayable for longer than the old patience.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import type { ChargeInstrument, Execution, ExecutionEngine } from "@codespar/agent-core";
|
|
10
|
+
import { pollUntilClosed } from "../src/poll.js";
|
|
11
|
+
|
|
12
|
+
function instrument(payable: boolean): ChargeInstrument {
|
|
13
|
+
return { payable, status: payable ? "PENDING" : "PROCESSING", pix_copy_paste: payable ? "000201..." : null, boleto_bank_line: payable ? "2".repeat(47) : null, boleto_bar_code: null, due_date: "2026-09-30" };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** An engine that answers one executing receivable, payable from look `payableFrom` on (never when undefined). */
|
|
17
|
+
function engineWith(payableFrom?: number) {
|
|
18
|
+
let looks = 0;
|
|
19
|
+
const execution = (): Execution =>
|
|
20
|
+
({
|
|
21
|
+
id: "exe_1",
|
|
22
|
+
state: "executing",
|
|
23
|
+
outcomes: [{ index: 0, attempt_id: "att_1_0", status: "accepted", transaction_id: "chg_1", instrument: instrument(payableFrom !== undefined && looks >= payableFrom) }],
|
|
24
|
+
}) as unknown as Execution;
|
|
25
|
+
const engine = {
|
|
26
|
+
get: () => execution(),
|
|
27
|
+
reconcile: async () => ((looks += 1), execution()),
|
|
28
|
+
markShown: () => true,
|
|
29
|
+
note: () => undefined,
|
|
30
|
+
} as unknown as ExecutionEngine;
|
|
31
|
+
return { engine, looks: () => looks };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function payerSpy() {
|
|
35
|
+
const calls: string[] = [];
|
|
36
|
+
return {
|
|
37
|
+
calls,
|
|
38
|
+
payer: {
|
|
39
|
+
kind: "stub" as const,
|
|
40
|
+
pay: async (chargeId: string) => (calls.push(chargeId), { ok: true as const, detail: "paid" }),
|
|
41
|
+
behave: () => undefined,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("the poll's sandbox payer pays only what is payable", () => {
|
|
47
|
+
it("a receivable that never becomes payable is never paid, however many looks the wait allows", async () => {
|
|
48
|
+
const { engine, looks } = engineWith(undefined);
|
|
49
|
+
const { payer, calls } = payerSpy();
|
|
50
|
+
const result = await pollUntilClosed(engine, "exe_1", { intervalMs: 0, timeoutMs: 0, maxRounds: 12, payer });
|
|
51
|
+
expect(looks()).toBe(12);
|
|
52
|
+
expect(calls).toEqual([]);
|
|
53
|
+
expect(result.payer_calls).toEqual([]);
|
|
54
|
+
expect(result.timed_out).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("the payer plays once, on the first look that finds it payable", async () => {
|
|
58
|
+
const { engine } = engineWith(7);
|
|
59
|
+
const { payer, calls } = payerSpy();
|
|
60
|
+
const result = await pollUntilClosed(engine, "exe_1", { intervalMs: 0, timeoutMs: 0, maxRounds: 12, payer });
|
|
61
|
+
expect(calls).toEqual(["chg_1"]);
|
|
62
|
+
expect(result.payer_calls).toEqual(["paid"]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `notReplayed` reads a bundle's events for what only the world can do. These
|
|
3
|
+
* are the events as the engine writes them, by hand, so the reading is held
|
|
4
|
+
* to the shape and not to whatever a scenario happens to produce.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
import { notReplayed } from "../src/commands/rerun.js";
|
|
8
|
+
|
|
9
|
+
const transition = (execution: string, to: string, reason?: string) => ({ type: "execution.transition", execution_id: execution, payload: { to, ...(reason ? { reason } : {}) } });
|
|
10
|
+
const outcome = (execution: string, status: string) => ({ type: "rail.outcome", execution_id: execution, payload: { status } });
|
|
11
|
+
|
|
12
|
+
describe("what a rerun does not replay", () => {
|
|
13
|
+
it("nothing, in a run that settled, failed on the rail or was denied by a person", () => {
|
|
14
|
+
expect(notReplayed([transition("a", "approved"), transition("a", "executing"), outcome("a", "settled"), transition("a", "settled")])).toEqual([]);
|
|
15
|
+
expect(notReplayed([transition("a", "executing"), outcome("a", "failed"), transition("a", "failed", "rail_failed")])).toEqual([]);
|
|
16
|
+
expect(notReplayed([transition("a", "awaiting_approval"), transition("a", "denied", "denied_by_approver")])).toEqual([]);
|
|
17
|
+
// A reason that is a key of every object is not one of the three this reads.
|
|
18
|
+
expect(notReplayed([transition("a", "denied", "constructor"), transition("b", "denied", "toString")])).toEqual([]);
|
|
19
|
+
// Left awaiting approval is the person not deciding, and a rerun does replay that.
|
|
20
|
+
expect(notReplayed([transition("a", "awaiting_approval")])).toEqual([]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("a mandate revoked or paused, and the organization's kill switch, at a gate or before a draft", () => {
|
|
24
|
+
expect(notReplayed([transition("a", "denied", "mandate_revoked")])).toEqual(["a mandate that was revoked"]);
|
|
25
|
+
expect(notReplayed([transition("a", "denied", "mandate_paused")])).toEqual(["a mandate that was paused"]);
|
|
26
|
+
expect(notReplayed([transition("a", "denied", "org_paused")])).toEqual(["an organization that paused every mandate"]);
|
|
27
|
+
expect(notReplayed([{ type: "execution.refused_before_draft", execution_id: null, payload: { reason: "mandate_revoked" } }])).toEqual(["a mandate that was revoked"]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("an uncertain answer from the rail, even one a later reconciliation settled", () => {
|
|
31
|
+
expect(notReplayed([transition("a", "executing"), outcome("a", "uncertain"), transition("a", "settled")])).toEqual(["an uncertain answer from the rail"]);
|
|
32
|
+
// Whichever of the engine's three events for it the bundle holds.
|
|
33
|
+
expect(notReplayed([{ type: "rail.uncertain", execution_id: "a", payload: {} }])).toEqual(["an uncertain answer from the rail"]);
|
|
34
|
+
expect(notReplayed([{ type: "execution.uncertain", execution_id: "a", payload: { detail: "attempt att_1: psp_dispatch_uncertain" } }])).toEqual(["an uncertain answer from the rail"]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("a charge issued and still out when the run ended, and not one that was paid", () => {
|
|
38
|
+
expect(notReplayed([transition("a", "executing"), outcome("a", "accepted")])).toEqual(["a payer who had not paid when it ended"]);
|
|
39
|
+
expect(notReplayed([transition("a", "executing"), outcome("a", "accepted"), transition("a", "settled")])).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("each thing once, in the order the run met them", () => {
|
|
43
|
+
const events = [transition("a", "executing"), outcome("a", "uncertain"), transition("b", "denied", "mandate_revoked"), { type: "execution.refused_before_draft", execution_id: null, payload: { reason: "mandate_revoked" } }];
|
|
44
|
+
expect(notReplayed(events)).toEqual(["an uncertain answer from the rail", "a mandate that was revoked"]);
|
|
45
|
+
});
|
|
46
|
+
});
|