open-agentpay 0.2.4__tar.gz → 0.2.8__tar.gz
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.
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/.gitignore +18 -6
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/PKG-INFO +30 -12
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/README.md +27 -9
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/pyproject.toml +3 -3
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/__init__.py +1 -1
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/budget/__init__.py +2 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/client.py +36 -36
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/transport.py +68 -56
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/models.py +29 -8
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/__init__.py +2 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/config.py +8 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/db.py +1 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/errors.py +3 -5
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/evaluator.py +60 -29
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/metered.py +5 -5
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/models.py +31 -3
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/sqlite_engine.py +123 -133
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/errors.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/interfaces.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/client/signer.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/codecs.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/errors.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/interop.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/core/state.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/evm/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/evm/constants.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/evm/eip3009.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/evm/rpc.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/integrations/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/integrations/langchain/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/integrations/langchain/http.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/integrations/langchain/tool.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/policy/interfaces.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/codecs.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/errors.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/interop.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/models.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/protocol/state.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/signer/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/state/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/state/buyer_coordinator.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/state/errors.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/state/guards.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/state/reconciliation.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/testing/__init__.py +0 -0
- {open_agentpay-0.2.4 → open_agentpay-0.2.8}/src/agentpay/testing/mock_seller.py +0 -0
|
@@ -18,6 +18,7 @@ Thumbs.db
|
|
|
18
18
|
|
|
19
19
|
# Node.js & pnpm
|
|
20
20
|
node_modules/
|
|
21
|
+
package-lock.json
|
|
21
22
|
npm-debug.log*
|
|
22
23
|
yarn-debug.log*
|
|
23
24
|
yarn-error.log*
|
|
@@ -82,8 +83,8 @@ release.properties
|
|
|
82
83
|
out/
|
|
83
84
|
|
|
84
85
|
# Visual Studio Code
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
**/.vscode/*
|
|
87
|
+
!**/.vscode/settings.json
|
|
87
88
|
!.vscode/tasks.json
|
|
88
89
|
!.vscode/launch.json
|
|
89
90
|
!.vscode/extensions.json
|
|
@@ -119,8 +120,9 @@ docs/.vitepress/cache/
|
|
|
119
120
|
docs/.vitepress/dist/
|
|
120
121
|
internal-docs/
|
|
121
122
|
|
|
122
|
-
# Local gateway
|
|
123
|
-
gateway
|
|
123
|
+
# Local gateway/facilitator configs with runtime credentials
|
|
124
|
+
services/gateway/configs/gateway.yaml
|
|
125
|
+
services/facilitator/configs/facilitator.yaml
|
|
124
126
|
|
|
125
127
|
# 同步产物不进 Git;手写的 index.md 与 reports/ 要进
|
|
126
128
|
docs/specs/*.md
|
|
@@ -135,5 +137,15 @@ docs/zh/specs/adr/
|
|
|
135
137
|
!docs/zh/specs/reports/
|
|
136
138
|
!docs/zh/specs/reports/**
|
|
137
139
|
|
|
138
|
-
# Agent skills
|
|
139
|
-
.agents/
|
|
140
|
+
# Agent skills & local assistant configs
|
|
141
|
+
.agents/
|
|
142
|
+
skills-lock.json
|
|
143
|
+
|
|
144
|
+
# Next.js build output
|
|
145
|
+
.next/
|
|
146
|
+
*.tsbuildinfo
|
|
147
|
+
|
|
148
|
+
# Internal specifications & proprietary strategy docs (local only, do not push to public GitHub)
|
|
149
|
+
specs/roadmap.md
|
|
150
|
+
specs/zh/roadmap.md
|
|
151
|
+
specs/zh/cn-enterprise-firewall-and-finops-strategy.md
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: open-agentpay
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: The Open-Source Payment Infrastructure & Financial Firewall for Autonomous AI Agents
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Documentation, https://
|
|
5
|
+
Project-URL: Homepage, https://openagentpay.dev/
|
|
6
|
+
Project-URL: Documentation, https://openagentpay.dev/
|
|
7
7
|
Project-URL: Repository, https://github.com/open-agentpay/AgentPay
|
|
8
8
|
Author: AgentPay Contributors
|
|
9
9
|
License-Expression: Apache-2.0
|
|
@@ -33,7 +33,7 @@ Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
35
35
|
<p align="center">
|
|
36
|
-
<a href="https://
|
|
36
|
+
<a href="https://openagentpay.dev/">
|
|
37
37
|
<img src="https://raw.githubusercontent.com/open-agentpay/AgentPay/main/docs/public/logo.png" alt="AgentPay Logo" width="120" height="120" />
|
|
38
38
|
</a>
|
|
39
39
|
</p>
|
|
@@ -46,7 +46,7 @@ Description-Content-Type: text/markdown
|
|
|
46
46
|
|
|
47
47
|
<p align="center">
|
|
48
48
|
<a href="https://pypi.org/project/open-agentpay/"><img src="https://img.shields.io/pypi/v/open-agentpay.svg" alt="PyPI Version"></a>
|
|
49
|
-
<a href="https://
|
|
49
|
+
<a href="https://openagentpay.dev/"><img src="https://img.shields.io/badge/Docs-Live-blue?logo=vitepress&logoColor=white" alt="Documentation"></a>
|
|
50
50
|
<a href="https://x.com/OpenAgentPay"><img src="https://img.shields.io/badge/Follow-%40OpenAgentPay-black?logo=x&logoColor=white" alt="Follow @OpenAgentPay"></a>
|
|
51
51
|
<a href="https://github.com/open-agentpay/AgentPay/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache-2.0"></a>
|
|
52
52
|
<a href="https://github.com/open-agentpay/AgentPay"><img src="https://img.shields.io/badge/Protocol-x402_V2-orange.svg" alt="x402 V2"></a>
|
|
@@ -55,7 +55,7 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
</p>
|
|
56
56
|
|
|
57
57
|
<p align="center">
|
|
58
|
-
<a href="https://
|
|
58
|
+
<a href="https://openagentpay.dev/">📚 Documentation</a> •
|
|
59
59
|
<a href="https://github.com/open-agentpay/AgentPay">💻 GitHub Repository</a> •
|
|
60
60
|
<a href="https://x.com/OpenAgentPay">🐦 Follow on X (@OpenAgentPay)</a> •
|
|
61
61
|
<a href="https://github.com/open-agentpay/AgentPay/issues">🐛 Report Issue</a>
|
|
@@ -65,7 +65,7 @@ Description-Content-Type: text/markdown
|
|
|
65
65
|
|
|
66
66
|
## 💡 What is AgentPay?
|
|
67
67
|
|
|
68
|
-
**AgentPay** equips autonomous AI agents with micro-payments (Circle USDC on Arbitrum Sepolia & Base) governed by an in-process, non-custodial **Financial Firewall**. It transparently intercepts `HTTP 402 Payment Required` responses, validates policy limits, and signs off-chain authorizations—protecting agent wallets against runaway loops and LLM hallucinations.
|
|
68
|
+
**AgentPay** equips autonomous AI agents with micro-payments (Circle USDC on Arbitrum Sepolia & Base Sepolia) governed by an in-process, non-custodial **Financial Firewall**. It transparently intercepts `HTTP 402 Payment Required` responses, validates policy limits, and signs off-chain authorizations—protecting agent wallets against runaway loops and LLM hallucinations.
|
|
69
69
|
|
|
70
70
|
> 📦 **Package Name Note**: The canonical PyPI distribution is [`open-agentpay`](https://pypi.org/project/open-agentpay/) (official aliases: `agentpay-core`, `agentpay-firewall`). Regardless of which package you install, you import `agentpay` in Python code.
|
|
71
71
|
|
|
@@ -89,16 +89,21 @@ pip install "open-agentpay[langchain]"
|
|
|
89
89
|
Transparently intercepts HTTP 402 challenges, enforces local policy limits, and signs off-chain EIP-712/EIP-3009 authorizations:
|
|
90
90
|
|
|
91
91
|
```python
|
|
92
|
+
import os
|
|
92
93
|
from agentpay import AgentPayClient, LocalSigner
|
|
93
94
|
from agentpay.policy import SQLitePolicyEngine, PolicyConfig
|
|
94
95
|
|
|
95
96
|
# 1. Initialize local signer (non-custodial private key, 0 gas required)
|
|
96
|
-
|
|
97
|
+
# ⚠️ TESTNET DEVELOPMENT ONLY: This fallback key is Hardhat/Anvil's public Account 0 key.
|
|
98
|
+
# NEVER transfer mainnet funds to this address! In production, inject via environment variable:
|
|
99
|
+
private_key = os.getenv("AGENT_PRIVATE_KEY", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
|
|
100
|
+
signer = LocalSigner(private_key)
|
|
97
101
|
|
|
98
102
|
# 2. Configure local financial firewall
|
|
99
103
|
policy = SQLitePolicyEngine.create_in_memory(
|
|
100
104
|
PolicyConfig(
|
|
101
105
|
id="agent_firewall",
|
|
106
|
+
name="Agent Firewall",
|
|
102
107
|
wallet_address=signer.address,
|
|
103
108
|
max_per_tx_base_units=100_000, # Max $0.10 per call
|
|
104
109
|
rolling_budget_24h_base_units=1_000_000, # Daily cap $1.00
|
|
@@ -119,13 +124,26 @@ print(response.json())
|
|
|
119
124
|
For sub-millisecond execution using a pre-funded virtual ledger:
|
|
120
125
|
|
|
121
126
|
```python
|
|
127
|
+
import os
|
|
122
128
|
from agentpay import AgentPayClient, LocalSigner
|
|
123
129
|
from agentpay.policy import SQLitePolicyEngine, PolicyConfig
|
|
124
130
|
|
|
131
|
+
private_key = os.getenv("AGENT_PRIVATE_KEY", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
|
|
132
|
+
signer = LocalSigner(private_key)
|
|
125
133
|
client = AgentPayClient(
|
|
126
|
-
signer=
|
|
127
|
-
policy=SQLitePolicyEngine.create_in_memory(
|
|
134
|
+
signer=signer,
|
|
135
|
+
policy=SQLitePolicyEngine.create_in_memory(
|
|
136
|
+
PolicyConfig(
|
|
137
|
+
id="wallet_firewall",
|
|
138
|
+
name="Wallet Firewall",
|
|
139
|
+
wallet_address=signer.address,
|
|
140
|
+
max_per_tx_base_units=100_000,
|
|
141
|
+
rolling_budget_24h_base_units=5_000_000,
|
|
142
|
+
whitelist_domains=frozenset(["gateway.seller.com"]),
|
|
143
|
+
)
|
|
144
|
+
),
|
|
128
145
|
headers={"Authorization": "Bearer agp_live_your_api_key"},
|
|
146
|
+
wallet_challenge_mode=True,
|
|
129
147
|
)
|
|
130
148
|
|
|
131
149
|
response = client.get("https://gateway.seller.com/v1/compute")
|
|
@@ -176,7 +194,7 @@ asyncio.run(main())
|
|
|
176
194
|
|---|---|
|
|
177
195
|
| **Zero-Trust Financial Firewall** | Enforces per-transaction caps, 24-hour rolling budgets, lifetime limits, and payee whitelists outside the LLM prompt. |
|
|
178
196
|
| **Autonomous Circuit Breaker** | Automatically halts agent loops and freezes spending when request frequency exceeds safety thresholds (`circuit_max_rpm`). |
|
|
179
|
-
| **Gasless Off-Chain Settlements** | AI Agents hold only Circle USDC; gas is sponsored on Arbitrum Sepolia & Base via EIP-3009 off-chain authorizations. |
|
|
197
|
+
| **Gasless Off-Chain Settlements** | AI Agents hold only Circle USDC; gas is sponsored on Arbitrum Sepolia & Base Sepolia via EIP-3009 off-chain authorizations. |
|
|
180
198
|
| **Agent Session & Audit Observability** | Automatic tracking headers (`X-Agent-Session-ID`, `X-Agent-Task-ID`) connect tool spending to tasks in the AgentPay Console. |
|
|
181
199
|
| **Fail-Closed Guarantees** | Any policy violation, budget overrun, or upstream failure aborts safely with zero funds deducted. |
|
|
182
200
|
|
|
@@ -184,7 +202,7 @@ asyncio.run(main())
|
|
|
184
202
|
|
|
185
203
|
## 📖 Documentation & Community
|
|
186
204
|
|
|
187
|
-
- **Official Documentation**: [https://
|
|
205
|
+
- **Official Documentation**: [https://openagentpay.dev/](https://openagentpay.dev/)
|
|
188
206
|
- **GitHub Repository**: [https://github.com/open-agentpay/AgentPay](https://github.com/open-agentpay/AgentPay)
|
|
189
207
|
- **Twitter / X**: [@OpenAgentPay](https://x.com/OpenAgentPay)
|
|
190
208
|
- **Issue Tracker**: [GitHub Issues](https://github.com/open-agentpay/AgentPay/issues)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://
|
|
2
|
+
<a href="https://openagentpay.dev/">
|
|
3
3
|
<img src="https://raw.githubusercontent.com/open-agentpay/AgentPay/main/docs/public/logo.png" alt="AgentPay Logo" width="120" height="120" />
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://pypi.org/project/open-agentpay/"><img src="https://img.shields.io/pypi/v/open-agentpay.svg" alt="PyPI Version"></a>
|
|
15
|
-
<a href="https://
|
|
15
|
+
<a href="https://openagentpay.dev/"><img src="https://img.shields.io/badge/Docs-Live-blue?logo=vitepress&logoColor=white" alt="Documentation"></a>
|
|
16
16
|
<a href="https://x.com/OpenAgentPay"><img src="https://img.shields.io/badge/Follow-%40OpenAgentPay-black?logo=x&logoColor=white" alt="Follow @OpenAgentPay"></a>
|
|
17
17
|
<a href="https://github.com/open-agentpay/AgentPay/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache-2.0"></a>
|
|
18
18
|
<a href="https://github.com/open-agentpay/AgentPay"><img src="https://img.shields.io/badge/Protocol-x402_V2-orange.svg" alt="x402 V2"></a>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</p>
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
|
-
<a href="https://
|
|
24
|
+
<a href="https://openagentpay.dev/">📚 Documentation</a> •
|
|
25
25
|
<a href="https://github.com/open-agentpay/AgentPay">💻 GitHub Repository</a> •
|
|
26
26
|
<a href="https://x.com/OpenAgentPay">🐦 Follow on X (@OpenAgentPay)</a> •
|
|
27
27
|
<a href="https://github.com/open-agentpay/AgentPay/issues">🐛 Report Issue</a>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
## 💡 What is AgentPay?
|
|
33
33
|
|
|
34
|
-
**AgentPay** equips autonomous AI agents with micro-payments (Circle USDC on Arbitrum Sepolia & Base) governed by an in-process, non-custodial **Financial Firewall**. It transparently intercepts `HTTP 402 Payment Required` responses, validates policy limits, and signs off-chain authorizations—protecting agent wallets against runaway loops and LLM hallucinations.
|
|
34
|
+
**AgentPay** equips autonomous AI agents with micro-payments (Circle USDC on Arbitrum Sepolia & Base Sepolia) governed by an in-process, non-custodial **Financial Firewall**. It transparently intercepts `HTTP 402 Payment Required` responses, validates policy limits, and signs off-chain authorizations—protecting agent wallets against runaway loops and LLM hallucinations.
|
|
35
35
|
|
|
36
36
|
> 📦 **Package Name Note**: The canonical PyPI distribution is [`open-agentpay`](https://pypi.org/project/open-agentpay/) (official aliases: `agentpay-core`, `agentpay-firewall`). Regardless of which package you install, you import `agentpay` in Python code.
|
|
37
37
|
|
|
@@ -55,16 +55,21 @@ pip install "open-agentpay[langchain]"
|
|
|
55
55
|
Transparently intercepts HTTP 402 challenges, enforces local policy limits, and signs off-chain EIP-712/EIP-3009 authorizations:
|
|
56
56
|
|
|
57
57
|
```python
|
|
58
|
+
import os
|
|
58
59
|
from agentpay import AgentPayClient, LocalSigner
|
|
59
60
|
from agentpay.policy import SQLitePolicyEngine, PolicyConfig
|
|
60
61
|
|
|
61
62
|
# 1. Initialize local signer (non-custodial private key, 0 gas required)
|
|
62
|
-
|
|
63
|
+
# ⚠️ TESTNET DEVELOPMENT ONLY: This fallback key is Hardhat/Anvil's public Account 0 key.
|
|
64
|
+
# NEVER transfer mainnet funds to this address! In production, inject via environment variable:
|
|
65
|
+
private_key = os.getenv("AGENT_PRIVATE_KEY", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
|
|
66
|
+
signer = LocalSigner(private_key)
|
|
63
67
|
|
|
64
68
|
# 2. Configure local financial firewall
|
|
65
69
|
policy = SQLitePolicyEngine.create_in_memory(
|
|
66
70
|
PolicyConfig(
|
|
67
71
|
id="agent_firewall",
|
|
72
|
+
name="Agent Firewall",
|
|
68
73
|
wallet_address=signer.address,
|
|
69
74
|
max_per_tx_base_units=100_000, # Max $0.10 per call
|
|
70
75
|
rolling_budget_24h_base_units=1_000_000, # Daily cap $1.00
|
|
@@ -85,13 +90,26 @@ print(response.json())
|
|
|
85
90
|
For sub-millisecond execution using a pre-funded virtual ledger:
|
|
86
91
|
|
|
87
92
|
```python
|
|
93
|
+
import os
|
|
88
94
|
from agentpay import AgentPayClient, LocalSigner
|
|
89
95
|
from agentpay.policy import SQLitePolicyEngine, PolicyConfig
|
|
90
96
|
|
|
97
|
+
private_key = os.getenv("AGENT_PRIVATE_KEY", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
|
|
98
|
+
signer = LocalSigner(private_key)
|
|
91
99
|
client = AgentPayClient(
|
|
92
|
-
signer=
|
|
93
|
-
policy=SQLitePolicyEngine.create_in_memory(
|
|
100
|
+
signer=signer,
|
|
101
|
+
policy=SQLitePolicyEngine.create_in_memory(
|
|
102
|
+
PolicyConfig(
|
|
103
|
+
id="wallet_firewall",
|
|
104
|
+
name="Wallet Firewall",
|
|
105
|
+
wallet_address=signer.address,
|
|
106
|
+
max_per_tx_base_units=100_000,
|
|
107
|
+
rolling_budget_24h_base_units=5_000_000,
|
|
108
|
+
whitelist_domains=frozenset(["gateway.seller.com"]),
|
|
109
|
+
)
|
|
110
|
+
),
|
|
94
111
|
headers={"Authorization": "Bearer agp_live_your_api_key"},
|
|
112
|
+
wallet_challenge_mode=True,
|
|
95
113
|
)
|
|
96
114
|
|
|
97
115
|
response = client.get("https://gateway.seller.com/v1/compute")
|
|
@@ -142,7 +160,7 @@ asyncio.run(main())
|
|
|
142
160
|
|---|---|
|
|
143
161
|
| **Zero-Trust Financial Firewall** | Enforces per-transaction caps, 24-hour rolling budgets, lifetime limits, and payee whitelists outside the LLM prompt. |
|
|
144
162
|
| **Autonomous Circuit Breaker** | Automatically halts agent loops and freezes spending when request frequency exceeds safety thresholds (`circuit_max_rpm`). |
|
|
145
|
-
| **Gasless Off-Chain Settlements** | AI Agents hold only Circle USDC; gas is sponsored on Arbitrum Sepolia & Base via EIP-3009 off-chain authorizations. |
|
|
163
|
+
| **Gasless Off-Chain Settlements** | AI Agents hold only Circle USDC; gas is sponsored on Arbitrum Sepolia & Base Sepolia via EIP-3009 off-chain authorizations. |
|
|
146
164
|
| **Agent Session & Audit Observability** | Automatic tracking headers (`X-Agent-Session-ID`, `X-Agent-Task-ID`) connect tool spending to tasks in the AgentPay Console. |
|
|
147
165
|
| **Fail-Closed Guarantees** | Any policy violation, budget overrun, or upstream failure aborts safely with zero funds deducted. |
|
|
148
166
|
|
|
@@ -150,7 +168,7 @@ asyncio.run(main())
|
|
|
150
168
|
|
|
151
169
|
## 📖 Documentation & Community
|
|
152
170
|
|
|
153
|
-
- **Official Documentation**: [https://
|
|
171
|
+
- **Official Documentation**: [https://openagentpay.dev/](https://openagentpay.dev/)
|
|
154
172
|
- **GitHub Repository**: [https://github.com/open-agentpay/AgentPay](https://github.com/open-agentpay/AgentPay)
|
|
155
173
|
- **Twitter / X**: [@OpenAgentPay](https://x.com/OpenAgentPay)
|
|
156
174
|
- **Issue Tracker**: [GitHub Issues](https://github.com/open-agentpay/AgentPay/issues)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "open-agentpay"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "The Open-Source Payment Infrastructure & Financial Firewall for Autonomous AI Agents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -44,8 +44,8 @@ dev = [
|
|
|
44
44
|
]
|
|
45
45
|
|
|
46
46
|
[project.urls]
|
|
47
|
-
Homepage = "https://
|
|
48
|
-
Documentation = "https://
|
|
47
|
+
Homepage = "https://openagentpay.dev/"
|
|
48
|
+
Documentation = "https://openagentpay.dev/"
|
|
49
49
|
Repository = "https://github.com/open-agentpay/AgentPay"
|
|
50
50
|
|
|
51
51
|
[tool.hatch.build.targets.wheel]
|
|
@@ -14,6 +14,7 @@ from agentpay.policy.models import (
|
|
|
14
14
|
PolicyConfig,
|
|
15
15
|
PolicyDecision,
|
|
16
16
|
ReservationToken,
|
|
17
|
+
WhitelistMode,
|
|
17
18
|
)
|
|
18
19
|
|
|
19
20
|
# Backward compatibility / convenient domain aliases
|
|
@@ -34,4 +35,5 @@ __all__ = [
|
|
|
34
35
|
"PolicyEvaluationResult",
|
|
35
36
|
"PolicyStatus",
|
|
36
37
|
"ReservationToken",
|
|
38
|
+
"WhitelistMode",
|
|
37
39
|
]
|
|
@@ -57,22 +57,22 @@ class AgentPayClient(httpx.Client):
|
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
59
|
def __init__(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
self,
|
|
61
|
+
signer: ISigner,
|
|
62
|
+
policy: IPolicyEngine,
|
|
63
|
+
*,
|
|
64
|
+
transport: httpx.BaseTransport | None = None,
|
|
65
|
+
auto_retry_on_402: bool = True,
|
|
66
|
+
raise_on_policy_rejection: bool = False,
|
|
67
|
+
clock: Callable[[], int] | None = None,
|
|
68
|
+
unmetered_credential_policy: CredentialMode = "block",
|
|
69
|
+
credential_headers: tuple[str, ...] = DEFAULT_CREDENTIAL_HEADERS,
|
|
70
|
+
credential_value_prefixes: tuple[str, ...] = DEFAULT_CREDENTIAL_VALUE_PREFIXES,
|
|
71
|
+
estimate_cost: Callable[[httpx.Request], int] | None = None,
|
|
72
|
+
actual_cost: Callable[[httpx.Response], int | None] | None = None,
|
|
73
|
+
credential_ttl_seconds: int = 60,
|
|
74
|
+
wallet_challenge_mode: bool = False,
|
|
75
|
+
**kwargs: Any,
|
|
76
76
|
) -> None:
|
|
77
77
|
inner_kwargs = _inner_transport_kwargs(kwargs)
|
|
78
78
|
|
|
@@ -101,10 +101,10 @@ class AgentPayClient(httpx.Client):
|
|
|
101
101
|
super().__init__(transport=agent_transport, **kwargs)
|
|
102
102
|
|
|
103
103
|
def async_client(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
self,
|
|
105
|
+
*,
|
|
106
|
+
transport: httpx.AsyncBaseTransport | None = None,
|
|
107
|
+
**kwargs: Any,
|
|
108
108
|
) -> AsyncAgentPayClient:
|
|
109
109
|
"""Create an AsyncAgentPayClient sharing the same signer, policy and firewall options."""
|
|
110
110
|
options = {**self._agentpay_options, **{k: v for k, v in kwargs.items() if k in self._agentpay_options}}
|
|
@@ -127,22 +127,22 @@ class AsyncAgentPayClient(httpx.AsyncClient):
|
|
|
127
127
|
"""
|
|
128
128
|
|
|
129
129
|
def __init__(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
130
|
+
self,
|
|
131
|
+
signer: ISigner,
|
|
132
|
+
policy: IPolicyEngine,
|
|
133
|
+
*,
|
|
134
|
+
transport: httpx.AsyncBaseTransport | None = None,
|
|
135
|
+
auto_retry_on_402: bool = True,
|
|
136
|
+
raise_on_policy_rejection: bool = False,
|
|
137
|
+
clock: Callable[[], int] | None = None,
|
|
138
|
+
unmetered_credential_policy: CredentialMode = "block",
|
|
139
|
+
credential_headers: tuple[str, ...] = DEFAULT_CREDENTIAL_HEADERS,
|
|
140
|
+
credential_value_prefixes: tuple[str, ...] = DEFAULT_CREDENTIAL_VALUE_PREFIXES,
|
|
141
|
+
estimate_cost: Callable[[httpx.Request], int] | None = None,
|
|
142
|
+
actual_cost: Callable[[httpx.Response], int | None] | None = None,
|
|
143
|
+
credential_ttl_seconds: int = 60,
|
|
144
|
+
wallet_challenge_mode: bool = False,
|
|
145
|
+
**kwargs: Any,
|
|
146
146
|
) -> None:
|
|
147
147
|
inner_kwargs = _inner_transport_kwargs(kwargs)
|
|
148
148
|
|
|
@@ -111,26 +111,27 @@ def _safe_record_failure(policy: Any, reason: str) -> None:
|
|
|
111
111
|
|
|
112
112
|
class _AgentPayCore:
|
|
113
113
|
def __init__(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
114
|
+
self,
|
|
115
|
+
signer: ISigner,
|
|
116
|
+
policy: IPolicyEngine,
|
|
117
|
+
*,
|
|
118
|
+
auto_retry_on_402: bool,
|
|
119
|
+
raise_on_policy_rejection: bool,
|
|
120
|
+
clock: Callable[[], int] | None,
|
|
121
|
+
unmetered_credential_policy: CredentialMode,
|
|
122
|
+
credential_headers: tuple[str, ...],
|
|
123
|
+
credential_value_prefixes: tuple[str, ...],
|
|
124
|
+
estimate_cost: Callable[[httpx.Request], int] | None,
|
|
125
|
+
actual_cost: Callable[[httpx.Response], int | None] | None,
|
|
126
|
+
credential_ttl_seconds: int,
|
|
127
|
+
wallet_challenge_mode: bool,
|
|
128
128
|
) -> None:
|
|
129
129
|
if unmetered_credential_policy not in ("block", "meter", "allow"):
|
|
130
130
|
raise ValueError(
|
|
131
|
-
f"unmetered_credential_policy must be block/meter/allow, got {unmetered_credential_policy!r}"
|
|
131
|
+
f"unmetered_credential_policy must be block/meter/allow, got {unmetered_credential_policy!r}"
|
|
132
|
+
)
|
|
132
133
|
if unmetered_credential_policy == "meter" and (
|
|
133
|
-
|
|
134
|
+
estimate_cost is None or not isinstance(policy, IMeteredPolicyEngine)
|
|
134
135
|
):
|
|
135
136
|
raise ValueError("meter mode requires estimate_cost and a policy implementing IMeteredPolicyEngine")
|
|
136
137
|
|
|
@@ -182,9 +183,7 @@ class _AgentPayCore:
|
|
|
182
183
|
try:
|
|
183
184
|
estimate = self._estimate_cost(request)
|
|
184
185
|
except Exception as exc: # noqa: BLE001
|
|
185
|
-
raise PolicyViolationError(
|
|
186
|
-
PolicyErrorCode.INVALID_AMOUNT_FORMAT, "estimate_cost callback failed"
|
|
187
|
-
) from exc
|
|
186
|
+
raise PolicyViolationError(PolicyErrorCode.INVALID_AMOUNT_FORMAT, "estimate_cost callback failed") from exc
|
|
188
187
|
|
|
189
188
|
intent_id = f"cred_{uuid.uuid4().hex}"
|
|
190
189
|
decision = self._policy.reserve_metered( # type: ignore[attr-defined]
|
|
@@ -225,11 +224,15 @@ class _AgentPayCore:
|
|
|
225
224
|
if challenge.is_expired(self._clock()):
|
|
226
225
|
return None
|
|
227
226
|
if challenge.scheme not in ("EIP-3009", "agentpay-wallet"):
|
|
228
|
-
raise PolicyViolationError(
|
|
227
|
+
raise PolicyViolationError(
|
|
228
|
+
PolicyErrorCode.POLICY_SYSTEM_ERROR, f"unsupported payment scheme: {challenge.scheme}"
|
|
229
|
+
)
|
|
229
230
|
if challenge.scheme == "agentpay-wallet":
|
|
230
231
|
expected_binding = self._request_binding(request)
|
|
231
232
|
if (challenge.extensions or {}).get("requestBinding") != expected_binding:
|
|
232
|
-
raise PolicyViolationError(
|
|
233
|
+
raise PolicyViolationError(
|
|
234
|
+
PolicyErrorCode.POLICY_SYSTEM_ERROR, "wallet challenge requestBinding mismatch"
|
|
235
|
+
)
|
|
233
236
|
if not (challenge.extensions or {}).get("routeId"):
|
|
234
237
|
raise PolicyViolationError(PolicyErrorCode.POLICY_SYSTEM_ERROR, "wallet challenge missing routeId")
|
|
235
238
|
raw_path, _, _ = request.url.raw_path.partition(b"?")
|
|
@@ -272,12 +275,18 @@ class _AgentPayCore:
|
|
|
272
275
|
if challenge.scheme == "agentpay-wallet":
|
|
273
276
|
# SECURITY-REVIEW: the challenge-bound reservation is the buyer-side approval gate.
|
|
274
277
|
if reservation.intent_id != challenge.challenge_id or reservation.amount != challenge.amount_base_units:
|
|
275
|
-
raise PolicyViolationError(
|
|
278
|
+
raise PolicyViolationError(
|
|
279
|
+
PolicyErrorCode.POLICY_SYSTEM_ERROR, "wallet reservation does not match challenge"
|
|
280
|
+
)
|
|
276
281
|
if reservation.expires_at < challenge.valid_before:
|
|
277
|
-
raise PolicyViolationError(
|
|
282
|
+
raise PolicyViolationError(
|
|
283
|
+
PolicyErrorCode.POLICY_SYSTEM_ERROR, "wallet reservation expires before challenge"
|
|
284
|
+
)
|
|
278
285
|
request_binding = (challenge.extensions or {}).get("requestBinding")
|
|
279
286
|
if not request_binding:
|
|
280
|
-
raise PolicyViolationError(
|
|
287
|
+
raise PolicyViolationError(
|
|
288
|
+
PolicyErrorCode.POLICY_SYSTEM_ERROR, "wallet challenge missing requestBinding"
|
|
289
|
+
)
|
|
281
290
|
wallet_auth = WalletAuthorization(
|
|
282
291
|
challengeId=challenge.challenge_id,
|
|
283
292
|
nonce="0x" + secrets.token_bytes(32).hex(),
|
|
@@ -291,8 +300,11 @@ class _AgentPayCore:
|
|
|
291
300
|
headers["PAYMENT-SIGNATURE"] = encode_wallet_authorization(wallet_auth)
|
|
292
301
|
content = request.read()
|
|
293
302
|
return httpx.Request(
|
|
294
|
-
method=request.method,
|
|
295
|
-
|
|
303
|
+
method=request.method,
|
|
304
|
+
url=request.url,
|
|
305
|
+
headers=headers,
|
|
306
|
+
content=content,
|
|
307
|
+
extensions=dict(request.extensions),
|
|
296
308
|
)
|
|
297
309
|
authorization = self._signer.sign_payment_authorization(challenge, reservation)
|
|
298
310
|
return _clone_request_with_authorization(request, authorization)
|
|
@@ -328,21 +340,21 @@ class AgentPayTransport(_AgentPayCore, httpx.BaseTransport):
|
|
|
328
340
|
"""
|
|
329
341
|
|
|
330
342
|
def __init__(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
343
|
+
self,
|
|
344
|
+
inner_transport: httpx.BaseTransport,
|
|
345
|
+
signer: ISigner,
|
|
346
|
+
policy: IPolicyEngine,
|
|
347
|
+
*,
|
|
348
|
+
auto_retry_on_402: bool = True,
|
|
349
|
+
raise_on_policy_rejection: bool = False,
|
|
350
|
+
clock: Callable[[], int] | None = None,
|
|
351
|
+
unmetered_credential_policy: CredentialMode = "block",
|
|
352
|
+
credential_headers: tuple[str, ...] = DEFAULT_CREDENTIAL_HEADERS,
|
|
353
|
+
credential_value_prefixes: tuple[str, ...] = DEFAULT_CREDENTIAL_VALUE_PREFIXES,
|
|
354
|
+
estimate_cost: Callable[[httpx.Request], int] | None = None,
|
|
355
|
+
actual_cost: Callable[[httpx.Response], int | None] | None = None,
|
|
356
|
+
credential_ttl_seconds: int = 60,
|
|
357
|
+
wallet_challenge_mode: bool = False,
|
|
346
358
|
) -> None:
|
|
347
359
|
httpx.BaseTransport.__init__(self)
|
|
348
360
|
_AgentPayCore.__init__(
|
|
@@ -415,21 +427,21 @@ class AsyncAgentPayTransport(_AgentPayCore, httpx.AsyncBaseTransport):
|
|
|
415
427
|
"""
|
|
416
428
|
|
|
417
429
|
def __init__(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
430
|
+
self,
|
|
431
|
+
inner_transport: httpx.AsyncBaseTransport,
|
|
432
|
+
signer: ISigner,
|
|
433
|
+
policy: IPolicyEngine,
|
|
434
|
+
*,
|
|
435
|
+
auto_retry_on_402: bool = True,
|
|
436
|
+
raise_on_policy_rejection: bool = False,
|
|
437
|
+
clock: Callable[[], int] | None = None,
|
|
438
|
+
unmetered_credential_policy: CredentialMode = "block",
|
|
439
|
+
credential_headers: tuple[str, ...] = DEFAULT_CREDENTIAL_HEADERS,
|
|
440
|
+
credential_value_prefixes: tuple[str, ...] = DEFAULT_CREDENTIAL_VALUE_PREFIXES,
|
|
441
|
+
estimate_cost: Callable[[httpx.Request], int] | None = None,
|
|
442
|
+
actual_cost: Callable[[httpx.Response], int | None] | None = None,
|
|
443
|
+
credential_ttl_seconds: int = 60,
|
|
444
|
+
wallet_challenge_mode: bool = False,
|
|
433
445
|
) -> None:
|
|
434
446
|
httpx.AsyncBaseTransport.__init__(self)
|
|
435
447
|
_AgentPayCore.__init__(
|