@codespar/cli 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/commands/login.js +52 -12
- package/dist/commands/login.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/surface.js +79 -9
- package/dist/surface.js.map +1 -1
- package/package.json +1 -1
- 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
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #50: the line a person reads after an execution moves carries the rail's own
|
|
3
|
+
* code and message, verbatim, after the reason — on a failure and on an answer
|
|
4
|
+
* that left an attempt unknown — and nothing more when there is none.
|
|
5
|
+
*/
|
|
6
|
+
import type { Execution } from "@codespar/agent-core";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { transitionLine } from "../src/terminal.js";
|
|
9
|
+
|
|
10
|
+
function execution(over: Partial<Execution>): Execution {
|
|
11
|
+
return { state: "settled", outcomes: [], ...over } as Execution;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("transitionLine", () => {
|
|
15
|
+
it("a failure: the reason, then the API's code and message", () => {
|
|
16
|
+
const failed = execution({ state: "failed", reason: "rail_failed", outcomes: [{ index: 0, attempt_id: "att_0", status: "failed", code: "insufficient_funds", message: "wallet cannot reserve the requested amount" }] });
|
|
17
|
+
expect(transitionLine(failed)).toBe(" -> failed (rail_failed): insufficient_funds — wallet cannot reserve the requested amount");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("an unknown outcome: the reason, then what the API answered", () => {
|
|
21
|
+
const open = execution({ state: "executing", reason: "rail_uncertain", uncertain_answers: [{ attempt_id: "att_0", code: "provider_error", message: "no receiving identity" }] });
|
|
22
|
+
expect(transitionLine(open)).toBe(" -> executing (rail_uncertain): provider_error — no receiving identity");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("nothing to add when nothing failed", () => {
|
|
26
|
+
expect(transitionLine(execution({ state: "settled" }))).toBe(" -> settled");
|
|
27
|
+
expect(transitionLine(execution({ state: "denied", reason: "cap_exceeded" as Execution["reason"] }))).toBe(" -> denied (cap_exceeded)");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import { createHash, generateKeyPairSync, sign as signDetached } from "node:crypto";
|
|
12
|
-
import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { createServer, type Server } from "node:http";
|
|
14
14
|
import type { AddressInfo } from "node:net";
|
|
15
15
|
import { tmpdir } from "node:os";
|
|
@@ -46,11 +46,11 @@ function fixture(over: Record<string, unknown> = {}) {
|
|
|
46
46
|
return { dir, receiptPath, keysPath };
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function run(args: string[], cwd: string) {
|
|
49
|
+
function run(args: string[], cwd: string, env: Record<string, string> = {}) {
|
|
50
50
|
const result = spawnSync(process.execPath, [BIN, "verify", ...args], {
|
|
51
51
|
cwd,
|
|
52
52
|
// No CodeSpar key, no model key: a verifier holds nothing.
|
|
53
|
-
env: { ...process.env, CODESPAR_API_KEY: "", ANTHROPIC_API_KEY: "" },
|
|
53
|
+
env: { ...process.env, CODESPAR_API_KEY: "", ANTHROPIC_API_KEY: "", ...env },
|
|
54
54
|
encoding: "utf8",
|
|
55
55
|
timeout: 60_000,
|
|
56
56
|
});
|
|
@@ -64,6 +64,10 @@ describe("codespar-agent verify", () => {
|
|
|
64
64
|
expect(out.code).toBe(7);
|
|
65
65
|
expect(out.stdout).toContain("SIGNATURE_ONLY");
|
|
66
66
|
expect(out.stdout).toContain(RECEIPT_ID);
|
|
67
|
+
// The offline check reads neither the deployment nor the project, so two names for them that disagree are none of its business.
|
|
68
|
+
const disagreeing = run([receiptPath, "--keys", keysPath], dir, { CODESPAR_API_URL: "https://api.codespar.dev", CODESPAR_BASE_URL: "https://api.staging.codespar.dev" });
|
|
69
|
+
expect(disagreeing.code).toBe(7);
|
|
70
|
+
expect(disagreeing.stderr).not.toContain("disagree");
|
|
67
71
|
expect(out.stdout).toContain("read_required");
|
|
68
72
|
expect(out.stderr).toContain("carries CodeSpar's signature");
|
|
69
73
|
expect(out.stderr).toContain("--from-api");
|
|
@@ -268,12 +272,12 @@ describe("codespar-agent verify --from-api", () => {
|
|
|
268
272
|
});
|
|
269
273
|
|
|
270
274
|
/** The server answers while the command runs, so the process is awaited, never spawned synchronously. */
|
|
271
|
-
function runAsync(args: string[], cwd: string): Promise<{ code: number | null; stdout: string; stderr: string }> {
|
|
275
|
+
function runAsync(args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<{ code: number | null; stdout: string; stderr: string }> {
|
|
272
276
|
return new Promise((done) => {
|
|
273
277
|
const child = spawn(process.execPath, [BIN, "verify", ...args], {
|
|
274
278
|
cwd,
|
|
275
|
-
//
|
|
276
|
-
env: { ...process.env, CODESPAR_API_KEY: "
|
|
279
|
+
// Not the placeholder, which the guard refuses (#50); the underscore keeps it below the secret scan's key shape.
|
|
280
|
+
env: env ?? { ...process.env, CODESPAR_API_KEY: "csk_test_unit_0000", CODESPAR_API_URL: baseUrl, ANTHROPIC_API_KEY: "" },
|
|
277
281
|
});
|
|
278
282
|
let stdout = "";
|
|
279
283
|
let stderr = "";
|
|
@@ -294,6 +298,20 @@ describe("codespar-agent verify --from-api", () => {
|
|
|
294
298
|
expect(readFileSync(f.paths.copy, "utf8")).not.toContain(PAYEE);
|
|
295
299
|
});
|
|
296
300
|
|
|
301
|
+
it("never prints or writes the mandate's signature a tenant's read carries, and shows what the chain sealed about the money", async () => {
|
|
302
|
+
const f = v4Fixture();
|
|
303
|
+
const mandateSig = "s".repeat(64);
|
|
304
|
+
served = { read: { ...f.read, mandate: { ...f.read.mandate, sig: mandateSig } }, keys: f.keys };
|
|
305
|
+
const human = await runAsync([f.paths.copy, "--from-api"], f.dir);
|
|
306
|
+
const json = await runAsync([f.paths.copy, "--from-api", "--json"], f.dir);
|
|
307
|
+
expect([human.code, json.code]).toEqual([0, 0]);
|
|
308
|
+
expect(human.stdout).toContain("payment sandbox true, money_moved false");
|
|
309
|
+
expect(JSON.parse(json.stdout).sealed_payment).toEqual({ sandbox: true, money_moved: false });
|
|
310
|
+
for (const out of [human, json]) expect(out.stdout + out.stderr).not.toContain(mandateSig);
|
|
311
|
+
const files = readdirSync(f.dir, { recursive: true, encoding: "utf8" }).map((name) => join(f.dir, name)).filter((path) => statSync(path).isFile());
|
|
312
|
+
for (const path of files) expect(readFileSync(path, "utf8")).not.toContain(mandateSig);
|
|
313
|
+
});
|
|
314
|
+
|
|
297
315
|
it("exits 9 when the run's artifact is not the list the receipt sealed", async () => {
|
|
298
316
|
const f = v4Fixture();
|
|
299
317
|
served = { read: f.read, keys: f.keys };
|
|
@@ -320,6 +338,81 @@ describe("codespar-agent verify --from-api", () => {
|
|
|
320
338
|
expect(JSON.parse(out.stdout)).toMatchObject({ verdict: "signature_only", reason: "read_unavailable" });
|
|
321
339
|
});
|
|
322
340
|
|
|
341
|
+
/*
|
|
342
|
+
* #66: the copy sits in its agent, and that agent's `.env` names the
|
|
343
|
+
* deployment as well as the key. A shell that exported neither must still
|
|
344
|
+
* read from the deployment the `.env` names, under `readDotEnv`'s rule: the
|
|
345
|
+
* environment wins, the file fills only what is unset.
|
|
346
|
+
*/
|
|
347
|
+
function inAgent(dir: string, dotEnv: Record<string, string>): void {
|
|
348
|
+
writeFileSync(join(dir, "agent.yaml"), 'name: "verify-fixture-agent"\n');
|
|
349
|
+
writeFileSync(join(dir, ".env"), Object.entries(dotEnv).map(([k, v]) => `${k}=${v}\n`).join(""));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function bareEnv(over: Record<string, string> = {}): NodeJS.ProcessEnv {
|
|
353
|
+
const env: NodeJS.ProcessEnv = { ...process.env, ANTHROPIC_API_KEY: "", ...over };
|
|
354
|
+
for (const name of ["CODESPAR_API_KEY", "CODESPAR_API_URL", "CODESPAR_PROJECT_ID", "CODESPAR_BASE_URL", "CODESPAR_PROJECT"]) if (!(name in over)) delete env[name];
|
|
355
|
+
return env;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
it("reads the receipt from the deployment the agent's .env names when the shell exported nothing", async () => {
|
|
359
|
+
const f = v4Fixture();
|
|
360
|
+
inAgent(f.dir, { CODESPAR_API_KEY: "csk_test_unit_0000", CODESPAR_API_URL: baseUrl });
|
|
361
|
+
served = { read: f.read, keys: f.keys };
|
|
362
|
+
asked.length = 0;
|
|
363
|
+
const out = await runAsync([f.paths.copy, "--from-api", "--json"], f.dir, bareEnv());
|
|
364
|
+
expect(out.code).toBe(0);
|
|
365
|
+
expect(JSON.parse(out.stdout)).toMatchObject({ verdict: "verified", keys_from: `${baseUrl}/.well-known/codespar-receipt-keys.json` });
|
|
366
|
+
expect(asked).toEqual([`GET /.well-known/codespar-receipt-keys.json anon`, `GET /v1/consumers/receipts/${RECEIPT_ID} auth`]);
|
|
367
|
+
expect(out.stdout + out.stderr).not.toContain("csk_test_unit_0000");
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("keeps an exported CODESPAR_API_URL over the one in the agent's .env, which still fills the unset key", async () => {
|
|
371
|
+
const f = v4Fixture();
|
|
372
|
+
inAgent(f.dir, { CODESPAR_API_KEY: "csk_test_unit_0000", CODESPAR_API_URL: "http://127.0.0.1:9" });
|
|
373
|
+
served = { read: f.read, keys: f.keys };
|
|
374
|
+
asked.length = 0;
|
|
375
|
+
const out = await runAsync([f.paths.copy, "--from-api", "--json"], f.dir, bareEnv({ CODESPAR_API_URL: baseUrl }));
|
|
376
|
+
expect(out.code).toBe(0);
|
|
377
|
+
expect(asked).toEqual([`GET /.well-known/codespar-receipt-keys.json anon`, `GET /v1/consumers/receipts/${RECEIPT_ID} auth`]);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const BOTH_ASKED = () => [`GET /.well-known/codespar-receipt-keys.json anon`, `GET /v1/consumers/receipts/${RECEIPT_ID} auth`];
|
|
381
|
+
|
|
382
|
+
it("reads from the deployment the .env names under the CLI's name, CODESPAR_BASE_URL", async () => {
|
|
383
|
+
const f = v4Fixture();
|
|
384
|
+
inAgent(f.dir, { CODESPAR_API_KEY: "csk_test_unit_0000", CODESPAR_BASE_URL: baseUrl });
|
|
385
|
+
served = { read: f.read, keys: f.keys };
|
|
386
|
+
asked.length = 0;
|
|
387
|
+
const out = await runAsync([f.paths.copy, "--from-api", "--json"], f.dir, bareEnv());
|
|
388
|
+
expect(out.code).toBe(0);
|
|
389
|
+
expect(asked).toEqual(BOTH_ASKED());
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("keeps the shell's deployment over the .env's when each uses the other name, either way round", async () => {
|
|
393
|
+
for (const [shellName, fileName] of [["CODESPAR_BASE_URL", "CODESPAR_API_URL"], ["CODESPAR_API_URL", "CODESPAR_BASE_URL"]] as const) {
|
|
394
|
+
const f = v4Fixture();
|
|
395
|
+
inAgent(f.dir, { CODESPAR_API_KEY: "csk_test_unit_0000", [fileName]: "http://127.0.0.1:9" });
|
|
396
|
+
served = { read: f.read, keys: f.keys };
|
|
397
|
+
asked.length = 0;
|
|
398
|
+
const out = await runAsync([f.paths.copy, "--from-api", "--json"], f.dir, bareEnv({ [shellName]: baseUrl }));
|
|
399
|
+
expect(out.stderr).not.toContain("disagree");
|
|
400
|
+
expect(out.code).toBe(0);
|
|
401
|
+
expect(asked).toEqual(BOTH_ASKED());
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("refuses two names that disagree as a usage error (2), before any request, and never as a failed verification (1)", async () => {
|
|
406
|
+
const f = v4Fixture();
|
|
407
|
+
inAgent(f.dir, { CODESPAR_API_KEY: "csk_test_unit_0000", CODESPAR_API_URL: baseUrl, CODESPAR_BASE_URL: "http://127.0.0.1:9" });
|
|
408
|
+
asked.length = 0;
|
|
409
|
+
const out = await runAsync([f.paths.copy, "--from-api"], f.dir, bareEnv());
|
|
410
|
+
expect(out.code).toBe(2);
|
|
411
|
+
expect(out.stderr).toContain(`CODESPAR_API_URL=${baseUrl}`);
|
|
412
|
+
expect(out.stderr).toContain("CODESPAR_BASE_URL=http://127.0.0.1:9");
|
|
413
|
+
expect(asked).toEqual([]);
|
|
414
|
+
});
|
|
415
|
+
|
|
323
416
|
it("refuses a key set from another deployment than the read", async () => {
|
|
324
417
|
const f = v4Fixture();
|
|
325
418
|
const out = await runAsync([f.paths.copy, "--from-api", "--url", "https://api.codespar.dev/.well-known/codespar-receipt-keys.json"], f.dir);
|
|
@@ -71,6 +71,14 @@ describe("the collection rules, tried through the channel", () => {
|
|
|
71
71
|
expect(backend.delivered).toHaveLength(0);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
it("refuses outside the hours in either locale, for the same rule, and only the detail is translated (#64)", () => {
|
|
75
|
+
const at = (locale: "pt-BR" | "en" | undefined) =>
|
|
76
|
+
checkOutbound(CONTACT, { kind: "text", text: "Oi, Joana!" }, { conversation: { contact: CONTACT }, hours: HOURS, now: () => OUTSIDE, ...(locale ? { locale } : {}) });
|
|
77
|
+
expect(at(undefined)).toEqual({ rule: "collection_hours", detail: "fora do horário de cobrança (08:00-20:00 America/Sao_Paulo); agora são 22:30" });
|
|
78
|
+
expect(at("pt-BR")).toEqual(at(undefined));
|
|
79
|
+
expect(at("en")).toEqual({ rule: "collection_hours", detail: "outside collection hours (08:00-20:00 America/Sao_Paulo); it is 22:30 now" });
|
|
80
|
+
});
|
|
81
|
+
|
|
74
82
|
it("refuses a message to any contact but the one the conversation is bound to", () => {
|
|
75
83
|
const refusal = checkOutbound("+5511900000000", { kind: "text", text: "sobre a sua divida" }, {
|
|
76
84
|
conversation: { contact: CONTACT, subject: "acordo-1042" },
|
|
@@ -165,3 +165,80 @@ describe("the local registry refuses what Meta would refuse", () => {
|
|
|
165
165
|
expect(templateArity("Oi {{ 1 }}.")).toBe(1);
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
|
+
|
|
169
|
+
describe("a conversation speaks one locale, and its templates and taps are that locale's copies (#64)", () => {
|
|
170
|
+
const VENCIDA_PT: WhatsAppTemplate = {
|
|
171
|
+
name: "acordo_cobranca_vencida",
|
|
172
|
+
language: "pt_BR",
|
|
173
|
+
description: "expired",
|
|
174
|
+
body: "A cobrança do {{1}} venceu.",
|
|
175
|
+
buttons: [{ id: "emitir_nova", title: "Emitir nova", intent: "quero uma nova cobrança" }],
|
|
176
|
+
};
|
|
177
|
+
const VENCIDA_EN: WhatsAppTemplate = {
|
|
178
|
+
name: "acordo_cobranca_vencida",
|
|
179
|
+
language: "en_US",
|
|
180
|
+
description: "expired",
|
|
181
|
+
body: "The charge for {{1}} expired.",
|
|
182
|
+
buttons: [{ id: "emitir_nova", title: "Issue a new one", intent: "I want a new charge" }],
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
class Tapper extends Recorder {
|
|
186
|
+
private tapped = false;
|
|
187
|
+
override async next(): Promise<InboundMessage | undefined> {
|
|
188
|
+
if (this.tapped) return undefined;
|
|
189
|
+
this.tapped = true;
|
|
190
|
+
return { id: "wamid.tap", from: CONTACT, text: "Emitir nova", timestamp: Math.floor(FRIDAY.getTime() / 1000), reply: { type: "button", id: "emitir_nova", title: "Emitir nova" } };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function localized(locale: "pt-BR" | "en", backend: Recorder = new Recorder()) {
|
|
195
|
+
const c = new WhatsAppChannel({
|
|
196
|
+
backend,
|
|
197
|
+
conversation: { contact: CONTACT, subject: "acordo-1042" },
|
|
198
|
+
now: () => FRIDAY,
|
|
199
|
+
templates: [VENCIDA_PT, VENCIDA_EN],
|
|
200
|
+
session: { lastInboundAt: Math.floor(TUESDAY.getTime() / 1000) },
|
|
201
|
+
locale,
|
|
202
|
+
});
|
|
203
|
+
return { channel: c, backend };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
it("an English conversation declares, and sends, the en_US copy with its own buttons", async () => {
|
|
207
|
+
const { channel: c, backend } = localized("en");
|
|
208
|
+
expect(c.language).toBe("en_US");
|
|
209
|
+
const declared = c.declaredTemplate("acordo_cobranca_vencida")!;
|
|
210
|
+
expect(declared.language).toBe("en_US");
|
|
211
|
+
const sent = await c.send({ kind: "template", template: declared.name, language: declared.language, variables: ["acordo-1042"] });
|
|
212
|
+
expect(sent.refused).toBeUndefined();
|
|
213
|
+
expect(backend.delivered).toEqual([{ kind: "template", template: "acordo_cobranca_vencida", language: "en_US", variables: ["acordo-1042"], buttons: [{ id: "emitir_nova", title: "Issue a new one" }] }]);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("the default locale is pt-BR and picks the pt_BR copy", () => {
|
|
217
|
+
const c = new WhatsAppChannel({ backend: new Recorder(), conversation: { contact: CONTACT }, now: () => FRIDAY, templates: [VENCIDA_PT, VENCIDA_EN] });
|
|
218
|
+
expect(c.language).toBe("pt_BR");
|
|
219
|
+
expect(c.declaredTemplate("acordo_cobranca_vencida")?.body).toBe("A cobrança do {{1}} venceu.");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("a tap is read as the intent its locale's copy declares: the same button id, the model handed that conversation's language", async () => {
|
|
223
|
+
const en = localized("en", new Tapper());
|
|
224
|
+
const pt = localized("pt-BR", new Tapper());
|
|
225
|
+
expect((await en.channel.next())?.text).toBe("I want a new charge");
|
|
226
|
+
expect((await pt.channel.next())?.text).toBe("quero uma nova cobrança");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("refuses a language nobody registered, naming the ones that were", async () => {
|
|
230
|
+
const { channel: c, backend } = localized("en");
|
|
231
|
+
const sent = await c.send({ kind: "template", template: "acordo_cobranca_vencida", language: "es_MX", variables: ["acordo-1042"] });
|
|
232
|
+
expect(sent.refused?.rule).toBe("template_language_unknown");
|
|
233
|
+
expect(sent.refused?.detail).toContain("pt_BR, en_US");
|
|
234
|
+
expect(backend.delivered).toHaveLength(0);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("an English conversation's refusal reaches the operator in English, and the rule it names is the same", async () => {
|
|
238
|
+
const said: string[] = [];
|
|
239
|
+
const c = new WhatsAppChannel({ backend: new Recorder(), conversation: { contact: CONTACT }, now: () => FRIDAY, templates: [VENCIDA_EN], session: { lastInboundAt: Math.floor(TUESDAY.getTime() / 1000) }, locale: "en", say: (l) => void said.push(l) });
|
|
240
|
+
const sent = await c.say("free text after the window");
|
|
241
|
+
expect(sent.refused?.rule).toBe("session_window_closed");
|
|
242
|
+
expect(said).toEqual([` [whatsapp] refused (session_window_closed): ${sent.refused!.detail}`]);
|
|
243
|
+
});
|
|
244
|
+
});
|
package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts
CHANGED
|
@@ -88,7 +88,7 @@ describe("1. a status webhook is read, and a failed outcome is an outcome not to
|
|
|
88
88
|
const status = ch.log().find((l) => l.direction === "status")!;
|
|
89
89
|
expect(status).toMatchObject({ kind: "status", message_id: sent.id, state: "failed", about: { execution_id: "exe_1", state: "settled" }, errors: [{ code: 131026, details: "not on whatsapp" }] });
|
|
90
90
|
expect(failed).toEqual([status]);
|
|
91
|
-
expect(said.join("\n")).toContain("a pessoa
|
|
91
|
+
expect(said.join("\n")).toContain("a pessoa NÃO foi avisada");
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
it("a read is recorded and nothing more: not consent, not an acknowledgement, not a reply", async () => {
|
|
@@ -121,6 +121,32 @@ describe("1. a status webhook is read, and a failed outcome is an outcome not to
|
|
|
121
121
|
expect(failed.map((l) => l.about)).toEqual([{ execution_id: "exe_2", state: "settled" }]);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
+
it("a delivered that lands AFTER the failed does not un-fail the message, and a late sent does not rewind a read (#63)", async () => {
|
|
125
|
+
// The emulator's own order when a failure is posted while the send is still dispatching its sent/delivered webhooks.
|
|
126
|
+
class Interleaved extends Scripted {
|
|
127
|
+
override async deliver(to: string, body: OutboundBody): Promise<SentMessage> {
|
|
128
|
+
const sent = await super.deliver(to, body);
|
|
129
|
+
this.report({ message_id: sent.id, status: "sent", timestamp: 1, errors: [] });
|
|
130
|
+
this.report({ message_id: sent.id, status: "failed", timestamp: 2, errors: [{ code: 131026 }] });
|
|
131
|
+
this.report({ message_id: sent.id, status: "delivered", timestamp: 2, errors: [] });
|
|
132
|
+
return sent;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const backend = new Interleaved();
|
|
136
|
+
const failed: ChannelLogLine[] = [];
|
|
137
|
+
const ch = new WhatsAppChannel({ backend, conversation: { contact: CONTACT }, now: () => NOW, templates: TEMPLATES, onDeliveryFailed: (l) => failed.push(l) });
|
|
138
|
+
await ch.open();
|
|
139
|
+
const sent = await ch.send({ kind: "template", template: "acordo_quitado", language: "pt_BR", variables: ["acordo-1042"], about: { execution_id: "exe_3", state: "settled" } });
|
|
140
|
+
expect(ch.deliveryOf(sent.id)).toBe("failed");
|
|
141
|
+
expect(failed.map((l) => l.about)).toEqual([{ execution_id: "exe_3", state: "settled" }]);
|
|
142
|
+
// Every status is still in the conversation's log, in the order it arrived.
|
|
143
|
+
expect(ch.log().filter((l) => l.direction === "status").map((l) => l.state)).toEqual(["sent", "failed", "delivered"]);
|
|
144
|
+
|
|
145
|
+
backend.report({ message_id: "wamid.other", status: "read", timestamp: 3, errors: [] });
|
|
146
|
+
backend.report({ message_id: "wamid.other", status: "sent", timestamp: 1, errors: [] });
|
|
147
|
+
expect(ch.deliveryOf("wamid.other")).toBe("read");
|
|
148
|
+
});
|
|
149
|
+
|
|
124
150
|
it("a status about a message an EARLIER run sent is tied back to the outcome that run recorded", async () => {
|
|
125
151
|
const prior: ChannelLogLine = { at: NOW.toISOString(), direction: "out", contact: "+55*****4321", kind: "template", message_id: "wamid.old", state: "sent", about: { execution_id: "exe_old", state: "settled" } };
|
|
126
152
|
const backend = new Scripted();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# {{name}}
|
|
2
2
|
|
|
3
3
|
Scaffolded by `codespar init --template collections-agent` from the `collections-agent` starter kit
|
|
4
|
-
(https://github.com/codespar/agent-starter-kits at `
|
|
4
|
+
(https://github.com/codespar/agent-starter-kits at `d50c3d2fbb8707a4de67a6f8db5ee0bfb1b33794`, agent 0.1.0).
|
|
5
5
|
|
|
6
6
|
The merchant's agent that collects: agrees terms with the payer inside a negotiation envelope, issues one bolepix per instalment with an idempotency key, presents the QR and the copy-and-paste in the conversation, and closes the cycle on commerce.charge.paid or commerce.charge.expired.
|
|
7
7
|
|
|
@@ -25,4 +25,4 @@ run at this root as they do in the kits repo:
|
|
|
25
25
|
|
|
26
26
|
The agent's guide is [`agents/collections-agent/README.md`](agents/collections-agent/README.md); its commands run at this root
|
|
27
27
|
(`npm run check`, `npm run eval`, `npm test`) or inside `agents/collections-agent/`. The manifest pins
|
|
28
|
-
`cli: "@codespar/cli@0.
|
|
28
|
+
`cli: "@codespar/cli@0.18.1"`, the CLI version whose `agent run`/`eval` this agent was written for.
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Copy to agents/collections-agent/.env. `npm install` runs at the repository ROOT (npm workspace), then `npm start`.
|
|
2
|
+
# Test key from https://codespar.dev/auth/signup (starts with csk_test_). A live key is refused.
|
|
2
3
|
CODESPAR_API_KEY=csk_test_your_key_here
|
|
3
|
-
# https://console.anthropic.com.
|
|
4
|
-
ANTHROPIC_API_KEY=
|
|
4
|
+
# https://console.anthropic.com. Leave empty to replay the recorded happy path (the old placeholder sk-ant-your_key_here also counts as empty).
|
|
5
|
+
ANTHROPIC_API_KEY=
|
|
6
|
+
# Staging only (docs/OPEN_QUESTIONS.md, item 12): a staging test key also needs the staging base URL. A production key needs nothing here. The CodeSpar CLI calls the same setting CODESPAR_BASE_URL (and the project CODESPAR_PROJECT, here CODESPAR_PROJECT_ID): the kit reads either name, and a command that talks to the API refuses to start if the two disagree. A CLI login kept in ~/.codespar/config.json is not read by the kit: only the environment and this file are.
|
|
7
|
+
# CODESPAR_API_URL=https://api.staging.codespar.dev
|
|
5
8
|
|
|
6
9
|
# --- WhatsApp, the official Cloud API backend. Commented out and empty on purpose. ---
|
|
7
10
|
# The default backend needs NONE of these: it talks to a local Cloud API emulator
|