agentworth 0.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentworth-0.1.8/.gitignore +15 -0
- agentworth-0.1.8/PKG-INFO +33 -0
- agentworth-0.1.8/README.md +23 -0
- agentworth-0.1.8/agentworth.py +103 -0
- agentworth-0.1.8/pyproject.toml +17 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentworth
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: Python client for the AgentWorth governance gate (REST over the HTTP ingress)
|
|
5
|
+
Author: General Liquidity
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: agentic-payments,agentworth,governance
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# agentworth (Python client)
|
|
12
|
+
|
|
13
|
+
A thin REST client for the [AgentWorth](https://github.com/general-liquidity/agentworth)
|
|
14
|
+
governance gate. Point it at a running `agentworth serve`; every payment it submits
|
|
15
|
+
runs through the same gate (auto-execute inside a mandate, park for operator approval,
|
|
16
|
+
or block). A `blocked` outcome is a normal result, not an error. Standard library
|
|
17
|
+
only - no dependencies.
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from agentworth import AgentWorthClient
|
|
21
|
+
|
|
22
|
+
os = AgentWorthClient("http://127.0.0.1:8787", token="...")
|
|
23
|
+
res = os.pay(payee="tesco", payee_class="groceries", amount=8000, # minor-units
|
|
24
|
+
rationale="the weekly grocery shop")
|
|
25
|
+
print(res["outcome"]) # settled | pending | blocked | failed
|
|
26
|
+
print(os.status(), os.ready())
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Idempotency keys are generated per `pay()` (override with `idempotency_key=`). The
|
|
30
|
+
full-feature surface is the TypeScript SDK (`@general-liquidity/agentworth`); this
|
|
31
|
+
is for Python hosts that talk to a running ingress.
|
|
32
|
+
|
|
33
|
+
License: MIT.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# agentworth (Python client)
|
|
2
|
+
|
|
3
|
+
A thin REST client for the [AgentWorth](https://github.com/general-liquidity/agentworth)
|
|
4
|
+
governance gate. Point it at a running `agentworth serve`; every payment it submits
|
|
5
|
+
runs through the same gate (auto-execute inside a mandate, park for operator approval,
|
|
6
|
+
or block). A `blocked` outcome is a normal result, not an error. Standard library
|
|
7
|
+
only - no dependencies.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from agentworth import AgentWorthClient
|
|
11
|
+
|
|
12
|
+
os = AgentWorthClient("http://127.0.0.1:8787", token="...")
|
|
13
|
+
res = os.pay(payee="tesco", payee_class="groceries", amount=8000, # minor-units
|
|
14
|
+
rationale="the weekly grocery shop")
|
|
15
|
+
print(res["outcome"]) # settled | pending | blocked | failed
|
|
16
|
+
print(os.status(), os.ready())
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Idempotency keys are generated per `pay()` (override with `idempotency_key=`). The
|
|
20
|
+
full-feature surface is the TypeScript SDK (`@general-liquidity/agentworth`); this
|
|
21
|
+
is for Python hosts that talk to a running ingress.
|
|
22
|
+
|
|
23
|
+
License: MIT.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""AgentWorth Python client — a thin REST client over the HTTP ingress.
|
|
2
|
+
|
|
3
|
+
The ingress runs the SAME gate as everything else, so this client adds no
|
|
4
|
+
authority: a payment it submits is auto-executed inside a mandate, parked for
|
|
5
|
+
operator approval, or blocked. Standard-library only (no dependencies).
|
|
6
|
+
|
|
7
|
+
from agentworth import AgentWorthClient
|
|
8
|
+
|
|
9
|
+
os = AgentWorthClient("http://127.0.0.1:8787", token="...")
|
|
10
|
+
result = os.pay(payee="tesco", payee_class="groceries", amount=8000,
|
|
11
|
+
rationale="the weekly grocery shop")
|
|
12
|
+
print(result["outcome"]) # "settled" | "pending" | "blocked" | "failed"
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import uuid
|
|
19
|
+
import urllib.error
|
|
20
|
+
import urllib.request
|
|
21
|
+
from typing import Any, Optional
|
|
22
|
+
|
|
23
|
+
__all__ = ["AgentWorthClient", "AgentWorthError"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AgentWorthError(Exception):
|
|
27
|
+
"""Raised on a transport error (not on a gate 'blocked' — that's a normal result)."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AgentWorthClient:
|
|
31
|
+
def __init__(self, base_url: str = "http://127.0.0.1:8787", token: Optional[str] = None):
|
|
32
|
+
self.base_url = base_url.rstrip("/")
|
|
33
|
+
self.token = token
|
|
34
|
+
|
|
35
|
+
def _request(self, method: str, path: str, body: Any = None, headers: Optional[dict] = None):
|
|
36
|
+
data = json.dumps(body).encode() if body is not None else None
|
|
37
|
+
h = {"content-type": "application/json"}
|
|
38
|
+
if self.token:
|
|
39
|
+
h["authorization"] = f"Bearer {self.token}"
|
|
40
|
+
if headers:
|
|
41
|
+
h.update(headers)
|
|
42
|
+
req = urllib.request.Request(self.base_url + path, data=data, method=method, headers=h)
|
|
43
|
+
try:
|
|
44
|
+
with urllib.request.urlopen(req) as resp:
|
|
45
|
+
payload = resp.read()
|
|
46
|
+
return resp.status, (json.loads(payload) if payload else None)
|
|
47
|
+
except urllib.error.HTTPError as e:
|
|
48
|
+
payload = e.read()
|
|
49
|
+
# 403/401/413/429 carry a JSON body too — return it, don't raise.
|
|
50
|
+
return e.code, (json.loads(payload) if payload else None)
|
|
51
|
+
except urllib.error.URLError as e:
|
|
52
|
+
raise AgentWorthError(f"transport error: {e}") from e
|
|
53
|
+
|
|
54
|
+
def pay(
|
|
55
|
+
self,
|
|
56
|
+
payee: str,
|
|
57
|
+
payee_class: str,
|
|
58
|
+
amount: int,
|
|
59
|
+
currency: str = "GBP",
|
|
60
|
+
rail: str = "card",
|
|
61
|
+
rationale: str = "",
|
|
62
|
+
idempotency_key: Optional[str] = None,
|
|
63
|
+
) -> dict:
|
|
64
|
+
"""Submit a payment intent. Returns the gate result
|
|
65
|
+
{intentId, outcome, reasons, receiptId, verified}. `amount` is minor-units."""
|
|
66
|
+
headers = {"idempotency-key": idempotency_key or str(uuid.uuid4())}
|
|
67
|
+
_, body = self._request(
|
|
68
|
+
"POST",
|
|
69
|
+
"/payment-intent",
|
|
70
|
+
{
|
|
71
|
+
"payee": payee,
|
|
72
|
+
"payeeClass": payee_class,
|
|
73
|
+
"amount": amount,
|
|
74
|
+
"currency": currency,
|
|
75
|
+
"rail": rail,
|
|
76
|
+
"rationale": rationale,
|
|
77
|
+
},
|
|
78
|
+
headers,
|
|
79
|
+
)
|
|
80
|
+
return body or {}
|
|
81
|
+
|
|
82
|
+
def status(self) -> dict:
|
|
83
|
+
"""Kill-switch / circuit-breaker state."""
|
|
84
|
+
return self._request("GET", "/status")[1] or {}
|
|
85
|
+
|
|
86
|
+
def ready(self) -> dict:
|
|
87
|
+
"""Readiness probe."""
|
|
88
|
+
return self._request("GET", "/ready")[1] or {}
|
|
89
|
+
|
|
90
|
+
def openapi(self) -> dict:
|
|
91
|
+
"""The served OpenAPI 3.1 document."""
|
|
92
|
+
return self._request("GET", "/openapi.json")[1] or {}
|
|
93
|
+
|
|
94
|
+
def get_disclosure(self) -> dict:
|
|
95
|
+
"""Fetch this node's signed Verifiable Agency disclosure (public, no auth)."""
|
|
96
|
+
return self._request("GET", "/.well-known/agent-disclosure")[1] or {}
|
|
97
|
+
|
|
98
|
+
def verify_disclosure(self, disclosure: dict) -> dict:
|
|
99
|
+
"""Verifier-as-a-service: submit a signed disclosure, get a verdict
|
|
100
|
+
{decision, tier, checks, reasons, cost}. Lets a heterogeneous counterparty
|
|
101
|
+
verify a peer without implementing ed25519 itself. A "refuse" decision is a
|
|
102
|
+
normal result, not an error."""
|
|
103
|
+
return self._request("POST", "/verify-disclosure", disclosure)[1] or {}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agentworth"
|
|
3
|
+
version = "0.1.8"
|
|
4
|
+
description = "Python client for the AgentWorth governance gate (REST over the HTTP ingress)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.8"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "General Liquidity" }]
|
|
9
|
+
keywords = ["agentic-payments", "governance", "agentworth"]
|
|
10
|
+
dependencies = []
|
|
11
|
+
|
|
12
|
+
[build-system]
|
|
13
|
+
requires = ["hatchling"]
|
|
14
|
+
build-backend = "hatchling.build"
|
|
15
|
+
|
|
16
|
+
[tool.hatch.build.targets.wheel]
|
|
17
|
+
only-include = ["agentworth.py"]
|