humanleg 0.1.0__py3-none-any.whl
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.
- humanleg/__init__.py +4 -0
- humanleg/client.py +105 -0
- humanleg-0.1.0.dist-info/METADATA +36 -0
- humanleg-0.1.0.dist-info/RECORD +5 -0
- humanleg-0.1.0.dist-info/WHEEL +4 -0
humanleg/__init__.py
ADDED
humanleg/client.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import uuid
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
from urllib import error, parse, request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HumanLegApiError(RuntimeError):
|
|
11
|
+
def __init__(self, status: int, problem: dict[str, Any]):
|
|
12
|
+
self.status = status
|
|
13
|
+
self.problem = problem
|
|
14
|
+
super().__init__(
|
|
15
|
+
str(problem.get("detail") or problem.get("title") or f"HumanLeg API failed with {status}")
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class HumanLegClient:
|
|
21
|
+
base_url: str
|
|
22
|
+
token: str
|
|
23
|
+
timeout: float = 15.0
|
|
24
|
+
idempotency_key: Callable[[], str] = lambda: str(uuid.uuid4())
|
|
25
|
+
|
|
26
|
+
def __post_init__(self) -> None:
|
|
27
|
+
if not self.base_url.startswith(("http://", "https://")):
|
|
28
|
+
raise ValueError("base_url must use http:// or https://")
|
|
29
|
+
if not self.token:
|
|
30
|
+
raise ValueError("token is required")
|
|
31
|
+
object.__setattr__(self, "base_url", self.base_url.rstrip("/"))
|
|
32
|
+
|
|
33
|
+
def create_fee_quote(self, *, reward_atomic: int, display_aud_cents: int) -> dict[str, Any]:
|
|
34
|
+
return self._request(
|
|
35
|
+
"/v1/fee-quotes",
|
|
36
|
+
method="POST",
|
|
37
|
+
body={"rewardAtomic": reward_atomic, "displayAudCents": display_aud_cents},
|
|
38
|
+
idempotent=True,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def create_task(self, **task: Any) -> dict[str, Any]:
|
|
42
|
+
return self._request("/v1/tasks", method="POST", body=task, idempotent=True)
|
|
43
|
+
|
|
44
|
+
def get_task(self, task_id: str) -> dict[str, Any]:
|
|
45
|
+
return self._request(f"/v1/tasks/{parse.quote(task_id, safe='')}")
|
|
46
|
+
|
|
47
|
+
def update_task(self, task_id: str, **task: Any) -> dict[str, Any]:
|
|
48
|
+
return self._request(
|
|
49
|
+
f"/v1/tasks/{parse.quote(task_id, safe='')}",
|
|
50
|
+
method="PATCH",
|
|
51
|
+
body=task,
|
|
52
|
+
idempotent=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def get_compliance_review(self, task_id: str) -> dict[str, Any]:
|
|
56
|
+
return self._request(f"/v1/tasks/{parse.quote(task_id, safe='')}/compliance-review")
|
|
57
|
+
|
|
58
|
+
def create_funding_intent(self, task_id: str) -> dict[str, Any]:
|
|
59
|
+
return self._request(
|
|
60
|
+
f"/v1/tasks/{parse.quote(task_id, safe='')}/funding-intents",
|
|
61
|
+
method="POST",
|
|
62
|
+
idempotent=True,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def publish_task(self, task_id: str, *, expected_version: int) -> dict[str, Any]:
|
|
66
|
+
return self._request(
|
|
67
|
+
f"/v1/tasks/{parse.quote(task_id, safe='')}/open",
|
|
68
|
+
method="POST",
|
|
69
|
+
body={"expectedVersion": expected_version},
|
|
70
|
+
idempotent=True,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def list_events(self, *, after: str | None = None) -> dict[str, Any]:
|
|
74
|
+
suffix = "" if after is None else f"?after={parse.quote(after)}"
|
|
75
|
+
return self._request(f"/v1/events{suffix}")
|
|
76
|
+
|
|
77
|
+
def _request(
|
|
78
|
+
self,
|
|
79
|
+
path: str,
|
|
80
|
+
*,
|
|
81
|
+
method: str = "GET",
|
|
82
|
+
body: dict[str, Any] | None = None,
|
|
83
|
+
idempotent: bool = False,
|
|
84
|
+
) -> dict[str, Any]:
|
|
85
|
+
headers = {"Accept": "application/json", "Authorization": f"Bearer {self.token}"}
|
|
86
|
+
data = None
|
|
87
|
+
if body is not None:
|
|
88
|
+
headers["Content-Type"] = "application/json"
|
|
89
|
+
data = json.dumps(body).encode("utf-8")
|
|
90
|
+
if idempotent:
|
|
91
|
+
headers["Idempotency-Key"] = self.idempotency_key()
|
|
92
|
+
api_request = request.Request(
|
|
93
|
+
f"{self.base_url}{path}", data=data, headers=headers, method=method
|
|
94
|
+
)
|
|
95
|
+
try:
|
|
96
|
+
with request.urlopen(api_request, timeout=self.timeout) as response:
|
|
97
|
+
content = response.read()
|
|
98
|
+
return json.loads(content) if content else {}
|
|
99
|
+
except error.HTTPError as exc:
|
|
100
|
+
content = exc.read()
|
|
101
|
+
try:
|
|
102
|
+
problem = json.loads(content) if content else {}
|
|
103
|
+
except json.JSONDecodeError:
|
|
104
|
+
problem = {"title": "HTTP error", "detail": content.decode("utf-8", "replace")}
|
|
105
|
+
raise HumanLegApiError(exc.code, problem) from exc
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: humanleg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the HumanLeg.ai public agent API
|
|
5
|
+
Project-URL: Homepage, https://humanleg.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/humanleg-ai/humanleg
|
|
7
|
+
Project-URL: Issues, https://github.com/humanleg-ai/humanleg/issues
|
|
8
|
+
Author: HumanLeg.ai contributors
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# humanleg
|
|
21
|
+
|
|
22
|
+
Dependency-light Python client for the HumanLeg.ai public agent API.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install humanleg
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from humanleg import HumanLegClient
|
|
30
|
+
|
|
31
|
+
client = HumanLegClient(
|
|
32
|
+
base_url="http://127.0.0.1:8787",
|
|
33
|
+
token="sandbox-agent-token",
|
|
34
|
+
)
|
|
35
|
+
task = client.get_task("task-id")
|
|
36
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
humanleg/__init__.py,sha256=lQ65nFI2JmhE7sjY1KcdfNRa0B02u3GI7RiZZzm0Pwc,125
|
|
2
|
+
humanleg/client.py,sha256=Lc0_XW7sv52ax8jjkKxbhr1CxoM6v0hGBibtnEerW7I,3921
|
|
3
|
+
humanleg-0.1.0.dist-info/METADATA,sha256=nPfgnC206pEY4kRiPfjIPjs50gsijECponNpg6W41Xw,1061
|
|
4
|
+
humanleg-0.1.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
5
|
+
humanleg-0.1.0.dist-info/RECORD,,
|