@codespar/cli 0.14.1 → 0.16.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 +44 -17
- package/dist/commands/audit-replay.js +267 -0
- package/dist/commands/audit-replay.js.map +1 -0
- package/dist/commands/init.js +28 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/surface.js +4 -1
- package/dist/surface.js.map +1 -1
- package/package.json +1 -1
- package/templates/bills-agent/README.md +8 -5
- package/templates/bills-agent/agents/bills-agent/.env.example +3 -3
- 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 +62 -22
- package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +1 -1
- package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -2
- package/templates/bills-agent/agents/bills-agent/package.json +14 -11
- package/templates/bills-agent/agents/bills-agent/src/kit.ts +193 -0
- package/templates/bills-agent/agents/bills-agent/test/adversarial.test.ts +8 -7
- package/templates/bills-agent/agents/bills-agent/test/check.test.ts +19 -2
- package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +72 -24
- package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -0
- package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +2 -0
- package/templates/bills-agent/agents/bills-agent/test/inspect.test.ts +124 -0
- package/templates/bills-agent/agents/bills-agent/test/provider.test.ts +25 -0
- package/templates/bills-agent/agents/bills-agent/test/scenarios.test.ts +10 -9
- package/templates/bills-agent/agents/bills-agent/tsconfig.json +0 -1
- package/templates/bills-agent/package.json +5 -2
- package/templates/bills-agent/packages/agent-core/README.md +2 -0
- package/templates/bills-agent/packages/agent-core/package.json +1 -1
- package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
- package/templates/bills-agent/packages/agent-core/src/api/rail.ts +16 -0
- package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
- package/templates/bills-agent/packages/agent-core/src/approval.ts +16 -2
- package/templates/bills-agent/packages/agent-core/src/bundle.ts +50 -4
- package/templates/bills-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/bills-agent/packages/agent-core/src/check.ts +90 -8
- package/templates/bills-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/bills-agent/packages/agent-core/src/engine.ts +119 -18
- package/templates/bills-agent/packages/agent-core/src/hash.ts +13 -0
- package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/bills-agent/packages/agent-core/src/manifest.ts +1 -1
- package/templates/bills-agent/packages/agent-core/src/rail.ts +16 -2
- package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/bills-agent/packages/agent-core/src/state-machine.ts +3 -1
- package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
- package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +19 -2
- package/templates/bills-agent/packages/agent-core/src/types.ts +28 -0
- package/templates/bills-agent/packages/agent-core/test/approval.test.ts +36 -2
- package/templates/bills-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/bills-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/bills-agent/packages/agent-core/test/engine.test.ts +73 -1
- package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/bills-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +51 -0
- package/templates/bills-agent/packages/agent-runtime/README.md +68 -0
- package/templates/bills-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/bills-agent/packages/agent-runtime/package.json +23 -0
- package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/adversarial.ts +36 -44
- package/templates/bills-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/bills-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/bills-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/bills-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/poll.ts +22 -11
- package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/scenarios.ts +50 -34
- package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/setup.ts +88 -66
- package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/{collections-agent/agents/collections-agent/channels/webhook/index.ts → bills-agent/packages/agent-runtime/src/webhook.ts} +1 -1
- package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/bills-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/bills-agent/vitest.config.ts +1 -1
- package/templates/collections-agent/README.md +8 -5
- package/templates/collections-agent/agents/collections-agent/.env.example +14 -0
- package/templates/collections-agent/agents/collections-agent/AGENTS.md +6 -4
- package/templates/collections-agent/agents/collections-agent/CLAUDE.md +6 -4
- package/templates/collections-agent/agents/collections-agent/README.md +184 -16
- package/templates/collections-agent/agents/collections-agent/agent.yaml +3 -3
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +111 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042.json +11 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1103.json +11 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +23 -0
- package/templates/collections-agent/agents/collections-agent/package.json +12 -10
- package/templates/collections-agent/agents/collections-agent/runbook.md +52 -1
- package/templates/collections-agent/agents/collections-agent/src/kit.ts +265 -0
- package/templates/collections-agent/agents/collections-agent/test/adversarial.test.ts +9 -8
- package/templates/collections-agent/agents/collections-agent/test/check.test.ts +43 -1
- package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +56 -18
- package/templates/collections-agent/agents/collections-agent/test/fixtures/agreed-1042-awaiting-payer.transcript.jsonl +4 -0
- package/templates/collections-agent/agents/collections-agent/test/scenarios.test.ts +11 -10
- package/templates/collections-agent/agents/collections-agent/test/webhook.test.ts +4 -7
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +271 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +213 -0
- package/templates/collections-agent/agents/collections-agent/tsconfig.json +0 -1
- package/templates/collections-agent/package.json +3 -1
- package/templates/collections-agent/packages/agent-core/README.md +2 -0
- package/templates/collections-agent/packages/agent-core/package.json +1 -1
- package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
- package/templates/collections-agent/packages/agent-core/src/api/rail.ts +16 -0
- package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
- package/templates/collections-agent/packages/agent-core/src/approval.ts +16 -2
- package/templates/collections-agent/packages/agent-core/src/bundle.ts +50 -4
- package/templates/collections-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/collections-agent/packages/agent-core/src/check.ts +90 -8
- package/templates/collections-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/collections-agent/packages/agent-core/src/engine.ts +119 -18
- package/templates/collections-agent/packages/agent-core/src/hash.ts +13 -0
- package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/collections-agent/packages/agent-core/src/manifest.ts +1 -1
- package/templates/collections-agent/packages/agent-core/src/rail.ts +16 -2
- package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/collections-agent/packages/agent-core/src/state-machine.ts +3 -1
- package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
- package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +19 -2
- package/templates/collections-agent/packages/agent-core/src/types.ts +28 -0
- package/templates/collections-agent/packages/agent-core/test/approval.test.ts +36 -2
- package/templates/collections-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/collections-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/collections-agent/packages/agent-core/test/engine.test.ts +73 -1
- package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/collections-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +51 -0
- package/templates/collections-agent/packages/agent-runtime/README.md +68 -0
- package/templates/collections-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/collections-agent/packages/agent-runtime/package.json +23 -0
- package/templates/collections-agent/{agents/collections-agent → packages/agent-runtime}/src/adversarial.ts +29 -50
- package/templates/collections-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/collections-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/collections-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/collections-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/collections-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/{bills-agent/agents/bills-agent → collections-agent/packages/agent-runtime}/src/scenarios.ts +98 -26
- package/templates/collections-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/collections-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/collections-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/collections-agent/vitest.config.ts +1 -1
- package/templates/hello-agent/LICENSE +21 -0
- package/templates/hello-agent/README.md +23 -0
- package/templates/hello-agent/_gitignore +10 -0
- package/templates/hello-agent/agents/hello-agent/.env.example +5 -0
- package/templates/hello-agent/agents/hello-agent/AGENTS.md +15 -0
- package/templates/hello-agent/agents/hello-agent/CLAUDE.md +15 -0
- package/templates/hello-agent/agents/hello-agent/README.md +33 -0
- package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +19 -0
- package/templates/hello-agent/agents/hello-agent/agent.yaml +19 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/webhook-replay.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/eval.yaml +7 -0
- package/templates/hello-agent/agents/hello-agent/guardrails.json +8 -0
- package/templates/hello-agent/agents/hello-agent/mandate.example.json +17 -0
- package/templates/hello-agent/agents/hello-agent/package.json +19 -0
- package/templates/hello-agent/agents/hello-agent/runbook.md +10 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +6 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +6 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/src/bills.ts +23 -0
- package/templates/hello-agent/agents/hello-agent/src/kit.ts +33 -0
- package/templates/hello-agent/agents/hello-agent/tools.json +11 -0
- package/templates/hello-agent/agents/hello-agent/tsconfig.json +9 -0
- package/templates/hello-agent/package.json +30 -0
- package/templates/hello-agent/packages/agent-core/README.md +21 -0
- package/templates/hello-agent/packages/agent-core/package.json +24 -0
- package/templates/hello-agent/packages/agent-core/src/agent.ts +125 -0
- package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
- package/templates/hello-agent/packages/agent-core/src/api/client.ts +53 -0
- package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
- package/templates/hello-agent/packages/agent-core/src/api/rail.ts +117 -0
- package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
- package/templates/hello-agent/packages/agent-core/src/approval.ts +123 -0
- package/templates/hello-agent/packages/agent-core/src/bundle.ts +159 -0
- package/templates/hello-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/hello-agent/packages/agent-core/src/check.ts +253 -0
- package/templates/hello-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/hello-agent/packages/agent-core/src/engine.ts +885 -0
- package/templates/hello-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/hello-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/hello-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/hello-agent/packages/agent-core/src/hash.ts +62 -0
- package/templates/hello-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/hello-agent/packages/agent-core/src/index.ts +32 -0
- package/templates/hello-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/hello-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/hello-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/hello-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/hello-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/hello-agent/packages/agent-core/src/rail.ts +101 -0
- package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/hello-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/hello-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/hello-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/hello-agent/packages/agent-core/src/state-machine.ts +148 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +141 -0
- package/templates/hello-agent/packages/agent-core/src/tools.ts +55 -0
- package/templates/hello-agent/packages/agent-core/src/types.ts +134 -0
- package/templates/hello-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/hello-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/hello-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/hello-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/hello-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/hello-agent/packages/agent-core/test/helpers.ts +139 -0
- package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
- package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +316 -0
- package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/hello-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/hello-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/hello-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/hello-agent/packages/agent-runtime/README.md +68 -0
- package/templates/hello-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/hello-agent/packages/agent-runtime/package.json +23 -0
- package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +169 -0
- package/templates/hello-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/hello-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/hello-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/hello-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/hello-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +268 -0
- package/templates/hello-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/hello-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/hello-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/hello-agent/tsconfig.base.json +16 -0
- package/templates/hello-agent/vitest.config.ts +12 -0
- package/templates/kits.lock.json +60 -12
- package/templates/supplier-payments-agent/LICENSE +21 -0
- package/templates/supplier-payments-agent/README.md +23 -0
- package/templates/supplier-payments-agent/_gitignore +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +7 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +118 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +29 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +26 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap-mandate.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.json +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.json +13 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.json +15 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.transcript.jsonl +6 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.json +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/webhook-replay.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/eval.yaml +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/guardrails.json +15 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +70 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/package.json +26 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/runbook.md +19 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.json +14 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.json +20 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +7 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.json +19 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.json +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +176 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +345 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +118 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +76 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/adversarial.test.ts +53 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +384 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/check.test.ts +109 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/scenarios.test.ts +81 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +53 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/tsconfig.json +9 -0
- package/templates/supplier-payments-agent/package.json +36 -0
- package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -0
- package/templates/supplier-payments-agent/packages/agent-core/package.json +24 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +125 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +53 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +117 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +123 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +159 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +253 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +885 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +62 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +32 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +101 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +148 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +141 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +55 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +134 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +139 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +316 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/supplier-payments-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/README.md +68 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/package.json +23 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +169 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +268 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/supplier-payments-agent/tsconfig.base.json +16 -0
- package/templates/supplier-payments-agent/vitest.config.ts +12 -0
- package/templates/bills-agent/agents/bills-agent/channels/terminal/index.ts +0 -108
- package/templates/bills-agent/agents/bills-agent/src/commands/approve.ts +0 -9
- package/templates/bills-agent/agents/bills-agent/src/commands/check.ts +0 -13
- package/templates/bills-agent/agents/bills-agent/src/commands/consent.ts +0 -26
- package/templates/bills-agent/agents/bills-agent/src/commands/decide.ts +0 -45
- package/templates/bills-agent/agents/bills-agent/src/commands/deny.ts +0 -7
- package/templates/bills-agent/agents/bills-agent/src/commands/eval.ts +0 -37
- package/templates/bills-agent/agents/bills-agent/src/commands/reconcile.ts +0 -38
- package/templates/bills-agent/agents/bills-agent/src/commands/rerun.ts +0 -65
- package/templates/bills-agent/agents/bills-agent/src/commands/resume.ts +0 -30
- package/templates/bills-agent/agents/bills-agent/src/main.ts +0 -185
- package/templates/collections-agent/agents/collections-agent/channels/terminal/index.ts +0 -178
- package/templates/collections-agent/agents/collections-agent/src/commands/approve.ts +0 -10
- package/templates/collections-agent/agents/collections-agent/src/commands/check.ts +0 -13
- package/templates/collections-agent/agents/collections-agent/src/commands/decide.ts +0 -48
- package/templates/collections-agent/agents/collections-agent/src/commands/deny.ts +0 -7
- package/templates/collections-agent/agents/collections-agent/src/commands/eval.ts +0 -39
- package/templates/collections-agent/agents/collections-agent/src/commands/poll.ts +0 -35
- package/templates/collections-agent/agents/collections-agent/src/commands/reconcile.ts +0 -38
- package/templates/collections-agent/agents/collections-agent/src/commands/rerun.ts +0 -55
- package/templates/collections-agent/agents/collections-agent/src/commands/resume.ts +0 -30
- package/templates/collections-agent/agents/collections-agent/src/commands/webhook.ts +0 -36
- package/templates/collections-agent/agents/collections-agent/src/main.ts +0 -193
- package/templates/collections-agent/agents/collections-agent/src/setup.ts +0 -250
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WhatsApp channel: one adapter, two backends.
|
|
3
|
+
*
|
|
4
|
+
* Everything that decides what may be said lives HERE and not in a backend,
|
|
5
|
+
* which is what makes "the rules are code" true rather than aspirational.
|
|
6
|
+
* Picking the simulator or the official API changes who carries the bytes; it
|
|
7
|
+
* does not change the hours, the bound contact, the secrecy of the debt, the
|
|
8
|
+
* document rule or the session window. A test that tries to get around a rule
|
|
9
|
+
* by choosing a backend is in `test/whatsapp-rules.test.ts` and fails.
|
|
10
|
+
*
|
|
11
|
+
* It also keeps the two audiences apart. `send` reaches the person who owes.
|
|
12
|
+
* The operator's console and the approval question are wired to stderr by the
|
|
13
|
+
* caller and have no path to this object at all — not a check, a shape: there
|
|
14
|
+
* is no method here that an operator line could be handed to.
|
|
15
|
+
*/
|
|
16
|
+
import type { ProofBundle, WhatsAppTemplate } from "@codespar/agent-core";
|
|
17
|
+
import { checkOutbound, type HoursRule, type RuleContext } from "../rules.js";
|
|
18
|
+
import type { Channel, ChannelBackend, ChannelLogLine, Conversation, InboundMessage, OutboundBody, SentMessage } from "../types.js";
|
|
19
|
+
import { maskContact } from "../contact.js";
|
|
20
|
+
import { SessionWindow, type SessionState } from "./session.js";
|
|
21
|
+
|
|
22
|
+
export interface WhatsAppChannelOptions {
|
|
23
|
+
backend: ChannelBackend;
|
|
24
|
+
conversation: Conversation;
|
|
25
|
+
now: () => Date;
|
|
26
|
+
hours?: HoursRule | undefined;
|
|
27
|
+
knownSubjects?: readonly string[] | undefined;
|
|
28
|
+
/** The run's bundle, so the conversation is part of the proof. */
|
|
29
|
+
bundle?: ProofBundle | undefined;
|
|
30
|
+
/** Templates the agent declares it uses, from `channels/whatsapp/templates.json`. Meta's approval of them is not knowable from here. */
|
|
31
|
+
templates?: readonly WhatsAppTemplate[] | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Where the window stood when an earlier run left this conversation. A run
|
|
34
|
+
* that JOINS a conversation — a poll looking at a charge agreed yesterday —
|
|
35
|
+
* has no inbound message of its own to open it from, and without this it
|
|
36
|
+
* would read every conversation as shut.
|
|
37
|
+
*/
|
|
38
|
+
session?: SessionState | undefined;
|
|
39
|
+
/** The operator's console. Refusals are reported here, never to the conversation. */
|
|
40
|
+
say?: ((line: string) => void) | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Draws the conversation for whoever is watching the run. It is a VIEW of
|
|
43
|
+
* what went over the channel, written after the fact, and never a way to put
|
|
44
|
+
* something in front of the person — that is `send`, and it is the only one.
|
|
45
|
+
*/
|
|
46
|
+
render?: ((line: string) => void) | undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class WhatsAppChannel implements Channel {
|
|
50
|
+
readonly name = "whatsapp" as const;
|
|
51
|
+
readonly conversation: Conversation;
|
|
52
|
+
private readonly session: SessionWindow;
|
|
53
|
+
private readonly lines: ChannelLogLine[] = [];
|
|
54
|
+
private lastInbound: InboundMessage | undefined;
|
|
55
|
+
|
|
56
|
+
constructor(private readonly options: WhatsAppChannelOptions) {
|
|
57
|
+
this.conversation = options.conversation;
|
|
58
|
+
this.session = new SessionWindow(options.templates ?? [], options.session);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get backend(): string {
|
|
62
|
+
return this.options.backend.name;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Whether the backend talks to a real provider. What the consent-evidence seam turns on. */
|
|
66
|
+
get live(): boolean {
|
|
67
|
+
return this.options.backend.live;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The message the person last sent, for the caller that needs to attest to an act. */
|
|
71
|
+
get lastInboundMessage(): InboundMessage | undefined {
|
|
72
|
+
return this.lastInbound;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Whether a free-form message may go out right now. A caller that has one
|
|
77
|
+
* thing to say and two ways to say it asks HERE which one the provider
|
|
78
|
+
* would carry — the alternative is composing a message, watching the
|
|
79
|
+
* channel refuse it, and calling that a decision.
|
|
80
|
+
*/
|
|
81
|
+
get sessionOpen(): boolean {
|
|
82
|
+
return this.session.open(this.options.now());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Seconds of free-form left, for the console line that explains the choice. */
|
|
86
|
+
get sessionRemainingSeconds(): number {
|
|
87
|
+
return this.session.remainingSeconds(this.options.now());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** What the agent declared about a template it is about to send. The language is the registry's, never the sender's guess. */
|
|
91
|
+
declaredTemplate(name: string): WhatsAppTemplate | undefined {
|
|
92
|
+
return this.session.declared(name);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async open(): Promise<void> {
|
|
96
|
+
await this.options.backend.open();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async next(): Promise<InboundMessage | undefined> {
|
|
100
|
+
const message = await this.options.backend.next();
|
|
101
|
+
if (!message) return undefined;
|
|
102
|
+
this.lastInbound = message;
|
|
103
|
+
this.session.observeInbound(message.timestamp);
|
|
104
|
+
this.record({
|
|
105
|
+
at: this.options.now().toISOString(),
|
|
106
|
+
direction: "in",
|
|
107
|
+
contact: maskContact(message.from),
|
|
108
|
+
kind: "text",
|
|
109
|
+
message_id: message.id,
|
|
110
|
+
state: "delivered",
|
|
111
|
+
text: message.text,
|
|
112
|
+
// The provider's clock, which is the only one the 24-hour window is
|
|
113
|
+
// counted on. A later run reads the window back from here.
|
|
114
|
+
provider_timestamp: message.timestamp,
|
|
115
|
+
});
|
|
116
|
+
return message;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async send(body: OutboundBody): Promise<SentMessage> {
|
|
120
|
+
const to = this.conversation.contact;
|
|
121
|
+
const ctx: RuleContext = {
|
|
122
|
+
conversation: this.conversation,
|
|
123
|
+
hours: this.options.hours,
|
|
124
|
+
now: this.options.now,
|
|
125
|
+
knownSubjects: this.options.knownSubjects,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// The house rules first: a message the law refuses is not a message the provider should ever see.
|
|
129
|
+
const refusal = checkOutbound(to, body, ctx) ?? this.providerRefusal(body);
|
|
130
|
+
if (refusal) {
|
|
131
|
+
const sent: SentMessage = { id: "", state: "failed", refused: refusal };
|
|
132
|
+
this.logOutbound(body, sent);
|
|
133
|
+
this.options.say?.(` [whatsapp] recusado (${refusal.rule}): ${refusal.detail}`);
|
|
134
|
+
return sent;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const sent = await this.options.backend.deliver(to, body);
|
|
138
|
+
if (sent.refused) this.options.say?.(` [whatsapp] recusado pelo backend (${sent.refused.rule}): ${sent.refused.detail}`);
|
|
139
|
+
this.logOutbound(body, sent);
|
|
140
|
+
return sent;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
say(text: string): Promise<SentMessage> {
|
|
144
|
+
return this.send({ kind: "text", text });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async close(): Promise<void> {
|
|
148
|
+
await this.options.backend.close();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Every message of this conversation, in order. */
|
|
152
|
+
log(): ReadonlyArray<ChannelLogLine> {
|
|
153
|
+
return this.lines;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private logOutbound(body: OutboundBody, sent: SentMessage): void {
|
|
157
|
+
this.record({
|
|
158
|
+
at: this.options.now().toISOString(),
|
|
159
|
+
direction: "out",
|
|
160
|
+
contact: maskContact(this.conversation.contact),
|
|
161
|
+
kind: body.kind,
|
|
162
|
+
message_id: sent.id,
|
|
163
|
+
state: sent.state,
|
|
164
|
+
...(textOf(body) !== undefined ? { text: textOf(body)! } : {}),
|
|
165
|
+
...(sent.refused ? { refused: sent.refused } : {}),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* WhatsApp's own rule, enforced on both backends: outside the 24 hours
|
|
171
|
+
* after the person's last message only an approved template may go out.
|
|
172
|
+
* The simulator obeys it because a rule that only bites in production is a
|
|
173
|
+
* rule you meet in production.
|
|
174
|
+
*/
|
|
175
|
+
private providerRefusal(body: OutboundBody): { rule: string; detail: string } | undefined {
|
|
176
|
+
const open = this.session.open(this.options.now());
|
|
177
|
+
if (body.kind === "template") return this.session.refuse(body);
|
|
178
|
+
if (!open) {
|
|
179
|
+
return {
|
|
180
|
+
rule: "session_window_closed",
|
|
181
|
+
detail: "more than 24h since the person's last message: WhatsApp only carries an approved template now, not a free-form message",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private record(line: ChannelLogLine): void {
|
|
188
|
+
this.lines.push(line);
|
|
189
|
+
this.options.bundle?.channel({ ...line, channel: "whatsapp", backend: this.backend });
|
|
190
|
+
this.options.render?.(` │ ${draw(line)}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** One console line for one message. The refusals are visible: a message nobody got is part of the conversation's story. */
|
|
195
|
+
function draw(line: ChannelLogLine): string {
|
|
196
|
+
const who = line.direction === "in" ? `${line.contact}:` : "loja:";
|
|
197
|
+
const what =
|
|
198
|
+
line.kind === "instrument"
|
|
199
|
+
? `[copia e cola] ${line.text ?? ""}`
|
|
200
|
+
: line.kind === "media"
|
|
201
|
+
? "[imagem: QR Pix]"
|
|
202
|
+
: line.kind === "template"
|
|
203
|
+
? line.text ?? "[template]"
|
|
204
|
+
: line.text ?? "";
|
|
205
|
+
return line.refused ? `${who} (nao enviada: ${line.refused.rule}) ${what}` : `${who} ${what}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function textOf(body: OutboundBody): string | undefined {
|
|
209
|
+
switch (body.kind) {
|
|
210
|
+
case "text":
|
|
211
|
+
return body.text;
|
|
212
|
+
case "instrument":
|
|
213
|
+
return body.value;
|
|
214
|
+
case "media":
|
|
215
|
+
return body.caption;
|
|
216
|
+
case "template":
|
|
217
|
+
return `[template ${body.template}] ${body.variables.join(" | ")}`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export * from "../contact.js";
|
|
222
|
+
export * from "./cloud-api.js";
|
|
223
|
+
export * from "./emulator.js";
|
|
224
|
+
export * from "./evidence.js";
|
|
225
|
+
export * from "./session.js";
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opening the WhatsApp channel: wiring, and only wiring.
|
|
3
|
+
*
|
|
4
|
+
* It lives apart from the command that starts a conversation because a second
|
|
5
|
+
* command now JOINS one — `codespar-agent poll --channel whatsapp`, which
|
|
6
|
+
* comes back to a conversation the run that opened it has long since ended.
|
|
7
|
+
* Two commands wiring the same channel by hand is how a rule ends up enforced
|
|
8
|
+
* on one path and not the other, and the whole claim of `channels/` is that
|
|
9
|
+
* the rules are above the backend. So both go through here.
|
|
10
|
+
*
|
|
11
|
+
* The decisions are all elsewhere: the rules in `channels/rules.ts`, the
|
|
12
|
+
* session window in `session.ts`, the gates in `terminal.ts`.
|
|
13
|
+
*/
|
|
14
|
+
import type { ConversationScript, ProofBundle } from "@codespar/agent-core";
|
|
15
|
+
import type { Agent } from "../../agent.js";
|
|
16
|
+
import type { Setup } from "../../setup.js";
|
|
17
|
+
import { knownSubjects, loadTemplates } from "../index.js";
|
|
18
|
+
import type { ChannelBackend, Conversation } from "../types.js";
|
|
19
|
+
import { WhatsAppChannel } from "./index.js";
|
|
20
|
+
import { toGraphNumber, WhatsAppCloudApi, loadCloudApiConfig, type CloudApiConfig } from "./cloud-api.js";
|
|
21
|
+
import { EmulatorDriver, EMULATOR_DEFAULTS, EMULATOR_ENV, WhatsAppEmulator } from "./emulator.js";
|
|
22
|
+
import type { SessionState } from "./session.js";
|
|
23
|
+
|
|
24
|
+
export type WhatsAppBackendName = "simulator" | "cloud-api";
|
|
25
|
+
|
|
26
|
+
export interface OpenWhatsAppOptions {
|
|
27
|
+
agent: Agent;
|
|
28
|
+
setup: Setup;
|
|
29
|
+
conversation: Conversation;
|
|
30
|
+
backend: WhatsAppBackendName;
|
|
31
|
+
now: () => Date;
|
|
32
|
+
say: (line: string) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Where the conversation is recorded. Normally the run's own bundle; a poll
|
|
35
|
+
* hands the bundle of the run it is continuing, because a conversation is
|
|
36
|
+
* one record and the message that closes it belongs with the ones that
|
|
37
|
+
* opened it.
|
|
38
|
+
*/
|
|
39
|
+
bundle: ProofBundle;
|
|
40
|
+
/** The person's turns, when a script drives them. Absent and with no `ask`, nobody writes. */
|
|
41
|
+
script?: ConversationScript | undefined;
|
|
42
|
+
/** Interactive only: reads the person's next line. */
|
|
43
|
+
ask?: ((question: string) => Promise<string>) | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Pins the emulator's CONVERSATION clock. A run that starts a conversation
|
|
46
|
+
* pins it; a run that joins one must not, because rewinding the provider's
|
|
47
|
+
* clock would reopen a window that really is shut. The agent's own notion of
|
|
48
|
+
* now is `now` above and is a different thing (#16).
|
|
49
|
+
*/
|
|
50
|
+
pinAt?: Date | undefined;
|
|
51
|
+
/** Where the session window stood when an earlier run left this conversation. */
|
|
52
|
+
session?: SessionState | undefined;
|
|
53
|
+
/** Draws the conversation on the operator's console. */
|
|
54
|
+
render?: ((line: string) => void) | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface OpenedWhatsApp {
|
|
58
|
+
channel: WhatsAppChannel;
|
|
59
|
+
/** The `_sim/*` side, when the backend is the emulator. Absent against Meta. */
|
|
60
|
+
driver?: EmulatorDriver;
|
|
61
|
+
/** How the emulator keys this conversation, for the priced timeline. */
|
|
62
|
+
sessionKey?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Builds the channel, or explains what is missing. Nothing is opened here:
|
|
67
|
+
* the caller opens it, because an emulator that is not running has to be
|
|
68
|
+
* reported differently depending on how far the command already got.
|
|
69
|
+
*/
|
|
70
|
+
export function buildWhatsApp(options: OpenWhatsAppOptions): OpenedWhatsApp | { refusal: string[] } {
|
|
71
|
+
const { agent, setup: s, say } = options;
|
|
72
|
+
let backend: ChannelBackend;
|
|
73
|
+
let driver: EmulatorDriver | undefined;
|
|
74
|
+
let sessionKey: string | undefined;
|
|
75
|
+
|
|
76
|
+
if (options.backend === "cloud-api") {
|
|
77
|
+
const { config, missing } = loadCloudApiConfig(process.env);
|
|
78
|
+
if (!config) {
|
|
79
|
+
return {
|
|
80
|
+
refusal: [
|
|
81
|
+
`the cloud-api backend needs credentials this repo ships none of: ${missing.join(", ")}.`,
|
|
82
|
+
`They live in the agent's .env (commented out in .env.example) and belong to a Meta Business account. The emulator needs none: drop --backend cloud-api.`,
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
say("[whatsapp] cloud-api backend: this repo has never run one against Meta. The shapes are written from the published documentation; the first live run is yours.");
|
|
87
|
+
backend = new WhatsAppCloudApi({ config, conversation: { contact: options.conversation.contact }, say });
|
|
88
|
+
} else {
|
|
89
|
+
// The SAME backend, pointed somewhere else. What the emulator adds is the
|
|
90
|
+
// `_sim/*` side: making the person write, and moving the conversation clock.
|
|
91
|
+
const env = process.env;
|
|
92
|
+
const url = env[EMULATOR_ENV.url]?.trim() || EMULATOR_DEFAULTS.url;
|
|
93
|
+
const config: CloudApiConfig = {
|
|
94
|
+
baseUrl: url,
|
|
95
|
+
phoneNumberId: env[EMULATOR_ENV.phoneNumberId]?.trim() || EMULATOR_DEFAULTS.phoneNumberId,
|
|
96
|
+
// Not credentials: the emulator has no auth, and these are the values
|
|
97
|
+
// `npm run whatsapp:emulator` starts it with.
|
|
98
|
+
accessToken: "emulator",
|
|
99
|
+
verifyToken: "emulator",
|
|
100
|
+
appSecret: env[EMULATOR_ENV.appSecret]?.trim() || EMULATOR_DEFAULTS.appSecret,
|
|
101
|
+
apiVersion: EMULATOR_DEFAULTS.apiVersion,
|
|
102
|
+
webhookPort: Number(env[EMULATOR_ENV.webhookPort]?.trim() || EMULATOR_DEFAULTS.webhookPort),
|
|
103
|
+
};
|
|
104
|
+
driver = new EmulatorDriver(url);
|
|
105
|
+
sessionKey = `${config.phoneNumberId}:${toGraphNumber(options.conversation.contact)}`;
|
|
106
|
+
backend = new WhatsAppEmulator({
|
|
107
|
+
config,
|
|
108
|
+
conversation: { contact: options.conversation.contact },
|
|
109
|
+
driver,
|
|
110
|
+
say,
|
|
111
|
+
render: options.render ?? say,
|
|
112
|
+
...(options.script ? { script: options.script } : {}),
|
|
113
|
+
...(options.ask ? { ask: options.ask } : {}),
|
|
114
|
+
...(options.pinAt ? { pinAt: options.pinAt } : {}),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The hours are the agent's, from `guardrails.envelope.collection_hours`. An agent that declares none gets no hours rule, which is correct: not every conversation is a collection.
|
|
119
|
+
const window = typeof s.guardrails.envelope?.["collection_hours"] === "string" ? (s.guardrails.envelope["collection_hours"] as string) : undefined;
|
|
120
|
+
|
|
121
|
+
const channel = new WhatsAppChannel({
|
|
122
|
+
backend,
|
|
123
|
+
conversation: options.conversation,
|
|
124
|
+
now: options.now,
|
|
125
|
+
...(window ? { hours: { window, timezone: s.guardrails.timezone } } : {}),
|
|
126
|
+
knownSubjects: knownSubjects(agent),
|
|
127
|
+
templates: loadTemplates(agent),
|
|
128
|
+
bundle: options.bundle,
|
|
129
|
+
say,
|
|
130
|
+
render: options.render ?? say,
|
|
131
|
+
...(options.session ? { session: options.session } : {}),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return { channel, ...(driver ? { driver } : {}), ...(sessionKey ? { sessionKey } : {}) };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The priced timeline the emulator computed: read for the console, never asserted on. */
|
|
138
|
+
export async function simulatedCost(driver: EmulatorDriver | undefined, sessionKey: string | undefined): Promise<{ total: number; currency: string } | undefined> {
|
|
139
|
+
if (!driver || !sessionKey) return undefined;
|
|
140
|
+
const state = (await driver.state(sessionKey).catch(() => undefined)) as { priced?: { total?: number; currency?: string } } | undefined;
|
|
141
|
+
if (typeof state?.priced?.total !== "number") return undefined;
|
|
142
|
+
return { total: state.priced.total, currency: state.priced.currency ?? "BRL" };
|
|
143
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a payable receivable is put into a conversation.
|
|
3
|
+
*
|
|
4
|
+
* It is here, and not inside the run loop, because two commands now present
|
|
5
|
+
* one: the run that issues the charge, and the poll that comes back to it
|
|
6
|
+
* later. A payer told how to pay by a poll must be told the same way as a
|
|
7
|
+
* payer told by a run, and the only way to guarantee that is for both to
|
|
8
|
+
* build the same messages from the same place.
|
|
9
|
+
*
|
|
10
|
+
* The shape is the point. The QR goes as an IMAGE and the copy-and-paste as
|
|
11
|
+
* its OWN message underneath, because a code inside a picture cannot be
|
|
12
|
+
* copied and a code inside a paragraph cannot be tapped.
|
|
13
|
+
*/
|
|
14
|
+
import type { ChargeInstrument, Execution } from "@codespar/agent-core";
|
|
15
|
+
import type { OutboundBody } from "../types.js";
|
|
16
|
+
|
|
17
|
+
export function instrumentBodies(execution: Execution, instalment: number, chargeId: string, instrument: ChargeInstrument, currency: string): OutboundBody[] {
|
|
18
|
+
const money = new Intl.NumberFormat("pt-BR", { style: "currency", currency });
|
|
19
|
+
const item = execution.items[instalment - 1];
|
|
20
|
+
const count = execution.items.length;
|
|
21
|
+
const bodies: OutboundBody[] = [
|
|
22
|
+
{
|
|
23
|
+
kind: "text",
|
|
24
|
+
text: [
|
|
25
|
+
count > 1 ? `Parcela ${instalment}/${count}: ` : "",
|
|
26
|
+
item ? money.format(item.amount / 100) : "",
|
|
27
|
+
instrument.due_date ? `, vence ${formatDate(instrument.due_date)}` : "",
|
|
28
|
+
` — cobranca ${chargeId}`,
|
|
29
|
+
].join(""),
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
if (instrument.pix_copy_paste) {
|
|
33
|
+
bodies.push({ kind: "media", media: "qr", data: instrument.pix_copy_paste });
|
|
34
|
+
bodies.push({ kind: "instrument", instrument: "pix_copy_paste", value: instrument.pix_copy_paste });
|
|
35
|
+
}
|
|
36
|
+
if (instrument.boleto_bank_line) {
|
|
37
|
+
bodies.push({ kind: "text", text: "Ou pelo boleto, linha digitavel:" });
|
|
38
|
+
bodies.push({ kind: "instrument", instrument: "boleto_bank_line", value: instrument.boleto_bank_line });
|
|
39
|
+
}
|
|
40
|
+
return bodies;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** `2026-09-30` -> `30/09/2026`. */
|
|
44
|
+
export function formatDate(iso: string): string {
|
|
45
|
+
const [y, m, d] = iso.split("-");
|
|
46
|
+
return `${d}/${m}/${y}`;
|
|
47
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The conversation loop: the WhatsApp equivalent of `interactive()`, and the
|
|
3
|
+
* same gates in the same order. The person writes, the model answers, the
|
|
4
|
+
* core decides, and what the core produced goes back into the conversation.
|
|
5
|
+
*
|
|
6
|
+
* The one difference from the terminal, and it is the whole reason the
|
|
7
|
+
* channel exists as its own thing: on a terminal the operator and the
|
|
8
|
+
* counterparty are the same pair of eyes, and here they are not. The
|
|
9
|
+
* approval question and the console go to stderr; only `tell` reaches the
|
|
10
|
+
* person. Nothing checks that — it is the wiring: `ask` and `say` are
|
|
11
|
+
* functions this module never hands to the channel.
|
|
12
|
+
*
|
|
13
|
+
* The payable artifact is sent the way a person can actually use it: the QR
|
|
14
|
+
* as an image, and the copy-and-paste as its OWN message underneath, because
|
|
15
|
+
* a code inside a picture cannot be copied and a code inside a paragraph
|
|
16
|
+
* cannot be tapped.
|
|
17
|
+
*/
|
|
18
|
+
import type { ChargeInstrument, Execution } from "@codespar/agent-core";
|
|
19
|
+
import { handleExecution, type TerminalOptions } from "../../terminal.js";
|
|
20
|
+
import type { Setup } from "../../setup.js";
|
|
21
|
+
import type { OutboundBody } from "../types.js";
|
|
22
|
+
import { instrumentBodies } from "./present.js";
|
|
23
|
+
import type { WhatsAppChannel } from "./index.js";
|
|
24
|
+
|
|
25
|
+
export interface ConverseOptions {
|
|
26
|
+
setup: Setup;
|
|
27
|
+
channel: WhatsAppChannel;
|
|
28
|
+
approver: { id: string; channel: string };
|
|
29
|
+
/** The operator's decision when nobody is at a keyboard. The gate runs `mandate`, where there is none to take. */
|
|
30
|
+
decision?: "approve" | "deny" | "none";
|
|
31
|
+
waitSeconds?: number | undefined;
|
|
32
|
+
simulatePayer?: boolean | undefined;
|
|
33
|
+
/** The operator's console. Never the conversation. */
|
|
34
|
+
say: (line: string) => void;
|
|
35
|
+
/** The operator's keyboard, when there is one. Never the conversation. */
|
|
36
|
+
ask?: ((question: string) => Promise<string>) | undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ConverseResult {
|
|
40
|
+
turns: number;
|
|
41
|
+
replies: string[];
|
|
42
|
+
toolCalls: Array<{ name: string; refused: boolean }>;
|
|
43
|
+
executions: Execution[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Keeps outbound messages in the order the run produced them, across await points. */
|
|
47
|
+
class Outbox {
|
|
48
|
+
private chain: Promise<void> = Promise.resolve();
|
|
49
|
+
|
|
50
|
+
constructor(private readonly channel: WhatsAppChannel) {}
|
|
51
|
+
|
|
52
|
+
push(body: OutboundBody): void {
|
|
53
|
+
this.chain = this.chain.then(async () => {
|
|
54
|
+
await this.channel.send(body);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
drain(): Promise<void> {
|
|
59
|
+
return this.chain;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function converse(options: ConverseOptions): Promise<ConverseResult> {
|
|
64
|
+
const { setup: s, channel, approver, say } = options;
|
|
65
|
+
const outbox = new Outbox(channel);
|
|
66
|
+
const replies: string[] = [];
|
|
67
|
+
const toolCalls: Array<{ name: string; refused: boolean }> = [];
|
|
68
|
+
let turns = 0;
|
|
69
|
+
|
|
70
|
+
const presentInstrument = (execution: Execution, instalment: number, chargeId: string, instrument: ChargeInstrument): Promise<void> => {
|
|
71
|
+
for (const body of instrumentBodies(execution, instalment, chargeId, instrument, s.mandate.currency)) outbox.push(body);
|
|
72
|
+
// Awaited by the poll: the person has the code in hand before the next look, not after the cycle closed.
|
|
73
|
+
return outbox.drain();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const terminalOptions: TerminalOptions = {
|
|
77
|
+
setup: s,
|
|
78
|
+
approver,
|
|
79
|
+
say,
|
|
80
|
+
tell: (line: string) => outbox.push({ kind: "text", text: line }),
|
|
81
|
+
presentInstrument,
|
|
82
|
+
...(options.decision ? { decision: options.decision } : {}),
|
|
83
|
+
...(options.ask ? { ask: options.ask } : {}),
|
|
84
|
+
...(options.waitSeconds !== undefined ? { waitSeconds: options.waitSeconds } : {}),
|
|
85
|
+
...(options.simulatePayer !== undefined ? { simulatePayer: options.simulatePayer } : {}),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// The channel is opened by the caller, which is where an emulator that is not
|
|
89
|
+
// running has to be reported: by here the run has already started.
|
|
90
|
+
const runtime = s.makeRuntime();
|
|
91
|
+
const loop = s.makeLoop(runtime, (execution) => handleExecution(execution, terminalOptions));
|
|
92
|
+
|
|
93
|
+
say(`${s.manifest.manifest.name} ${s.manifest.manifest.version} — canal: whatsapp (${channel.backend}) — approval: ${s.mode} — trilho: ${s.railKind} — ${s.kit.labels.mandateWord} ${s.mandate.id}`);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
for (;;) {
|
|
97
|
+
const message = await channel.next();
|
|
98
|
+
if (!message) break;
|
|
99
|
+
turns += 1;
|
|
100
|
+
const result = await loop.turn(message.text);
|
|
101
|
+
toolCalls.push(...result.tool_calls);
|
|
102
|
+
// Whatever the execution put in the conversation goes first: the QR before the sentence that explains it.
|
|
103
|
+
await outbox.drain();
|
|
104
|
+
if (result.reply.trim()) await channel.say(result.reply);
|
|
105
|
+
replies.push(result.reply);
|
|
106
|
+
}
|
|
107
|
+
await outbox.drain();
|
|
108
|
+
} finally {
|
|
109
|
+
await channel.close();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { turns, replies, toolCalls, executions: s.engine.list().filter((e) => e.run_id === s.runId) };
|
|
113
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsApp's own rule, which is not ours and which the simulator obeys
|
|
3
|
+
* anyway: outside the 24 hours that follow the person's last message, a
|
|
4
|
+
* business may only send a TEMPLATE that Meta approved in advance. Inside
|
|
5
|
+
* the window it may write freely.
|
|
6
|
+
*
|
|
7
|
+
* The simulator enforces it for the reason a simulator exists: something that
|
|
8
|
+
* only fails against the real provider is something you discover in
|
|
9
|
+
* production. A collections agent hits this constantly — the debtor answers
|
|
10
|
+
* on Tuesday, the charge is paid on Friday, and "recebemos, acordo quitado"
|
|
11
|
+
* falls outside the window.
|
|
12
|
+
*
|
|
13
|
+
* Template APPROVAL is a STUB and cannot be anything else from here: a
|
|
14
|
+
* template is registered in a Meta Business account, reviewed by Meta, and
|
|
15
|
+
* given a status we have no way to read without that account. What this holds
|
|
16
|
+
* is the LOCAL registry — the templates the agent declares it uses, from
|
|
17
|
+
* `channels/whatsapp/templates.json` — so sending one that was never declared
|
|
18
|
+
* is refused here instead of 400-ing at Meta. Whether Meta approved it is the
|
|
19
|
+
* developer's to check, and the README says so.
|
|
20
|
+
*/
|
|
21
|
+
import { templateArity, type WhatsAppTemplate } from "@codespar/agent-core";
|
|
22
|
+
|
|
23
|
+
export const SESSION_WINDOW_SECONDS = 24 * 60 * 60;
|
|
24
|
+
|
|
25
|
+
export interface SessionState {
|
|
26
|
+
/** Unix seconds of the last message the PERSON sent, on the provider's clock. */
|
|
27
|
+
lastInboundAt?: number | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Why a template send would be refused. `undefined` means it may go. */
|
|
31
|
+
export type TemplateRefusal = { rule: string; detail: string } | undefined;
|
|
32
|
+
|
|
33
|
+
export class SessionWindow {
|
|
34
|
+
private readonly templates: Map<string, WhatsAppTemplate>;
|
|
35
|
+
private lastInboundAt: number | undefined;
|
|
36
|
+
|
|
37
|
+
constructor(templates: readonly WhatsAppTemplate[], initial?: SessionState) {
|
|
38
|
+
this.templates = new Map(templates.map((t) => [t.name, t]));
|
|
39
|
+
this.lastInboundAt = initial?.lastInboundAt;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
observeInbound(timestamp: number): void {
|
|
43
|
+
if (this.lastInboundAt === undefined || timestamp > this.lastInboundAt) this.lastInboundAt = timestamp;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Seconds left before free-form messages stop being allowed; 0 when the window is shut or was never opened. */
|
|
47
|
+
remainingSeconds(now: Date): number {
|
|
48
|
+
if (this.lastInboundAt === undefined) return 0;
|
|
49
|
+
return Math.max(0, this.lastInboundAt + SESSION_WINDOW_SECONDS - Math.floor(now.getTime() / 1000));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
open(now: Date): boolean {
|
|
53
|
+
return this.remainingSeconds(now) > 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The declaration, for a caller that has to build a send: the language is the registry's, never the caller's guess. */
|
|
57
|
+
declared(name: string): WhatsAppTemplate | undefined {
|
|
58
|
+
return this.templates.get(name);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* What the Cloud API would refuse about this template send, decided against
|
|
63
|
+
* the declaration. Three things are visible to a registry: a name nobody
|
|
64
|
+
* declared, a language the template was not registered in, and a variable
|
|
65
|
+
* count the body has no placeholders for. Meta answers each with a 4xx and
|
|
66
|
+
* delivers nothing, so each is refused here instead.
|
|
67
|
+
*/
|
|
68
|
+
refuse(body: { template: string; language: string; variables: readonly string[] }): TemplateRefusal {
|
|
69
|
+
const declared = this.templates.get(body.template);
|
|
70
|
+
if (!declared) {
|
|
71
|
+
return {
|
|
72
|
+
rule: "template_unknown",
|
|
73
|
+
detail: `the agent declares no template named ${body.template}; Meta only delivers templates it approved, and this one was never registered here`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (declared.language !== body.language) {
|
|
77
|
+
return {
|
|
78
|
+
rule: "template_language_unknown",
|
|
79
|
+
detail: `${body.template} is declared in ${declared.language}, not ${body.language}; a template approved in one language does not exist in another`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const expected = templateArity(declared.body);
|
|
83
|
+
if (body.variables.length !== expected) {
|
|
84
|
+
return { rule: "template_variables_mismatch", detail: `${body.template} takes ${expected} variable(s) and this send carries ${body.variables.length}` };
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Where a conversation's window stood, read back from a bundle's
|
|
92
|
+
* `channel.jsonl`. This is what lets a later process — a poll, days after the
|
|
93
|
+
* run that opened the conversation — know whether it may still write freely,
|
|
94
|
+
* instead of assuming the worst and always sending a template.
|
|
95
|
+
*
|
|
96
|
+
* It reads the PROVIDER's timestamp and never the line's `at`, which is the
|
|
97
|
+
* run's own clock: the 24 hours are counted by WhatsApp on WhatsApp's clock,
|
|
98
|
+
* and a record written by a machine whose clock drifted is not evidence about
|
|
99
|
+
* theirs. A log carrying no provider timestamp on any inbound line yields no
|
|
100
|
+
* state, and the window then reads as SHUT — the safe direction, because a
|
|
101
|
+
* template is deliverable in both halves of the rule and a free-form message
|
|
102
|
+
* is deliverable in one.
|
|
103
|
+
*/
|
|
104
|
+
export function sessionStateFromChannelLog(lines: ReadonlyArray<Record<string, unknown>>): SessionState {
|
|
105
|
+
let lastInboundAt: number | undefined;
|
|
106
|
+
for (const line of lines) {
|
|
107
|
+
if (line["direction"] !== "in") continue;
|
|
108
|
+
const at = line["provider_timestamp"];
|
|
109
|
+
if (typeof at !== "number" || !Number.isFinite(at)) continue;
|
|
110
|
+
if (lastInboundAt === undefined || at > lastInboundAt) lastInboundAt = at;
|
|
111
|
+
}
|
|
112
|
+
return { lastInboundAt };
|
|
113
|
+
}
|