@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
|
@@ -10,9 +10,10 @@ import { existsSync, mkdtempSync, readdirSync, readFileSync } from "node:fs";
|
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { basename, join, resolve } from "node:path";
|
|
12
12
|
import { z } from "zod";
|
|
13
|
-
import type { ApprovalMode, Execution } from "@codespar/agent-core";
|
|
13
|
+
import type { ApprovalMode, Execution, Locale, StubChargeRailOptions, StubRailOptions } from "@codespar/agent-core";
|
|
14
14
|
import type { Agent } from "./agent.js";
|
|
15
15
|
import type { RailKind } from "./kit.js";
|
|
16
|
+
import { draftRefusals } from "./outcome.js";
|
|
16
17
|
import { setup, type Setup } from "./setup.js";
|
|
17
18
|
import { announceOutcome, followUp, handleExecution } from "./terminal.js";
|
|
18
19
|
|
|
@@ -84,14 +85,33 @@ export interface ScenarioRun {
|
|
|
84
85
|
run_id: string;
|
|
85
86
|
bundle_dir: string;
|
|
86
87
|
replies: string[];
|
|
87
|
-
executions: Array<{
|
|
88
|
+
executions: Array<{
|
|
89
|
+
id: string;
|
|
90
|
+
state: string;
|
|
91
|
+
reason: string | null;
|
|
92
|
+
trigger: string | null;
|
|
93
|
+
total: number;
|
|
94
|
+
trail: string[];
|
|
95
|
+
charge_ids: string[];
|
|
96
|
+
receipt_ids: string[];
|
|
97
|
+
/**
|
|
98
|
+
* A receivable that settled: whether a payable instrument (a Pix or a boleto line) was SEEN before anything paid it.
|
|
99
|
+
* `null` for anything that is not a settled receivable. `false` means the order settled on something nobody could
|
|
100
|
+
* have paid, which is how a failed issuance read as a closed cycle on staging (OPEN_QUESTIONS §63).
|
|
101
|
+
*/
|
|
102
|
+
payable_seen: boolean | null;
|
|
103
|
+
}>;
|
|
88
104
|
refused_before_draft: number;
|
|
89
105
|
receipts: number;
|
|
90
106
|
settled_total: number;
|
|
91
107
|
charges_issued: number;
|
|
92
108
|
debtor_messages: number;
|
|
93
|
-
/**
|
|
94
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Seconds from the first issuance to the last terminal state (wall clock on the API; the fake clock's ticks on the stub).
|
|
111
|
+
* `null` when there was no real cycle to time: nothing was issued, nothing closed, or a receivable settled with no
|
|
112
|
+
* payable instrument seen first.
|
|
113
|
+
*/
|
|
114
|
+
cycle_seconds: number | null;
|
|
95
115
|
payer_calls: string[];
|
|
96
116
|
}
|
|
97
117
|
|
|
@@ -127,6 +147,10 @@ export interface RunScenarioOptions {
|
|
|
127
147
|
say?: (line: string) => void;
|
|
128
148
|
tell?: (line: string) => void;
|
|
129
149
|
waitSeconds?: number | undefined;
|
|
150
|
+
/** Test only: stub rail options merged over the scenario's, to script an issuer the packs do not (an error, an unpayable settlement). */
|
|
151
|
+
stubRail?: StubRailOptions | StubChargeRailOptions;
|
|
152
|
+
/** The locale of the lines the run prints. The pack's assertions are on states, never on wording, so it passes in either. */
|
|
153
|
+
locale?: Locale | undefined;
|
|
130
154
|
}
|
|
131
155
|
|
|
132
156
|
export async function runScenario(agent: Agent, scenario: Scenario, options: RunScenarioOptions): Promise<ScenarioRun> {
|
|
@@ -149,7 +173,8 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
149
173
|
runsDir: options.runsDir ?? join(agent.dir, "runs"),
|
|
150
174
|
stateDir,
|
|
151
175
|
...(rail === "stub" ? { now: tick } : {}),
|
|
152
|
-
...(
|
|
176
|
+
...(options.locale ? { locale: options.locale } : {}),
|
|
177
|
+
...(scenario.stub_refuse_payees.length > 0 || options.stubRail ? { stubRail: { ...(scenario.stub_refuse_payees.length > 0 ? { refusePayees: scenario.stub_refuse_payees } : {}), ...(options.stubRail ?? {}) } } : {}),
|
|
153
178
|
say,
|
|
154
179
|
});
|
|
155
180
|
const stub = s.rail as { armUncertainOnce?: () => void };
|
|
@@ -186,7 +211,7 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
186
211
|
});
|
|
187
212
|
const result = await loop.turn(turn.input);
|
|
188
213
|
replies.push(result.reply);
|
|
189
|
-
refusedBeforeDraft
|
|
214
|
+
refusedBeforeDraft = draftRefusals(s.store, s.runId).length;
|
|
190
215
|
if (turn.payer === "late") for (const e of s.engine.list({ state: "executing" })) if (!before.has(e.id)) late.push(e.id);
|
|
191
216
|
}
|
|
192
217
|
// A late payer pays after the conversation ended (the receivable was in flight while the world changed).
|
|
@@ -219,6 +244,8 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
219
244
|
if (e.type === "sandbox_payer") payerCalls.push(String((e.payload as { detail: string }).detail));
|
|
220
245
|
}
|
|
221
246
|
const executions = s.engine.list().filter((e) => e.run_id === s.runId);
|
|
247
|
+
const payableSeen = new Map(executions.map((e) => [e.id, awaitsPayer ? payableSeenBeforePayment(e, events) : null]));
|
|
248
|
+
const cycleIsReal = firstIssued !== undefined && lastClosed !== undefined && [...payableSeen.values()].every((seen) => seen !== false);
|
|
222
249
|
return {
|
|
223
250
|
scenario: scenario.name,
|
|
224
251
|
mode: options.mode,
|
|
@@ -235,13 +262,14 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
235
262
|
trail: e.history.map((h) => h.to),
|
|
236
263
|
charge_ids: e.outcomes.map((o) => o.transaction_id).filter((x): x is string => typeof x === "string"),
|
|
237
264
|
receipt_ids: e.outcomes.filter((o) => o.receipt_id).map((o) => o.receipt_id as string),
|
|
265
|
+
payable_seen: payableSeen.get(e.id) ?? null,
|
|
238
266
|
})),
|
|
239
267
|
refused_before_draft: refusedBeforeDraft,
|
|
240
268
|
receipts: s.bundle.listReceipts().length,
|
|
241
269
|
settled_total: executions.filter((e) => e.state === "settled").reduce((sum, e) => sum + e.total, 0),
|
|
242
270
|
charges_issued: events.filter((e) => e.type === "rail.outcome" && (e.payload as { status: string }).status === "accepted").length,
|
|
243
271
|
debtor_messages: events.filter((e) => e.type === "message.debtor").length,
|
|
244
|
-
cycle_seconds:
|
|
272
|
+
cycle_seconds: cycleIsReal ? Math.round(((lastClosed! - firstIssued!) / 1000) * 10) / 10 : null,
|
|
245
273
|
payer_calls: payerCalls,
|
|
246
274
|
};
|
|
247
275
|
} finally {
|
|
@@ -249,6 +277,20 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
249
277
|
}
|
|
250
278
|
}
|
|
251
279
|
|
|
280
|
+
/**
|
|
281
|
+
* For a receivable that settled: was a payable instrument (`charge.instrument` with `payable: true`) recorded for it BEFORE the
|
|
282
|
+
* first thing that paid it (the sandbox payer's call, `commerce.charge.paid`, or the transition to `settled`)? `null` for an
|
|
283
|
+
* execution that is not a settled receivable.
|
|
284
|
+
*/
|
|
285
|
+
export function payableSeenBeforePayment(execution: Execution, events: ReadonlyArray<{ seq: number; execution_id: string | null; type: string; payload: unknown }>): boolean | null {
|
|
286
|
+
if (execution.state !== "settled") return null;
|
|
287
|
+
const own = events.filter((e) => e.execution_id === execution.id).sort((a, b) => a.seq - b.seq);
|
|
288
|
+
if (!own.some((e) => e.type === "rail.outcome" && (e.payload as { status?: string }).status === "accepted")) return null;
|
|
289
|
+
const paid = own.find((e) => e.type === "sandbox_payer" || e.type === "commerce.charge.paid" || (e.type === "execution.transition" && (e.payload as { to?: string }).to === "settled"));
|
|
290
|
+
if (!paid) return null;
|
|
291
|
+
return own.some((e) => e.seq < paid.seq && e.type === "charge.instrument" && (e.payload as { payable?: boolean }).payable === true);
|
|
292
|
+
}
|
|
293
|
+
|
|
252
294
|
function applyHook(s: Setup, hook: "revoke_mandate" | "pause_all" | undefined): void {
|
|
253
295
|
if (hook === "revoke_mandate") s.gate.revoke(s.mandate.id, "revoked mid-run by the scenario");
|
|
254
296
|
if (hook === "pause_all") s.gate.pauseAll();
|
|
@@ -267,7 +309,12 @@ export function checkScenario(scenario: Scenario, run: ScenarioRun): ScenarioChe
|
|
|
267
309
|
if (expect.settled_total !== undefined && run.settled_total !== expect.settled_total) failures.push(`settled_total ${run.settled_total} != ${expect.settled_total}`);
|
|
268
310
|
if (expect.charges_issued !== undefined && run.charges_issued !== expect.charges_issued) failures.push(`charges_issued ${run.charges_issued} != ${expect.charges_issued}`);
|
|
269
311
|
if (expect.debtor_messages !== undefined && run.debtor_messages !== expect.debtor_messages) failures.push(`debtor_messages ${run.debtor_messages} != ${expect.debtor_messages}`);
|
|
270
|
-
if (expect.max_cycle_seconds !== undefined && run.rail === "api" && run.cycle_seconds > expect.max_cycle_seconds) failures.push(`cycle_seconds ${run.cycle_seconds} > ${expect.max_cycle_seconds}`);
|
|
312
|
+
if (expect.max_cycle_seconds !== undefined && run.rail === "api" && run.cycle_seconds !== null && run.cycle_seconds > expect.max_cycle_seconds) failures.push(`cycle_seconds ${run.cycle_seconds} > ${expect.max_cycle_seconds}`);
|
|
313
|
+
if (expect.max_cycle_seconds !== undefined && run.rail === "api" && run.cycle_seconds === null && !run.executions.some((e) => e.payable_seen === false)) failures.push("cycle_seconds: no cycle was measured");
|
|
314
|
+
}
|
|
315
|
+
// Every run, every rail: a receivable that settled on an instrument nobody saw is not a closed cycle, whatever state it reached.
|
|
316
|
+
for (const e of run.executions) {
|
|
317
|
+
if (e.payable_seen === false) failures.push(`no_payable_instrument: ${e.id} settled on ${e.charge_ids.join(", ") || "a receivable"} with no payable instrument seen before the payment`);
|
|
271
318
|
}
|
|
272
319
|
// Every run, every mode: nothing reaches executing without an approval artifact carrying its hash.
|
|
273
320
|
return { ok: failures.length === 0, mode: run.mode, failures, run };
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* rail, the tool handlers and the policy extension, through its kit.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
8
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
9
9
|
import {
|
|
10
10
|
AgentLoop,
|
|
11
11
|
ExecutionEngine,
|
|
@@ -19,7 +19,13 @@ import {
|
|
|
19
19
|
loadToolsFile,
|
|
20
20
|
newRunId,
|
|
21
21
|
resolveFixedClock,
|
|
22
|
+
resolveLocale,
|
|
23
|
+
isLocale,
|
|
24
|
+
parseLocale,
|
|
25
|
+
CORE_STRINGS,
|
|
22
26
|
type AgentRuntime,
|
|
27
|
+
type CoreStrings,
|
|
28
|
+
type Locale,
|
|
23
29
|
type ApprovalMode,
|
|
24
30
|
type ConversationScript,
|
|
25
31
|
type Execution,
|
|
@@ -32,15 +38,30 @@ import {
|
|
|
32
38
|
type StubRailOptions,
|
|
33
39
|
type ToolContext,
|
|
34
40
|
type ToolHandler,
|
|
41
|
+
CODESPAR_KEY_PLACEHOLDER,
|
|
35
42
|
} from "@codespar/agent-core";
|
|
36
43
|
import { AnthropicRuntime } from "@codespar/agent-core/providers/anthropic";
|
|
37
44
|
import type { ApiClient } from "@codespar/sdk";
|
|
38
45
|
import { envName, type Agent } from "./agent.js";
|
|
39
|
-
import type { AgentKit, RailKind, SandboxPayer, Settlement } from "./kit.js";
|
|
46
|
+
import type { AgentKit, KitStrings, RailKind, SandboxPayer, Settlement } from "./kit.js";
|
|
40
47
|
|
|
41
48
|
/** The `.env.example` placeholder counts as no key: a copied example must replay, not call Anthropic with a fake key. */
|
|
42
49
|
export const ANTHROPIC_KEY_PLACEHOLDER = "sk-ant-your_key_here";
|
|
43
|
-
export
|
|
50
|
+
export { CODESPAR_KEY_PLACEHOLDER };
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The `.env` an agent reads (`readDotEnv(agent.dir)`), as a person would type
|
|
54
|
+
* it from where they ran the command: relative when it is below, absolute when
|
|
55
|
+
* it is not. `npm run` moves a workspace script into the agent's directory, so
|
|
56
|
+
* where the PERSON ran it is `INIT_CWD`, which npm sets; `npm run consent` at
|
|
57
|
+
* the root names `agents/bills-agent/.env`, not `.env`. The key refusals name
|
|
58
|
+
* this path, never a guess (#50).
|
|
59
|
+
*/
|
|
60
|
+
export function envFileOf(agentDir: string, cwd: string = process.env["INIT_CWD"] || process.cwd()): string {
|
|
61
|
+
const path = join(agentDir, ".env");
|
|
62
|
+
const rel = relative(cwd, path);
|
|
63
|
+
return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? path : rel;
|
|
64
|
+
}
|
|
44
65
|
|
|
45
66
|
export type ProviderKind = "anthropic" | "replay";
|
|
46
67
|
|
|
@@ -71,6 +92,8 @@ export interface SetupOptions {
|
|
|
71
92
|
mandate?: Mandate | undefined;
|
|
72
93
|
env?: NodeJS.ProcessEnv;
|
|
73
94
|
say?: ((line: string) => void) | undefined;
|
|
95
|
+
/** `--locale`. Absent: the manifest's `locale`, else pt-BR. */
|
|
96
|
+
locale?: Locale | undefined;
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
export interface Setup {
|
|
@@ -97,6 +120,18 @@ export interface Setup {
|
|
|
97
120
|
system: string;
|
|
98
121
|
handlers: Record<string, ToolHandler>;
|
|
99
122
|
tools: ReturnType<typeof loadToolsFile>;
|
|
123
|
+
/**
|
|
124
|
+
* The language of what the code prints in this run. Fixed at setup, and
|
|
125
|
+
* recorded in the bundle's `run.json`. The one command that changes it is
|
|
126
|
+
* `poll --channel whatsapp`, which sets it to the locale the conversation
|
|
127
|
+
* was recorded in before it says anything, so a conversation that started
|
|
128
|
+
* in one language is not told its outcome in the other.
|
|
129
|
+
*/
|
|
130
|
+
locale: Locale;
|
|
131
|
+
/** The kit's words in `locale`. */
|
|
132
|
+
readonly strings: KitStrings;
|
|
133
|
+
/** The words every agent shares, in `locale`. */
|
|
134
|
+
readonly coreStrings: CoreStrings;
|
|
100
135
|
/**
|
|
101
136
|
* The conversation this run is bound to, when a channel binds one (WhatsApp):
|
|
102
137
|
* its contact and its subject. Set by the channel's start, read by a kit
|
|
@@ -144,6 +179,7 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
144
179
|
const tools = loadToolsFile(manifest.resolvePath(manifest.manifest.tools));
|
|
145
180
|
const system = readFileSync(join(agent.dir, "SYSTEM_PROMPT.md"), "utf8");
|
|
146
181
|
const mode: ApprovalMode = options.mode ?? manifest.manifest.default_approval;
|
|
182
|
+
const locale = resolveLocale(options.locale, manifest.manifest);
|
|
147
183
|
if (!manifest.manifest.approval.includes(mode)) throw new Error(`agent.yaml does not support approval: ${mode}`);
|
|
148
184
|
|
|
149
185
|
// <PREFIX>_STATE_DIR / <PREFIX>_RUNS_DIR exist for the restart test, which drives a child process over a scratch state.
|
|
@@ -174,9 +210,10 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
174
210
|
const bundle = new ProofBundle(runs, runId);
|
|
175
211
|
bundle.mandateSnapshot(mandate);
|
|
176
212
|
// Section 11: mode, rail and mandate id. The VERSION rides with the id, so a reader knows which signing of the mandate authorised the run without opening the snapshot.
|
|
177
|
-
bundle.meta({ run_id: runId, agent: `${manifest.manifest.name}@${manifest.manifest.version}`, mode, rail: railKind, mandate_id: mandate.id, mandate_version: mandate.version, started_at: (now ?? (() => new Date()))().toISOString() });
|
|
213
|
+
bundle.meta({ run_id: runId, agent: `${manifest.manifest.name}@${manifest.manifest.version}`, mode, rail: railKind, mandate_id: mandate.id, mandate_version: mandate.version, locale, started_at: (now ?? (() => new Date()))().toISOString() });
|
|
178
214
|
|
|
179
|
-
|
|
215
|
+
// Read at call time, because `poll --channel whatsapp` may move the run to the conversation's recorded locale after setup.
|
|
216
|
+
const policyExtension = agent.kit.policyExtension?.({ agentDir: agent.dir, manifest, guardrails, store, locale: () => s.locale });
|
|
180
217
|
const engine = new ExecutionEngine({
|
|
181
218
|
store,
|
|
182
219
|
rail,
|
|
@@ -223,6 +260,13 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
223
260
|
system,
|
|
224
261
|
handlers: {},
|
|
225
262
|
tools,
|
|
263
|
+
locale,
|
|
264
|
+
get strings() {
|
|
265
|
+
return agent.kit.strings[this.locale];
|
|
266
|
+
},
|
|
267
|
+
get coreStrings() {
|
|
268
|
+
return CORE_STRINGS[this.locale];
|
|
269
|
+
},
|
|
226
270
|
makeRuntime,
|
|
227
271
|
makeLoop: (runtime, onExecution, onBatch) => new AgentLoop({ runtime, tools, handlers: s.handlers, system, bundle, engine, onExecution, ...(onBatch ? { onBatch } : {}), ...(now ? { clock: now } : {}) }),
|
|
228
272
|
close: () => store.close(),
|
|
@@ -231,6 +275,32 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
231
275
|
return s;
|
|
232
276
|
}
|
|
233
277
|
|
|
278
|
+
/** `--locale <pt-BR|en>` out of a command's argv, validated. `undefined` when absent. */
|
|
279
|
+
export function localeFlag(argv: readonly string[]): Locale | undefined {
|
|
280
|
+
const at = argv.indexOf("--locale");
|
|
281
|
+
if (at < 0) return undefined;
|
|
282
|
+
const value = argv[at + 1];
|
|
283
|
+
if (value === undefined) throw new Error("--locale needs a value");
|
|
284
|
+
return parseLocale(value);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** The locale the run `runId` recorded in its bundle, if the bundle is here and records one. */
|
|
288
|
+
export function recordedLocale(agent: Agent, runId: string, env: NodeJS.ProcessEnv = process.env): Locale | undefined {
|
|
289
|
+
const locale = ProofBundle.open(runsDir(agent, env), runId)?.readMeta()?.["locale"];
|
|
290
|
+
return isLocale(locale) ? locale : undefined;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* The same setup, speaking the locale the run that created `execution`
|
|
295
|
+
* recorded. For a command that tells an outcome days after the run that
|
|
296
|
+
* proposed it (`poll`, `webhook`): the counterparty is told in the language
|
|
297
|
+
* they were spoken to in, whatever this command's own locale is.
|
|
298
|
+
*/
|
|
299
|
+
export function inLocaleOf(s: Setup, execution: Execution): Setup {
|
|
300
|
+
const locale = recordedLocale(s.agent, execution.run_id);
|
|
301
|
+
return locale === undefined || locale === s.locale ? s : (Object.create(s, { locale: { value: locale } }) as Setup);
|
|
302
|
+
}
|
|
303
|
+
|
|
234
304
|
export class NoMandateError extends Error {
|
|
235
305
|
constructor() {
|
|
236
306
|
super("no signed mandate yet: run `npm run consent -- --yes` first (or `npm start` without --input, which starts the consent when a test key is present)");
|
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* The terminal channel: what `codespar-agent start` opens. No account, no
|
|
3
3
|
* server. It shows what the core decided, asks the person when an execution
|
|
4
4
|
* is awaiting approval, and prints where the sealed outcome landed. The
|
|
5
|
-
* words are the agent's (`kit.
|
|
6
|
-
*
|
|
5
|
+
* words are the agent's (`kit.strings`, `kit.describeExecution`) and the
|
|
6
|
+
* shared ones (`CORE_STRINGS`), in the run's locale; the order of the gates
|
|
7
|
+
* is the runner's and is the same for every agent, and so is what an answer
|
|
8
|
+
* decides: the parsers below read both languages whatever the locale.
|
|
7
9
|
*/
|
|
8
10
|
import { createInterface } from "node:readline/promises";
|
|
9
11
|
import { stdin, stderr, stdout } from "node:process";
|
|
10
12
|
import { relative } from "node:path";
|
|
11
|
-
import type
|
|
13
|
+
import { formatBRL, railErrorOf, type AgentRuntime, type BatchGesture, type BatchPresentation, type ChargeInstrument, type Execution, type NotRunLine } from "@codespar/agent-core";
|
|
12
14
|
import { pollUntilClosed, type PollResult } from "./poll.js";
|
|
13
|
-
import
|
|
15
|
+
import { draftRefusals, refusalLine, sayOutcome } from "./outcome.js";
|
|
16
|
+
import { inLocaleOf, type Setup } from "./setup.js";
|
|
14
17
|
|
|
15
18
|
export interface TerminalOptions {
|
|
16
19
|
setup: Setup;
|
|
@@ -69,7 +72,7 @@ export async function followUp(execution: Execution, setup: Setup, say: (line: s
|
|
|
69
72
|
|
|
70
73
|
function receiptLines(execution: Execution, setup: Setup, say: (line: string) => void): void {
|
|
71
74
|
for (const outcome of execution.outcomes) {
|
|
72
|
-
if (outcome.receipt_id) say(` ${setup.
|
|
75
|
+
if (outcome.receipt_id) say(` ${setup.strings.receiptWord}: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -78,7 +81,8 @@ export async function handleExecution(execution: Execution, options: TerminalOpt
|
|
|
78
81
|
const { setup, approver } = options;
|
|
79
82
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
80
83
|
const tell = options.tell ?? ((l: string) => stdout.write(l + "\n"));
|
|
81
|
-
const
|
|
84
|
+
const words = setup.strings;
|
|
85
|
+
const text = setup.coreStrings;
|
|
82
86
|
const engine = setup.engine;
|
|
83
87
|
|
|
84
88
|
for (const line of describeExecution(execution, setup)) say(line);
|
|
@@ -91,42 +95,43 @@ export async function handleExecution(execution: Execution, options: TerminalOpt
|
|
|
91
95
|
} else {
|
|
92
96
|
let decision = options.decision;
|
|
93
97
|
if (!decision) {
|
|
94
|
-
if (current.blocking_reasons.length > 0) say(
|
|
98
|
+
if (current.blocking_reasons.length > 0) say(text.onlyDeny);
|
|
95
99
|
const ask = options.ask ?? defaultAsk;
|
|
96
|
-
|
|
97
|
-
decision = answer === "s" || answer === "sim" || answer === "y" || answer === "yes" ? "approve" : "deny";
|
|
100
|
+
decision = parseApproval(await ask(words.approveQuestion));
|
|
98
101
|
}
|
|
99
102
|
if (decision === "approve") current = engine.approve(current.id, approver);
|
|
100
103
|
else if (decision === "deny") current = engine.deny(current.id, approver);
|
|
101
104
|
else {
|
|
102
|
-
say(
|
|
105
|
+
say(text.leftAwaiting);
|
|
103
106
|
return current;
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
|
-
say(
|
|
109
|
+
say(transitionLine(current));
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
// An agent that issues on request (`executeOnApproval: false`) leaves the approved execution for its own tool to issue.
|
|
110
113
|
if (current.state === "approved" && setup.kit.executeOnApproval !== false) {
|
|
111
114
|
current = await engine.execute(current.id);
|
|
112
|
-
say(
|
|
115
|
+
say(transitionLine(current));
|
|
113
116
|
if (setup.settlement === "immediate") {
|
|
114
117
|
receiptLines(current, setup, say);
|
|
115
|
-
if (current.state === "executing") say(
|
|
118
|
+
if (current.state === "executing") say(words.uncertainDispatch);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
if (setup.settlement === "await-payer") {
|
|
123
|
+
// The counterparty is spoken to in the locale of the run that proposed this execution (`npm run approve` is a later command); the operator's lines stay in this one's.
|
|
124
|
+
const counterparty = inLocaleOf(setup, current);
|
|
120
125
|
if (current.state === "executing" && current.reason === "awaiting_settlement") {
|
|
121
|
-
const result = await waitForPayer(current.id, options);
|
|
126
|
+
const result = await waitForPayer(current.id, { ...options, setup: counterparty });
|
|
122
127
|
current = result.execution;
|
|
123
|
-
say(
|
|
128
|
+
say(`${transitionLine(current)}${text.afterLooks(result.rounds, result.seconds, result.timed_out)}`);
|
|
124
129
|
receiptLines(current, setup, say);
|
|
125
130
|
} else if (current.state === "executing") {
|
|
126
|
-
say(
|
|
131
|
+
say(words.uncertainDispatch);
|
|
127
132
|
}
|
|
128
133
|
const told = current;
|
|
129
|
-
announceOutcome(told,
|
|
134
|
+
announceOutcome(told, counterparty, (line) => tell(line, told));
|
|
130
135
|
await followUp(current, setup, say);
|
|
131
136
|
}
|
|
132
137
|
return current;
|
|
@@ -150,6 +155,16 @@ function decideByGesture(execution: Execution, gesture: BatchGestureRecord, setu
|
|
|
150
155
|
return engine.approve(execution.id, approver);
|
|
151
156
|
}
|
|
152
157
|
|
|
158
|
+
/**
|
|
159
|
+
* What the person answered to the per-line question. Yes is s, sim, y or yes,
|
|
160
|
+
* in any locale; anything else is no, which is the default the `[s/N]` and
|
|
161
|
+
* `[y/N]` prompts show.
|
|
162
|
+
*/
|
|
163
|
+
export function parseApproval(answer: string): "approve" | "deny" {
|
|
164
|
+
const text = answer.trim().toLowerCase();
|
|
165
|
+
return text === "s" || text === "sim" || text === "y" || text === "yes" ? "approve" : "deny";
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
/**
|
|
154
169
|
* What the person answered to a whole list, or `undefined` when the answer
|
|
155
170
|
* cannot be read as one. Lines are numbered from 1, as they were shown.
|
|
@@ -181,28 +196,30 @@ export async function presentBatch(batch: BatchPresentation, options: TerminalOp
|
|
|
181
196
|
const { setup, approver } = options;
|
|
182
197
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
183
198
|
const ask = options.ask ?? defaultAsk;
|
|
184
|
-
|
|
199
|
+
const text = setup.coreStrings;
|
|
200
|
+
// The amounts are formatted here from their minor units, in the run's locale; the presentation's own strings are the model's.
|
|
201
|
+
say(text.batchHeader(batch.ref, batch.label, batch.count, formatBRL(batch.total_minor, setup.locale), batch.batch_hash.slice(0, 19)));
|
|
185
202
|
for (const line of batch.lines) {
|
|
186
203
|
const note =
|
|
187
204
|
line.status === "already_settled"
|
|
188
|
-
?
|
|
205
|
+
? text.batchAlreadySettled
|
|
189
206
|
: line.status === "in_progress"
|
|
190
|
-
?
|
|
207
|
+
? text.batchInProgress
|
|
191
208
|
: line.status === "attempt_id_conflict"
|
|
192
|
-
?
|
|
209
|
+
? text.batchAttemptConflict
|
|
193
210
|
: "";
|
|
194
|
-
say(` ${line.index + 1}. ${line.beneficiary}: ${line.
|
|
211
|
+
say(` ${line.index + 1}. ${line.beneficiary}: ${formatBRL(line.amount_minor, setup.locale)}${note}`);
|
|
195
212
|
}
|
|
196
213
|
let parsed: { vetoed: number[] } | undefined;
|
|
197
214
|
while (!parsed) {
|
|
198
|
-
parsed = parseBatchGesture(await ask(
|
|
199
|
-
if (!parsed) say(
|
|
215
|
+
parsed = parseBatchGesture(await ask(text.batchQuestion), batch.count);
|
|
216
|
+
if (!parsed) say(text.batchUnreadable(batch.count));
|
|
200
217
|
}
|
|
201
218
|
const vetoed = new Set(parsed.vetoed);
|
|
202
219
|
const gesture: BatchGesture = { batch_hash: batch.batch_hash, approved: batch.lines.map((l) => l.index).filter((i) => !vetoed.has(i)), vetoed: parsed.vetoed };
|
|
203
220
|
options.gestures.set(batch.ref, { batch_hash: batch.batch_hash, count: batch.count, vetoed });
|
|
204
221
|
setup.engine.note("batch.gesture", null, { batch_ref: batch.ref, batch_hash: batch.batch_hash, count: batch.count, total_minor: batch.total_minor, approved: gesture.approved, vetoed: gesture.vetoed, approver: { type: "human", id: approver.id, channel: approver.channel } });
|
|
205
|
-
say(
|
|
222
|
+
say(gesture.vetoed.length === 0 ? text.batchApprovedAll : gesture.approved.length === 0 ? text.batchDeniedAll : text.batchApprovedExcept(gesture.vetoed.map((i) => i + 1).join(", ")));
|
|
206
223
|
return gesture;
|
|
207
224
|
}
|
|
208
225
|
|
|
@@ -215,9 +232,9 @@ export async function waitForPayer(executionId: string, options: TerminalOptions
|
|
|
215
232
|
intervalMs: setup.pollIntervalMs,
|
|
216
233
|
timeoutMs: waitSeconds * 1000,
|
|
217
234
|
payer: options.simulatePayer ? setup.payer : undefined,
|
|
218
|
-
onInstrument: (e, n, id, instrument) => (options.presentInstrument ?? setup.kit.presentInstrument)?.(e, n, id, instrument, tell),
|
|
235
|
+
onInstrument: (e, n, id, instrument) => (options.presentInstrument ?? setup.kit.presentInstrument)?.(e, n, id, instrument, tell, setup.locale),
|
|
219
236
|
onWait: (_e, round) => {
|
|
220
|
-
const line = setup.
|
|
237
|
+
const line = setup.strings.waitingForPayer?.(round);
|
|
221
238
|
if (setup.railKind === "api" && line !== undefined && round % 5 === 0) say(line);
|
|
222
239
|
},
|
|
223
240
|
});
|
|
@@ -238,18 +255,20 @@ export function closeTerminal(): void {
|
|
|
238
255
|
export async function interactive(options: TerminalOptions & { runtime: AgentRuntime }): Promise<void> {
|
|
239
256
|
const { setup } = options;
|
|
240
257
|
const say = options.say ?? ((l: string) => stderr.write(l + "\n"));
|
|
241
|
-
const
|
|
258
|
+
const words = setup.strings;
|
|
242
259
|
// Interactive only: a person at the keyboard can decide a list in one go. The one-shot and the scenario runner pass one decision to every line and never reach this.
|
|
243
260
|
const gestures: BatchGestures = new Map();
|
|
244
261
|
const withGestures = { ...options, gestures };
|
|
245
262
|
const loop = setup.makeLoop(options.runtime, (execution) => handleExecution(execution, withGestures), (batch) => presentBatch(batch, withGestures));
|
|
246
|
-
say(
|
|
247
|
-
say(
|
|
248
|
-
say(
|
|
263
|
+
say(setup.coreStrings.banner(setup.manifest.manifest.name, setup.manifest.manifest.version, setup.mode, setup.railKind, words.mandateWord, setup.mandate.id));
|
|
264
|
+
say(setup.coreStrings.bundleAt(setup.runId, relative(process.cwd(), setup.bundle.dir)));
|
|
265
|
+
say(words.intro);
|
|
266
|
+
const notRun: NotRunLine[] = [];
|
|
267
|
+
let refusalsSaid = 0;
|
|
249
268
|
for (;;) {
|
|
250
269
|
let text: string;
|
|
251
270
|
try {
|
|
252
|
-
text = await defaultAsk(
|
|
271
|
+
text = await defaultAsk(words.prompt);
|
|
253
272
|
} catch {
|
|
254
273
|
break;
|
|
255
274
|
}
|
|
@@ -257,7 +276,26 @@ export async function interactive(options: TerminalOptions & { runtime: AgentRun
|
|
|
257
276
|
if (!trimmed) continue;
|
|
258
277
|
if (["sair", "exit", "quit"].includes(trimmed.toLowerCase())) break;
|
|
259
278
|
const result = await loop.turn(trimmed);
|
|
260
|
-
stdout.write(result.reply
|
|
279
|
+
stdout.write(`${result.reply}\n`);
|
|
280
|
+
// The line counts the run so far, and is said only after a turn that paid, tried to, or skipped a line: a greeting or a read moved nothing.
|
|
281
|
+
notRun.push(...result.not_run);
|
|
282
|
+
// A request refused before a draft: said with the engine's own reason, once, in the turn that met it.
|
|
283
|
+
const refused = draftRefusals(setup.store, setup.runId).slice(refusalsSaid);
|
|
284
|
+
refusalsSaid += refused.length;
|
|
285
|
+
for (const refusal of refused) say(refusalLine(refusal));
|
|
286
|
+
if (result.executions.length > 0 || result.not_run.length > 0 || refused.length > 0) sayOutcome(setup, notRun, (line) => stdout.write(`${line}\n`));
|
|
261
287
|
}
|
|
262
288
|
closeTerminal();
|
|
263
289
|
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* ` -> failed (rail_failed): insufficient_funds — wallet cannot reserve the requested amount`.
|
|
293
|
+
* The reason says which gate closed the execution; on a failure, or an answer
|
|
294
|
+
* that left an attempt unknown, the rail's own code and message follow it,
|
|
295
|
+
* verbatim, so the first failure explains itself (#50).
|
|
296
|
+
*/
|
|
297
|
+
export function transitionLine(execution: Execution): string {
|
|
298
|
+
const failure = execution.state === "failed" || execution.state === "executing" ? railErrorOf(execution) : null;
|
|
299
|
+
const answer = failure ? `: ${failure.code}${failure.message && failure.message !== failure.code ? ` — ${failure.message}` : ""}` : "";
|
|
300
|
+
return ` -> ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}${answer}`;
|
|
301
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit reads `CODESPAR_API_URL` and `CODESPAR_PROJECT_ID`; the CodeSpar CLI
|
|
3
|
+
* reads `CODESPAR_BASE_URL` and `CODESPAR_PROJECT`. A shell set up for one
|
|
4
|
+
* must not send the other to production in silence: the kit takes the CLI's
|
|
5
|
+
* names as aliases, and refuses to start when the two names disagree.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { EnvNamesDisagreeError, reconcileEnvNames } from "../src/env.js";
|
|
9
|
+
|
|
10
|
+
const STAGING = "https://api.staging.codespar.dev";
|
|
11
|
+
|
|
12
|
+
describe("reconcileEnvNames", () => {
|
|
13
|
+
it("fills the kit's names from the CLI's when only the CLI's are set", () => {
|
|
14
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_BASE_URL: STAGING, CODESPAR_PROJECT: "prj_cli" };
|
|
15
|
+
reconcileEnvNames(env);
|
|
16
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
17
|
+
expect(env["CODESPAR_PROJECT_ID"]).toBe("prj_cli");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("fills the CLI's names from the kit's too, so a .env read later cannot reopen a pair the shell closed", () => {
|
|
21
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_PROJECT_ID: "prj_kit" };
|
|
22
|
+
reconcileEnvNames(env);
|
|
23
|
+
expect(env["CODESPAR_BASE_URL"]).toBe(STAGING);
|
|
24
|
+
expect(env["CODESPAR_PROJECT"]).toBe("prj_kit");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("leaves the kit's names alone when the CLI's are unset or empty", () => {
|
|
28
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_BASE_URL: "", CODESPAR_PROJECT_ID: "prj_kit" };
|
|
29
|
+
reconcileEnvNames(env);
|
|
30
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
31
|
+
expect(env["CODESPAR_PROJECT_ID"]).toBe("prj_kit");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("treats an empty kit name as unset, as the CLI does with its own", () => {
|
|
35
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: "", CODESPAR_BASE_URL: STAGING };
|
|
36
|
+
reconcileEnvNames(env);
|
|
37
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("accepts both names when they say the same thing, a trailing slash aside", () => {
|
|
41
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: STAGING, CODESPAR_BASE_URL: `${STAGING}/`, CODESPAR_PROJECT_ID: "prj_1", CODESPAR_PROJECT: "prj_1" };
|
|
42
|
+
expect(() => reconcileEnvNames(env)).not.toThrow();
|
|
43
|
+
expect(env["CODESPAR_API_URL"]).toBe(STAGING);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("refuses two URLs that disagree, naming both", () => {
|
|
47
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_API_URL: "https://api.codespar.dev", CODESPAR_BASE_URL: STAGING };
|
|
48
|
+
expect(() => reconcileEnvNames(env)).toThrow(EnvNamesDisagreeError);
|
|
49
|
+
expect(() => reconcileEnvNames(env)).toThrow(/CODESPAR_API_URL=https:\/\/api\.codespar\.dev.*CODESPAR_BASE_URL=https:\/\/api\.staging\.codespar\.dev/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("refuses two projects that disagree, naming both", () => {
|
|
53
|
+
const env: NodeJS.ProcessEnv = { CODESPAR_PROJECT_ID: "prj_kit", CODESPAR_PROJECT: "prj_cli" };
|
|
54
|
+
expect(() => reconcileEnvNames(env)).toThrow(/CODESPAR_PROJECT_ID=prj_kit.*CODESPAR_PROJECT=prj_cli/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header of `inspect` and the mandate's status. The snapshot in the
|
|
3
|
+
* bundle is the local copy at the start of the run and says `active` for a
|
|
4
|
+
* mandate the API answered was revoked two lines below; the header says what
|
|
5
|
+
* a gate of the run heard, when that is the last word the run has.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
import { ProofBundle } from "@codespar/agent-core";
|
|
12
|
+
import { assembleTimeline, renderHtml, renderText } from "../src/inspect.js";
|
|
13
|
+
|
|
14
|
+
const AGENT = { type: "agent", agent: "bills-agent@0.1.0", on_behalf_of: "usr_demo_titular" };
|
|
15
|
+
const SNAPSHOT = "active in the snapshot at the start of the run";
|
|
16
|
+
|
|
17
|
+
type Step = { execution: string | null; to?: string; reason?: string; detail?: string; at: string };
|
|
18
|
+
|
|
19
|
+
function bundleOf(steps: Step[]): ProofBundle {
|
|
20
|
+
const bundle = new ProofBundle(mkdtempSync(join(tmpdir(), "inspect-mandate-status-")), "run_status_mandate_abc123");
|
|
21
|
+
bundle.meta({ run_id: bundle.runId, agent: "bills-agent@0.1.0", mode: "mandate", rail: "api", mandate_id: "cm_fixture", mandate_version: 1, started_at: "2026-09-23T18:00:00.000Z" });
|
|
22
|
+
writeFileSync(join(bundle.dir, "mandate.snapshot.json"), JSON.stringify({ id: "cm_fixture", version: 1, status: "active", currency: "BRL", cap_minor: 7200000, per_tx_cap_minor: 250000, expires_at: "2027-09-23T00:00:00.000Z", beneficiaries: [] }));
|
|
23
|
+
steps.forEach((step, i) => {
|
|
24
|
+
const payload = { ...(step.to ? { from: "approved", to: step.to, at: step.at, actor: AGENT } : {}), ...(step.reason ? { reason: step.reason } : {}), ...(step.detail ? { detail: step.detail } : {}) };
|
|
25
|
+
bundle.event({ seq: i + 1, run_id: bundle.runId, execution_id: step.execution, type: step.to ? "execution.transition" : "execution.refused_before_draft", payload, at: step.at, actor: AGENT });
|
|
26
|
+
});
|
|
27
|
+
return bundle;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const header = (bundle: ProofBundle) => renderText(assembleTimeline(bundle)).split("\n")[2];
|
|
31
|
+
|
|
32
|
+
describe("inspect: the mandate's status in the header", () => {
|
|
33
|
+
it("is the snapshot's when no gate of the run heard otherwise", () => {
|
|
34
|
+
const bundle = bundleOf([
|
|
35
|
+
{ execution: "exe_a", to: "executing", at: "2026-09-23T18:00:10.000Z" },
|
|
36
|
+
{ execution: "exe_a", to: "settled", at: "2026-09-23T18:00:12.000Z" },
|
|
37
|
+
]);
|
|
38
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
39
|
+
expect(header(bundle)).toMatch(/^ {2}mandate active, expires 2027-09-23T00:00:00.000Z · /);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("is what the API answered at the gate, with the source, the time and what the snapshot had said", () => {
|
|
43
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "denied", reason: "mandate_revoked", detail: "mandate cm_fixture was revoked (source: api)", at: "2026-09-23T18:00:13.000Z" }]);
|
|
44
|
+
const report = assembleTimeline(bundle);
|
|
45
|
+
expect(report.mandate).toMatchObject({ status: "active", status_seen: { status: "revoked", source: "api", at: "2026-09-23T18:00:13.000Z" } });
|
|
46
|
+
expect(header(bundle)).toContain(`mandate revoked (source: api, 18:00:13; ${SNAPSHOT}), expires `);
|
|
47
|
+
expect(header(bundle)).not.toContain("mandate active,");
|
|
48
|
+
// The page says the same thing as the terminal.
|
|
49
|
+
expect(renderHtml(report)).toContain(`mandate revoked (source: api, 18:00:13; ${SNAPSHOT}), expires `);
|
|
50
|
+
expect(renderHtml(report)).not.toContain("mandate active,");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("reads a refusal before a draft the same way, and a paused mandate, and the stub", () => {
|
|
54
|
+
const refused = bundleOf([{ execution: null, reason: "mandate_revoked", detail: "mandate cm_fixture was revoked (source: stub)", at: "2026-09-23T18:02:00.000Z" }]);
|
|
55
|
+
expect(header(refused)).toContain(`mandate revoked (source: stub, 18:02:00; ${SNAPSHOT})`);
|
|
56
|
+
const paused = bundleOf([{ execution: "exe_a", to: "denied", reason: "mandate_paused", detail: "mandate cm_fixture is paused (source: api)", at: "2026-09-23T18:00:13.000Z" }]);
|
|
57
|
+
expect(header(paused)).toContain(`mandate paused (source: api, 18:00:13; ${SNAPSHOT})`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("an expiry the run's own clock found names the clock, not a source that never answered it", () => {
|
|
61
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "expired", reason: "mandate_expired", detail: "mandate cm_fixture expired at 2027-09-23T00:00:00.000Z", at: "2027-09-23T00:00:05.000Z" }]);
|
|
62
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toMatchObject({ status: "expired", source: null });
|
|
63
|
+
expect(header(bundle)).toContain(`mandate expired (by the run's clock, 00:00:05; ${SNAPSHOT})`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("a payment that executed after a pause is the last word: the mandate was resumed, and the header is the snapshot's again", () => {
|
|
67
|
+
const bundle = bundleOf([
|
|
68
|
+
{ execution: "exe_a", to: "denied", reason: "mandate_paused", detail: "mandate cm_fixture is paused (source: api)", at: "2026-09-23T18:00:13.000Z" },
|
|
69
|
+
{ execution: "exe_b", to: "executing", at: "2026-09-23T18:05:00.000Z" },
|
|
70
|
+
{ execution: "exe_b", to: "settled", at: "2026-09-23T18:05:02.000Z" },
|
|
71
|
+
]);
|
|
72
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
73
|
+
expect(header(bundle)).toContain("mandate active, expires ");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("a refusal that is not about the mandate's status leaves the header alone", () => {
|
|
77
|
+
const bundle = bundleOf([{ execution: "exe_a", to: "denied", reason: "cap_exceeded", detail: "300000 is above the cap per payment", at: "2026-09-23T18:00:13.000Z" }]);
|
|
78
|
+
expect(assembleTimeline(bundle).mandate?.status_seen).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
});
|