agentic-settle 0.2.0__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.
- agentic_settle-0.2.0/LICENSE +17 -0
- agentic_settle-0.2.0/PKG-INFO +99 -0
- agentic_settle-0.2.0/README.md +74 -0
- agentic_settle-0.2.0/__init__.py +65 -0
- agentic_settle-0.2.0/agentic_settle.egg-info/PKG-INFO +99 -0
- agentic_settle-0.2.0/agentic_settle.egg-info/SOURCES.txt +16 -0
- agentic_settle-0.2.0/agentic_settle.egg-info/dependency_links.txt +1 -0
- agentic_settle-0.2.0/agentic_settle.egg-info/requires.txt +2 -0
- agentic_settle-0.2.0/agentic_settle.egg-info/top_level.txt +1 -0
- agentic_settle-0.2.0/client.py +434 -0
- agentic_settle-0.2.0/py.typed +0 -0
- agentic_settle-0.2.0/pyproject.toml +55 -0
- agentic_settle-0.2.0/setup.cfg +4 -0
- agentic_settle-0.2.0/types.py +98 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 AgenticSettle.IO
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-settle
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK for AgenticSettle — verify any AI agent's output, settle with pre-paid token escrow, earn the Verified badge.
|
|
5
|
+
Author-email: "AgenticSettle.IO" <engineering@agenticsettle.io>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/agenticsettleio/agentic-settle-core
|
|
8
|
+
Project-URL: Issues, https://github.com/agenticsettleio/agentic-settle-core/issues
|
|
9
|
+
Keywords: agentic,settlement,web3,kms,fastapi,sdk
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# agentic-settle
|
|
27
|
+
|
|
28
|
+
Python client SDK for the **AgenticSettle Pro** settlement engine.
|
|
29
|
+
|
|
30
|
+
A deliberately thin wrapper over the REST API so AI-native applications can
|
|
31
|
+
spend less than 30 seconds wiring up on-chain settlement for their agents.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install agentic-settle
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quickstart (synchronous)
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import os
|
|
41
|
+
from agentic_settle import SettleClient
|
|
42
|
+
|
|
43
|
+
client = SettleClient(
|
|
44
|
+
base_url="https://api.agenticsettle.io",
|
|
45
|
+
api_key=os.environ["AGENTIC_SETTLE_API_KEY"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
receipt = client.settle(
|
|
49
|
+
agent_id="gpt-4o",
|
|
50
|
+
request_content="What is the capital of France?",
|
|
51
|
+
result_content="Paris",
|
|
52
|
+
target_wallet="0x0000000000000000000000000000000000000000",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
print(receipt.status, receipt.chain_tx_hash)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quickstart (asyncio)
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import asyncio
|
|
62
|
+
from agentic_settle import AsyncSettleClient
|
|
63
|
+
|
|
64
|
+
async def main() -> None:
|
|
65
|
+
client = AsyncSettleClient(api_key="...")
|
|
66
|
+
receipt = await client.settle(
|
|
67
|
+
agent_id="claude-3.5",
|
|
68
|
+
request_content="...",
|
|
69
|
+
result_content="...",
|
|
70
|
+
target_wallet="0x...",
|
|
71
|
+
)
|
|
72
|
+
print(receipt)
|
|
73
|
+
|
|
74
|
+
asyncio.run(main())
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Environment variables
|
|
78
|
+
|
|
79
|
+
The client falls back to the following env vars when constructor arguments
|
|
80
|
+
are omitted:
|
|
81
|
+
|
|
82
|
+
| Variable | Purpose |
|
|
83
|
+
|-----------------------------|------------------------------------------|
|
|
84
|
+
| `AGENTIC_SETTLE_BASE_URL` | Base URL of the settlement service |
|
|
85
|
+
| `AGENTIC_SETTLE_API_KEY` | API key (preferred) |
|
|
86
|
+
| `BRUCE_SECRET_KEY` | Legacy fallback for local dev convenience |
|
|
87
|
+
|
|
88
|
+
## What's in the box
|
|
89
|
+
|
|
90
|
+
- `SettleClient` — synchronous client (httpx under the hood)
|
|
91
|
+
- `AsyncSettleClient` — asyncio variant for high-throughput agents
|
|
92
|
+
- `SettleRequest` — request payload model (pydantic v2)
|
|
93
|
+
- `SettleReceipt` — response receipt model (pydantic v2)
|
|
94
|
+
|
|
95
|
+
Type annotations ship with `py.typed`.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
Apache-2.0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# agentic-settle
|
|
2
|
+
|
|
3
|
+
Python client SDK for the **AgenticSettle Pro** settlement engine.
|
|
4
|
+
|
|
5
|
+
A deliberately thin wrapper over the REST API so AI-native applications can
|
|
6
|
+
spend less than 30 seconds wiring up on-chain settlement for their agents.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install agentic-settle
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quickstart (synchronous)
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import os
|
|
16
|
+
from agentic_settle import SettleClient
|
|
17
|
+
|
|
18
|
+
client = SettleClient(
|
|
19
|
+
base_url="https://api.agenticsettle.io",
|
|
20
|
+
api_key=os.environ["AGENTIC_SETTLE_API_KEY"],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
receipt = client.settle(
|
|
24
|
+
agent_id="gpt-4o",
|
|
25
|
+
request_content="What is the capital of France?",
|
|
26
|
+
result_content="Paris",
|
|
27
|
+
target_wallet="0x0000000000000000000000000000000000000000",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
print(receipt.status, receipt.chain_tx_hash)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quickstart (asyncio)
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import asyncio
|
|
37
|
+
from agentic_settle import AsyncSettleClient
|
|
38
|
+
|
|
39
|
+
async def main() -> None:
|
|
40
|
+
client = AsyncSettleClient(api_key="...")
|
|
41
|
+
receipt = await client.settle(
|
|
42
|
+
agent_id="claude-3.5",
|
|
43
|
+
request_content="...",
|
|
44
|
+
result_content="...",
|
|
45
|
+
target_wallet="0x...",
|
|
46
|
+
)
|
|
47
|
+
print(receipt)
|
|
48
|
+
|
|
49
|
+
asyncio.run(main())
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Environment variables
|
|
53
|
+
|
|
54
|
+
The client falls back to the following env vars when constructor arguments
|
|
55
|
+
are omitted:
|
|
56
|
+
|
|
57
|
+
| Variable | Purpose |
|
|
58
|
+
|-----------------------------|------------------------------------------|
|
|
59
|
+
| `AGENTIC_SETTLE_BASE_URL` | Base URL of the settlement service |
|
|
60
|
+
| `AGENTIC_SETTLE_API_KEY` | API key (preferred) |
|
|
61
|
+
| `BRUCE_SECRET_KEY` | Legacy fallback for local dev convenience |
|
|
62
|
+
|
|
63
|
+
## What's in the box
|
|
64
|
+
|
|
65
|
+
- `SettleClient` — synchronous client (httpx under the hood)
|
|
66
|
+
- `AsyncSettleClient` — asyncio variant for high-throughput agents
|
|
67
|
+
- `SettleRequest` — request payload model (pydantic v2)
|
|
68
|
+
- `SettleReceipt` — response receipt model (pydantic v2)
|
|
69
|
+
|
|
70
|
+
Type annotations ship with `py.typed`.
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
Apache-2.0
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AgenticSettle SDK
|
|
3
|
+
=================
|
|
4
|
+
|
|
5
|
+
A thin client for the AgenticSettle Pro settlement engine.
|
|
6
|
+
|
|
7
|
+
V1 quickstart (legacy sync settlement)::
|
|
8
|
+
|
|
9
|
+
from agentic_settle import SettleClient
|
|
10
|
+
|
|
11
|
+
client = SettleClient(
|
|
12
|
+
base_url="https://api.agenticsettle.io",
|
|
13
|
+
api_key="...",
|
|
14
|
+
)
|
|
15
|
+
receipt = client.settle(
|
|
16
|
+
agent_id="gpt-4o",
|
|
17
|
+
request_content="prompt...",
|
|
18
|
+
result_content="answer...",
|
|
19
|
+
target_wallet="0x...",
|
|
20
|
+
)
|
|
21
|
+
print(receipt.status, receipt.chain_tx_hash)
|
|
22
|
+
|
|
23
|
+
V2 quickstart (prepaid-token + verification-gated)::
|
|
24
|
+
|
|
25
|
+
client.register_agent("acme-ai")
|
|
26
|
+
client.register_token("ACME-CREDIT", "acme-ai")
|
|
27
|
+
client.purchase_tokens(customer_id="cust_42", token_id="ACME-CREDIT", amount=1000)
|
|
28
|
+
|
|
29
|
+
task = client.create_task(
|
|
30
|
+
customer_id="cust_42", agent_id="acme-ai", token_id="ACME-CREDIT",
|
|
31
|
+
escrow_amount=100, request_content="Summarize this 80-page PDF",
|
|
32
|
+
)
|
|
33
|
+
delivered = client.deliver(task.task_id, result_content=agent_result)
|
|
34
|
+
if delivered.verdict["verdict"] == "PASS":
|
|
35
|
+
client.decide(task.task_id, "SATISFIED")
|
|
36
|
+
else:
|
|
37
|
+
client.decide(task.task_id, "UNSATISFIED", reason="섹션 2 누락")
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from .client import AsyncSettleClient, SettleClient
|
|
41
|
+
from .types import (
|
|
42
|
+
DecisionResult,
|
|
43
|
+
DeliveryResult,
|
|
44
|
+
SettleReceipt,
|
|
45
|
+
SettleRequest,
|
|
46
|
+
TaskOrder,
|
|
47
|
+
TokenBalance,
|
|
48
|
+
VerificationReport,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
# V1
|
|
53
|
+
"SettleClient",
|
|
54
|
+
"AsyncSettleClient",
|
|
55
|
+
"SettleRequest",
|
|
56
|
+
"SettleReceipt",
|
|
57
|
+
# V2
|
|
58
|
+
"TokenBalance",
|
|
59
|
+
"TaskOrder",
|
|
60
|
+
"VerificationReport",
|
|
61
|
+
"DeliveryResult",
|
|
62
|
+
"DecisionResult",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-settle
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK for AgenticSettle — verify any AI agent's output, settle with pre-paid token escrow, earn the Verified badge.
|
|
5
|
+
Author-email: "AgenticSettle.IO" <engineering@agenticsettle.io>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/agenticsettleio/agentic-settle-core
|
|
8
|
+
Project-URL: Issues, https://github.com/agenticsettleio/agentic-settle-core/issues
|
|
9
|
+
Keywords: agentic,settlement,web3,kms,fastapi,sdk
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# agentic-settle
|
|
27
|
+
|
|
28
|
+
Python client SDK for the **AgenticSettle Pro** settlement engine.
|
|
29
|
+
|
|
30
|
+
A deliberately thin wrapper over the REST API so AI-native applications can
|
|
31
|
+
spend less than 30 seconds wiring up on-chain settlement for their agents.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install agentic-settle
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quickstart (synchronous)
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import os
|
|
41
|
+
from agentic_settle import SettleClient
|
|
42
|
+
|
|
43
|
+
client = SettleClient(
|
|
44
|
+
base_url="https://api.agenticsettle.io",
|
|
45
|
+
api_key=os.environ["AGENTIC_SETTLE_API_KEY"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
receipt = client.settle(
|
|
49
|
+
agent_id="gpt-4o",
|
|
50
|
+
request_content="What is the capital of France?",
|
|
51
|
+
result_content="Paris",
|
|
52
|
+
target_wallet="0x0000000000000000000000000000000000000000",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
print(receipt.status, receipt.chain_tx_hash)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quickstart (asyncio)
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import asyncio
|
|
62
|
+
from agentic_settle import AsyncSettleClient
|
|
63
|
+
|
|
64
|
+
async def main() -> None:
|
|
65
|
+
client = AsyncSettleClient(api_key="...")
|
|
66
|
+
receipt = await client.settle(
|
|
67
|
+
agent_id="claude-3.5",
|
|
68
|
+
request_content="...",
|
|
69
|
+
result_content="...",
|
|
70
|
+
target_wallet="0x...",
|
|
71
|
+
)
|
|
72
|
+
print(receipt)
|
|
73
|
+
|
|
74
|
+
asyncio.run(main())
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Environment variables
|
|
78
|
+
|
|
79
|
+
The client falls back to the following env vars when constructor arguments
|
|
80
|
+
are omitted:
|
|
81
|
+
|
|
82
|
+
| Variable | Purpose |
|
|
83
|
+
|-----------------------------|------------------------------------------|
|
|
84
|
+
| `AGENTIC_SETTLE_BASE_URL` | Base URL of the settlement service |
|
|
85
|
+
| `AGENTIC_SETTLE_API_KEY` | API key (preferred) |
|
|
86
|
+
| `BRUCE_SECRET_KEY` | Legacy fallback for local dev convenience |
|
|
87
|
+
|
|
88
|
+
## What's in the box
|
|
89
|
+
|
|
90
|
+
- `SettleClient` — synchronous client (httpx under the hood)
|
|
91
|
+
- `AsyncSettleClient` — asyncio variant for high-throughput agents
|
|
92
|
+
- `SettleRequest` — request payload model (pydantic v2)
|
|
93
|
+
- `SettleReceipt` — response receipt model (pydantic v2)
|
|
94
|
+
|
|
95
|
+
Type annotations ship with `py.typed`.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
Apache-2.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
__init__.py
|
|
4
|
+
client.py
|
|
5
|
+
py.typed
|
|
6
|
+
pyproject.toml
|
|
7
|
+
types.py
|
|
8
|
+
./__init__.py
|
|
9
|
+
./client.py
|
|
10
|
+
./py.typed
|
|
11
|
+
./types.py
|
|
12
|
+
agentic_settle.egg-info/PKG-INFO
|
|
13
|
+
agentic_settle.egg-info/SOURCES.txt
|
|
14
|
+
agentic_settle.egg-info/dependency_links.txt
|
|
15
|
+
agentic_settle.egg-info/requires.txt
|
|
16
|
+
agentic_settle.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agentic_settle
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTTP clients for the AgenticSettle settlement engine.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
- ``SettleClient`` — synchronous (requests-free; uses ``httpx``)
|
|
6
|
+
- ``AsyncSettleClient`` — asyncio-friendly variant for high-throughput agents
|
|
7
|
+
|
|
8
|
+
Both share identical surface area; pick whichever fits your runtime.
|
|
9
|
+
|
|
10
|
+
V1 helpers (`settle`, `get_status`, `dashboard_metrics`) are unchanged.
|
|
11
|
+
V2 helpers cover the new prepaid-token + verification-gated flow.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import uuid
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
import httpx
|
|
21
|
+
|
|
22
|
+
from .types import (
|
|
23
|
+
DecisionResult,
|
|
24
|
+
DeliveryResult,
|
|
25
|
+
SettleReceipt,
|
|
26
|
+
SettleRequest,
|
|
27
|
+
TaskOrder,
|
|
28
|
+
TokenBalance,
|
|
29
|
+
VerificationReport,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
_DEFAULT_TIMEOUT = 30.0
|
|
33
|
+
_SDK_VERSION = "0.2.0"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _gen_request_id() -> str:
|
|
37
|
+
return f"REQ-{uuid.uuid4().hex[:12].upper()}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _gen_task_id() -> str:
|
|
41
|
+
return f"TSK-{uuid.uuid4().hex[:12].upper()}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _headers(api_key: str) -> dict[str, str]:
|
|
45
|
+
return {
|
|
46
|
+
"x-api-key": api_key,
|
|
47
|
+
"content-type": "application/json",
|
|
48
|
+
"user-agent": f"agentic-settle-sdk/{_SDK_VERSION}",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class _Base:
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
base_url: str | None = None,
|
|
56
|
+
api_key: str | None = None,
|
|
57
|
+
timeout: float = _DEFAULT_TIMEOUT,
|
|
58
|
+
) -> None:
|
|
59
|
+
self.base_url = (
|
|
60
|
+
base_url or os.getenv("AGENTIC_SETTLE_BASE_URL", "http://localhost:8000")
|
|
61
|
+
).rstrip("/")
|
|
62
|
+
self.api_key = (
|
|
63
|
+
api_key
|
|
64
|
+
or os.getenv("AGENTIC_SETTLE_API_KEY")
|
|
65
|
+
or os.getenv("BRUCE_SECRET_KEY")
|
|
66
|
+
)
|
|
67
|
+
if not self.api_key:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
"AgenticSettle SDK: no API key. "
|
|
70
|
+
"Pass api_key=... or set AGENTIC_SETTLE_API_KEY in the environment."
|
|
71
|
+
)
|
|
72
|
+
self.timeout = timeout
|
|
73
|
+
|
|
74
|
+
def _build_payload(
|
|
75
|
+
self,
|
|
76
|
+
*,
|
|
77
|
+
agent_id: str,
|
|
78
|
+
request_content: str,
|
|
79
|
+
result_content: str,
|
|
80
|
+
target_wallet: str,
|
|
81
|
+
request_id: str | None,
|
|
82
|
+
) -> dict[str, Any]:
|
|
83
|
+
req = SettleRequest(
|
|
84
|
+
request_id=request_id or _gen_request_id(),
|
|
85
|
+
agent_id=agent_id,
|
|
86
|
+
request_content=request_content,
|
|
87
|
+
result_content=result_content,
|
|
88
|
+
target_wallet=target_wallet,
|
|
89
|
+
)
|
|
90
|
+
return req.model_dump()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
94
|
+
# Sync client
|
|
95
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
96
|
+
class SettleClient(_Base):
|
|
97
|
+
"""Synchronous client (V1 + V2)."""
|
|
98
|
+
|
|
99
|
+
# ── V1 (unchanged) ──────────────────────────────────────────────
|
|
100
|
+
def settle(
|
|
101
|
+
self,
|
|
102
|
+
*,
|
|
103
|
+
agent_id: str,
|
|
104
|
+
request_content: str,
|
|
105
|
+
result_content: str,
|
|
106
|
+
target_wallet: str,
|
|
107
|
+
request_id: str | None = None,
|
|
108
|
+
) -> SettleReceipt:
|
|
109
|
+
payload = self._build_payload(
|
|
110
|
+
agent_id=agent_id,
|
|
111
|
+
request_content=request_content,
|
|
112
|
+
result_content=result_content,
|
|
113
|
+
target_wallet=target_wallet,
|
|
114
|
+
request_id=request_id,
|
|
115
|
+
)
|
|
116
|
+
with httpx.Client(timeout=self.timeout) as c:
|
|
117
|
+
r = c.post(f"{self.base_url}/v1/settle", json=payload, headers=_headers(self.api_key))
|
|
118
|
+
r.raise_for_status()
|
|
119
|
+
return SettleReceipt.model_validate(r.json())
|
|
120
|
+
|
|
121
|
+
def get_status(self, request_id: str) -> SettleReceipt:
|
|
122
|
+
with httpx.Client(timeout=self.timeout) as c:
|
|
123
|
+
r = c.get(
|
|
124
|
+
f"{self.base_url}/v1/settle/status/{request_id}",
|
|
125
|
+
headers=_headers(self.api_key),
|
|
126
|
+
)
|
|
127
|
+
r.raise_for_status()
|
|
128
|
+
return SettleReceipt.model_validate(r.json())
|
|
129
|
+
|
|
130
|
+
def dashboard_metrics(self) -> dict[str, Any]:
|
|
131
|
+
with httpx.Client(timeout=self.timeout) as c:
|
|
132
|
+
r = c.get(
|
|
133
|
+
f"{self.base_url}/v1/settle/dashboard-metrics",
|
|
134
|
+
headers=_headers(self.api_key),
|
|
135
|
+
)
|
|
136
|
+
r.raise_for_status()
|
|
137
|
+
return r.json()
|
|
138
|
+
|
|
139
|
+
# ── V2: prepaid-token + verification-gated flow ────────────────
|
|
140
|
+
def register_agent(
|
|
141
|
+
self, agent_id: str, *, company_name: str | None = None,
|
|
142
|
+
payout_wallet: str | None = None,
|
|
143
|
+
) -> dict[str, Any]:
|
|
144
|
+
return self._post("/v2/agents/register", {
|
|
145
|
+
"agent_id": agent_id,
|
|
146
|
+
"company_name": company_name,
|
|
147
|
+
"payout_wallet": payout_wallet,
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
def register_token(
|
|
151
|
+
self, token_id: str, agent_id: str, *, symbol: str | None = None,
|
|
152
|
+
decimals: int = 0, unit_price_wei: str | None = None,
|
|
153
|
+
erc20_address: str | None = None,
|
|
154
|
+
) -> dict[str, Any]:
|
|
155
|
+
return self._post("/v2/tokens/register", {
|
|
156
|
+
"token_id": token_id,
|
|
157
|
+
"agent_id": agent_id,
|
|
158
|
+
"symbol": symbol,
|
|
159
|
+
"decimals": decimals,
|
|
160
|
+
"unit_price_wei": unit_price_wei,
|
|
161
|
+
"erc20_address": erc20_address,
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
def purchase_tokens(
|
|
165
|
+
self, *, customer_id: str, token_id: str, amount: int,
|
|
166
|
+
paid_wei: str | None = None, paid_method: str = "OFFCHAIN",
|
|
167
|
+
tx_ref: str | None = None,
|
|
168
|
+
) -> dict[str, Any]:
|
|
169
|
+
return self._post("/v2/tokens/purchase", {
|
|
170
|
+
"customer_id": customer_id,
|
|
171
|
+
"token_id": token_id,
|
|
172
|
+
"amount": amount,
|
|
173
|
+
"paid_wei": paid_wei,
|
|
174
|
+
"paid_method": paid_method,
|
|
175
|
+
"tx_ref": tx_ref,
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
def get_balance(self, customer_id: str, token_id: str) -> TokenBalance:
|
|
179
|
+
return TokenBalance.model_validate(self._get(
|
|
180
|
+
"/v2/tokens/balance",
|
|
181
|
+
params={"customer_id": customer_id, "token_id": token_id},
|
|
182
|
+
))
|
|
183
|
+
|
|
184
|
+
def create_task(
|
|
185
|
+
self, *, customer_id: str, agent_id: str, token_id: str,
|
|
186
|
+
escrow_amount: int, request_content: str,
|
|
187
|
+
task_id: str | None = None, max_rework: int | None = None,
|
|
188
|
+
) -> TaskOrder:
|
|
189
|
+
body = {
|
|
190
|
+
"task_id": task_id or _gen_task_id(),
|
|
191
|
+
"customer_id": customer_id,
|
|
192
|
+
"agent_id": agent_id,
|
|
193
|
+
"token_id": token_id,
|
|
194
|
+
"escrow_amount": escrow_amount,
|
|
195
|
+
"request_content": request_content,
|
|
196
|
+
"max_rework": max_rework,
|
|
197
|
+
}
|
|
198
|
+
return TaskOrder.model_validate(self._post("/v2/tasks", body))
|
|
199
|
+
|
|
200
|
+
def deliver(
|
|
201
|
+
self, task_id: str, *, result_content: str,
|
|
202
|
+
result_uri: str | None = None,
|
|
203
|
+
) -> DeliveryResult:
|
|
204
|
+
return DeliveryResult.model_validate(self._post(
|
|
205
|
+
f"/v2/tasks/{task_id}/deliver",
|
|
206
|
+
{"result_content": result_content, "result_uri": result_uri},
|
|
207
|
+
))
|
|
208
|
+
|
|
209
|
+
def decide(
|
|
210
|
+
self, task_id: str, decision: str, *, reason: str | None = None,
|
|
211
|
+
) -> DecisionResult:
|
|
212
|
+
return DecisionResult.model_validate(self._post(
|
|
213
|
+
f"/v2/tasks/{task_id}/decide",
|
|
214
|
+
{"decision": decision, "reason": reason},
|
|
215
|
+
))
|
|
216
|
+
|
|
217
|
+
def dispute(self, task_id: str, *, reason: str | None = None) -> TaskOrder:
|
|
218
|
+
return TaskOrder.model_validate(self._post(
|
|
219
|
+
f"/v2/tasks/{task_id}/dispute", {"reason": reason}
|
|
220
|
+
))
|
|
221
|
+
|
|
222
|
+
def get_task(self, task_id: str) -> TaskOrder:
|
|
223
|
+
return TaskOrder.model_validate(self._get(f"/v2/tasks/{task_id}"))
|
|
224
|
+
|
|
225
|
+
def get_reports(self, task_id: str) -> list[VerificationReport]:
|
|
226
|
+
raw = self._get(f"/v2/tasks/{task_id}/report")
|
|
227
|
+
return [VerificationReport.model_validate(r) for r in raw.get("reports", [])]
|
|
228
|
+
|
|
229
|
+
def v2_metrics(self) -> dict[str, Any]:
|
|
230
|
+
return self._get("/v2/metrics")
|
|
231
|
+
|
|
232
|
+
# ── V2 verify-only (field-test, PIVOT_V2.md §14) ─────────────────
|
|
233
|
+
def verify(
|
|
234
|
+
self,
|
|
235
|
+
*,
|
|
236
|
+
request_content: str,
|
|
237
|
+
result_content: str,
|
|
238
|
+
agent_id: str | None = None,
|
|
239
|
+
customer_label: str | None = None,
|
|
240
|
+
title: str | None = None,
|
|
241
|
+
sla: dict | None = None,
|
|
242
|
+
work_seconds: int | None = None,
|
|
243
|
+
sla_seconds: int | None = None,
|
|
244
|
+
audience: str = "customer",
|
|
245
|
+
verification_id: str | None = None,
|
|
246
|
+
) -> dict[str, Any]:
|
|
247
|
+
"""One-shot quality verification with no escrow / settlement."""
|
|
248
|
+
return self._post("/v2/verify", {
|
|
249
|
+
"verification_id": verification_id,
|
|
250
|
+
"agent_id": agent_id,
|
|
251
|
+
"customer_label": customer_label,
|
|
252
|
+
"title": title,
|
|
253
|
+
"request_content": request_content,
|
|
254
|
+
"result_content": result_content,
|
|
255
|
+
"sla": sla,
|
|
256
|
+
"work_seconds": work_seconds,
|
|
257
|
+
"sla_seconds": sla_seconds,
|
|
258
|
+
"audience": audience,
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
def get_verification(
|
|
262
|
+
self, verification_id: str, *, audience: str = "customer"
|
|
263
|
+
) -> dict[str, Any]:
|
|
264
|
+
return self._get(
|
|
265
|
+
f"/v2/verifications/{verification_id}",
|
|
266
|
+
params={"audience": audience},
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def agent_performance(self, agent_id: str) -> dict[str, Any]:
|
|
270
|
+
return self._get(f"/v2/agents/{agent_id}/performance")
|
|
271
|
+
|
|
272
|
+
# ── V2.1.C — Agent credits (AC) ──────────────────────────────────
|
|
273
|
+
def agent_credits(self, agent_id: str) -> dict[str, Any]:
|
|
274
|
+
"""Read the agent's accrued AgentCredit balance."""
|
|
275
|
+
return self._get(f"/v2/agents/{agent_id}/credits")
|
|
276
|
+
|
|
277
|
+
def convert_agent_credits(
|
|
278
|
+
self, agent_id: str, *, amount_ac: int, ref: str | None = None,
|
|
279
|
+
) -> dict[str, Any]:
|
|
280
|
+
"""Burn ``amount_ac`` AC → record VOP-conversion event."""
|
|
281
|
+
return self._post(
|
|
282
|
+
f"/v2/agents/{agent_id}/credits/convert",
|
|
283
|
+
{"amount_ac": amount_ac, "ref": ref},
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ── Tiny transport helpers ─────────────────────────────────────
|
|
289
|
+
def _post(self, path: str, body: dict[str, Any]) -> dict[str, Any]:
|
|
290
|
+
with httpx.Client(timeout=self.timeout) as c:
|
|
291
|
+
r = c.post(f"{self.base_url}{path}", json=body, headers=_headers(self.api_key))
|
|
292
|
+
r.raise_for_status()
|
|
293
|
+
return r.json()
|
|
294
|
+
|
|
295
|
+
def _get(
|
|
296
|
+
self, path: str, *, params: dict[str, Any] | None = None,
|
|
297
|
+
) -> dict[str, Any]:
|
|
298
|
+
with httpx.Client(timeout=self.timeout) as c:
|
|
299
|
+
r = c.get(
|
|
300
|
+
f"{self.base_url}{path}", params=params,
|
|
301
|
+
headers=_headers(self.api_key),
|
|
302
|
+
)
|
|
303
|
+
r.raise_for_status()
|
|
304
|
+
return r.json()
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
308
|
+
# Async client
|
|
309
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
310
|
+
class AsyncSettleClient(_Base):
|
|
311
|
+
"""Asyncio variant — recommended for high-throughput agent runtimes."""
|
|
312
|
+
|
|
313
|
+
# ── V1 (unchanged) ─────────────────────────────────────────────
|
|
314
|
+
async def settle(
|
|
315
|
+
self,
|
|
316
|
+
*,
|
|
317
|
+
agent_id: str,
|
|
318
|
+
request_content: str,
|
|
319
|
+
result_content: str,
|
|
320
|
+
target_wallet: str,
|
|
321
|
+
request_id: str | None = None,
|
|
322
|
+
) -> SettleReceipt:
|
|
323
|
+
payload = self._build_payload(
|
|
324
|
+
agent_id=agent_id,
|
|
325
|
+
request_content=request_content,
|
|
326
|
+
result_content=result_content,
|
|
327
|
+
target_wallet=target_wallet,
|
|
328
|
+
request_id=request_id,
|
|
329
|
+
)
|
|
330
|
+
async with httpx.AsyncClient(timeout=self.timeout) as c:
|
|
331
|
+
r = await c.post(
|
|
332
|
+
f"{self.base_url}/v1/settle",
|
|
333
|
+
json=payload,
|
|
334
|
+
headers=_headers(self.api_key),
|
|
335
|
+
)
|
|
336
|
+
r.raise_for_status()
|
|
337
|
+
return SettleReceipt.model_validate(r.json())
|
|
338
|
+
|
|
339
|
+
async def get_status(self, request_id: str) -> SettleReceipt:
|
|
340
|
+
async with httpx.AsyncClient(timeout=self.timeout) as c:
|
|
341
|
+
r = await c.get(
|
|
342
|
+
f"{self.base_url}/v1/settle/status/{request_id}",
|
|
343
|
+
headers=_headers(self.api_key),
|
|
344
|
+
)
|
|
345
|
+
r.raise_for_status()
|
|
346
|
+
return SettleReceipt.model_validate(r.json())
|
|
347
|
+
|
|
348
|
+
async def dashboard_metrics(self) -> dict[str, Any]:
|
|
349
|
+
async with httpx.AsyncClient(timeout=self.timeout) as c:
|
|
350
|
+
r = await c.get(
|
|
351
|
+
f"{self.base_url}/v1/settle/dashboard-metrics",
|
|
352
|
+
headers=_headers(self.api_key),
|
|
353
|
+
)
|
|
354
|
+
r.raise_for_status()
|
|
355
|
+
return r.json()
|
|
356
|
+
|
|
357
|
+
# ── V2 (async mirrors of the sync API) ─────────────────────────
|
|
358
|
+
async def purchase_tokens(
|
|
359
|
+
self, *, customer_id: str, token_id: str, amount: int,
|
|
360
|
+
paid_wei: str | None = None, paid_method: str = "OFFCHAIN",
|
|
361
|
+
tx_ref: str | None = None,
|
|
362
|
+
) -> dict[str, Any]:
|
|
363
|
+
return await self._apost("/v2/tokens/purchase", {
|
|
364
|
+
"customer_id": customer_id,
|
|
365
|
+
"token_id": token_id,
|
|
366
|
+
"amount": amount,
|
|
367
|
+
"paid_wei": paid_wei,
|
|
368
|
+
"paid_method": paid_method,
|
|
369
|
+
"tx_ref": tx_ref,
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
async def get_balance(self, customer_id: str, token_id: str) -> TokenBalance:
|
|
373
|
+
return TokenBalance.model_validate(await self._aget(
|
|
374
|
+
"/v2/tokens/balance",
|
|
375
|
+
params={"customer_id": customer_id, "token_id": token_id},
|
|
376
|
+
))
|
|
377
|
+
|
|
378
|
+
async def create_task(
|
|
379
|
+
self, *, customer_id: str, agent_id: str, token_id: str,
|
|
380
|
+
escrow_amount: int, request_content: str,
|
|
381
|
+
task_id: str | None = None, max_rework: int | None = None,
|
|
382
|
+
) -> TaskOrder:
|
|
383
|
+
body = {
|
|
384
|
+
"task_id": task_id or _gen_task_id(),
|
|
385
|
+
"customer_id": customer_id,
|
|
386
|
+
"agent_id": agent_id,
|
|
387
|
+
"token_id": token_id,
|
|
388
|
+
"escrow_amount": escrow_amount,
|
|
389
|
+
"request_content": request_content,
|
|
390
|
+
"max_rework": max_rework,
|
|
391
|
+
}
|
|
392
|
+
return TaskOrder.model_validate(await self._apost("/v2/tasks", body))
|
|
393
|
+
|
|
394
|
+
async def deliver(
|
|
395
|
+
self, task_id: str, *, result_content: str,
|
|
396
|
+
result_uri: str | None = None,
|
|
397
|
+
) -> DeliveryResult:
|
|
398
|
+
return DeliveryResult.model_validate(await self._apost(
|
|
399
|
+
f"/v2/tasks/{task_id}/deliver",
|
|
400
|
+
{"result_content": result_content, "result_uri": result_uri},
|
|
401
|
+
))
|
|
402
|
+
|
|
403
|
+
async def decide(
|
|
404
|
+
self, task_id: str, decision: str, *, reason: str | None = None,
|
|
405
|
+
) -> DecisionResult:
|
|
406
|
+
return DecisionResult.model_validate(await self._apost(
|
|
407
|
+
f"/v2/tasks/{task_id}/decide",
|
|
408
|
+
{"decision": decision, "reason": reason},
|
|
409
|
+
))
|
|
410
|
+
|
|
411
|
+
async def get_reports(self, task_id: str) -> list[VerificationReport]:
|
|
412
|
+
raw = await self._aget(f"/v2/tasks/{task_id}/report")
|
|
413
|
+
return [VerificationReport.model_validate(r) for r in raw.get("reports", [])]
|
|
414
|
+
|
|
415
|
+
# ── Transport ──────────────────────────────────────────────────
|
|
416
|
+
async def _apost(self, path: str, body: dict[str, Any]) -> dict[str, Any]:
|
|
417
|
+
async with httpx.AsyncClient(timeout=self.timeout) as c:
|
|
418
|
+
r = await c.post(
|
|
419
|
+
f"{self.base_url}{path}", json=body,
|
|
420
|
+
headers=_headers(self.api_key),
|
|
421
|
+
)
|
|
422
|
+
r.raise_for_status()
|
|
423
|
+
return r.json()
|
|
424
|
+
|
|
425
|
+
async def _aget(
|
|
426
|
+
self, path: str, *, params: dict[str, Any] | None = None,
|
|
427
|
+
) -> dict[str, Any]:
|
|
428
|
+
async with httpx.AsyncClient(timeout=self.timeout) as c:
|
|
429
|
+
r = await c.get(
|
|
430
|
+
f"{self.base_url}{path}", params=params,
|
|
431
|
+
headers=_headers(self.api_key),
|
|
432
|
+
)
|
|
433
|
+
r.raise_for_status()
|
|
434
|
+
return r.json()
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# SDK-only build target.
|
|
2
|
+
#
|
|
3
|
+
# The repository root carries the *service* metadata in /pyproject.toml
|
|
4
|
+
# (pytest + ruff config + the FastAPI app version). This file isolates the
|
|
5
|
+
# **public client SDK** so it can be built and published independently:
|
|
6
|
+
#
|
|
7
|
+
# python -m build agentic_settle
|
|
8
|
+
# twine upload --repository testpypi agentic_settle/dist/*
|
|
9
|
+
#
|
|
10
|
+
# The SDK has a deliberately tiny dependency set — only what end-user agents
|
|
11
|
+
# need to call the settlement service. No FastAPI / boto3 / web3 / streamlit.
|
|
12
|
+
|
|
13
|
+
[build-system]
|
|
14
|
+
requires = ["setuptools>=68", "wheel"]
|
|
15
|
+
build-backend = "setuptools.build_meta"
|
|
16
|
+
|
|
17
|
+
[project]
|
|
18
|
+
name = "agentic-settle"
|
|
19
|
+
version = "0.2.0"
|
|
20
|
+
description = "Python SDK for AgenticSettle — verify any AI agent's output, settle with pre-paid token escrow, earn the Verified badge."
|
|
21
|
+
readme = "README.md"
|
|
22
|
+
requires-python = ">=3.10"
|
|
23
|
+
license = { text = "Apache-2.0" }
|
|
24
|
+
keywords = ["agentic", "settlement", "web3", "kms", "fastapi", "sdk"]
|
|
25
|
+
authors = [
|
|
26
|
+
{ name = "AgenticSettle.IO", email = "engineering@agenticsettle.io" },
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 3 - Alpha",
|
|
30
|
+
"Intended Audience :: Developers",
|
|
31
|
+
"License :: OSI Approved :: Apache Software License",
|
|
32
|
+
"Operating System :: OS Independent",
|
|
33
|
+
"Programming Language :: Python :: 3",
|
|
34
|
+
"Programming Language :: Python :: 3.10",
|
|
35
|
+
"Programming Language :: Python :: 3.11",
|
|
36
|
+
"Programming Language :: Python :: 3.12",
|
|
37
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
38
|
+
]
|
|
39
|
+
dependencies = [
|
|
40
|
+
"httpx>=0.27.0",
|
|
41
|
+
"pydantic>=2.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/agenticsettleio/agentic-settle-core"
|
|
46
|
+
Issues = "https://github.com/agenticsettleio/agentic-settle-core/issues"
|
|
47
|
+
|
|
48
|
+
# Tell setuptools that the package directory IS the project root for this
|
|
49
|
+
# sub-build (we're inside agentic_settle/ already).
|
|
50
|
+
[tool.setuptools]
|
|
51
|
+
packages = ["agentic_settle"]
|
|
52
|
+
package-dir = { "agentic_settle" = "." }
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.package-data]
|
|
55
|
+
agentic_settle = ["py.typed"]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public data types exposed by the SDK.
|
|
3
|
+
|
|
4
|
+
Kept intentionally framework-agnostic (pydantic v2 dataclasses) so SDK users
|
|
5
|
+
don't have to install FastAPI / SQLite / web3 to call the API.
|
|
6
|
+
|
|
7
|
+
V1 types are retained verbatim. V2 types implement the prepaid-token +
|
|
8
|
+
verification-gated settlement flow (see ``PIVOT_V2.md``).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, Field
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
17
|
+
# V1 — legacy settle endpoint (kept for backward compatibility)
|
|
18
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
19
|
+
class SettleRequest(BaseModel):
|
|
20
|
+
"""Payload posted to ``POST /v1/settle``."""
|
|
21
|
+
|
|
22
|
+
request_id: str = Field(..., description="Caller-generated idempotency key.")
|
|
23
|
+
agent_id: str = Field(..., description="Logical agent identifier, e.g. 'gpt-4o'.")
|
|
24
|
+
request_content: str = Field(..., description="Original user prompt / task input.")
|
|
25
|
+
result_content: str = Field(..., description="Agent's produced result to be scored.")
|
|
26
|
+
target_wallet: str = Field(..., description="Recipient EOA for the on-chain payout.")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SettleReceipt(BaseModel):
|
|
30
|
+
"""Response returned by the settlement engine."""
|
|
31
|
+
|
|
32
|
+
request_id: str
|
|
33
|
+
status: str = Field(..., description="One of PENDING / COMPLETED / GAS_HOLD / DISPUTED / SLASHED.")
|
|
34
|
+
score: int | None = None
|
|
35
|
+
tier: str | None = None
|
|
36
|
+
payout_eth: float | None = None
|
|
37
|
+
gas_saved_gwei: int | None = None
|
|
38
|
+
chain_tx_hash: str | None = None
|
|
39
|
+
receipt: str | None = Field(None, description="Signed receipt blob (HMAC).")
|
|
40
|
+
timestamp: str | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
44
|
+
# V2 — prepaid-token + verification-gated settlement
|
|
45
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
46
|
+
class TokenBalance(BaseModel):
|
|
47
|
+
"""Customer × agent-token balance snapshot."""
|
|
48
|
+
|
|
49
|
+
customer_id: str
|
|
50
|
+
token_id: str
|
|
51
|
+
balance: int = Field(..., description="Total credited tokens.")
|
|
52
|
+
locked: int = Field(0, description="Currently held in escrow.")
|
|
53
|
+
available: int = Field(..., description="balance - locked")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TaskOrder(BaseModel):
|
|
57
|
+
"""Task created against an escrowed bag of tokens (``POST /v2/tasks``)."""
|
|
58
|
+
|
|
59
|
+
task_id: str
|
|
60
|
+
customer_id: str
|
|
61
|
+
agent_id: str
|
|
62
|
+
token_id: str
|
|
63
|
+
escrow_amount: int = Field(..., gt=0)
|
|
64
|
+
request_content: str = ""
|
|
65
|
+
status: str | None = None
|
|
66
|
+
rework_count: int = 0
|
|
67
|
+
max_rework: int | None = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class VerificationReport(BaseModel):
|
|
71
|
+
"""One round of VOP verification (``GET /v2/tasks/{id}/report``)."""
|
|
72
|
+
|
|
73
|
+
report_id: str
|
|
74
|
+
round_no: int
|
|
75
|
+
vop_score: int
|
|
76
|
+
tier: str | None = None
|
|
77
|
+
verdict: str = Field(..., description="PASS | FAIL")
|
|
78
|
+
fail_codes: list[str] = Field(default_factory=list)
|
|
79
|
+
onchain_tx_hash: str | None = None
|
|
80
|
+
issued_at: str | None = None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class DeliveryResult(BaseModel):
|
|
84
|
+
"""Response from ``POST /v2/tasks/{id}/deliver``."""
|
|
85
|
+
|
|
86
|
+
delivery_id: str
|
|
87
|
+
round_no: int
|
|
88
|
+
report_id: str
|
|
89
|
+
verdict: dict
|
|
90
|
+
task: dict
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class DecisionResult(BaseModel):
|
|
94
|
+
"""Response from ``POST /v2/tasks/{id}/decide``."""
|
|
95
|
+
|
|
96
|
+
decision_id: str
|
|
97
|
+
task: dict
|
|
98
|
+
charge_id: str | None = None
|