aotrust-protocol 2.3.6__tar.gz → 2.3.7__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.
- {aotrust_protocol-2.3.6/aotrust_protocol.egg-info → aotrust_protocol-2.3.7}/PKG-INFO +54 -4
- aotrust_protocol-2.3.7/README.md +141 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/agent_notary/__init__.py +1 -1
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/agent_notary/client.py +7 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/agent_notary/exceptions.py +9 -1
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7/aotrust_protocol.egg-info}/PKG-INFO +54 -4
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/pyproject.toml +1 -1
- aotrust_protocol-2.3.6/README.md +0 -91
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/LICENSE +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/agent_notary/models.py +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/agent_notary/tools.py +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/aotrust_protocol.egg-info/SOURCES.txt +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/aotrust_protocol.egg-info/dependency_links.txt +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/aotrust_protocol.egg-info/requires.txt +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/aotrust_protocol.egg-info/top_level.txt +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/setup.cfg +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/tests/test_client.py +0 -0
- {aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/tests/test_live_smoke.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aotrust-protocol
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.7
|
|
4
4
|
Summary: Asyncio-native SDK for A&O Trust Layer — Agent Notary Service
|
|
5
5
|
Author: A&O Trust Layer
|
|
6
6
|
License: MIT
|
|
@@ -39,6 +39,37 @@ pip install aotrust-protocol
|
|
|
39
39
|
|
|
40
40
|
## Quickstart
|
|
41
41
|
|
|
42
|
+
### Free tier — no API key, no wallet (fastest way to try)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import asyncio, hashlib
|
|
46
|
+
from agent_notary import NotaryClient
|
|
47
|
+
|
|
48
|
+
async def main():
|
|
49
|
+
# IMPORTANT: no /v1 suffix — the SDK appends API paths itself.
|
|
50
|
+
client = NotaryClient(base_url="https://api.aotrust.link")
|
|
51
|
+
|
|
52
|
+
work_hash = hashlib.sha256(b"my artifact text").hexdigest()
|
|
53
|
+
result = await client.shield_free(work_hash)
|
|
54
|
+
job_id = result["job_id"] # keep this UUID — it is the handle
|
|
55
|
+
print("job_id:", job_id)
|
|
56
|
+
|
|
57
|
+
# Check status BY job_id (not by the artifact text!)
|
|
58
|
+
status = await client.get_status(job_id)
|
|
59
|
+
print("status:", status.status) # PENDING → anchored (anchor batches)
|
|
60
|
+
|
|
61
|
+
# Fetch + verify the PDR
|
|
62
|
+
pdr = await client.get_pdr(job_id)
|
|
63
|
+
print("verify in browser:", pdr.verify_url)
|
|
64
|
+
assert (await client.verify_pdr(pdr.pdr_b64))["valid"]
|
|
65
|
+
|
|
66
|
+
asyncio.run(main())
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Free tier: 5 PDR / 24h per IP. Examples: [`examples/04_free_tier.py`](examples/04_free_tier.py).
|
|
70
|
+
|
|
71
|
+
### Witness mode (pre-paid tx_hash)
|
|
72
|
+
|
|
42
73
|
```python
|
|
43
74
|
import asyncio
|
|
44
75
|
from agent_notary import NotaryClient, NotarizeRequest
|
|
@@ -46,7 +77,7 @@ from agent_notary import NotaryClient, NotarizeRequest
|
|
|
46
77
|
async def main():
|
|
47
78
|
client = NotaryClient(
|
|
48
79
|
api_key="your-api-key",
|
|
49
|
-
base_url="https://api.aotrust.link/v1
|
|
80
|
+
base_url="https://api.aotrust.link" # no /v1 suffix!
|
|
50
81
|
)
|
|
51
82
|
|
|
52
83
|
# Submit notarization
|
|
@@ -59,7 +90,7 @@ async def main():
|
|
|
59
90
|
result = await client.notarize(req)
|
|
60
91
|
print(f"Job: {result.job_id}")
|
|
61
92
|
|
|
62
|
-
# Poll for PDR
|
|
93
|
+
# Poll for PDR — status/pdr calls always take the job_id returned above
|
|
63
94
|
status = await client.wait_for_pdr(result.job_id, timeout=60)
|
|
64
95
|
if status.is_anchored:
|
|
65
96
|
pdr = await client.get_pdr(result.job_id)
|
|
@@ -69,6 +100,11 @@ async def main():
|
|
|
69
100
|
asyncio.run(main())
|
|
70
101
|
```
|
|
71
102
|
|
|
103
|
+
> **Why no `/v1`?** `base_url` must be `https://api.aotrust.link`. The SDK
|
|
104
|
+
> already builds `/v1/...` request paths; adding `/v1` yourself produces
|
|
105
|
+
> `/v1/v1/...` → HTTP 404 on every call. This bit a real user (2026-09-29:
|
|
106
|
+
> quickstart copy-paste + status lookups by artifact text instead of job_id).
|
|
107
|
+
|
|
72
108
|
## Configuration
|
|
73
109
|
|
|
74
110
|
| Env Var | Constructor Arg | Description |
|
|
@@ -100,7 +136,15 @@ Uses NEP-413 raw-buffer verification. No SHA256 pre-hash.
|
|
|
100
136
|
## Error Handling
|
|
101
137
|
|
|
102
138
|
```python
|
|
103
|
-
from agent_notary.exceptions import
|
|
139
|
+
from agent_notary.exceptions import (
|
|
140
|
+
NotaryAuthError, # 401 (authenticated CI surfaces; anonymous x402 gives 402 instead)
|
|
141
|
+
NotaryPaymentError, # 402 x402-challenge / 403
|
|
142
|
+
NotaryNotFoundError, # 404
|
|
143
|
+
NotaryValidationError, # 400/422 — invalid params, INVALID_AGENT_SIGNATURE
|
|
144
|
+
NotaryConflictError, # 409 — tx_hash/job_id already used (idempotency)
|
|
145
|
+
NotaryServerError, # 5xx, carries status_code
|
|
146
|
+
NotaryError, # base — safety net
|
|
147
|
+
)
|
|
104
148
|
|
|
105
149
|
try:
|
|
106
150
|
result = await client.notarize(req)
|
|
@@ -108,6 +152,12 @@ except NotaryAuthError:
|
|
|
108
152
|
print("Invalid API key")
|
|
109
153
|
except NotaryPaymentError as e:
|
|
110
154
|
print(f"Payment/sig failed: {e}")
|
|
155
|
+
except NotaryValidationError as e:
|
|
156
|
+
print(f"Bad request or invalid signature: {e}")
|
|
157
|
+
except NotaryConflictError:
|
|
158
|
+
print("This tx_hash/job_id was already used — generate a new one")
|
|
159
|
+
except NotaryError as e:
|
|
160
|
+
print(f"Other SDK error: {e}")
|
|
111
161
|
```
|
|
112
162
|
|
|
113
163
|
## Development
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# aotrust-protocol SDK
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: link.aotrust/notary -->
|
|
4
|
+
|
|
5
|
+
Asyncio-native Python SDK for the AOTrust Notary API — cryptographic proof-of-existence for AI agent outputs.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install aotrust-protocol
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
### Free tier — no API key, no wallet (fastest way to try)
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import asyncio, hashlib
|
|
19
|
+
from agent_notary import NotaryClient
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
# IMPORTANT: no /v1 suffix — the SDK appends API paths itself.
|
|
23
|
+
client = NotaryClient(base_url="https://api.aotrust.link")
|
|
24
|
+
|
|
25
|
+
work_hash = hashlib.sha256(b"my artifact text").hexdigest()
|
|
26
|
+
result = await client.shield_free(work_hash)
|
|
27
|
+
job_id = result["job_id"] # keep this UUID — it is the handle
|
|
28
|
+
print("job_id:", job_id)
|
|
29
|
+
|
|
30
|
+
# Check status BY job_id (not by the artifact text!)
|
|
31
|
+
status = await client.get_status(job_id)
|
|
32
|
+
print("status:", status.status) # PENDING → anchored (anchor batches)
|
|
33
|
+
|
|
34
|
+
# Fetch + verify the PDR
|
|
35
|
+
pdr = await client.get_pdr(job_id)
|
|
36
|
+
print("verify in browser:", pdr.verify_url)
|
|
37
|
+
assert (await client.verify_pdr(pdr.pdr_b64))["valid"]
|
|
38
|
+
|
|
39
|
+
asyncio.run(main())
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Free tier: 5 PDR / 24h per IP. Examples: [`examples/04_free_tier.py`](examples/04_free_tier.py).
|
|
43
|
+
|
|
44
|
+
### Witness mode (pre-paid tx_hash)
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import asyncio
|
|
48
|
+
from agent_notary import NotaryClient, NotarizeRequest
|
|
49
|
+
|
|
50
|
+
async def main():
|
|
51
|
+
client = NotaryClient(
|
|
52
|
+
api_key="your-api-key",
|
|
53
|
+
base_url="https://api.aotrust.link" # no /v1 suffix!
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Submit notarization
|
|
57
|
+
req = NotarizeRequest(
|
|
58
|
+
tx_hash="EzrfDW5b...",
|
|
59
|
+
work_hash="599d6999...",
|
|
60
|
+
agent_sig="base64_sig_A...",
|
|
61
|
+
agent_pubkey="aff91a18...",
|
|
62
|
+
)
|
|
63
|
+
result = await client.notarize(req)
|
|
64
|
+
print(f"Job: {result.job_id}")
|
|
65
|
+
|
|
66
|
+
# Poll for PDR — status/pdr calls always take the job_id returned above
|
|
67
|
+
status = await client.wait_for_pdr(result.job_id, timeout=60)
|
|
68
|
+
if status.is_anchored:
|
|
69
|
+
pdr = await client.get_pdr(result.job_id)
|
|
70
|
+
assert pdr.verify(client.notary_pubkey)
|
|
71
|
+
print("PDR Valid: YES")
|
|
72
|
+
|
|
73
|
+
asyncio.run(main())
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> **Why no `/v1`?** `base_url` must be `https://api.aotrust.link`. The SDK
|
|
77
|
+
> already builds `/v1/...` request paths; adding `/v1` yourself produces
|
|
78
|
+
> `/v1/v1/...` → HTTP 404 on every call. This bit a real user (2026-09-29:
|
|
79
|
+
> quickstart copy-paste + status lookups by artifact text instead of job_id).
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
| Env Var | Constructor Arg | Description |
|
|
84
|
+
|---------|-----------------|-------------|
|
|
85
|
+
| `NOTARY_API_KEY` | `api_key` | API key for auth |
|
|
86
|
+
| `NOTARY_API_URL` | `base_url` | API base URL |
|
|
87
|
+
| `NOTARY_PUBKEY` | `notary_pubkey` | Notary Ed25519 public key (hex) |
|
|
88
|
+
|
|
89
|
+
## Endpoints
|
|
90
|
+
|
|
91
|
+
| Method | Path | Description |
|
|
92
|
+
|--------|------|-------------|
|
|
93
|
+
| POST | `/v1/notarize` | Submit notarization |
|
|
94
|
+
| GET | `/v1/status/{job_id}` | Poll job status |
|
|
95
|
+
| GET | `/v1/pdr/{job_id}` | Get PDR |
|
|
96
|
+
| POST | `/v1/notarize/quote` | Get price quote |
|
|
97
|
+
| GET | `/.well-known/agent.json` | MCP Server Card |
|
|
98
|
+
| GET | `/openapi.json` | OpenAPI 3.0 spec |
|
|
99
|
+
|
|
100
|
+
## PDR Verification
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
pdr = await client.get_pdr(job_id)
|
|
104
|
+
is_valid = pdr.verify(notary_pubkey_hex="9c7d64bb...")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Uses NEP-413 raw-buffer verification. No SHA256 pre-hash.
|
|
108
|
+
|
|
109
|
+
## Error Handling
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from agent_notary.exceptions import (
|
|
113
|
+
NotaryAuthError, # 401 (authenticated CI surfaces; anonymous x402 gives 402 instead)
|
|
114
|
+
NotaryPaymentError, # 402 x402-challenge / 403
|
|
115
|
+
NotaryNotFoundError, # 404
|
|
116
|
+
NotaryValidationError, # 400/422 — invalid params, INVALID_AGENT_SIGNATURE
|
|
117
|
+
NotaryConflictError, # 409 — tx_hash/job_id already used (idempotency)
|
|
118
|
+
NotaryServerError, # 5xx, carries status_code
|
|
119
|
+
NotaryError, # base — safety net
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
result = await client.notarize(req)
|
|
124
|
+
except NotaryAuthError:
|
|
125
|
+
print("Invalid API key")
|
|
126
|
+
except NotaryPaymentError as e:
|
|
127
|
+
print(f"Payment/sig failed: {e}")
|
|
128
|
+
except NotaryValidationError as e:
|
|
129
|
+
print(f"Bad request or invalid signature: {e}")
|
|
130
|
+
except NotaryConflictError:
|
|
131
|
+
print("This tx_hash/job_id was already used — generate a new one")
|
|
132
|
+
except NotaryError as e:
|
|
133
|
+
print(f"Other SDK error: {e}")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install -e ".[dev]"
|
|
140
|
+
pytest tests/ -v
|
|
141
|
+
```
|
|
@@ -15,6 +15,8 @@ from .exceptions import (
|
|
|
15
15
|
NotaryNotFoundError,
|
|
16
16
|
NotaryPaymentError,
|
|
17
17
|
NotaryServerError,
|
|
18
|
+
NotaryValidationError,
|
|
19
|
+
NotaryConflictError,
|
|
18
20
|
)
|
|
19
21
|
|
|
20
22
|
DEFAULT_TIMEOUT = 30
|
|
@@ -119,6 +121,11 @@ class NotaryClient:
|
|
|
119
121
|
raise NotaryNotFoundError(body.get("error", "Not found"))
|
|
120
122
|
if status == 429:
|
|
121
123
|
raise NotaryError(body.get("error", body.get("message", "Rate limit reached")))
|
|
124
|
+
if status == 409:
|
|
125
|
+
raise NotaryConflictError(body.get("error", body.get("message", "Conflict")))
|
|
126
|
+
if status in (400, 422):
|
|
127
|
+
detail = body.get("message") or body.get("detail") or body.get("error") or f"Invalid request ({status})"
|
|
128
|
+
raise NotaryValidationError(f"{detail} (HTTP {status})")
|
|
122
129
|
if status >= 500:
|
|
123
130
|
raise NotaryServerError(body.get("error", f"Server error {status}"), status_code=status)
|
|
124
131
|
|
|
@@ -22,4 +22,12 @@ class NotaryServerError(NotaryError):
|
|
|
22
22
|
|
|
23
23
|
def __init__(self, message: str, status_code: int = 0):
|
|
24
24
|
super().__init__(message)
|
|
25
|
-
self.status_code = status_code
|
|
25
|
+
self.status_code = status_code
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NotaryValidationError(NotaryError):
|
|
29
|
+
"""400/422 — request payload rejected: invalid params or signature/content mismatch."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class NotaryConflictError(NotaryError):
|
|
33
|
+
"""409 — idempotency conflict: this tx_hash/job_id was already used."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aotrust-protocol
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.7
|
|
4
4
|
Summary: Asyncio-native SDK for A&O Trust Layer — Agent Notary Service
|
|
5
5
|
Author: A&O Trust Layer
|
|
6
6
|
License: MIT
|
|
@@ -39,6 +39,37 @@ pip install aotrust-protocol
|
|
|
39
39
|
|
|
40
40
|
## Quickstart
|
|
41
41
|
|
|
42
|
+
### Free tier — no API key, no wallet (fastest way to try)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import asyncio, hashlib
|
|
46
|
+
from agent_notary import NotaryClient
|
|
47
|
+
|
|
48
|
+
async def main():
|
|
49
|
+
# IMPORTANT: no /v1 suffix — the SDK appends API paths itself.
|
|
50
|
+
client = NotaryClient(base_url="https://api.aotrust.link")
|
|
51
|
+
|
|
52
|
+
work_hash = hashlib.sha256(b"my artifact text").hexdigest()
|
|
53
|
+
result = await client.shield_free(work_hash)
|
|
54
|
+
job_id = result["job_id"] # keep this UUID — it is the handle
|
|
55
|
+
print("job_id:", job_id)
|
|
56
|
+
|
|
57
|
+
# Check status BY job_id (not by the artifact text!)
|
|
58
|
+
status = await client.get_status(job_id)
|
|
59
|
+
print("status:", status.status) # PENDING → anchored (anchor batches)
|
|
60
|
+
|
|
61
|
+
# Fetch + verify the PDR
|
|
62
|
+
pdr = await client.get_pdr(job_id)
|
|
63
|
+
print("verify in browser:", pdr.verify_url)
|
|
64
|
+
assert (await client.verify_pdr(pdr.pdr_b64))["valid"]
|
|
65
|
+
|
|
66
|
+
asyncio.run(main())
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Free tier: 5 PDR / 24h per IP. Examples: [`examples/04_free_tier.py`](examples/04_free_tier.py).
|
|
70
|
+
|
|
71
|
+
### Witness mode (pre-paid tx_hash)
|
|
72
|
+
|
|
42
73
|
```python
|
|
43
74
|
import asyncio
|
|
44
75
|
from agent_notary import NotaryClient, NotarizeRequest
|
|
@@ -46,7 +77,7 @@ from agent_notary import NotaryClient, NotarizeRequest
|
|
|
46
77
|
async def main():
|
|
47
78
|
client = NotaryClient(
|
|
48
79
|
api_key="your-api-key",
|
|
49
|
-
base_url="https://api.aotrust.link/v1
|
|
80
|
+
base_url="https://api.aotrust.link" # no /v1 suffix!
|
|
50
81
|
)
|
|
51
82
|
|
|
52
83
|
# Submit notarization
|
|
@@ -59,7 +90,7 @@ async def main():
|
|
|
59
90
|
result = await client.notarize(req)
|
|
60
91
|
print(f"Job: {result.job_id}")
|
|
61
92
|
|
|
62
|
-
# Poll for PDR
|
|
93
|
+
# Poll for PDR — status/pdr calls always take the job_id returned above
|
|
63
94
|
status = await client.wait_for_pdr(result.job_id, timeout=60)
|
|
64
95
|
if status.is_anchored:
|
|
65
96
|
pdr = await client.get_pdr(result.job_id)
|
|
@@ -69,6 +100,11 @@ async def main():
|
|
|
69
100
|
asyncio.run(main())
|
|
70
101
|
```
|
|
71
102
|
|
|
103
|
+
> **Why no `/v1`?** `base_url` must be `https://api.aotrust.link`. The SDK
|
|
104
|
+
> already builds `/v1/...` request paths; adding `/v1` yourself produces
|
|
105
|
+
> `/v1/v1/...` → HTTP 404 on every call. This bit a real user (2026-09-29:
|
|
106
|
+
> quickstart copy-paste + status lookups by artifact text instead of job_id).
|
|
107
|
+
|
|
72
108
|
## Configuration
|
|
73
109
|
|
|
74
110
|
| Env Var | Constructor Arg | Description |
|
|
@@ -100,7 +136,15 @@ Uses NEP-413 raw-buffer verification. No SHA256 pre-hash.
|
|
|
100
136
|
## Error Handling
|
|
101
137
|
|
|
102
138
|
```python
|
|
103
|
-
from agent_notary.exceptions import
|
|
139
|
+
from agent_notary.exceptions import (
|
|
140
|
+
NotaryAuthError, # 401 (authenticated CI surfaces; anonymous x402 gives 402 instead)
|
|
141
|
+
NotaryPaymentError, # 402 x402-challenge / 403
|
|
142
|
+
NotaryNotFoundError, # 404
|
|
143
|
+
NotaryValidationError, # 400/422 — invalid params, INVALID_AGENT_SIGNATURE
|
|
144
|
+
NotaryConflictError, # 409 — tx_hash/job_id already used (idempotency)
|
|
145
|
+
NotaryServerError, # 5xx, carries status_code
|
|
146
|
+
NotaryError, # base — safety net
|
|
147
|
+
)
|
|
104
148
|
|
|
105
149
|
try:
|
|
106
150
|
result = await client.notarize(req)
|
|
@@ -108,6 +152,12 @@ except NotaryAuthError:
|
|
|
108
152
|
print("Invalid API key")
|
|
109
153
|
except NotaryPaymentError as e:
|
|
110
154
|
print(f"Payment/sig failed: {e}")
|
|
155
|
+
except NotaryValidationError as e:
|
|
156
|
+
print(f"Bad request or invalid signature: {e}")
|
|
157
|
+
except NotaryConflictError:
|
|
158
|
+
print("This tx_hash/job_id was already used — generate a new one")
|
|
159
|
+
except NotaryError as e:
|
|
160
|
+
print(f"Other SDK error: {e}")
|
|
111
161
|
```
|
|
112
162
|
|
|
113
163
|
## Development
|
aotrust_protocol-2.3.6/README.md
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# aotrust-protocol SDK
|
|
2
|
-
|
|
3
|
-
<!-- mcp-name: link.aotrust/notary -->
|
|
4
|
-
|
|
5
|
-
Asyncio-native Python SDK for the AOTrust Notary API — cryptographic proof-of-existence for AI agent outputs.
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pip install aotrust-protocol
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Quickstart
|
|
14
|
-
|
|
15
|
-
```python
|
|
16
|
-
import asyncio
|
|
17
|
-
from agent_notary import NotaryClient, NotarizeRequest
|
|
18
|
-
|
|
19
|
-
async def main():
|
|
20
|
-
client = NotaryClient(
|
|
21
|
-
api_key="your-api-key",
|
|
22
|
-
base_url="https://api.aotrust.link/v1"
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
# Submit notarization
|
|
26
|
-
req = NotarizeRequest(
|
|
27
|
-
tx_hash="EzrfDW5b...",
|
|
28
|
-
work_hash="599d6999...",
|
|
29
|
-
agent_sig="base64_sig_A...",
|
|
30
|
-
agent_pubkey="aff91a18...",
|
|
31
|
-
)
|
|
32
|
-
result = await client.notarize(req)
|
|
33
|
-
print(f"Job: {result.job_id}")
|
|
34
|
-
|
|
35
|
-
# Poll for PDR
|
|
36
|
-
status = await client.wait_for_pdr(result.job_id, timeout=60)
|
|
37
|
-
if status.is_anchored:
|
|
38
|
-
pdr = await client.get_pdr(result.job_id)
|
|
39
|
-
assert pdr.verify(client.notary_pubkey)
|
|
40
|
-
print("PDR Valid: YES")
|
|
41
|
-
|
|
42
|
-
asyncio.run(main())
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Configuration
|
|
46
|
-
|
|
47
|
-
| Env Var | Constructor Arg | Description |
|
|
48
|
-
|---------|-----------------|-------------|
|
|
49
|
-
| `NOTARY_API_KEY` | `api_key` | API key for auth |
|
|
50
|
-
| `NOTARY_API_URL` | `base_url` | API base URL |
|
|
51
|
-
| `NOTARY_PUBKEY` | `notary_pubkey` | Notary Ed25519 public key (hex) |
|
|
52
|
-
|
|
53
|
-
## Endpoints
|
|
54
|
-
|
|
55
|
-
| Method | Path | Description |
|
|
56
|
-
|--------|------|-------------|
|
|
57
|
-
| POST | `/v1/notarize` | Submit notarization |
|
|
58
|
-
| GET | `/v1/status/{job_id}` | Poll job status |
|
|
59
|
-
| GET | `/v1/pdr/{job_id}` | Get PDR |
|
|
60
|
-
| POST | `/v1/notarize/quote` | Get price quote |
|
|
61
|
-
| GET | `/.well-known/agent.json` | MCP Server Card |
|
|
62
|
-
| GET | `/openapi.json` | OpenAPI 3.0 spec |
|
|
63
|
-
|
|
64
|
-
## PDR Verification
|
|
65
|
-
|
|
66
|
-
```python
|
|
67
|
-
pdr = await client.get_pdr(job_id)
|
|
68
|
-
is_valid = pdr.verify(notary_pubkey_hex="9c7d64bb...")
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Uses NEP-413 raw-buffer verification. No SHA256 pre-hash.
|
|
72
|
-
|
|
73
|
-
## Error Handling
|
|
74
|
-
|
|
75
|
-
```python
|
|
76
|
-
from agent_notary.exceptions import NotaryAuthError, NotaryPaymentError, NotaryNotFoundError
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
result = await client.notarize(req)
|
|
80
|
-
except NotaryAuthError:
|
|
81
|
-
print("Invalid API key")
|
|
82
|
-
except NotaryPaymentError as e:
|
|
83
|
-
print(f"Payment/sig failed: {e}")
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Development
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
pip install -e ".[dev]"
|
|
90
|
-
pytest tests/ -v
|
|
91
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aotrust_protocol-2.3.6 → aotrust_protocol-2.3.7}/aotrust_protocol.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|