@codespar/cli 0.17.0 → 0.18.1
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 -0
- package/dist/surface.js +53 -1
- package/dist/surface.js.map +1 -1
- package/package.json +1 -1
- package/templates/bills-agent/README.md +1 -1
- package/templates/bills-agent/agents/bills-agent/AGENTS.md +1 -1
- package/templates/bills-agent/agents/bills-agent/CLAUDE.md +1 -1
- package/templates/bills-agent/agents/bills-agent/README.md +6 -5
- package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +5 -4
- package/templates/bills-agent/packages/agent-core/README.md +14 -1
- package/templates/bills-agent/packages/agent-core/package.json +1 -1
- package/templates/bills-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/bills-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/bills-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/bills-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/bills-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/bills-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/bills-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/bills-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/bills-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/bills-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/bills-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/bills-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/bills-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/bills-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/bills-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/bills-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/bills-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/bills-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/bills-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/bills-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/bills-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/bills-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/bills-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/bills-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/bills-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/bills-agent/packages/agent-runtime/README.md +12 -0
- package/templates/bills-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/bills-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/bills-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/bills-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/checkout-agent/LICENSE +21 -0
- package/templates/checkout-agent/README.md +28 -0
- package/templates/checkout-agent/_gitignore +10 -0
- package/templates/checkout-agent/agents/checkout-agent/.env.example +5 -0
- package/templates/checkout-agent/agents/checkout-agent/AGENTS.md +20 -0
- package/templates/checkout-agent/agents/checkout-agent/CLAUDE.md +20 -0
- package/templates/checkout-agent/agents/checkout-agent/README.md +94 -0
- package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +36 -0
- package/templates/checkout-agent/agents/checkout-agent/agent.yaml +30 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +28 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-beatriz.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina-retomada.json +10 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +49 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.json +26 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +7 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.json +16 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +8 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/webhook-replay.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/eval.yaml +11 -0
- package/templates/checkout-agent/agents/checkout-agent/guardrails.json +25 -0
- package/templates/checkout-agent/agents/checkout-agent/mandate.example.json +28 -0
- package/templates/checkout-agent/agents/checkout-agent/package.json +33 -0
- package/templates/checkout-agent/agents/checkout-agent/runbook.md +19 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.json +42 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.json +32 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.json +61 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +61 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +36 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.json +23 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.json +72 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.json +23 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +3 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.json +42 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +12 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.json +14 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +34 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +7 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.json +33 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.json +32 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +92 -0
- package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +338 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +179 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +374 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +220 -0
- package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +297 -0
- package/templates/checkout-agent/agents/checkout-agent/test/adversarial.test.ts +117 -0
- package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +67 -0
- package/templates/checkout-agent/agents/checkout-agent/test/cli.test.ts +169 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +2 -0
- package/templates/checkout-agent/agents/checkout-agent/test/nfse.test.ts +170 -0
- package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +138 -0
- package/templates/checkout-agent/agents/checkout-agent/test/scenarios.test.ts +113 -0
- package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +171 -0
- package/templates/checkout-agent/agents/checkout-agent/tools.json +68 -0
- package/templates/checkout-agent/agents/checkout-agent/tsconfig.json +10 -0
- package/templates/checkout-agent/package.json +38 -0
- package/templates/checkout-agent/packages/agent-core/README.md +34 -0
- package/templates/checkout-agent/packages/agent-core/package.json +24 -0
- package/templates/checkout-agent/packages/agent-core/src/agent.ts +163 -0
- package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +195 -0
- package/templates/checkout-agent/packages/agent-core/src/api/client.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/api/mandate-status.ts +74 -0
- package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +153 -0
- package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +43 -0
- package/templates/checkout-agent/packages/agent-core/src/approval.ts +135 -0
- package/templates/checkout-agent/packages/agent-core/src/bundle.ts +191 -0
- package/templates/checkout-agent/packages/agent-core/src/channels.ts +186 -0
- package/templates/checkout-agent/packages/agent-core/src/check.ts +276 -0
- package/templates/checkout-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/checkout-agent/packages/agent-core/src/engine.ts +1074 -0
- package/templates/checkout-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/checkout-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/checkout-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/checkout-agent/packages/agent-core/src/hash.ts +118 -0
- package/templates/checkout-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/checkout-agent/packages/agent-core/src/index.ts +34 -0
- package/templates/checkout-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/checkout-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/checkout-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/checkout-agent/packages/agent-core/src/rail.ts +186 -0
- package/templates/checkout-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +577 -0
- package/templates/checkout-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/checkout-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/checkout-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +157 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/mandate-status.ts +58 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +209 -0
- package/templates/checkout-agent/packages/agent-core/src/tools.ts +66 -0
- package/templates/checkout-agent/packages/agent-core/src/types.ts +187 -0
- package/templates/checkout-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/checkout-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/checkout-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/checkout-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/checkout-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/checkout-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/checkout-agent/packages/agent-core/test/helpers.ts +142 -0
- package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +229 -0
- package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/checkout-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +416 -0
- package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/checkout-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/checkout-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/checkout-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/checkout-agent/packages/agent-runtime/README.md +80 -0
- package/templates/checkout-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/checkout-agent/packages/agent-runtime/package.json +23 -0
- package/templates/checkout-agent/packages/agent-runtime/src/adversarial.ts +199 -0
- package/templates/checkout-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/types.ts +173 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +459 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +216 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +350 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +180 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +120 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +127 -0
- package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +367 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +145 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +49 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +134 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +248 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +330 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +40 -0
- package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/checkout-agent/packages/agent-runtime/src/index.ts +13 -0
- package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +801 -0
- package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +229 -0
- package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +274 -0
- package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +239 -0
- package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +263 -0
- package/templates/checkout-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +329 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +277 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +167 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/checkout-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/checkout-agent/scripts/whatsapp-emulator.mjs +84 -0
- package/templates/checkout-agent/tsconfig.base.json +16 -0
- package/templates/checkout-agent/vitest.config.ts +12 -0
- package/templates/collections-agent/README.md +6 -1
- package/templates/collections-agent/agents/collections-agent/README.md +12 -8
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +8 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042-retomada.json +10 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +27 -1
- package/templates/collections-agent/agents/collections-agent/src/kit.ts +2 -0
- package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +12 -2
- package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +55 -0
- package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +2 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +12 -6
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +148 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +5 -0
- package/templates/collections-agent/package.json +1 -0
- package/templates/collections-agent/packages/agent-core/README.md +14 -1
- package/templates/collections-agent/packages/agent-core/package.json +1 -1
- package/templates/collections-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/collections-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/collections-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/collections-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/collections-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/collections-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/collections-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/collections-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/collections-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/collections-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/collections-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/collections-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/collections-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/collections-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/collections-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/collections-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/collections-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/collections-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/collections-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/collections-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/collections-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/collections-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/collections-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/collections-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/collections-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/collections-agent/packages/agent-runtime/README.md +12 -0
- package/templates/collections-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/collections-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/collections-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/collections-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/collections-agent/scripts/whatsapp-emulator.mjs +84 -0
- package/templates/hello-agent/README.md +1 -1
- package/templates/hello-agent/packages/agent-core/README.md +14 -1
- package/templates/hello-agent/packages/agent-core/package.json +1 -1
- package/templates/hello-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/hello-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/hello-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/hello-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/hello-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/hello-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/hello-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/hello-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/hello-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/hello-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/hello-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/hello-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/hello-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/hello-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/hello-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/hello-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/hello-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/hello-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/hello-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/hello-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/hello-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/hello-agent/packages/agent-runtime/README.md +12 -0
- package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/hello-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/hello-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/hello-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/kits.lock.json +29 -6
- package/templates/supplier-payments-agent/README.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +11 -9
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +67 -20
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +504 -5
- package/templates/supplier-payments-agent/packages/agent-core/README.md +14 -1
- package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/supplier-payments-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/supplier-payments-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/README.md +12 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
|
@@ -1,31 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `codespar-agent verify <receipt-file> [--json] [--keys <file>
|
|
2
|
+
* `codespar-agent verify <receipt-file> [--json] [--keys <file> | --url <url>] [--approval <file> [--approval-id <id>]] [--from-api]`:
|
|
3
3
|
* the wave-5 gate — someone outside verifies a receipt without access to
|
|
4
|
-
* CodeSpar.
|
|
4
|
+
* CodeSpar — and, since ent#1670, the body and the approval behind it.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Ed25519 signature
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* Three checks, in order, each one only on the answer of the one before:
|
|
7
|
+
*
|
|
8
|
+
* 1. The Ed25519 signature over `codespar-receipt:v1:<id>:<chain>`, against
|
|
9
|
+
* the public key set, fetched over plain HTTPS or read off disk.
|
|
10
|
+
* 2. The chain, recomputed from the API's receipt READ under the
|
|
11
|
+
* `chain_recipe` the SAME key document publishes, held against the
|
|
12
|
+
* signed one: this is what binds the payee, the amount and the approval
|
|
13
|
+
* to the signature.
|
|
14
|
+
* 3. For a v4 chain, the sealed approval link held against the local
|
|
15
|
+
* approval artifact: "this payment was made against the list H".
|
|
16
|
+
*
|
|
17
|
+
* The receipt file is either the read itself — what a tenant hands a third
|
|
18
|
+
* party, payee unmasked; checked with no credential at all — or a copy from a
|
|
19
|
+
* run's `runs/<run-id>/receipts/`, which masks the payee and carries none of
|
|
20
|
+
* the links. A copy reaches check 2 only with `--from-api`: the tenant's
|
|
21
|
+
* `CODESPAR_API_KEY` (the environment, or the `.env` of the agent the copy
|
|
22
|
+
* sits in) reads the receipt from the API, in memory, and nothing unmasked is
|
|
23
|
+
* written anywhere. Without it a copy answers `signature_only`, which is the
|
|
24
|
+
* truth about what a masked copy can prove. The approval artifact of a copy
|
|
25
|
+
* is the one its `approval_id` names in the run's own `approval.json`.
|
|
26
|
+
*
|
|
27
|
+
* It is the one command here that does NOT need an agent — `cli.ts`
|
|
28
|
+
* dispatches it before it looks for an `agent.yaml` — because the file it
|
|
29
|
+
* reads has usually been copied off the machine that produced it.
|
|
13
30
|
*
|
|
14
31
|
* `--json` follows the rule of section 14.5: machine data on stdout, valid
|
|
15
32
|
* JSON and nothing else, human sentences on stderr. The exit code is the
|
|
16
33
|
* verdict (`VERDICT_EXIT_CODES`), so a script branches on WHICH answer it got
|
|
17
34
|
* rather than on "did it fail" — an unsigned receipt is not a failure and must
|
|
18
|
-
* not exit 0 either.
|
|
35
|
+
* not exit 0 either, and neither is a signature whose body was not bound.
|
|
19
36
|
*/
|
|
20
|
-
import { readFileSync } from "node:fs";
|
|
21
|
-
import { resolve } from "node:path";
|
|
37
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
38
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
22
39
|
import { stderr, stdout } from "node:process";
|
|
23
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
DEFAULT_BASE_URL,
|
|
42
|
+
DEFAULT_RECEIPT_KEYS_URL,
|
|
43
|
+
VERDICT_EXIT_CODES,
|
|
44
|
+
copyDisagreesWithRead,
|
|
45
|
+
createCodeSparClient,
|
|
46
|
+
describeApiError,
|
|
47
|
+
isReceiptRead,
|
|
48
|
+
readSignedReceipt,
|
|
49
|
+
receiptKeysUrl,
|
|
50
|
+
signatureOnly,
|
|
51
|
+
verifyReceiptRead,
|
|
52
|
+
verifyReceiptWithKeys,
|
|
53
|
+
type ApprovalClaim,
|
|
54
|
+
type ExecutionItem,
|
|
55
|
+
type ReceiptVerification,
|
|
56
|
+
} from "@codespar/agent-core";
|
|
57
|
+
import { findAgentDir } from "../agent.js";
|
|
58
|
+
import { readDotEnv } from "../setup.js";
|
|
24
59
|
|
|
25
|
-
const USAGE =
|
|
60
|
+
const USAGE =
|
|
61
|
+
"usage: npm run verify <receipt-file> [--json] [--keys <key-set.json> | --url <https://.../.well-known/codespar-receipt-keys.json>] [--approval <approval.json> [--approval-id <apr_...>]] [--from-api]";
|
|
26
62
|
|
|
27
|
-
/** The fetcher the
|
|
28
|
-
* lives here rather than in the core so a unit test injects its own. */
|
|
63
|
+
/** The fetcher the key set comes through: the one unauthenticated call in this command. */
|
|
29
64
|
async function fetchKeyDocument(url: string): Promise<unknown> {
|
|
30
65
|
const controller = new AbortController();
|
|
31
66
|
const timer = setTimeout(() => controller.abort(), 10_000);
|
|
@@ -38,69 +73,226 @@ async function fetchKeyDocument(url: string): Promise<unknown> {
|
|
|
38
73
|
}
|
|
39
74
|
}
|
|
40
75
|
|
|
76
|
+
interface Args {
|
|
77
|
+
json: boolean;
|
|
78
|
+
keysFile?: string;
|
|
79
|
+
url?: string;
|
|
80
|
+
approvalFile?: string;
|
|
81
|
+
approvalId?: string;
|
|
82
|
+
fromApi: boolean;
|
|
83
|
+
receiptFile?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const VALUED: readonly string[] = ["--keys", "--url", "--approval", "--approval-id"];
|
|
87
|
+
|
|
41
88
|
export async function verify(argv: string[]): Promise<number> {
|
|
42
89
|
const say = (line: string) => stderr.write(line + "\n");
|
|
43
|
-
|
|
44
|
-
let keysFile: string | undefined;
|
|
45
|
-
let url: string | undefined;
|
|
46
|
-
let receiptFile: string | undefined;
|
|
90
|
+
const args: Args = { json: false, fromApi: false };
|
|
47
91
|
|
|
48
92
|
for (let i = 0; i < argv.length; i += 1) {
|
|
49
93
|
const a = argv[i]!;
|
|
50
|
-
if (a === "--json") json = true;
|
|
51
|
-
else if (a === "--
|
|
94
|
+
if (a === "--json") args.json = true;
|
|
95
|
+
else if (a === "--from-api") args.fromApi = true;
|
|
96
|
+
else if (VALUED.includes(a)) {
|
|
52
97
|
const value = argv[i + 1];
|
|
53
98
|
if (value === undefined || value.startsWith("--")) {
|
|
54
99
|
say(`${a} needs a value\n${USAGE}`);
|
|
55
100
|
return 2;
|
|
56
101
|
}
|
|
57
|
-
if (a === "--keys") keysFile = value;
|
|
58
|
-
else url = value;
|
|
102
|
+
if (a === "--keys") args.keysFile = value;
|
|
103
|
+
else if (a === "--url") args.url = value;
|
|
104
|
+
else if (a === "--approval") args.approvalFile = value;
|
|
105
|
+
else args.approvalId = value;
|
|
59
106
|
i += 1;
|
|
60
107
|
} else if (a === "--help" || a === "-h") {
|
|
61
108
|
say(USAGE);
|
|
62
109
|
say(`the key set is public and needs no credential; its default is ${DEFAULT_RECEIPT_KEYS_URL}`);
|
|
63
110
|
say("--keys reads a saved copy of that document instead, so the check runs with no network at all");
|
|
111
|
+
say("the receipt file is the API's read (GET /v1/consumers/receipts/{id}), whose body is recomputed against the signed chain, or a run's copy, which proves the signature only");
|
|
112
|
+
say("--from-api reads a run's copy from the API with CODESPAR_API_KEY (in memory, nothing written), so its body and its approval are checked too; the key set then defaults to that deployment's");
|
|
113
|
+
say("--approval holds a v4 receipt's sealed approval link against an approval artifact (a run's copy uses its own approval.json)");
|
|
64
114
|
return 0;
|
|
65
115
|
} else if (a.startsWith("-")) {
|
|
66
116
|
say(`unknown argument ${a}\n${USAGE}`);
|
|
67
117
|
return 2;
|
|
68
|
-
} else if (receiptFile === undefined) receiptFile = a;
|
|
118
|
+
} else if (args.receiptFile === undefined) args.receiptFile = a;
|
|
69
119
|
else {
|
|
70
|
-
say(`verify takes one receipt file (got ${receiptFile} and ${a})\n${USAGE}`);
|
|
120
|
+
say(`verify takes one receipt file (got ${args.receiptFile} and ${a})\n${USAGE}`);
|
|
71
121
|
return 2;
|
|
72
122
|
}
|
|
73
123
|
}
|
|
74
124
|
|
|
75
|
-
if (!receiptFile) {
|
|
125
|
+
if (!args.receiptFile) {
|
|
76
126
|
say(USAGE);
|
|
77
127
|
say("the receipt is the JSON the API returns from GET /v1/consumers/receipts/{id}, or a copy from a run's runs/<run-id>/receipts/");
|
|
78
128
|
return 2;
|
|
79
129
|
}
|
|
80
|
-
if (keysFile && url) {
|
|
130
|
+
if (args.keysFile && args.url) {
|
|
81
131
|
say(`--keys and --url name two different key sets; pass one\n${USAGE}`);
|
|
82
132
|
return 2;
|
|
83
133
|
}
|
|
134
|
+
if (args.approvalId && !args.approvalFile) {
|
|
135
|
+
say(`--approval-id picks one artifact out of --approval; pass the file too\n${USAGE}`);
|
|
136
|
+
return 2;
|
|
137
|
+
}
|
|
84
138
|
|
|
85
|
-
const receipt = readJson(receiptFile, say);
|
|
139
|
+
const receipt = readJson(args.receiptFile, say);
|
|
86
140
|
if (receipt === undefined) return 2;
|
|
87
141
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
142
|
+
// The read and the key set must come from ONE deployment: the recipe that
|
|
143
|
+
// binds the body is the key document's, and a staging read checked under
|
|
144
|
+
// production's document is the §47 trap again.
|
|
145
|
+
const apiBase = process.env["CODESPAR_API_URL"]?.trim() || DEFAULT_BASE_URL;
|
|
146
|
+
if (args.fromApi && args.url && new URL(args.url).origin !== new URL(apiBase).origin) {
|
|
147
|
+
say(`--from-api reads the receipt from ${new URL(apiBase).origin} and --url names the key set of ${new URL(args.url).origin}; the read and the key set must come from the same deployment\n${USAGE}`);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let approval: ApprovalClaim | undefined;
|
|
152
|
+
if (args.approvalFile) {
|
|
153
|
+
const claim = readApprovalClaim(args.approvalFile, args.approvalId, say);
|
|
154
|
+
if (!claim) return 2;
|
|
155
|
+
approval = claim;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let keysDocument: unknown;
|
|
159
|
+
if (args.keysFile) {
|
|
160
|
+
keysDocument = readJson(args.keysFile, say);
|
|
161
|
+
if (keysDocument === undefined) return 2;
|
|
95
162
|
}
|
|
96
163
|
|
|
97
|
-
const report = await
|
|
98
|
-
if (json) stdout.write(JSON.stringify(report) + "\n");
|
|
164
|
+
const report = await check(receipt, args, apiBase, approval, keysDocument);
|
|
165
|
+
if (args.json) stdout.write(JSON.stringify(report) + "\n");
|
|
99
166
|
else stdout.write(render(report));
|
|
100
167
|
say(report.message);
|
|
101
168
|
return VERDICT_EXIT_CODES[report.verdict];
|
|
102
169
|
}
|
|
103
170
|
|
|
171
|
+
async function check(receipt: unknown, args: Args, apiBase: string, approval: ApprovalClaim | undefined, keysDocument: unknown): Promise<ReceiptVerification> {
|
|
172
|
+
// Answered before the network is touched, as before: an unsigned or
|
|
173
|
+
// malformed file needs no key set, and fetching one to check a signature
|
|
174
|
+
// that is not there would turn an offline answer into an outage.
|
|
175
|
+
const signed = readSignedReceipt(receipt);
|
|
176
|
+
if (!signed.ok || signed.fields.receipt_sig_ed25519 === null) return verifyReceiptWithKeys(receipt, { keys: [] }, "none");
|
|
177
|
+
|
|
178
|
+
let document: unknown;
|
|
179
|
+
let label: string;
|
|
180
|
+
if (args.keysFile) {
|
|
181
|
+
label = resolve(args.keysFile);
|
|
182
|
+
document = keysDocument;
|
|
183
|
+
} else {
|
|
184
|
+
label = args.url ?? (args.fromApi ? receiptKeysUrl(apiBase) : DEFAULT_RECEIPT_KEYS_URL);
|
|
185
|
+
try {
|
|
186
|
+
document = await fetchKeyDocument(label);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
return unreachable(
|
|
189
|
+
signed.fields.receipt_id,
|
|
190
|
+
label,
|
|
191
|
+
`the published key set could not be read from ${label}: ${err instanceof Error ? err.message : String(err)}. Nothing is proved and nothing is disproved; the keys can also be saved to a file and passed in`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (isReceiptRead(receipt)) return verifyReceiptRead(receipt, document, { label, ...(approval ? { approval } : {}) });
|
|
197
|
+
|
|
198
|
+
// A run's copy: the signature is checked on the copy itself, as it always was.
|
|
199
|
+
const signature = verifyReceiptWithKeys(receipt, document, label);
|
|
200
|
+
if (signature.verdict !== "verified") return signature;
|
|
201
|
+
if (!args.fromApi) {
|
|
202
|
+
return signatureOnly(signature, "read_required", "this is a run's copy, which masks the payee and carries none of the chain's links. Recompute from the API's read: run this again with --from-api (the tenant's key, read-only, nothing written), or verify the read itself");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const read = await readFromApi(signed.fields.receipt_id, args.receiptFile!, apiBase);
|
|
206
|
+
if (!read.ok) return signatureOnly(signature, "read_unavailable", `the API's read of it could not be fetched (${read.detail}), so nothing is proved and nothing is disproved about the body`);
|
|
207
|
+
const differs = copyDisagreesWithRead(receipt as Record<string, unknown>, read.body);
|
|
208
|
+
if (differs.includes("chain")) {
|
|
209
|
+
// The copy's chain carries a signature that checked above, so a read with another chain is a re-seal, not an edit.
|
|
210
|
+
return signatureOnly(signature, "read_resealed", "the API's read carries a different chain than this copy: the receipt was re-sealed after the copy was written (a delivery or metering update). Verify the read itself");
|
|
211
|
+
}
|
|
212
|
+
if (differs.length > 0) {
|
|
213
|
+
return {
|
|
214
|
+
...signature,
|
|
215
|
+
verdict: "chain_mismatch",
|
|
216
|
+
reason: "copy_differs_from_read",
|
|
217
|
+
message: `receipt ${signature.receipt_id}: this copy says something the sealed receipt does not (${differs.join(", ")}). The signature covers the id and the chain, not the copy's body, so the copy was edited after it was written`,
|
|
218
|
+
chain_check: { status: "mismatch", version: null, recomputed: null, reason: "copy_differs_from_read" },
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const claim = approval ?? approvalOfCopy(receipt as Record<string, unknown>, args.receiptFile!);
|
|
222
|
+
return verifyReceiptRead(read.body, document, { label, ...(claim ? { approval: claim } : {}) });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function unreachable(receiptId: string, label: string, message: string): ReceiptVerification {
|
|
226
|
+
return { verdict: "unreachable", receipt_id: receiptId, kid: null, key_status: null, signing_string: null, keys_from: label, reason: "fetch_failed", message };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* The receipt as the API reads it, for a copy, with the tenant's key. The key
|
|
231
|
+
* is the environment's, or the `.env` of the agent the copy sits in — the
|
|
232
|
+
* same place `npm start` reads it from — and only a `csk_test_` key is
|
|
233
|
+
* accepted, like everywhere else in this repository.
|
|
234
|
+
*/
|
|
235
|
+
async function readFromApi(receiptId: string, receiptFile: string, apiBase: string): Promise<{ ok: true; body: Record<string, unknown> } | { ok: false; detail: string }> {
|
|
236
|
+
const agentDir = findAgentDir(dirname(resolve(receiptFile)));
|
|
237
|
+
if (agentDir) readDotEnv(agentDir);
|
|
238
|
+
try {
|
|
239
|
+
const api = createCodeSparClient({ apiKey: process.env["CODESPAR_API_KEY"], baseUrl: apiBase, projectId: process.env["CODESPAR_PROJECT_ID"], timeoutMs: 15_000 });
|
|
240
|
+
const body: unknown = await api.get("/v1/consumers/receipts/{id}", { path: { id: receiptId } });
|
|
241
|
+
if (!isReceiptRead(body)) return { ok: false, detail: "the API answered something that is not a receipt read" };
|
|
242
|
+
return { ok: true, body };
|
|
243
|
+
} catch (err) {
|
|
244
|
+
const failure = describeApiError(err);
|
|
245
|
+
return { ok: false, detail: `${failure.code}: ${failure.message}` };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* The artifact a run's copy names by `approval_id`, from the same run's
|
|
251
|
+
* `approval.json`. Found by identity: picking whichever artifact matched the
|
|
252
|
+
* sealed hash would make a mismatch impossible to see.
|
|
253
|
+
*/
|
|
254
|
+
function approvalOfCopy(copy: Record<string, unknown>, receiptFile: string): ApprovalClaim | undefined {
|
|
255
|
+
const id = copy["approval_id"];
|
|
256
|
+
const receipts = dirname(resolve(receiptFile));
|
|
257
|
+
const path = join(dirname(receipts), "approval.json");
|
|
258
|
+
if (typeof id !== "string" || basename(receipts) !== "receipts" || !existsSync(path)) return undefined;
|
|
259
|
+
try {
|
|
260
|
+
return pickArtifact(JSON.parse(readFileSync(path, "utf8")) as unknown, id);
|
|
261
|
+
} catch {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
267
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** One artifact out of an `approval.json` (a list) or a single artifact file, as the part the approval link is held against. */
|
|
271
|
+
function pickArtifact(input: unknown, id: string | undefined): ApprovalClaim | undefined {
|
|
272
|
+
const candidates = (Array.isArray(input) ? input : [input]).filter((a): a is Record<string, unknown> => isRecord(a) && typeof a["items_hash"] === "string" && typeof a["approval_id"] === "string");
|
|
273
|
+
const chosen = id === undefined ? (candidates.length === 1 ? candidates[0] : undefined) : candidates.find((a) => a["approval_id"] === id);
|
|
274
|
+
if (!chosen) return undefined;
|
|
275
|
+
const batch = chosen["batch"];
|
|
276
|
+
return {
|
|
277
|
+
approval_id: chosen["approval_id"] as string,
|
|
278
|
+
items_hash: chosen["items_hash"] as string,
|
|
279
|
+
...(Array.isArray(chosen["items"]) ? { items: chosen["items"] as ExecutionItem[] } : {}),
|
|
280
|
+
...(isRecord(batch) && typeof batch["batch_hash"] === "string" ? { batch: { batch_hash: batch["batch_hash"] } } : {}),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** `--approval`: `undefined` is a usage error, already said. */
|
|
285
|
+
function readApprovalClaim(path: string, id: string | undefined, say: (line: string) => void): ApprovalClaim | undefined {
|
|
286
|
+
const input = readJson(path, say);
|
|
287
|
+
if (input === undefined) return undefined;
|
|
288
|
+
const claim = pickArtifact(input, id);
|
|
289
|
+
if (!claim) {
|
|
290
|
+
const count = Array.isArray(input) ? input.length : 1;
|
|
291
|
+
say(id ? `${resolve(path)} holds no approval artifact ${id}` : `${resolve(path)} holds ${count} approval artifacts, not one; name the one this payment carried with --approval-id`);
|
|
292
|
+
}
|
|
293
|
+
return claim;
|
|
294
|
+
}
|
|
295
|
+
|
|
104
296
|
/** A file that is missing or is not JSON is a refusal a person can act on, never a stack trace. */
|
|
105
297
|
function readJson(path: string, say: (line: string) => void): unknown {
|
|
106
298
|
let text: string;
|
|
@@ -124,6 +316,15 @@ function render(report: ReceiptVerification): string {
|
|
|
124
316
|
if (report.kid) lines.push(` key ${report.kid}${report.key_status ? ` (${report.key_status})` : ""}`);
|
|
125
317
|
if (report.keys_from) lines.push(` key set ${report.keys_from}`);
|
|
126
318
|
if (report.signing_string) lines.push(` signed ${report.signing_string}`);
|
|
319
|
+
if (report.chain_check) {
|
|
320
|
+
const c = report.chain_check;
|
|
321
|
+
lines.push(` body ${c.status}${c.version !== null ? ` (chain v${c.version})` : ""}${c.recomputed && c.status === "mismatch" ? `, recomputes to ${c.recomputed}` : ""}`);
|
|
322
|
+
}
|
|
323
|
+
if (report.approval_check) {
|
|
324
|
+
const a = report.approval_check;
|
|
325
|
+
lines.push(` approval ${a.status}: sealed ${a.sealed.items_hash}${a.sealed.batch_hash ? ` batch ${a.sealed.batch_hash}` : ""}`);
|
|
326
|
+
if (a.artifact) lines.push(` artifact ${a.artifact.approval_id} ${a.artifact.items_hash}${a.artifact.batch_hash ? ` batch ${a.artifact.batch_hash}` : ""}`);
|
|
327
|
+
}
|
|
127
328
|
lines.push(` reason ${report.reason}`);
|
|
128
329
|
return lines.join("\n") + "\n";
|
|
129
330
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { stderr, stdout } from "node:process";
|
|
9
9
|
import { envName, type Agent } from "../agent.js";
|
|
10
10
|
import { setup } from "../setup.js";
|
|
11
|
-
import { announceOutcome } from "../terminal.js";
|
|
11
|
+
import { announceOutcome, followUp } from "../terminal.js";
|
|
12
12
|
import { startWebhookServer } from "../webhook.js";
|
|
13
13
|
|
|
14
14
|
export async function webhook(agent: Agent, argv: string[]): Promise<number> {
|
|
@@ -21,8 +21,9 @@ export async function webhook(agent: Agent, argv: string[]): Promise<number> {
|
|
|
21
21
|
{
|
|
22
22
|
engine: s.engine,
|
|
23
23
|
secret,
|
|
24
|
-
onClosed: (execution) => {
|
|
24
|
+
onClosed: async (execution) => {
|
|
25
25
|
announceOutcome(execution, s, (l) => void stdout.write(l + "\n"));
|
|
26
|
+
await followUp(execution, s, say);
|
|
26
27
|
},
|
|
27
28
|
},
|
|
28
29
|
say,
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* text: a debtor's own words are in `transcript.jsonl` and are not this
|
|
19
19
|
* command's to re-publish.
|
|
20
20
|
*/
|
|
21
|
-
import { maskPayee, type ApprovalArtifact, type ExecutionBatch, type ProofBundle } from "@codespar/agent-core";
|
|
21
|
+
import { maskPayee, type ApprovalArtifact, type ExecutionBatch, type ExecutionComposition, type ProofBundle } from "@codespar/agent-core";
|
|
22
22
|
import { formatMinor } from "./default-kit.js";
|
|
23
23
|
|
|
24
24
|
export interface InspectItem {
|
|
@@ -87,6 +87,8 @@ export interface InspectExecution {
|
|
|
87
87
|
items_hash: string;
|
|
88
88
|
/** The set binding as the ARTIFACT carries it, which is the signed copy. */
|
|
89
89
|
batch: ExecutionBatch | null;
|
|
90
|
+
/** What the single amount was composed of (a cart), as the artifact signed it. */
|
|
91
|
+
composition?: ExecutionComposition;
|
|
90
92
|
mandate: { id: string; version: number };
|
|
91
93
|
escalation: { trigger: string; detail: string } | null;
|
|
92
94
|
} | null;
|
|
@@ -453,6 +455,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
|
|
|
453
455
|
expires_at: artifact.expires_at,
|
|
454
456
|
items_hash: artifact.items_hash,
|
|
455
457
|
batch: batchBinding(artifact.batch),
|
|
458
|
+
...(artifact.composition ? { composition: artifact.composition } : {}),
|
|
456
459
|
mandate: artifact.mandate,
|
|
457
460
|
escalation: artifact.escalation ? { trigger: artifact.escalation.trigger, detail: redact(artifact.escalation.detail) ?? "" } : null,
|
|
458
461
|
};
|
|
@@ -575,6 +578,7 @@ function executionLines(execution: InspectExecution): Array<{ at: string; label:
|
|
|
575
578
|
if (approval) {
|
|
576
579
|
const wrapped = [`${approval.approval_id} · items_hash ${approval.items_hash}`, `under mandate ${approval.mandate.id} v${approval.mandate.version} · the artifact expires ${clock(approval.expires_at)}`];
|
|
577
580
|
if (approval.batch) wrapped.push(`line ${approval.batch.index + 1} of ${approval.batch.count} of batch ${approval.batch.ref} · batch_hash ${approval.batch.batch_hash}`);
|
|
581
|
+
if (approval.composition) wrapped.push(`composed of ${approval.composition.line_count} line(s) of ${approval.composition.ref} · composition_hash ${approval.composition.composition_hash}`);
|
|
578
582
|
if (approval.escalation) wrapped.push(`escalated by ${approval.escalation.trigger}: ${approval.escalation.detail}`);
|
|
579
583
|
lines.push({ at: approval.approved_at, label: "approved", text: approverLabel(approval.approver), wrapped });
|
|
580
584
|
}
|
|
@@ -157,8 +157,19 @@ export interface AgentKit {
|
|
|
157
157
|
usage(manifest: LoadedManifest): string;
|
|
158
158
|
buildRail(ctx: RailContext): RailBuild;
|
|
159
159
|
handlers(setup: Setup): Record<string, ToolHandler>;
|
|
160
|
-
/**
|
|
161
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Whether the channel dispatches an execution the moment it is approved.
|
|
162
|
+
* Default true. False when approving and issuing are two moments of the
|
|
163
|
+
* agent's own flow — a sale: the attendant (or the policy) confirms the
|
|
164
|
+
* order, and the charge goes out when the customer asks for it. The
|
|
165
|
+
* approved execution then waits, and the agent's own tool hands it to
|
|
166
|
+
* `engine.execute`, which runs the last gate like any other caller: a cart
|
|
167
|
+
* changed in between is caught there. An approved execution nobody issues
|
|
168
|
+
* expires on the approval TTL.
|
|
169
|
+
*/
|
|
170
|
+
executeOnApproval?: boolean;
|
|
171
|
+
/** The deterministic policy the core runs as its `policyExtension`. `store` is the run's state.db, for a policy that judges durable state of the agent's own (a cart). */
|
|
172
|
+
policyExtension?(ctx: { agentDir: string; manifest: LoadedManifest; guardrails: Guardrails; store: StateStore }): PolicyExtension | undefined;
|
|
162
173
|
/** The console lines that describe one execution. */
|
|
163
174
|
describeExecution(execution: Execution, setup: Setup): string[];
|
|
164
175
|
/** The `--json` body of a one-shot. */
|
|
@@ -184,6 +195,18 @@ export interface AgentKit {
|
|
|
184
195
|
* who was not told was not told.
|
|
185
196
|
*/
|
|
186
197
|
outcomeTemplate?(execution: Execution): { template: string; variables: string[] } | undefined;
|
|
198
|
+
/**
|
|
199
|
+
* Work that FOLLOWS an outcome and is not part of it: a sale's service
|
|
200
|
+
* invoice once the order is `settled`. Runs after `announceOutcome`,
|
|
201
|
+
* wherever an outcome is announced (the terminal, the scenario runner,
|
|
202
|
+
* `poll`, `webhook`, the WhatsApp poll), and is awaited there. It can never
|
|
203
|
+
* move the execution it follows: a throw is reported on the operator's
|
|
204
|
+
* console and the outcome stands, because a paid order stays paid whatever
|
|
205
|
+
* happens after it.
|
|
206
|
+
*/
|
|
207
|
+
followUp?(execution: Execution, setup: Setup, say: (line: string) => void): Promise<void>;
|
|
208
|
+
/** `resume` only: the follow-ups a crash left half-done. The same rule as the core's outbox: what provably never left may go; what may have left is reported, never sent again. */
|
|
209
|
+
resumeFollowUps?(setup: Setup, say: (line: string) => void): Promise<void>;
|
|
187
210
|
/** Runs before a one-shot or an interactive session, when the mandate may have to be born first. Returns false to stop the run. */
|
|
188
211
|
ensureMandate?(ctx: EnsureMandateContext): Promise<boolean>;
|
|
189
212
|
/** `codespar-agent consent`. Absent means the agent has no consent step. */
|
|
@@ -14,7 +14,7 @@ import type { ApprovalMode, Execution } from "@codespar/agent-core";
|
|
|
14
14
|
import type { Agent } from "./agent.js";
|
|
15
15
|
import type { RailKind } from "./kit.js";
|
|
16
16
|
import { setup, type Setup } from "./setup.js";
|
|
17
|
-
import { announceOutcome, handleExecution } from "./terminal.js";
|
|
17
|
+
import { announceOutcome, followUp, handleExecution } from "./terminal.js";
|
|
18
18
|
|
|
19
19
|
const TurnSchema = z
|
|
20
20
|
.object({
|
|
@@ -204,7 +204,13 @@ export async function runScenario(agent: Agent, scenario: Scenario, options: Run
|
|
|
204
204
|
for (const stuck of s.engine.list({ state: "executing" })) await s.engine.reconcile(stuck.id);
|
|
205
205
|
}
|
|
206
206
|
// Whatever closed after the conversation is told to the counterparty once, as the poll or the webhook would.
|
|
207
|
-
if (awaitsPayer)
|
|
207
|
+
if (awaitsPayer) {
|
|
208
|
+
for (const e of s.engine.list()) {
|
|
209
|
+
if (e.run_id !== s.runId) continue;
|
|
210
|
+
announceOutcome(e, s, tell);
|
|
211
|
+
await followUp(e, s, say);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
208
214
|
|
|
209
215
|
const events = s.store.listEvents({ run_id: s.runId });
|
|
210
216
|
for (const e of events) {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
resolveFixedClock,
|
|
22
22
|
type AgentRuntime,
|
|
23
23
|
type ApprovalMode,
|
|
24
|
+
type ConversationScript,
|
|
24
25
|
type Execution,
|
|
25
26
|
type Guardrails,
|
|
26
27
|
type LoadedManifest,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
type PaymentRail,
|
|
30
31
|
type StubChargeRailOptions,
|
|
31
32
|
type StubRailOptions,
|
|
33
|
+
type ToolContext,
|
|
32
34
|
type ToolHandler,
|
|
33
35
|
} from "@codespar/agent-core";
|
|
34
36
|
import { AnthropicRuntime } from "@codespar/agent-core/providers/anthropic";
|
|
@@ -95,7 +97,15 @@ export interface Setup {
|
|
|
95
97
|
system: string;
|
|
96
98
|
handlers: Record<string, ToolHandler>;
|
|
97
99
|
tools: ReturnType<typeof loadToolsFile>;
|
|
98
|
-
|
|
100
|
+
/**
|
|
101
|
+
* The conversation this run is bound to, when a channel binds one (WhatsApp):
|
|
102
|
+
* its contact and its subject. Set by the channel's start, read by a kit
|
|
103
|
+
* whose rules depend on who the person is — a sale is charged to the
|
|
104
|
+
* customer the conversation is with, and to nobody else.
|
|
105
|
+
*/
|
|
106
|
+
conversation?: ConversationScript | undefined;
|
|
107
|
+
/** `onBatch` is for a channel that takes one gesture per batch; without it every line is decided in `onExecution`. */
|
|
108
|
+
makeLoop(runtime: AgentRuntime, onExecution: (execution: Execution) => Promise<Execution>, onBatch?: ToolContext["onBatch"]): AgentLoop;
|
|
99
109
|
makeRuntime(): AgentRuntime;
|
|
100
110
|
close(): void;
|
|
101
111
|
}
|
|
@@ -166,7 +176,7 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
166
176
|
// 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.
|
|
167
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() });
|
|
168
178
|
|
|
169
|
-
const policyExtension = agent.kit.policyExtension?.({ agentDir: agent.dir, manifest, guardrails });
|
|
179
|
+
const policyExtension = agent.kit.policyExtension?.({ agentDir: agent.dir, manifest, guardrails, store });
|
|
170
180
|
const engine = new ExecutionEngine({
|
|
171
181
|
store,
|
|
172
182
|
rail,
|
|
@@ -214,7 +224,7 @@ export function setup(agent: Agent, options: SetupOptions = {}): Setup {
|
|
|
214
224
|
handlers: {},
|
|
215
225
|
tools,
|
|
216
226
|
makeRuntime,
|
|
217
|
-
makeLoop: (runtime, onExecution) => new AgentLoop({ runtime, tools, handlers: s.handlers, system, bundle, engine, onExecution, ...(now ? { clock: now } : {}) }),
|
|
227
|
+
makeLoop: (runtime, onExecution, onBatch) => new AgentLoop({ runtime, tools, handlers: s.handlers, system, bundle, engine, onExecution, ...(onBatch ? { onBatch } : {}), ...(now ? { clock: now } : {}) }),
|
|
218
228
|
close: () => store.close(),
|
|
219
229
|
};
|
|
220
230
|
s.handlers = agent.kit.handlers(s);
|