agentlattice 0.3.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.
- agentlattice-0.3.0/.gitignore +7 -0
- agentlattice-0.3.0/LICENSE +21 -0
- agentlattice-0.3.0/PKG-INFO +221 -0
- agentlattice-0.3.0/README.md +195 -0
- agentlattice-0.3.0/agentlattice/__init__.py +50 -0
- agentlattice-0.3.0/agentlattice/client.py +735 -0
- agentlattice-0.3.0/agentlattice/py.typed +0 -0
- agentlattice-0.3.0/pyproject.toml +43 -0
- agentlattice-0.3.0/tests/__init__.py +0 -0
- agentlattice-0.3.0/tests/test_client.py +368 -0
- agentlattice-0.3.0/tests/test_delegate.py +315 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AgentLattice
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentlattice
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Governance SDK for AI agents — audit trails, policy engine, approval gates.
|
|
5
|
+
Project-URL: Homepage, https://agentlattice.com
|
|
6
|
+
Project-URL: Repository, https://github.com/inder/agentlattice
|
|
7
|
+
Project-URL: Documentation, https://agentlattice.com/docs
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agents,ai,approval,audit,governance
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
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.9
|
|
20
|
+
Requires-Dist: httpx>=0.25.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# agentlattice — Python SDK
|
|
28
|
+
|
|
29
|
+
Governance-aware SDK for AI agents. Wraps agent actions with audit trails,
|
|
30
|
+
approval gates, and circuit breaker integration.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install agentlattice
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import asyncio
|
|
42
|
+
import os
|
|
43
|
+
from agentlattice import AgentLattice
|
|
44
|
+
|
|
45
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
46
|
+
|
|
47
|
+
async def main():
|
|
48
|
+
# gate() blocks until approved — your agent code only runs if it passes
|
|
49
|
+
await al.gate("pr.merge")
|
|
50
|
+
await merge_pr(42)
|
|
51
|
+
|
|
52
|
+
asyncio.run(main())
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Handle denials and timeouts:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from agentlattice import AgentLattice, AgentLatticeDeniedError, AgentLatticeTimeoutError
|
|
59
|
+
|
|
60
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
61
|
+
|
|
62
|
+
async def main():
|
|
63
|
+
try:
|
|
64
|
+
await al.gate("code.commit")
|
|
65
|
+
except AgentLatticeDeniedError as e:
|
|
66
|
+
print(f"Denied: {e.reason}, policy: {e.policy}")
|
|
67
|
+
print(f"Failed conditions: {e.conditions}")
|
|
68
|
+
except AgentLatticeTimeoutError as e:
|
|
69
|
+
print(f"Approval timed out: {e.approval_id}")
|
|
70
|
+
|
|
71
|
+
asyncio.run(main())
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Sync usage
|
|
75
|
+
|
|
76
|
+
If you're not in an async context:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import os
|
|
80
|
+
from agentlattice import AgentLattice
|
|
81
|
+
|
|
82
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
83
|
+
al.gate_sync("code.commit")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
### `AgentLattice(api_key, *, base_url?, gate_poll_timeout_ms?, gate_poll_interval_ms?)`
|
|
89
|
+
|
|
90
|
+
| Parameter | Default | Description |
|
|
91
|
+
|-----------|---------|-------------|
|
|
92
|
+
| `api_key` | required | Bearer token — pass via `os.environ["AL_API_KEY"]`, never hardcoded |
|
|
93
|
+
| `base_url` | `https://agentlattice.com` | Override for self-hosted or staging |
|
|
94
|
+
| `gate_poll_timeout_ms` | `8 * 60 * 60 * 1000` (8 hours) | How long `gate()` polls for approval |
|
|
95
|
+
| `gate_poll_interval_ms` | `5000` | Poll interval in ms |
|
|
96
|
+
|
|
97
|
+
### `await al.execute(action_type, options?)`
|
|
98
|
+
|
|
99
|
+
Submit an action and return immediately. Returns an `ActionResult`. Does not block.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from agentlattice import AgentLattice, ActionOptions
|
|
103
|
+
|
|
104
|
+
al = AgentLattice(api_key="al_...")
|
|
105
|
+
result = await al.execute("pr.open", ActionOptions(
|
|
106
|
+
data_accessed=[{"type": "source_code", "count": 5, "sensitivity": "low"}],
|
|
107
|
+
metadata={"pr_number": 42},
|
|
108
|
+
event_id="my-idempotency-key", # optional: dedup by your own key
|
|
109
|
+
))
|
|
110
|
+
|
|
111
|
+
if result.status == "executed":
|
|
112
|
+
print(f"Auto-executed under policy: {result.policy_name}")
|
|
113
|
+
elif result.status == "requested":
|
|
114
|
+
print(f"Awaiting approval: {result.approval_id}")
|
|
115
|
+
elif result.status == "denied":
|
|
116
|
+
print(f"Denied ({result.denial_reason}): {result.conditions_evaluated}")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### `await al.gate(action_type, options?)`
|
|
120
|
+
|
|
121
|
+
Submit an action and block until it is approved or denied.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
try:
|
|
125
|
+
await al.gate("pr.merge")
|
|
126
|
+
except AgentLatticeDeniedError as e:
|
|
127
|
+
# e.reason: "CONDITIONS_DENIED" | "POLICY_TAMPERED" | "DENIED_BY_REVIEWER"
|
|
128
|
+
# e.policy: name of the governing policy (if conditions-based)
|
|
129
|
+
# e.conditions: list of ConditionResult (which rule failed and why)
|
|
130
|
+
# e.approval_id: set if a human reviewer denied it
|
|
131
|
+
...
|
|
132
|
+
except AgentLatticeTimeoutError as e:
|
|
133
|
+
# e.approval_id: the approval that timed out
|
|
134
|
+
...
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `al.gate_sync(action_type, options?)` / `al.execute_sync(action_type, options?)`
|
|
138
|
+
|
|
139
|
+
Synchronous wrappers — identical semantics, no `asyncio.run()` needed.
|
|
140
|
+
|
|
141
|
+
## ActionResult
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
@dataclass
|
|
145
|
+
class ActionResult:
|
|
146
|
+
status: str # "executed" | "requested" | "denied" | ...
|
|
147
|
+
audit_event_id: str
|
|
148
|
+
approval_id: str | None # set when status="requested"
|
|
149
|
+
message: str | None
|
|
150
|
+
timeout_at: str | None
|
|
151
|
+
denial_reason: str | None # "CONDITIONS_DENIED" | "POLICY_TAMPERED" | ...
|
|
152
|
+
policy_name: str | None # governing policy name
|
|
153
|
+
conditions_evaluated: list[ConditionResult] # which rules passed/failed
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## ConditionResult
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
@dataclass
|
|
160
|
+
class ConditionResult:
|
|
161
|
+
field: str # e.g. "pr_size"
|
|
162
|
+
operator: str # e.g. "lt"
|
|
163
|
+
expected: Any # e.g. 100
|
|
164
|
+
result: bool # True = passed, False = failed
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Agents can read `conditions_evaluated` to understand exactly which governance
|
|
168
|
+
rule blocked them and adapt their behavior accordingly.
|
|
169
|
+
|
|
170
|
+
## Self-correcting agent pattern
|
|
171
|
+
|
|
172
|
+
`conditions_evaluated` is what makes this more than a compliance layer — it
|
|
173
|
+
closes the feedback loop so agents can adapt, not just fail.
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from agentlattice import AgentLattice, AgentLatticeDeniedError, ActionOptions
|
|
177
|
+
|
|
178
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
179
|
+
|
|
180
|
+
async def commit_with_governance(files: list[str]) -> None:
|
|
181
|
+
try:
|
|
182
|
+
await al.gate("pr.open", ActionOptions(
|
|
183
|
+
metadata={"pr_size": len(files), "repo": "acme/backend"},
|
|
184
|
+
))
|
|
185
|
+
await open_pr(files)
|
|
186
|
+
|
|
187
|
+
except AgentLatticeDeniedError as e:
|
|
188
|
+
if e.reason == "CONDITIONS_DENIED":
|
|
189
|
+
# Find which rules failed and why
|
|
190
|
+
failed = [c for c in e.conditions if not c.result]
|
|
191
|
+
# e.g. [ConditionResult(field="pr_size", operator="lt", expected=50, result=False)]
|
|
192
|
+
|
|
193
|
+
for rule in failed:
|
|
194
|
+
if rule.field == "pr_size":
|
|
195
|
+
# Policy says PRs must be < 50 files — split and retry
|
|
196
|
+
mid = len(files) // 2
|
|
197
|
+
await commit_with_governance(files[:mid])
|
|
198
|
+
await commit_with_governance(files[mid:])
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# Reviewer denial or policy tamper — no retry
|
|
202
|
+
raise
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Error hierarchy
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
AgentLatticeError base — code, message, details
|
|
209
|
+
AgentLatticeDeniedError approval_id?, reason?, policy?, conditions?
|
|
210
|
+
AgentLatticeTimeoutError approval_id
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Reliability
|
|
214
|
+
|
|
215
|
+
`execute()` and `gate()` retry automatically on 5xx and network errors — up to 3 attempts with 1s/2s/4s exponential backoff. Each request has a 30-second timeout. Pass `event_id` to make retries idempotent.
|
|
216
|
+
|
|
217
|
+
`execute_sync()` and `gate_sync()` are safe in async runtimes (LangGraph, FastAPI, CrewAI) — they detect a running event loop and dispatch to a thread pool automatically.
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
MIT
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# agentlattice — Python SDK
|
|
2
|
+
|
|
3
|
+
Governance-aware SDK for AI agents. Wraps agent actions with audit trails,
|
|
4
|
+
approval gates, and circuit breaker integration.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install agentlattice
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quickstart
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import asyncio
|
|
16
|
+
import os
|
|
17
|
+
from agentlattice import AgentLattice
|
|
18
|
+
|
|
19
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
# gate() blocks until approved — your agent code only runs if it passes
|
|
23
|
+
await al.gate("pr.merge")
|
|
24
|
+
await merge_pr(42)
|
|
25
|
+
|
|
26
|
+
asyncio.run(main())
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Handle denials and timeouts:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from agentlattice import AgentLattice, AgentLatticeDeniedError, AgentLatticeTimeoutError
|
|
33
|
+
|
|
34
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
try:
|
|
38
|
+
await al.gate("code.commit")
|
|
39
|
+
except AgentLatticeDeniedError as e:
|
|
40
|
+
print(f"Denied: {e.reason}, policy: {e.policy}")
|
|
41
|
+
print(f"Failed conditions: {e.conditions}")
|
|
42
|
+
except AgentLatticeTimeoutError as e:
|
|
43
|
+
print(f"Approval timed out: {e.approval_id}")
|
|
44
|
+
|
|
45
|
+
asyncio.run(main())
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Sync usage
|
|
49
|
+
|
|
50
|
+
If you're not in an async context:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import os
|
|
54
|
+
from agentlattice import AgentLattice
|
|
55
|
+
|
|
56
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
57
|
+
al.gate_sync("code.commit")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### `AgentLattice(api_key, *, base_url?, gate_poll_timeout_ms?, gate_poll_interval_ms?)`
|
|
63
|
+
|
|
64
|
+
| Parameter | Default | Description |
|
|
65
|
+
|-----------|---------|-------------|
|
|
66
|
+
| `api_key` | required | Bearer token — pass via `os.environ["AL_API_KEY"]`, never hardcoded |
|
|
67
|
+
| `base_url` | `https://agentlattice.com` | Override for self-hosted or staging |
|
|
68
|
+
| `gate_poll_timeout_ms` | `8 * 60 * 60 * 1000` (8 hours) | How long `gate()` polls for approval |
|
|
69
|
+
| `gate_poll_interval_ms` | `5000` | Poll interval in ms |
|
|
70
|
+
|
|
71
|
+
### `await al.execute(action_type, options?)`
|
|
72
|
+
|
|
73
|
+
Submit an action and return immediately. Returns an `ActionResult`. Does not block.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from agentlattice import AgentLattice, ActionOptions
|
|
77
|
+
|
|
78
|
+
al = AgentLattice(api_key="al_...")
|
|
79
|
+
result = await al.execute("pr.open", ActionOptions(
|
|
80
|
+
data_accessed=[{"type": "source_code", "count": 5, "sensitivity": "low"}],
|
|
81
|
+
metadata={"pr_number": 42},
|
|
82
|
+
event_id="my-idempotency-key", # optional: dedup by your own key
|
|
83
|
+
))
|
|
84
|
+
|
|
85
|
+
if result.status == "executed":
|
|
86
|
+
print(f"Auto-executed under policy: {result.policy_name}")
|
|
87
|
+
elif result.status == "requested":
|
|
88
|
+
print(f"Awaiting approval: {result.approval_id}")
|
|
89
|
+
elif result.status == "denied":
|
|
90
|
+
print(f"Denied ({result.denial_reason}): {result.conditions_evaluated}")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `await al.gate(action_type, options?)`
|
|
94
|
+
|
|
95
|
+
Submit an action and block until it is approved or denied.
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
try:
|
|
99
|
+
await al.gate("pr.merge")
|
|
100
|
+
except AgentLatticeDeniedError as e:
|
|
101
|
+
# e.reason: "CONDITIONS_DENIED" | "POLICY_TAMPERED" | "DENIED_BY_REVIEWER"
|
|
102
|
+
# e.policy: name of the governing policy (if conditions-based)
|
|
103
|
+
# e.conditions: list of ConditionResult (which rule failed and why)
|
|
104
|
+
# e.approval_id: set if a human reviewer denied it
|
|
105
|
+
...
|
|
106
|
+
except AgentLatticeTimeoutError as e:
|
|
107
|
+
# e.approval_id: the approval that timed out
|
|
108
|
+
...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `al.gate_sync(action_type, options?)` / `al.execute_sync(action_type, options?)`
|
|
112
|
+
|
|
113
|
+
Synchronous wrappers — identical semantics, no `asyncio.run()` needed.
|
|
114
|
+
|
|
115
|
+
## ActionResult
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
@dataclass
|
|
119
|
+
class ActionResult:
|
|
120
|
+
status: str # "executed" | "requested" | "denied" | ...
|
|
121
|
+
audit_event_id: str
|
|
122
|
+
approval_id: str | None # set when status="requested"
|
|
123
|
+
message: str | None
|
|
124
|
+
timeout_at: str | None
|
|
125
|
+
denial_reason: str | None # "CONDITIONS_DENIED" | "POLICY_TAMPERED" | ...
|
|
126
|
+
policy_name: str | None # governing policy name
|
|
127
|
+
conditions_evaluated: list[ConditionResult] # which rules passed/failed
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## ConditionResult
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
@dataclass
|
|
134
|
+
class ConditionResult:
|
|
135
|
+
field: str # e.g. "pr_size"
|
|
136
|
+
operator: str # e.g. "lt"
|
|
137
|
+
expected: Any # e.g. 100
|
|
138
|
+
result: bool # True = passed, False = failed
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Agents can read `conditions_evaluated` to understand exactly which governance
|
|
142
|
+
rule blocked them and adapt their behavior accordingly.
|
|
143
|
+
|
|
144
|
+
## Self-correcting agent pattern
|
|
145
|
+
|
|
146
|
+
`conditions_evaluated` is what makes this more than a compliance layer — it
|
|
147
|
+
closes the feedback loop so agents can adapt, not just fail.
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from agentlattice import AgentLattice, AgentLatticeDeniedError, ActionOptions
|
|
151
|
+
|
|
152
|
+
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
|
|
153
|
+
|
|
154
|
+
async def commit_with_governance(files: list[str]) -> None:
|
|
155
|
+
try:
|
|
156
|
+
await al.gate("pr.open", ActionOptions(
|
|
157
|
+
metadata={"pr_size": len(files), "repo": "acme/backend"},
|
|
158
|
+
))
|
|
159
|
+
await open_pr(files)
|
|
160
|
+
|
|
161
|
+
except AgentLatticeDeniedError as e:
|
|
162
|
+
if e.reason == "CONDITIONS_DENIED":
|
|
163
|
+
# Find which rules failed and why
|
|
164
|
+
failed = [c for c in e.conditions if not c.result]
|
|
165
|
+
# e.g. [ConditionResult(field="pr_size", operator="lt", expected=50, result=False)]
|
|
166
|
+
|
|
167
|
+
for rule in failed:
|
|
168
|
+
if rule.field == "pr_size":
|
|
169
|
+
# Policy says PRs must be < 50 files — split and retry
|
|
170
|
+
mid = len(files) // 2
|
|
171
|
+
await commit_with_governance(files[:mid])
|
|
172
|
+
await commit_with_governance(files[mid:])
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
# Reviewer denial or policy tamper — no retry
|
|
176
|
+
raise
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Error hierarchy
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
AgentLatticeError base — code, message, details
|
|
183
|
+
AgentLatticeDeniedError approval_id?, reason?, policy?, conditions?
|
|
184
|
+
AgentLatticeTimeoutError approval_id
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Reliability
|
|
188
|
+
|
|
189
|
+
`execute()` and `gate()` retry automatically on 5xx and network errors — up to 3 attempts with 1s/2s/4s exponential backoff. Each request has a 30-second timeout. Pass `event_id` to make retries idempotent.
|
|
190
|
+
|
|
191
|
+
`execute_sync()` and `gate_sync()` are safe in async runtimes (LangGraph, FastAPI, CrewAI) — they detect a running event loop and dispatch to a thread pool automatically.
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentlattice — Governance SDK for AI agents.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
import asyncio
|
|
6
|
+
from agentlattice import AgentLattice, AgentLatticeDeniedError
|
|
7
|
+
|
|
8
|
+
al = AgentLattice(api_key="al_...")
|
|
9
|
+
|
|
10
|
+
# gate() blocks until approved (or raises if denied/timeout)
|
|
11
|
+
async def main():
|
|
12
|
+
await al.gate("code.commit")
|
|
13
|
+
|
|
14
|
+
asyncio.run(main())
|
|
15
|
+
|
|
16
|
+
# Sync wrappers if you're not in an async context
|
|
17
|
+
al.gate_sync("code.commit")
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from agentlattice.client import (
|
|
21
|
+
AgentLattice,
|
|
22
|
+
AgentLatticeError,
|
|
23
|
+
AgentLatticeDeniedError,
|
|
24
|
+
AgentLatticeTimeoutError,
|
|
25
|
+
ActionResult,
|
|
26
|
+
ActionOptions,
|
|
27
|
+
ConditionResult,
|
|
28
|
+
DelegatedAgent,
|
|
29
|
+
DelegationContext,
|
|
30
|
+
SyncDelegationContext,
|
|
31
|
+
ParallelDelegation,
|
|
32
|
+
SyncParallelDelegation,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"AgentLattice",
|
|
37
|
+
"AgentLatticeError",
|
|
38
|
+
"AgentLatticeDeniedError",
|
|
39
|
+
"AgentLatticeTimeoutError",
|
|
40
|
+
"ActionResult",
|
|
41
|
+
"ActionOptions",
|
|
42
|
+
"ConditionResult",
|
|
43
|
+
"DelegatedAgent",
|
|
44
|
+
"DelegationContext",
|
|
45
|
+
"SyncDelegationContext",
|
|
46
|
+
"ParallelDelegation",
|
|
47
|
+
"SyncParallelDelegation",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
__version__ = "0.3.0"
|