auctra 0.2.3__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.
auctra-0.2.3/PKG-INFO ADDED
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: auctra
3
+ Version: 0.2.3
4
+ Summary: Authority Protocol Python client — issue authority, execute actions, verify evidence
5
+ License: MIT
6
+ Project-URL: Homepage, https://auctra.tech/docs
7
+ Keywords: auctra,ai-agents,authority,delegation
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+
11
+ # auctra (Python SDK)
12
+
13
+ Stage 0/1 Python client — same Authority Protocol as `@auctra/sdk`.
14
+
15
+ ```bash
16
+ pip install auctra # when published; local: pip install -e packages/python-sdk
17
+ ```
18
+
19
+ ## Quick start (with intent anchor)
20
+
21
+ High-risk actions require **`create_intent`** first, then pass the returned **`intent`** (id + `anchor_token`) on execute:
22
+
23
+ ```python
24
+ from auctra import Auctra
25
+
26
+ client = Auctra(api_key="auctra_...", base_url="https://app.auctra.tech")
27
+
28
+ agent_id = "your-agent-uuid"
29
+ expires_at = "2027-01-01T00:00:00Z"
30
+
31
+ client.authority.issue(
32
+ subject=agent_id,
33
+ capabilities=["send_payment"],
34
+ expires_at=expires_at,
35
+ max_amount=500,
36
+ currency="USD",
37
+ )
38
+
39
+ created = client.create_intent(
40
+ title="Pay matched vendor invoices",
41
+ intent_type="payment",
42
+ risk_level="high",
43
+ max_risk_level="critical",
44
+ allowed_action_types=["send_payment"],
45
+ expires_at=expires_at,
46
+ )
47
+ intent = created["intent"]
48
+
49
+ preview = client.action.evaluate(
50
+ agent_id=agent_id,
51
+ action_type="send_payment",
52
+ payload={"amount": 50, "currency": "USD"},
53
+ intent=intent,
54
+ )
55
+
56
+ decision = client.action.execute(
57
+ agent_id=agent_id,
58
+ action_type="send_payment",
59
+ payload={"amount": 50, "currency": "USD", "target": "vendor:acme"},
60
+ intent=intent,
61
+ action={
62
+ "target": "vendor:acme",
63
+ "description": "Net-30 invoice payment",
64
+ "risk_level": "medium",
65
+ },
66
+ )
67
+
68
+ print(decision["decision"])
69
+ client.evidence.verify(payload=decision["evidence_payload"], evidence=decision["evidence"])
70
+ ```
71
+
72
+ ### New-client gotcha
73
+
74
+ Sending only `claimed_intent_id` (without `intent_anchor_token` or the `intent` object) returns **`require_approval`** with a reason about the missing anchor. Pass `intent=` from `create_intent`, or set both `claimed_intent_id` and `intent_anchor_token` explicitly.
75
+
76
+ See [`docs/integrations/intent-anchors.md`](../../docs/integrations/intent-anchors.md).
77
+
78
+ ## Public surface
79
+
80
+ ```text
81
+ client.create_intent
82
+ client.authority.issue | verify | delegate | revoke
83
+ client.action.evaluate | execute
84
+ client.get_action_request
85
+ client.evidence.verify
86
+ ```
auctra-0.2.3/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # auctra (Python SDK)
2
+
3
+ Stage 0/1 Python client — same Authority Protocol as `@auctra/sdk`.
4
+
5
+ ```bash
6
+ pip install auctra # when published; local: pip install -e packages/python-sdk
7
+ ```
8
+
9
+ ## Quick start (with intent anchor)
10
+
11
+ High-risk actions require **`create_intent`** first, then pass the returned **`intent`** (id + `anchor_token`) on execute:
12
+
13
+ ```python
14
+ from auctra import Auctra
15
+
16
+ client = Auctra(api_key="auctra_...", base_url="https://app.auctra.tech")
17
+
18
+ agent_id = "your-agent-uuid"
19
+ expires_at = "2027-01-01T00:00:00Z"
20
+
21
+ client.authority.issue(
22
+ subject=agent_id,
23
+ capabilities=["send_payment"],
24
+ expires_at=expires_at,
25
+ max_amount=500,
26
+ currency="USD",
27
+ )
28
+
29
+ created = client.create_intent(
30
+ title="Pay matched vendor invoices",
31
+ intent_type="payment",
32
+ risk_level="high",
33
+ max_risk_level="critical",
34
+ allowed_action_types=["send_payment"],
35
+ expires_at=expires_at,
36
+ )
37
+ intent = created["intent"]
38
+
39
+ preview = client.action.evaluate(
40
+ agent_id=agent_id,
41
+ action_type="send_payment",
42
+ payload={"amount": 50, "currency": "USD"},
43
+ intent=intent,
44
+ )
45
+
46
+ decision = client.action.execute(
47
+ agent_id=agent_id,
48
+ action_type="send_payment",
49
+ payload={"amount": 50, "currency": "USD", "target": "vendor:acme"},
50
+ intent=intent,
51
+ action={
52
+ "target": "vendor:acme",
53
+ "description": "Net-30 invoice payment",
54
+ "risk_level": "medium",
55
+ },
56
+ )
57
+
58
+ print(decision["decision"])
59
+ client.evidence.verify(payload=decision["evidence_payload"], evidence=decision["evidence"])
60
+ ```
61
+
62
+ ### New-client gotcha
63
+
64
+ Sending only `claimed_intent_id` (without `intent_anchor_token` or the `intent` object) returns **`require_approval`** with a reason about the missing anchor. Pass `intent=` from `create_intent`, or set both `claimed_intent_id` and `intent_anchor_token` explicitly.
65
+
66
+ See [`docs/integrations/intent-anchors.md`](../../docs/integrations/intent-anchors.md).
67
+
68
+ ## Public surface
69
+
70
+ ```text
71
+ client.create_intent
72
+ client.authority.issue | verify | delegate | revoke
73
+ client.action.evaluate | execute
74
+ client.get_action_request
75
+ client.evidence.verify
76
+ ```
@@ -0,0 +1,4 @@
1
+ from .client import Auctra, AuctraApiError, DEFAULT_BASE_URL
2
+
3
+ __all__ = ["Auctra", "AuctraApiError", "DEFAULT_BASE_URL"]
4
+ __version__ = "0.2.3"
@@ -0,0 +1,273 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import urllib.error
5
+ import urllib.request
6
+ from typing import Any
7
+
8
+ __version__ = "0.2.3"
9
+
10
+
11
+ class AuctraApiError(Exception):
12
+ def __init__(self, status: int, message: str, body: Any | None = None) -> None:
13
+ super().__init__(message)
14
+ self.status = status
15
+ self.body = body
16
+
17
+
18
+ def _normalize_guard_blocked(payload: Any, status: int) -> dict[str, Any]:
19
+ data = payload if isinstance(payload, dict) else {}
20
+ reason = data.get("reason") or data.get("error") or "Blocked before evaluation"
21
+ action_request_id = data.get("action_request_id")
22
+ guard_error = data.get("error")
23
+ return {
24
+ "decision": "blocked",
25
+ "reason": reason,
26
+ "action_request_id": action_request_id if isinstance(action_request_id, str) else None,
27
+ "guard": {
28
+ "httpStatus": status,
29
+ "error": guard_error if isinstance(guard_error, str) else None,
30
+ },
31
+ }
32
+
33
+
34
+ class _AuthorityAPI:
35
+ def __init__(self, client: "Auctra") -> None:
36
+ self._client = client
37
+
38
+ def issue(
39
+ self,
40
+ *,
41
+ subject: str,
42
+ capabilities: list[str],
43
+ expires_at: str,
44
+ max_amount: float | None = None,
45
+ currency: str | None = None,
46
+ parent: str | None = None,
47
+ ) -> dict[str, Any]:
48
+ body: dict[str, Any] = {
49
+ "agent_id": subject,
50
+ "action_types": capabilities,
51
+ "valid_until": expires_at,
52
+ }
53
+ if max_amount is not None:
54
+ body["max_amount"] = max_amount
55
+ if currency is not None:
56
+ body["currency"] = currency
57
+ if parent is not None:
58
+ body["parent_authority_id"] = parent
59
+ return self._client._request("POST", "/v1/authorities", body)
60
+
61
+ def delegate(
62
+ self,
63
+ *,
64
+ parent: str,
65
+ subject: str,
66
+ capabilities: list[str],
67
+ expires_at: str,
68
+ max_amount: float | None = None,
69
+ currency: str | None = None,
70
+ ) -> dict[str, Any]:
71
+ return self.issue(
72
+ subject=subject,
73
+ capabilities=capabilities,
74
+ expires_at=expires_at,
75
+ max_amount=max_amount,
76
+ currency=currency,
77
+ parent=parent,
78
+ )
79
+
80
+ def revoke(self, authority_id: str) -> dict[str, Any]:
81
+ return self._client._request("POST", f"/v1/authorities/{authority_id}/revoke", {})
82
+
83
+ def verify(self, *, payload: dict[str, Any], artifact: dict[str, Any]) -> dict[str, Any]:
84
+ return self._client._request(
85
+ "POST",
86
+ "/v1/authorities/verify",
87
+ {"payload": payload, "artifact": artifact},
88
+ )
89
+
90
+
91
+ class _ActionAPI:
92
+ def __init__(self, client: "Auctra") -> None:
93
+ self._client = client
94
+
95
+ def evaluate(
96
+ self,
97
+ *,
98
+ agent_id: str,
99
+ action_type: str,
100
+ payload: dict[str, Any] | None = None,
101
+ claimed_intent_id: str | None = None,
102
+ intent_anchor_token: str | None = None,
103
+ intent: dict[str, Any] | None = None,
104
+ ) -> dict[str, Any]:
105
+ body: dict[str, Any] = {
106
+ "agent_id": agent_id,
107
+ "action_type": action_type,
108
+ "payload": payload or {},
109
+ "dry_run": True,
110
+ }
111
+ intent_id = claimed_intent_id or (intent or {}).get("id")
112
+ anchor = intent_anchor_token or (intent or {}).get("anchor_token") or (intent or {}).get(
113
+ "anchorToken"
114
+ )
115
+ if intent_id:
116
+ body["claimed_intent_id"] = intent_id
117
+ if anchor:
118
+ body["intent_anchor_token"] = anchor
119
+ return self._client._request(
120
+ "POST",
121
+ "/v1/actions/evaluate",
122
+ body,
123
+ normalize_guard_blocked=True,
124
+ )
125
+
126
+ def execute(
127
+ self,
128
+ *,
129
+ agent_id: str,
130
+ action_type: str,
131
+ payload: dict[str, Any] | None = None,
132
+ claimed_intent_id: str | None = None,
133
+ intent_anchor_token: str | None = None,
134
+ intent: dict[str, Any] | None = None,
135
+ ) -> dict[str, Any]:
136
+ body: dict[str, Any] = {
137
+ "agent_id": agent_id,
138
+ "action_type": action_type,
139
+ "payload": payload or {},
140
+ "dry_run": False,
141
+ }
142
+ intent_id = claimed_intent_id or (intent or {}).get("id")
143
+ anchor = intent_anchor_token or (intent or {}).get("anchor_token") or (intent or {}).get(
144
+ "anchorToken"
145
+ )
146
+ if intent_id:
147
+ body["claimed_intent_id"] = intent_id
148
+ if anchor:
149
+ body["intent_anchor_token"] = anchor
150
+ return self._client._request(
151
+ "POST",
152
+ "/v1/actions/execute",
153
+ body,
154
+ normalize_guard_blocked=True,
155
+ )
156
+
157
+
158
+ class _EvidenceAPI:
159
+ def __init__(self, client: "Auctra") -> None:
160
+ self._client = client
161
+
162
+ def verify(self, *, payload: dict[str, Any], evidence: dict[str, Any]) -> dict[str, Any]:
163
+ return self._client._request(
164
+ "POST",
165
+ "/v1/evidence/verify",
166
+ {"payload": payload, "evidence": evidence},
167
+ )
168
+
169
+
170
+ DEFAULT_BASE_URL = "https://app.auctra.tech"
171
+
172
+
173
+ class Auctra:
174
+ def __init__(
175
+ self,
176
+ api_key: str,
177
+ base_url: str = DEFAULT_BASE_URL,
178
+ timeout: float = 30.0,
179
+ ) -> None:
180
+ self.api_key = api_key
181
+ self.base_url = base_url.rstrip("/")
182
+ self.timeout = timeout
183
+ self.authority = _AuthorityAPI(self)
184
+ self.action = _ActionAPI(self)
185
+ self.evidence = _EvidenceAPI(self)
186
+
187
+ def _request(
188
+ self,
189
+ method: str,
190
+ path: str,
191
+ body: dict[str, Any] | None = None,
192
+ *,
193
+ normalize_guard_blocked: bool = False,
194
+ ) -> Any:
195
+ url = f"{self.base_url}{path}"
196
+ data = None if body is None else json.dumps(body).encode("utf-8")
197
+ request = urllib.request.Request(
198
+ url,
199
+ data=data,
200
+ method=method,
201
+ headers={
202
+ "Authorization": f"Bearer {self.api_key}",
203
+ "Content-Type": "application/json",
204
+ "Accept": "application/json",
205
+ # Cloudflare bot score can block bare urllib user-agents (Error 1010).
206
+ "User-Agent": f"auctra-python-sdk/{__version__} (+https://auctra.tech)",
207
+ },
208
+ )
209
+ try:
210
+ with urllib.request.urlopen(request, timeout=self.timeout) as response:
211
+ return json.loads(response.read().decode("utf-8"))
212
+ except urllib.error.HTTPError as error:
213
+ payload = None
214
+ try:
215
+ payload = json.loads(error.read().decode("utf-8"))
216
+ except Exception:
217
+ payload = None
218
+ if (
219
+ normalize_guard_blocked
220
+ and error.code in (400, 404)
221
+ and isinstance(payload, dict)
222
+ and payload.get("decision") == "blocked"
223
+ ):
224
+ return _normalize_guard_blocked(payload, error.code)
225
+ message = payload.get("error") if isinstance(payload, dict) else str(error)
226
+ raise AuctraApiError(error.code, message or "Request failed", payload) from error
227
+
228
+ def verify_audit_chain(self) -> dict[str, Any]:
229
+ return self._request("GET", "/v1/audit-events/verify")
230
+
231
+ def get_audit_event(self, audit_event_id: str) -> dict[str, Any]:
232
+ return self._request("GET", f"/v1/audit-events/{audit_event_id}")
233
+
234
+ def verify_mandate(self, *, payload: dict[str, Any], evidence: dict[str, Any]) -> dict[str, Any]:
235
+ return self._request(
236
+ "POST",
237
+ "/v1/mandates/verify",
238
+ {"payload": payload, "evidence": evidence},
239
+ )
240
+
241
+ def list_audit_events(self) -> dict[str, Any]:
242
+ return self._request("GET", "/v1/audit-events")
243
+
244
+ def get_action_request(self, action_request_id: str) -> dict[str, Any]:
245
+ """Dispute pack: decision, receipt, evidence, audit anchors."""
246
+ return self._request("GET", f"/v1/action-requests/{action_request_id}")
247
+
248
+ def create_intent(
249
+ self,
250
+ *,
251
+ title: str,
252
+ description: str | None = None,
253
+ intent_type: str | None = None,
254
+ risk_level: str = "medium",
255
+ max_risk_level: str = "high",
256
+ allowed_action_types: list[str] | None = None,
257
+ expires_at: str | None = None,
258
+ ) -> dict[str, Any]:
259
+ """Declare a human intent. Response includes anchor_token for action.execute."""
260
+ body: dict[str, Any] = {
261
+ "title": title,
262
+ "risk_level": risk_level,
263
+ "max_risk_level": max_risk_level,
264
+ }
265
+ if description is not None:
266
+ body["description"] = description
267
+ if intent_type is not None:
268
+ body["intent_type"] = intent_type
269
+ if allowed_action_types is not None:
270
+ body["allowed_action_types"] = allowed_action_types
271
+ if expires_at is not None:
272
+ body["expires_at"] = expires_at
273
+ return self._request("POST", "/v1/intents", body)
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: auctra
3
+ Version: 0.2.3
4
+ Summary: Authority Protocol Python client — issue authority, execute actions, verify evidence
5
+ License: MIT
6
+ Project-URL: Homepage, https://auctra.tech/docs
7
+ Keywords: auctra,ai-agents,authority,delegation
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+
11
+ # auctra (Python SDK)
12
+
13
+ Stage 0/1 Python client — same Authority Protocol as `@auctra/sdk`.
14
+
15
+ ```bash
16
+ pip install auctra # when published; local: pip install -e packages/python-sdk
17
+ ```
18
+
19
+ ## Quick start (with intent anchor)
20
+
21
+ High-risk actions require **`create_intent`** first, then pass the returned **`intent`** (id + `anchor_token`) on execute:
22
+
23
+ ```python
24
+ from auctra import Auctra
25
+
26
+ client = Auctra(api_key="auctra_...", base_url="https://app.auctra.tech")
27
+
28
+ agent_id = "your-agent-uuid"
29
+ expires_at = "2027-01-01T00:00:00Z"
30
+
31
+ client.authority.issue(
32
+ subject=agent_id,
33
+ capabilities=["send_payment"],
34
+ expires_at=expires_at,
35
+ max_amount=500,
36
+ currency="USD",
37
+ )
38
+
39
+ created = client.create_intent(
40
+ title="Pay matched vendor invoices",
41
+ intent_type="payment",
42
+ risk_level="high",
43
+ max_risk_level="critical",
44
+ allowed_action_types=["send_payment"],
45
+ expires_at=expires_at,
46
+ )
47
+ intent = created["intent"]
48
+
49
+ preview = client.action.evaluate(
50
+ agent_id=agent_id,
51
+ action_type="send_payment",
52
+ payload={"amount": 50, "currency": "USD"},
53
+ intent=intent,
54
+ )
55
+
56
+ decision = client.action.execute(
57
+ agent_id=agent_id,
58
+ action_type="send_payment",
59
+ payload={"amount": 50, "currency": "USD", "target": "vendor:acme"},
60
+ intent=intent,
61
+ action={
62
+ "target": "vendor:acme",
63
+ "description": "Net-30 invoice payment",
64
+ "risk_level": "medium",
65
+ },
66
+ )
67
+
68
+ print(decision["decision"])
69
+ client.evidence.verify(payload=decision["evidence_payload"], evidence=decision["evidence"])
70
+ ```
71
+
72
+ ### New-client gotcha
73
+
74
+ Sending only `claimed_intent_id` (without `intent_anchor_token` or the `intent` object) returns **`require_approval`** with a reason about the missing anchor. Pass `intent=` from `create_intent`, or set both `claimed_intent_id` and `intent_anchor_token` explicitly.
75
+
76
+ See [`docs/integrations/intent-anchors.md`](../../docs/integrations/intent-anchors.md).
77
+
78
+ ## Public surface
79
+
80
+ ```text
81
+ client.create_intent
82
+ client.authority.issue | verify | delegate | revoke
83
+ client.action.evaluate | execute
84
+ client.get_action_request
85
+ client.evidence.verify
86
+ ```
@@ -0,0 +1,8 @@
1
+ README.md
2
+ pyproject.toml
3
+ auctra/__init__.py
4
+ auctra/client.py
5
+ auctra.egg-info/PKG-INFO
6
+ auctra.egg-info/SOURCES.txt
7
+ auctra.egg-info/dependency_links.txt
8
+ auctra.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ auctra
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "auctra"
7
+ version = "0.2.3"
8
+ description = "Authority Protocol Python client — issue authority, execute actions, verify evidence"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ keywords = ["auctra", "ai-agents", "authority", "delegation"]
13
+ dependencies = []
14
+
15
+ [project.urls]
16
+ Homepage = "https://auctra.tech/docs"
17
+
18
+ [tool.setuptools.packages.find]
19
+ where = ["."]
20
+ include = ["auctra*"]
auctra-0.2.3/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+