agentguard-python-sdk 0.1.3__tar.gz → 0.2.1__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.
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/PKG-INFO +7 -2
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/README.md +6 -1
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/client.py +86 -68
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/consent.py +21 -38
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/types.py +4 -4
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/PKG-INFO +7 -2
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/pyproject.toml +1 -1
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/__init__.py +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/auth.py +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/config.py +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/errors.py +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard/observability.py +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/SOURCES.txt +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/dependency_links.txt +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/requires.txt +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/top_level.txt +0 -0
- {agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentguard-python-sdk
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A production-grade middleware for AI agents to perform on-chain payments and verifiable consent.
|
|
5
5
|
Author: AgentGuard Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -32,7 +32,12 @@ from agentguard import AgentGuardClient
|
|
|
32
32
|
|
|
33
33
|
async def main():
|
|
34
34
|
# 1. Initialize the client
|
|
35
|
-
|
|
35
|
+
# NOTE: The backend requires a cryptographic signature on `/pay`.
|
|
36
|
+
# Provide `private_key` as a base64-encoded Algorand private key seed for request signing.
|
|
37
|
+
async with AgentGuardClient(
|
|
38
|
+
wallet_address="YOUR_WALLET_ADDRESS",
|
|
39
|
+
private_key="YOUR_PRIVATE_KEY_B64",
|
|
40
|
+
) as client:
|
|
36
41
|
|
|
37
42
|
# 2. Perform a secure payment (includes automatic DPDP consent hashing)
|
|
38
43
|
receipt = await client.pay_and_fetch(
|
|
@@ -18,7 +18,12 @@ from agentguard import AgentGuardClient
|
|
|
18
18
|
|
|
19
19
|
async def main():
|
|
20
20
|
# 1. Initialize the client
|
|
21
|
-
|
|
21
|
+
# NOTE: The backend requires a cryptographic signature on `/pay`.
|
|
22
|
+
# Provide `private_key` as a base64-encoded Algorand private key seed for request signing.
|
|
23
|
+
async with AgentGuardClient(
|
|
24
|
+
wallet_address="YOUR_WALLET_ADDRESS",
|
|
25
|
+
private_key="YOUR_PRIVATE_KEY_B64",
|
|
26
|
+
) as client:
|
|
22
27
|
|
|
23
28
|
# 2. Perform a secure payment (includes automatic DPDP consent hashing)
|
|
24
29
|
receipt = await client.pay_and_fetch(
|
|
@@ -15,7 +15,7 @@ from typing import Optional, Dict, Any
|
|
|
15
15
|
from .consent import generate_consent_proof
|
|
16
16
|
from . import auth
|
|
17
17
|
from .types import AgentGuardReceipt, AuditProof
|
|
18
|
-
from .errors import map_backend_error, TransportError, AgentGuardError, VerificationError
|
|
18
|
+
from .errors import map_backend_error, TransportError, AgentGuardError, VerificationError, PaymentError
|
|
19
19
|
from .config import AgentGuardConfig
|
|
20
20
|
from .observability import start_span
|
|
21
21
|
|
|
@@ -105,48 +105,63 @@ class AgentGuardClient:
|
|
|
105
105
|
correlation_id: Optional[str] = None
|
|
106
106
|
) -> AgentGuardReceipt:
|
|
107
107
|
"""
|
|
108
|
-
|
|
108
|
+
End-to-end flow for accessing resources (Probe -> Pay -> Fetch).
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
amount_algo: The amount in ALGO as a string (e.g. '0.05').
|
|
114
|
-
microalgos: Alternatively, the exact amount in microAlgos (int).
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
AgentGuardReceipt: A structured receipt with transaction details.
|
|
110
|
+
1. SDK sends GET resource_url with no payment.
|
|
111
|
+
2. If 200 -> return data directly, no payment.
|
|
112
|
+
3. If 402 -> extract price from headers, pay via backend, and retry with proof.
|
|
118
113
|
"""
|
|
119
|
-
#
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
# Step A — Probe Request
|
|
115
|
+
async with httpx.AsyncClient(timeout=self.timeout) as probe_client:
|
|
116
|
+
try:
|
|
117
|
+
probe_res = await probe_client.get(resource_url)
|
|
118
|
+
|
|
119
|
+
if probe_res.status_code == 200:
|
|
120
|
+
logger.info(f"Resource {resource_url} is free. Accessing directly.")
|
|
121
|
+
return AgentGuardReceipt(
|
|
122
|
+
tx_id=None,
|
|
123
|
+
consent_hash=None,
|
|
124
|
+
audit_url=None,
|
|
125
|
+
data=probe_res.json()
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if probe_res.status_code != 402:
|
|
129
|
+
raise PaymentError(f"Resource server returned unexpected status: {probe_res.status_code}", "ERR_UNEXPECTED_STATUS")
|
|
130
|
+
|
|
131
|
+
# Extract 402 headers
|
|
132
|
+
header_amount = probe_res.headers.get("X-402-Payment-Amount")
|
|
133
|
+
header_receiver = probe_res.headers.get("X-402-Receiver-Address")
|
|
134
|
+
|
|
135
|
+
if header_amount:
|
|
136
|
+
actual_microalgos = int(header_amount)
|
|
137
|
+
logger.info(f"Resource requires payment: {actual_microalgos} microAlgos (per header)")
|
|
138
|
+
elif microalgos is not None:
|
|
139
|
+
actual_microalgos = microalgos
|
|
140
|
+
elif amount_algo is not None:
|
|
141
|
+
actual_microalgos = parse_algo_amount_to_microalgos(amount_algo)
|
|
142
|
+
else:
|
|
143
|
+
raise ValueError("Resource requires payment but provided no price header, and no fallback amount was provided.")
|
|
144
|
+
|
|
145
|
+
except httpx.RequestError as e:
|
|
146
|
+
raise TransportError(f"Failed to probe resource: {e}")
|
|
147
|
+
except Exception as e:
|
|
148
|
+
if isinstance(e, AgentGuardError): raise
|
|
149
|
+
raise AgentGuardError(f"Unexpected error during probe: {str(e)}", "ERR_PROBE_FAILED")
|
|
131
150
|
|
|
132
|
-
#
|
|
133
|
-
# We generate these early so they can be persisted across retries if needed.
|
|
151
|
+
# Step B — Payment (Using Backend Relay)
|
|
134
152
|
idem_key = idempotency_key or str(uuid.uuid4())
|
|
135
153
|
act_nonce = nonce or str(uuid.uuid4())
|
|
136
154
|
act_correlation_id = correlation_id or str(idem_key)
|
|
137
155
|
|
|
138
|
-
# 3. Generate Consent Proof (SHA256 of metadata including microalgos)
|
|
139
|
-
# If timestamp is provided (from a previous retry), we reuse it.
|
|
140
156
|
consent_hash, act_timestamp = generate_consent_proof(
|
|
141
157
|
principal_id=self.wallet_address,
|
|
142
158
|
resource_url=resource_url,
|
|
143
159
|
purpose=purpose,
|
|
144
160
|
nonce=act_nonce,
|
|
145
161
|
microalgos=actual_microalgos,
|
|
146
|
-
timestamp=timestamp
|
|
162
|
+
timestamp=timestamp
|
|
147
163
|
)
|
|
148
164
|
|
|
149
|
-
# 4. Payload Construction
|
|
150
165
|
payload = {
|
|
151
166
|
"resource_url": resource_url,
|
|
152
167
|
"microalgos": actual_microalgos,
|
|
@@ -164,7 +179,6 @@ class AgentGuardClient:
|
|
|
164
179
|
"X-Correlation-ID": act_correlation_id
|
|
165
180
|
}
|
|
166
181
|
|
|
167
|
-
# 5. Cryptographic Signing (Priority 5)
|
|
168
182
|
if self.private_key:
|
|
169
183
|
signature = auth.sign_request(payload, self.private_key)
|
|
170
184
|
headers.update({
|
|
@@ -173,63 +187,57 @@ class AgentGuardClient:
|
|
|
173
187
|
"X-AgentGuard-Key-Id": self.wallet_address,
|
|
174
188
|
"X-AgentGuard-Nonce": act_nonce
|
|
175
189
|
})
|
|
176
|
-
# Priority 6: Signing verified via Span attributes if needed
|
|
177
190
|
|
|
178
|
-
# 6. Request with Retries
|
|
179
191
|
span = start_span("sdk.pay_request", act_correlation_id)
|
|
180
|
-
span.set_attribute("wallet", self.wallet_address)
|
|
181
|
-
span.set_attribute("microalgos", actual_microalgos)
|
|
182
|
-
span.set_attribute("idempotency_key", idem_key)
|
|
183
|
-
|
|
184
192
|
max_attempts = self.config.max_retries
|
|
185
193
|
base_delay = self.config.retry_base_delay
|
|
186
194
|
|
|
195
|
+
receipt = None
|
|
187
196
|
for attempt in range(max_attempts):
|
|
188
|
-
attempt_span = start_span(f"sdk.request_attempt_{attempt + 1}", act_correlation_id, parent_id=span.span_id)
|
|
189
197
|
try:
|
|
190
198
|
response = await self.async_client.post(f"{self.base_url}/pay", json=payload, headers=headers)
|
|
191
199
|
|
|
192
200
|
if response.status_code == 200:
|
|
193
201
|
res_data = response.json()
|
|
194
|
-
|
|
195
|
-
span.set_attribute("tx_id", res_data["tx_id"])
|
|
196
|
-
span.end()
|
|
197
|
-
return AgentGuardReceipt(
|
|
202
|
+
receipt = AgentGuardReceipt(
|
|
198
203
|
tx_id=res_data["tx_id"],
|
|
199
204
|
consent_hash=res_data["consent_hash"],
|
|
200
205
|
audit_url=res_data["audit_url"],
|
|
201
|
-
data=res_data.get("data", {})
|
|
202
206
|
)
|
|
207
|
+
break
|
|
203
208
|
else:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
attempt_span.end(error=f"http_{response.status_code}: {error_data.get('message')}")
|
|
210
|
-
|
|
211
|
-
# Transient errors -> retry
|
|
212
|
-
if response.status_code in [502, 503, 504, 429]:
|
|
213
|
-
if attempt < max_attempts - 1:
|
|
214
|
-
delay = base_delay * (2 ** attempt) + random.uniform(0, 0.5)
|
|
215
|
-
await asyncio.sleep(delay)
|
|
216
|
-
continue
|
|
217
|
-
|
|
218
|
-
span.end(error=f"backend_rejection_{response.status_code}")
|
|
219
|
-
raise map_backend_error(response.status_code, error_data)
|
|
220
|
-
|
|
209
|
+
if response.status_code in [502, 503, 504, 429] and attempt < max_attempts - 1:
|
|
210
|
+
await asyncio.sleep(base_delay * (2 ** attempt))
|
|
211
|
+
continue
|
|
212
|
+
raise map_backend_error(response.status_code, response.json())
|
|
221
213
|
except httpx.RequestError as e:
|
|
222
|
-
attempt_span.end(error=str(e))
|
|
223
214
|
if attempt < max_attempts - 1:
|
|
224
|
-
|
|
225
|
-
await asyncio.sleep(delay)
|
|
215
|
+
await asyncio.sleep(base_delay * (2 ** attempt))
|
|
226
216
|
continue
|
|
227
|
-
|
|
228
|
-
|
|
217
|
+
raise TransportError(f"Backend unreachable: {e}")
|
|
218
|
+
|
|
219
|
+
if not receipt:
|
|
220
|
+
raise PaymentError("Payment failed or timed out.")
|
|
221
|
+
|
|
222
|
+
# Step C — Retry with Proof
|
|
223
|
+
async with httpx.AsyncClient(timeout=self.timeout) as fetch_client:
|
|
224
|
+
logger.info(f"Payment successful (TX: {receipt.tx_id}). Fetching data...")
|
|
225
|
+
proof_headers = {
|
|
226
|
+
"X-AgentGuard-Proof": receipt.tx_id,
|
|
227
|
+
"X-AgentGuard-Principal": self.wallet_address
|
|
228
|
+
}
|
|
229
|
+
try:
|
|
230
|
+
final_res = await fetch_client.get(resource_url, headers=proof_headers)
|
|
231
|
+
if final_res.status_code == 200:
|
|
232
|
+
receipt.data = final_res.json()
|
|
233
|
+
span.end()
|
|
234
|
+
return receipt
|
|
235
|
+
else:
|
|
236
|
+
span.end(error=f"Resource rejected proof: {final_res.status_code}")
|
|
237
|
+
raise PaymentError(f"Proof rejected by resource server: {final_res.status_code}")
|
|
229
238
|
except Exception as e:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
raise
|
|
239
|
+
span.end(error=str(e))
|
|
240
|
+
raise TransportError(f"Failed to fetch data with proof: {e}")
|
|
233
241
|
|
|
234
242
|
async def verify(self, tx_id: str, verify_onchain: bool = False, local_proof: Optional[Dict[str, Any]] = None) -> AuditProof:
|
|
235
243
|
"""
|
|
@@ -265,9 +273,19 @@ class AgentGuardClient:
|
|
|
265
273
|
canonical_json = res_data.get("canonical_json")
|
|
266
274
|
|
|
267
275
|
if not canonical_json and local_proof:
|
|
268
|
-
# [Priority 8 BONUS] Reconstruct canonical JSON
|
|
276
|
+
# [Priority 8 BONUS] Reconstruct canonical JSON using SHARED SCHEMA BUILDER
|
|
277
|
+
from .consent import build_canonical_payload
|
|
269
278
|
from .auth import canonicalize_payload
|
|
270
|
-
|
|
279
|
+
|
|
280
|
+
canonical_payload = build_canonical_payload(
|
|
281
|
+
principal_id=local_proof.get("principal_id", self.wallet_address),
|
|
282
|
+
resource_url=local_proof.get("resource_url", ""),
|
|
283
|
+
purpose=local_proof.get("purpose", ""),
|
|
284
|
+
microalgos=int(local_proof.get("microalgos", 0)),
|
|
285
|
+
nonce=local_proof.get("nonce", ""),
|
|
286
|
+
timestamp=int(local_proof.get("timestamp", 0))
|
|
287
|
+
)
|
|
288
|
+
canonical_bytes = canonicalize_payload(canonical_payload)
|
|
271
289
|
canonical_json = canonical_bytes.decode("utf-8")
|
|
272
290
|
|
|
273
291
|
if not canonical_json:
|
|
@@ -8,56 +8,36 @@ from typing import Dict, Any
|
|
|
8
8
|
# Configure logging
|
|
9
9
|
logger = logging.getLogger("agentguard-sdk")
|
|
10
10
|
|
|
11
|
-
def
|
|
11
|
+
def build_canonical_payload(
|
|
12
12
|
principal_id: str,
|
|
13
|
+
resource_url: str,
|
|
13
14
|
purpose: str,
|
|
14
|
-
item: str,
|
|
15
|
-
nonce: str,
|
|
16
15
|
microalgos: int,
|
|
17
|
-
|
|
18
|
-
timestamp: int
|
|
16
|
+
nonce: str,
|
|
17
|
+
timestamp: int,
|
|
18
|
+
data_fiduciary: str = "AlgoBharat Agentic Node"
|
|
19
19
|
) -> Dict[str, Any]:
|
|
20
20
|
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Representation Rule:
|
|
25
|
-
- Internal: microalgos (int) is the single source of truth.
|
|
26
|
-
- Strings: All metadata is normalized to NFC.
|
|
21
|
+
SINGLE SOURCE OF TRUTH for the audit payload schema.
|
|
22
|
+
Guarantees deterministic parity between SDK, Backend, and recovery logic.
|
|
27
23
|
"""
|
|
28
|
-
|
|
29
|
-
timestamp = int(time.time())
|
|
30
|
-
|
|
31
|
-
# Normalize strings to NFC at the creation boundary
|
|
32
|
-
consent_obj = {
|
|
33
|
-
"principal_id": unicodedata.normalize("NFC", principal_id),
|
|
24
|
+
return {
|
|
34
25
|
"data_fiduciary": unicodedata.normalize("NFC", data_fiduciary),
|
|
35
|
-
"
|
|
36
|
-
"item": unicodedata.normalize("NFC",
|
|
37
|
-
"microalgos": microalgos,
|
|
38
|
-
"timestamp": timestamp,
|
|
26
|
+
"hash_version": 2, # Current Refactor Version
|
|
27
|
+
"item": unicodedata.normalize("NFC", resource_url),
|
|
28
|
+
"microalgos": int(microalgos),
|
|
39
29
|
"nonce": nonce,
|
|
40
|
-
"
|
|
30
|
+
"principal_id": unicodedata.normalize("NFC", principal_id),
|
|
31
|
+
"purpose": unicodedata.normalize("NFC", purpose),
|
|
32
|
+
"timestamp": int(timestamp)
|
|
41
33
|
}
|
|
42
|
-
|
|
43
|
-
logger.info(f"Generated DPDP consent (v2) for principal={principal_id} at {timestamp}")
|
|
44
|
-
return consent_obj
|
|
45
34
|
|
|
46
35
|
def hash_consent(consent: Dict[str, Any]) -> str:
|
|
47
36
|
"""
|
|
48
37
|
Canonical hashing implementation.
|
|
49
38
|
MUST REMAINT SYNCED with Backend and MCP Server.
|
|
50
|
-
|
|
51
|
-
Rules:
|
|
52
|
-
1. sort_keys=True
|
|
53
|
-
2. separators=(',', ':')
|
|
54
|
-
3. ensure_ascii=False
|
|
55
|
-
4. Encoding: utf-8
|
|
56
39
|
"""
|
|
57
|
-
# Convert consent dict to JSON string with strict canonical form
|
|
58
|
-
# - Sorted keys
|
|
59
|
-
# - No spaces (separators=(",", ":"))
|
|
60
|
-
# Use separators=(",", ":") and ensure_ascii=False for identical bytes across boundaries
|
|
40
|
+
# Convert consent dict to JSON string with strict canonical form
|
|
61
41
|
consent_json = json.dumps(consent, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
|
|
62
42
|
consent_hash = hashlib.sha256(consent_json.encode("utf-8")).hexdigest()
|
|
63
43
|
|
|
@@ -68,12 +48,15 @@ def generate_consent_proof(principal_id: str, resource_url: str, purpose: str, n
|
|
|
68
48
|
"""
|
|
69
49
|
High-level helper to generate a consent hash and return the timestamp used.
|
|
70
50
|
"""
|
|
71
|
-
|
|
51
|
+
if timestamp is None:
|
|
52
|
+
timestamp = int(time.time())
|
|
53
|
+
|
|
54
|
+
consent = build_canonical_payload(
|
|
72
55
|
principal_id=principal_id,
|
|
56
|
+
resource_url=resource_url,
|
|
73
57
|
purpose=purpose,
|
|
74
|
-
item=resource_url,
|
|
75
|
-
nonce=nonce,
|
|
76
58
|
microalgos=microalgos,
|
|
59
|
+
nonce=nonce,
|
|
77
60
|
timestamp=timestamp
|
|
78
61
|
)
|
|
79
62
|
return hash_consent(consent), consent["timestamp"]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Dict, Any
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
3
|
|
|
4
4
|
@dataclass
|
|
5
5
|
class AgentGuardReceipt:
|
|
6
6
|
"""
|
|
7
7
|
Structured response for a successful AgentGuard payment.
|
|
8
8
|
"""
|
|
9
|
-
tx_id: str
|
|
10
|
-
consent_hash: str
|
|
11
|
-
audit_url: str
|
|
9
|
+
tx_id: Optional[str]
|
|
10
|
+
consent_hash: Optional[str]
|
|
11
|
+
audit_url: Optional[str]
|
|
12
12
|
data: Dict[str, Any] = field(default_factory=dict)
|
|
13
13
|
|
|
14
14
|
@dataclass
|
{agentguard_python_sdk-0.1.3 → agentguard_python_sdk-0.2.1}/agentguard_python_sdk.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentguard-python-sdk
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A production-grade middleware for AI agents to perform on-chain payments and verifiable consent.
|
|
5
5
|
Author: AgentGuard Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -32,7 +32,12 @@ from agentguard import AgentGuardClient
|
|
|
32
32
|
|
|
33
33
|
async def main():
|
|
34
34
|
# 1. Initialize the client
|
|
35
|
-
|
|
35
|
+
# NOTE: The backend requires a cryptographic signature on `/pay`.
|
|
36
|
+
# Provide `private_key` as a base64-encoded Algorand private key seed for request signing.
|
|
37
|
+
async with AgentGuardClient(
|
|
38
|
+
wallet_address="YOUR_WALLET_ADDRESS",
|
|
39
|
+
private_key="YOUR_PRIVATE_KEY_B64",
|
|
40
|
+
) as client:
|
|
36
41
|
|
|
37
42
|
# 2. Perform a secure payment (includes automatic DPDP consent hashing)
|
|
38
43
|
receipt = await client.pay_and_fetch(
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentguard-python-sdk"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "A production-grade middleware for AI agents to perform on-chain payments and verifiable consent."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
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
|