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.
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ *.egg
@@ -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"