open-agentpay 0.2.2__tar.gz → 0.2.4__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.2 → open_agentpay-0.2.4}/PKG-INFO +1 -1
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/pyproject.toml +1 -1
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/__init__.py +1 -1
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/models.py +5 -2
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/evaluator.py +27 -18
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/models.py +27 -2
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/sqlite_engine.py +7 -6
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/.gitignore +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/README.md +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/budget/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/client.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/errors.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/interfaces.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/signer.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/client/transport.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/codecs.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/errors.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/interop.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/core/state.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/evm/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/evm/constants.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/evm/eip3009.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/evm/rpc.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/integrations/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/integrations/langchain/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/integrations/langchain/http.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/integrations/langchain/tool.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/config.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/db.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/errors.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/interfaces.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/policy/metered.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/codecs.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/errors.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/interop.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/models.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/protocol/state.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/signer/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/state/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/state/buyer_coordinator.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/state/errors.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/state/guards.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/state/reconciliation.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/testing/__init__.py +0 -0
- {open_agentpay-0.2.2 → open_agentpay-0.2.4}/src/agentpay/testing/mock_seller.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: open-agentpay
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: The Open-Source Payment Infrastructure & Financial Firewall for Autonomous AI Agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/open-agentpay/AgentPay
|
|
6
6
|
Project-URL: Documentation, https://open-agentpay.github.io/AgentPay/
|
|
@@ -46,6 +46,9 @@ _BYTES32_HEX_RE = re.compile(r"^(0x)?[0-9a-fA-F]{64}$")
|
|
|
46
46
|
# Maximum signed 64-bit integer for base units
|
|
47
47
|
SQLITE_MAX_INT = 9_223_372_036_854_775_807
|
|
48
48
|
|
|
49
|
+
# Supported fiat base currencies for AgentPay internal virtual wallet
|
|
50
|
+
WALLET_FIAT_CURRENCIES = frozenset({"CNY", "USD", "EUR"})
|
|
51
|
+
|
|
49
52
|
|
|
50
53
|
def _validate_evm_address(value: str, field_name: str) -> str:
|
|
51
54
|
"""Validate EVM address format and normalise to lowercase."""
|
|
@@ -228,7 +231,7 @@ class PaymentChallenge(BaseModel):
|
|
|
228
231
|
@field_validator("asset")
|
|
229
232
|
@classmethod
|
|
230
233
|
def _validate_asset(cls, v: str | None, info: Any) -> str | None:
|
|
231
|
-
if info.data.get("scheme") == "agentpay-wallet" and v
|
|
234
|
+
if info.data.get("scheme") == "agentpay-wallet" and v in WALLET_FIAT_CURRENCIES:
|
|
232
235
|
return v
|
|
233
236
|
if v is None:
|
|
234
237
|
raise X402ValidationError("asset is required", code=X402ErrorCode.MISSING_REQUIRED_FIELD)
|
|
@@ -331,7 +334,7 @@ class PaymentChallenge(BaseModel):
|
|
|
331
334
|
@model_validator(mode="after")
|
|
332
335
|
def _validate_scheme_fields(self) -> PaymentChallenge:
|
|
333
336
|
if self.scheme == "agentpay-wallet":
|
|
334
|
-
if self.network != "agentpay:internal-ledger" or self.asset
|
|
337
|
+
if self.network != "agentpay:internal-ledger" or self.asset not in WALLET_FIAT_CURRENCIES or not self.resource_uri:
|
|
335
338
|
raise X402ValidationError("invalid agentpay-wallet challenge fields", code=X402ErrorCode.INVALID_SCHEME)
|
|
336
339
|
if self.facilitator_url:
|
|
337
340
|
raise X402ValidationError("agentpay-wallet challenge must not name an EIP-3009 facilitator", code=X402ErrorCode.INVALID_SCHEME)
|
|
@@ -60,26 +60,35 @@ def evaluate_static_rules(
|
|
|
60
60
|
reason=f"Invalid payment amount: {request.amount!r}",
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
-
# 3. Whitelist Matrix (
|
|
64
|
-
|
|
63
|
+
# 3. Whitelist Matrix (EVM only). AgentPay's internal wallet ledger uses
|
|
64
|
+
# non-EVM identifiers; its trust boundary is the required gateway domain.
|
|
65
|
+
if not request.is_agentpay_wallet:
|
|
66
|
+
if request.network not in config.whitelist_networks:
|
|
67
|
+
return StaticEvaluationResult(
|
|
68
|
+
passed=False,
|
|
69
|
+
error_code=PolicyErrorCode.NETWORK_NOT_WHITELISTED,
|
|
70
|
+
reason=f"Network {request.network} is not in whitelisted networks",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if request.asset not in config.whitelist_assets:
|
|
74
|
+
return StaticEvaluationResult(
|
|
75
|
+
passed=False,
|
|
76
|
+
error_code=PolicyErrorCode.ASSET_NOT_WHITELISTED,
|
|
77
|
+
reason=f"Asset {request.asset} is not in whitelisted assets",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if request.payee not in config.whitelist_payees:
|
|
81
|
+
return StaticEvaluationResult(
|
|
82
|
+
passed=False,
|
|
83
|
+
error_code=PolicyErrorCode.PAYEE_NOT_WHITELISTED,
|
|
84
|
+
reason=f"Payee {request.payee} is not in whitelisted payees",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if request.is_agentpay_wallet and request.domain is None:
|
|
65
88
|
return StaticEvaluationResult(
|
|
66
89
|
passed=False,
|
|
67
|
-
error_code=PolicyErrorCode.
|
|
68
|
-
reason=
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
if request.asset not in config.whitelist_assets:
|
|
72
|
-
return StaticEvaluationResult(
|
|
73
|
-
passed=False,
|
|
74
|
-
error_code=PolicyErrorCode.ASSET_NOT_WHITELISTED,
|
|
75
|
-
reason=f"Asset {request.asset} is not in whitelisted assets",
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
if request.payee not in config.whitelist_payees:
|
|
79
|
-
return StaticEvaluationResult(
|
|
80
|
-
passed=False,
|
|
81
|
-
error_code=PolicyErrorCode.PAYEE_NOT_WHITELISTED,
|
|
82
|
-
reason=f"Payee {request.payee} is not in whitelisted payees",
|
|
90
|
+
error_code=PolicyErrorCode.DOMAIN_NOT_WHITELISTED,
|
|
91
|
+
reason="AgentPay wallet requests require a whitelisted gateway domain",
|
|
83
92
|
)
|
|
84
93
|
|
|
85
94
|
if request.domain is not None and request.domain.lower() not in config.whitelist_domains:
|
|
@@ -17,7 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import enum
|
|
18
18
|
import re
|
|
19
19
|
|
|
20
|
-
from pydantic import BaseModel, field_validator
|
|
20
|
+
from pydantic import BaseModel, field_validator, model_validator
|
|
21
21
|
|
|
22
22
|
from agentpay.policy.errors import PolicyErrorCode
|
|
23
23
|
|
|
@@ -30,6 +30,9 @@ _CAIP2_RE = re.compile(r"^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}$")
|
|
|
30
30
|
|
|
31
31
|
# Canonical EVM address: 0x followed by exactly 40 hex chars
|
|
32
32
|
_EVM_ADDRESS_RE = re.compile(r"^0x[0-9a-fA-F]{40}$")
|
|
33
|
+
_AGENTPAY_ROUTE_RE = re.compile(r"^agentpay:route:[A-Za-z0-9_-]+$")
|
|
34
|
+
_AGENTPAY_INTERNAL_NETWORK = "agentpay:internal-ledger"
|
|
35
|
+
_WALLET_FIAT_CURRENCIES = frozenset({"CNY", "USD", "EUR"})
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
# ---------------------------------------------------------------------------
|
|
@@ -219,7 +222,7 @@ class PolicyConfig(BaseModel):
|
|
|
219
222
|
raise TypeError(f"whitelist_assets elements must be strings, got {type(addr).__name__}")
|
|
220
223
|
normalized: list[str] = []
|
|
221
224
|
for addr in v:
|
|
222
|
-
normalized.append(
|
|
225
|
+
normalized.append(addr if addr in _WALLET_FIAT_CURRENCIES else _validate_evm_address(addr, "whitelist_assets"))
|
|
223
226
|
return frozenset(normalized)
|
|
224
227
|
|
|
225
228
|
@field_validator("whitelist_networks", mode="before")
|
|
@@ -278,18 +281,40 @@ class PaymentRequest(BaseModel):
|
|
|
278
281
|
@field_validator("payee")
|
|
279
282
|
@classmethod
|
|
280
283
|
def _normalise_payee(cls, v: str) -> str:
|
|
284
|
+
if _AGENTPAY_ROUTE_RE.fullmatch(v):
|
|
285
|
+
return v
|
|
281
286
|
return _validate_evm_address(v, "payee")
|
|
282
287
|
|
|
283
288
|
@field_validator("asset")
|
|
284
289
|
@classmethod
|
|
285
290
|
def _normalise_asset(cls, v: str) -> str:
|
|
291
|
+
if v in _WALLET_FIAT_CURRENCIES:
|
|
292
|
+
return v
|
|
286
293
|
return _validate_evm_address(v, "asset")
|
|
287
294
|
|
|
288
295
|
@field_validator("network")
|
|
289
296
|
@classmethod
|
|
290
297
|
def _validate_network(cls, v: str) -> str:
|
|
298
|
+
if v == _AGENTPAY_INTERNAL_NETWORK:
|
|
299
|
+
return v
|
|
291
300
|
return _validate_caip2(v)
|
|
292
301
|
|
|
302
|
+
@model_validator(mode="after")
|
|
303
|
+
def _validate_payment_identifiers(self) -> PaymentRequest:
|
|
304
|
+
wallet_fields = (
|
|
305
|
+
self.network == _AGENTPAY_INTERNAL_NETWORK,
|
|
306
|
+
self.asset in _WALLET_FIAT_CURRENCIES,
|
|
307
|
+
bool(_AGENTPAY_ROUTE_RE.fullmatch(self.payee)),
|
|
308
|
+
)
|
|
309
|
+
if any(wallet_fields) and not all(wallet_fields):
|
|
310
|
+
raise ValueError("AgentPay wallet requests require internal-ledger, a supported fiat currency (CNY/USD/EUR), and an agentpay:route payee")
|
|
311
|
+
return self
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def is_agentpay_wallet(self) -> bool:
|
|
315
|
+
"""Whether this request uses AgentPay's internal wallet ledger rather than EVM settlement."""
|
|
316
|
+
return self.network == _AGENTPAY_INTERNAL_NETWORK
|
|
317
|
+
|
|
293
318
|
@field_validator("domain", mode="before")
|
|
294
319
|
@classmethod
|
|
295
320
|
def _normalise_domain(cls, v: object) -> str | None:
|
|
@@ -14,23 +14,24 @@ References:
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
|
+
import logging
|
|
17
18
|
import sqlite3
|
|
18
19
|
import time
|
|
19
20
|
import uuid
|
|
20
21
|
from collections.abc import Callable
|
|
21
22
|
|
|
22
|
-
import logger
|
|
23
23
|
from pydantic import ValidationError
|
|
24
24
|
|
|
25
25
|
from agentpay.policy.errors import PolicyErrorCode, PolicyViolationError
|
|
26
|
-
from agentpay.policy.evaluator import
|
|
26
|
+
from agentpay.policy.evaluator import evaluate_metered_rules, evaluate_static_rules
|
|
27
27
|
from agentpay.policy.interfaces import IPolicyEngine
|
|
28
28
|
from agentpay.policy.models import (
|
|
29
|
+
SQLITE_MAX_INT,
|
|
29
30
|
BreakerState,
|
|
30
31
|
PaymentRequest,
|
|
31
32
|
PolicyConfig,
|
|
32
33
|
PolicyDecision,
|
|
33
|
-
ReservationToken,
|
|
34
|
+
ReservationToken,
|
|
34
35
|
)
|
|
35
36
|
|
|
36
37
|
|
|
@@ -757,7 +758,7 @@ class SQLitePolicyEngine(IPolicyEngine):
|
|
|
757
758
|
self._rollback_quietly(cursor)
|
|
758
759
|
return PolicyDecision(approved=False, error_code=PolicyErrorCode.DUPLICATE_INTENT)
|
|
759
760
|
except Exception: # noqa: BLE001
|
|
760
|
-
|
|
761
|
+
logging.exception("policy reserve_metered failed; failing closed")
|
|
761
762
|
self._rollback_quietly(cursor)
|
|
762
763
|
return PolicyDecision(approved=False, error_code=PolicyErrorCode.POLICY_SYSTEM_ERROR)
|
|
763
764
|
|
|
@@ -774,7 +775,7 @@ class SQLitePolicyEngine(IPolicyEngine):
|
|
|
774
775
|
or not isinstance(actual_amount, int)
|
|
775
776
|
or not (0 < actual_amount <= SQLITE_MAX_INT)
|
|
776
777
|
):
|
|
777
|
-
|
|
778
|
+
logging.warning("invalid actual_amount %r for %s; keeping reserved estimate", actual_amount, intent_id)
|
|
778
779
|
actual_amount = None
|
|
779
780
|
|
|
780
781
|
now = self._clock()
|
|
@@ -805,7 +806,7 @@ class SQLitePolicyEngine(IPolicyEngine):
|
|
|
805
806
|
(now, self._config.id),
|
|
806
807
|
)
|
|
807
808
|
else:
|
|
808
|
-
|
|
809
|
+
logging.warning("settle_metered: no RESERVED row for intent %s", intent_id)
|
|
809
810
|
self._conn.commit()
|
|
810
811
|
except Exception:
|
|
811
812
|
self._rollback_quietly(cursor)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|