aigp-python 1.0.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.
- aigp_python-1.0.0/.gitignore +29 -0
- aigp_python-1.0.0/PKG-INFO +280 -0
- aigp_python-1.0.0/README.md +249 -0
- aigp_python-1.0.0/aigp/__init__.py +128 -0
- aigp_python-1.0.0/aigp/attributes.py +129 -0
- aigp_python-1.0.0/aigp/baggage.py +126 -0
- aigp_python-1.0.0/aigp/cloudevents.py +264 -0
- aigp_python-1.0.0/aigp/decorators.py +747 -0
- aigp_python-1.0.0/aigp/events.py +535 -0
- aigp_python-1.0.0/aigp/instrumentor.py +1312 -0
- aigp_python-1.0.0/aigp/openlineage.py +249 -0
- aigp_python-1.0.0/aigp/tracestate.py +149 -0
- aigp_python-1.0.0/examples/end_to_end.py +1005 -0
- aigp_python-1.0.0/pyproject.toml +53 -0
- aigp_python-1.0.0/tests/__init__.py +0 -0
- aigp_python-1.0.0/tests/test_cloudevents.py +341 -0
- aigp_python-1.0.0/tests/test_decorators.py +542 -0
- aigp_python-1.0.0/tests/test_events.py +199 -0
- aigp_python-1.0.0/tests/test_merkle.py +620 -0
- aigp_python-1.0.0/tests/test_new_events.py +632 -0
- aigp_python-1.0.0/tests/test_openlineage.py +324 -0
- aigp_python-1.0.0/tests/test_tracestate.py +98 -0
- aigp_python-1.0.0/tests/test_v080_features.py +428 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
Thumbs.db
|
|
4
|
+
|
|
5
|
+
# Editors
|
|
6
|
+
.vscode/
|
|
7
|
+
.idea/
|
|
8
|
+
*.swp
|
|
9
|
+
*.swo
|
|
10
|
+
*~
|
|
11
|
+
|
|
12
|
+
# Node (for test tooling)
|
|
13
|
+
node_modules/
|
|
14
|
+
package-lock.json
|
|
15
|
+
|
|
16
|
+
# Python (for test tooling)
|
|
17
|
+
__pycache__/
|
|
18
|
+
*.pyc
|
|
19
|
+
*.pyo
|
|
20
|
+
.venv/
|
|
21
|
+
venv/
|
|
22
|
+
|
|
23
|
+
# Environment
|
|
24
|
+
.env
|
|
25
|
+
.env.local
|
|
26
|
+
|
|
27
|
+
# Build artifacts
|
|
28
|
+
dist/
|
|
29
|
+
build/
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aigp-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AIGP — AI Governance Proof. Open standard for proving your AI agents used the approved policies, prompts, and tools.
|
|
5
|
+
Project-URL: Homepage, https://github.com/open-aigp/aigp
|
|
6
|
+
Project-URL: Documentation, https://github.com/open-aigp/aigp/tree/main/sdks/python
|
|
7
|
+
Project-URL: Repository, https://github.com/open-aigp/aigp
|
|
8
|
+
Project-URL: Issues, https://github.com/open-aigp/aigp/issues
|
|
9
|
+
Author: AIGP Community
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Keywords: ai-agents,ai-governance,aigp,audit,governance,lineage,merkle-proof,openlineage,opentelemetry,tracing
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: System :: Monitoring
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: opentelemetry-api>=1.20.0
|
|
24
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
|
+
Provides-Extra: exporters
|
|
29
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'exporters'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# AIGP-OpenTelemetry Python SDK
|
|
33
|
+
|
|
34
|
+
[](../../LICENSE)
|
|
35
|
+
[](https://www.python.org/)
|
|
36
|
+
|
|
37
|
+
**Bridge between AIGP governance events and OpenTelemetry spans.**
|
|
38
|
+
|
|
39
|
+
AIGP is the governance-proof semantic payload. OpenTelemetry is the transport and correlation layer. This SDK handles dual-emit: every governance action produces both an AIGP event (compliance store) and an OTel span event (observability backend).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install opentelemetry-api opentelemetry-sdk
|
|
47
|
+
|
|
48
|
+
# Then add this package to your project
|
|
49
|
+
# (from the AIGP repo root)
|
|
50
|
+
pip install -e sdks/python/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from opentelemetry import trace
|
|
57
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
58
|
+
from opentelemetry.sdk.resources import Resource
|
|
59
|
+
|
|
60
|
+
from aigp import AIGPInstrumentor
|
|
61
|
+
|
|
62
|
+
# 1. Initialize with AIGP Resource attributes
|
|
63
|
+
instrumentor = AIGPInstrumentor(
|
|
64
|
+
agent_id="agent.trading-bot-v2",
|
|
65
|
+
agent_name="Trading Bot",
|
|
66
|
+
org_id="org.finco",
|
|
67
|
+
event_callback=send_to_store, # your AI governance store
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
resource = Resource.create({
|
|
71
|
+
**instrumentor.get_resource_attributes(),
|
|
72
|
+
"service.name": "trading-bot-v2",
|
|
73
|
+
})
|
|
74
|
+
provider = TracerProvider(resource=resource)
|
|
75
|
+
trace.set_tracer_provider(provider)
|
|
76
|
+
tracer = trace.get_tracer("aigp.example")
|
|
77
|
+
|
|
78
|
+
# 2. Emit governance events within OTel spans
|
|
79
|
+
with tracer.start_as_current_span("invoke_agent") as span:
|
|
80
|
+
event = instrumentor.inject_success(
|
|
81
|
+
policy_name="policy.trading-limits",
|
|
82
|
+
policy_version=4,
|
|
83
|
+
content="Max position: $10M...",
|
|
84
|
+
data_classification="confidential",
|
|
85
|
+
)
|
|
86
|
+
# -> AIGP event sent to AI governance store (compliance)
|
|
87
|
+
# -> OTel span event with aigp.* attributes (observability)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Features
|
|
91
|
+
|
|
92
|
+
### Dual-Emit Architecture
|
|
93
|
+
|
|
94
|
+
Every call produces two outputs automatically:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
instrumentor.inject_success(...)
|
|
98
|
+
|
|
|
99
|
+
+---> AIGP Event (JSON) ---> event_callback (AI governance store)
|
|
100
|
+
|
|
|
101
|
+
+---> OTel Span Event -----> OTel-compatible observability backend
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Supported Event Types
|
|
105
|
+
|
|
106
|
+
| Method | AIGP Event Type | OTel Span Event |
|
|
107
|
+
|--------|----------------|-----------------|
|
|
108
|
+
| `inject_success()` | `INJECT_SUCCESS` | `aigp.inject.success` |
|
|
109
|
+
| `inject_denied()` | `INJECT_DENIED` | `aigp.inject.denied` |
|
|
110
|
+
| `prompt_used()` | `PROMPT_USED` | `aigp.prompt.used` |
|
|
111
|
+
| `prompt_denied()` | `PROMPT_DENIED` | `aigp.prompt.denied` |
|
|
112
|
+
| `policy_violation()` | `POLICY_VIOLATION` | `aigp.policy.violation` |
|
|
113
|
+
| `a2a_call()` | `A2A_CALL` | `aigp.a2a.call` |
|
|
114
|
+
| `governance_proof()` | `GOVERNANCE_PROOF` | `aigp.governance.proof` |
|
|
115
|
+
| `multi_policy_inject()` | `INJECT_SUCCESS` | `aigp.inject.success` (with array attributes) |
|
|
116
|
+
| `multi_resource_governance_proof()` | `GOVERNANCE_PROOF` | `aigp.governance.proof` (with Merkle tree) |
|
|
117
|
+
|
|
118
|
+
### Multi-Policy / Multi-Prompt Support
|
|
119
|
+
|
|
120
|
+
When an agent is governed by multiple policies simultaneously:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
event = instrumentor.multi_policy_inject(
|
|
124
|
+
policies=[
|
|
125
|
+
{"name": "policy.trading-limits", "version": 4},
|
|
126
|
+
{"name": "policy.risk-controls", "version": 2},
|
|
127
|
+
],
|
|
128
|
+
content="Combined governed content...",
|
|
129
|
+
data_classification="confidential",
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This produces OTel array-valued attributes:
|
|
134
|
+
```
|
|
135
|
+
aigp.policies.names = ["policy.trading-limits", "policy.risk-controls"]
|
|
136
|
+
aigp.policies.versions = [4, 2]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Merkle Tree Governance Hash
|
|
140
|
+
|
|
141
|
+
When an agent is governed by multiple resources (policies, prompts, tools, contexts, lineage), compute a Merkle tree for per-resource verification:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from aigp.events import compute_merkle_governance_hash
|
|
145
|
+
|
|
146
|
+
resources = [
|
|
147
|
+
("policy", "policy.refund-limits", "Refund max: $500..."),
|
|
148
|
+
("prompt", "prompt.customer-support-v3", "You are a helpful..."),
|
|
149
|
+
("tool", "tool.order-lookup", '{"name": "order-lookup", "scope": "read"}'),
|
|
150
|
+
("context", "context.env-config", '{"env": "production", "region": "us-east-1"}'),
|
|
151
|
+
("lineage", "lineage.upstream-orders", '{"datasets": ["orders", "customers"]}'),
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
root_hash, merkle_tree = compute_merkle_governance_hash(resources)
|
|
155
|
+
# root_hash: "a3f2b8..." (Merkle root, used as governance_hash)
|
|
156
|
+
# merkle_tree: {"algorithm": "sha256", "leaf_count": 5, "leaves": [...]}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Or use the instrumentor for triple-emit with Merkle:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
event = instrumentor.multi_resource_governance_proof(
|
|
163
|
+
resources=[
|
|
164
|
+
("policy", "policy.refund-limits", "Refund max: $500..."),
|
|
165
|
+
("prompt", "prompt.customer-support-v3", "You are a helpful..."),
|
|
166
|
+
("tool", "tool.order-lookup", '{"name": "order-lookup"}'),
|
|
167
|
+
("context", "context.env-config", '{"env": "production"}'),
|
|
168
|
+
("lineage", "lineage.upstream-orders", '{"datasets": ["orders"]}'),
|
|
169
|
+
],
|
|
170
|
+
data_classification="confidential",
|
|
171
|
+
)
|
|
172
|
+
# governance_hash is the Merkle root
|
|
173
|
+
# hash_type is "merkle-sha256"
|
|
174
|
+
# governance_merkle_tree contains per-resource leaf hashes
|
|
175
|
+
# OTel span event carries aigp.governance.merkle.leaf_count
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Single-resource calls continue to produce flat SHA-256 hashes for full backward compatibility.
|
|
179
|
+
|
|
180
|
+
### Baggage Propagation (Agent-to-Agent)
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from aigp.baggage import AIGPBaggage
|
|
184
|
+
|
|
185
|
+
# Calling agent: inject governance context
|
|
186
|
+
ctx = AIGPBaggage.inject(
|
|
187
|
+
policy_name="policy.trading-limits",
|
|
188
|
+
data_classification="confidential",
|
|
189
|
+
org_id="org.finco",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Receiving agent: extract governance context
|
|
193
|
+
extracted = AIGPBaggage.extract()
|
|
194
|
+
# {'aigp.policy.name': 'policy.trading-limits', ...}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### W3C tracestate Vendor Key
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from aigp.tracestate import AIGPTraceState
|
|
201
|
+
|
|
202
|
+
# Encode AIGP into tracestate
|
|
203
|
+
tracestate = AIGPTraceState.inject_into_tracestate(
|
|
204
|
+
existing_tracestate="dd=s:1",
|
|
205
|
+
data_classification="confidential",
|
|
206
|
+
policy_name="policy.trading-limits",
|
|
207
|
+
policy_version=4,
|
|
208
|
+
)
|
|
209
|
+
# "aigp=cls:con;pol:policy.trading-limits;ver:4,dd=s:1"
|
|
210
|
+
|
|
211
|
+
# Decode on receiving side
|
|
212
|
+
context = AIGPTraceState.extract_from_tracestate(tracestate)
|
|
213
|
+
# {'data_classification': 'confidential', 'policy_name': 'policy.trading-limits', ...}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### OpenLineage Facet Builder
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from aigp.openlineage import build_openlineage_run_event
|
|
220
|
+
from aigp.events import compute_merkle_governance_hash, create_aigp_event
|
|
221
|
+
|
|
222
|
+
# Context + lineage resources as governed inputs
|
|
223
|
+
resources = [
|
|
224
|
+
("policy", "policy.fair-lending", policy_content),
|
|
225
|
+
("prompt", "prompt.scoring-v3", prompt_content),
|
|
226
|
+
("context", "context.env-config", env_config_json),
|
|
227
|
+
("lineage", "lineage.upstream-orders", lineage_snapshot_json),
|
|
228
|
+
]
|
|
229
|
+
root, tree = compute_merkle_governance_hash(resources)
|
|
230
|
+
|
|
231
|
+
aigp_event = create_aigp_event(
|
|
232
|
+
event_type="GOVERNANCE_PROOF",
|
|
233
|
+
event_category="governance-proof",
|
|
234
|
+
agent_id="agent.credit-scorer-v2",
|
|
235
|
+
trace_id="abc123...",
|
|
236
|
+
governance_hash=root,
|
|
237
|
+
hash_type="merkle-sha256",
|
|
238
|
+
governance_merkle_tree=tree,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Build OpenLineage RunEvent (zero OL dependency)
|
|
242
|
+
ol_event = build_openlineage_run_event(
|
|
243
|
+
aigp_event,
|
|
244
|
+
job_namespace="finco.scoring",
|
|
245
|
+
job_name="credit-scorer-v2.invoke",
|
|
246
|
+
)
|
|
247
|
+
# Send to any OpenLineage-compatible lineage backend
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Modules
|
|
251
|
+
|
|
252
|
+
| Module | Purpose |
|
|
253
|
+
|--------|---------|
|
|
254
|
+
| `aigp.instrumentor` | Core triple-emit bridge (`AIGPInstrumentor`) |
|
|
255
|
+
| `aigp.attributes` | `aigp.*` semantic attribute constants |
|
|
256
|
+
| `aigp.events` | AIGP event creation, hash computation, and Merkle tree |
|
|
257
|
+
| `aigp.openlineage` | OpenLineage facet builder (zero OL dependency) |
|
|
258
|
+
| `aigp.baggage` | OTel Baggage propagation for A2A calls |
|
|
259
|
+
| `aigp.tracestate` | W3C tracestate vendor key encode/decode |
|
|
260
|
+
|
|
261
|
+
## Running Tests
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
cd sdks/python
|
|
265
|
+
pip install opentelemetry-api opentelemetry-sdk pytest
|
|
266
|
+
PYTHONPATH=. pytest tests/ -v
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Running the End-to-End Example
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
cd sdks/python
|
|
273
|
+
PYTHONPATH=. python examples/end_to_end.py
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Related Documentation
|
|
277
|
+
|
|
278
|
+
- [AIGP Specification](../../spec/aigp-spec.md) (Sections 11.4-11.7)
|
|
279
|
+
- [AIGP OTel Semantic Conventions](../../integrations/opentelemetry/semantic-conventions.md)
|
|
280
|
+
- [OTel Collector Reference Config](../../integrations/opentelemetry/collector-config.yaml)
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# AIGP-OpenTelemetry Python SDK
|
|
2
|
+
|
|
3
|
+
[](../../LICENSE)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
|
|
6
|
+
**Bridge between AIGP governance events and OpenTelemetry spans.**
|
|
7
|
+
|
|
8
|
+
AIGP is the governance-proof semantic payload. OpenTelemetry is the transport and correlation layer. This SDK handles dual-emit: every governance action produces both an AIGP event (compliance store) and an OTel span event (observability backend).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install opentelemetry-api opentelemetry-sdk
|
|
16
|
+
|
|
17
|
+
# Then add this package to your project
|
|
18
|
+
# (from the AIGP repo root)
|
|
19
|
+
pip install -e sdks/python/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from opentelemetry import trace
|
|
26
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
27
|
+
from opentelemetry.sdk.resources import Resource
|
|
28
|
+
|
|
29
|
+
from aigp import AIGPInstrumentor
|
|
30
|
+
|
|
31
|
+
# 1. Initialize with AIGP Resource attributes
|
|
32
|
+
instrumentor = AIGPInstrumentor(
|
|
33
|
+
agent_id="agent.trading-bot-v2",
|
|
34
|
+
agent_name="Trading Bot",
|
|
35
|
+
org_id="org.finco",
|
|
36
|
+
event_callback=send_to_store, # your AI governance store
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
resource = Resource.create({
|
|
40
|
+
**instrumentor.get_resource_attributes(),
|
|
41
|
+
"service.name": "trading-bot-v2",
|
|
42
|
+
})
|
|
43
|
+
provider = TracerProvider(resource=resource)
|
|
44
|
+
trace.set_tracer_provider(provider)
|
|
45
|
+
tracer = trace.get_tracer("aigp.example")
|
|
46
|
+
|
|
47
|
+
# 2. Emit governance events within OTel spans
|
|
48
|
+
with tracer.start_as_current_span("invoke_agent") as span:
|
|
49
|
+
event = instrumentor.inject_success(
|
|
50
|
+
policy_name="policy.trading-limits",
|
|
51
|
+
policy_version=4,
|
|
52
|
+
content="Max position: $10M...",
|
|
53
|
+
data_classification="confidential",
|
|
54
|
+
)
|
|
55
|
+
# -> AIGP event sent to AI governance store (compliance)
|
|
56
|
+
# -> OTel span event with aigp.* attributes (observability)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
### Dual-Emit Architecture
|
|
62
|
+
|
|
63
|
+
Every call produces two outputs automatically:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
instrumentor.inject_success(...)
|
|
67
|
+
|
|
|
68
|
+
+---> AIGP Event (JSON) ---> event_callback (AI governance store)
|
|
69
|
+
|
|
|
70
|
+
+---> OTel Span Event -----> OTel-compatible observability backend
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Supported Event Types
|
|
74
|
+
|
|
75
|
+
| Method | AIGP Event Type | OTel Span Event |
|
|
76
|
+
|--------|----------------|-----------------|
|
|
77
|
+
| `inject_success()` | `INJECT_SUCCESS` | `aigp.inject.success` |
|
|
78
|
+
| `inject_denied()` | `INJECT_DENIED` | `aigp.inject.denied` |
|
|
79
|
+
| `prompt_used()` | `PROMPT_USED` | `aigp.prompt.used` |
|
|
80
|
+
| `prompt_denied()` | `PROMPT_DENIED` | `aigp.prompt.denied` |
|
|
81
|
+
| `policy_violation()` | `POLICY_VIOLATION` | `aigp.policy.violation` |
|
|
82
|
+
| `a2a_call()` | `A2A_CALL` | `aigp.a2a.call` |
|
|
83
|
+
| `governance_proof()` | `GOVERNANCE_PROOF` | `aigp.governance.proof` |
|
|
84
|
+
| `multi_policy_inject()` | `INJECT_SUCCESS` | `aigp.inject.success` (with array attributes) |
|
|
85
|
+
| `multi_resource_governance_proof()` | `GOVERNANCE_PROOF` | `aigp.governance.proof` (with Merkle tree) |
|
|
86
|
+
|
|
87
|
+
### Multi-Policy / Multi-Prompt Support
|
|
88
|
+
|
|
89
|
+
When an agent is governed by multiple policies simultaneously:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
event = instrumentor.multi_policy_inject(
|
|
93
|
+
policies=[
|
|
94
|
+
{"name": "policy.trading-limits", "version": 4},
|
|
95
|
+
{"name": "policy.risk-controls", "version": 2},
|
|
96
|
+
],
|
|
97
|
+
content="Combined governed content...",
|
|
98
|
+
data_classification="confidential",
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This produces OTel array-valued attributes:
|
|
103
|
+
```
|
|
104
|
+
aigp.policies.names = ["policy.trading-limits", "policy.risk-controls"]
|
|
105
|
+
aigp.policies.versions = [4, 2]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Merkle Tree Governance Hash
|
|
109
|
+
|
|
110
|
+
When an agent is governed by multiple resources (policies, prompts, tools, contexts, lineage), compute a Merkle tree for per-resource verification:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from aigp.events import compute_merkle_governance_hash
|
|
114
|
+
|
|
115
|
+
resources = [
|
|
116
|
+
("policy", "policy.refund-limits", "Refund max: $500..."),
|
|
117
|
+
("prompt", "prompt.customer-support-v3", "You are a helpful..."),
|
|
118
|
+
("tool", "tool.order-lookup", '{"name": "order-lookup", "scope": "read"}'),
|
|
119
|
+
("context", "context.env-config", '{"env": "production", "region": "us-east-1"}'),
|
|
120
|
+
("lineage", "lineage.upstream-orders", '{"datasets": ["orders", "customers"]}'),
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
root_hash, merkle_tree = compute_merkle_governance_hash(resources)
|
|
124
|
+
# root_hash: "a3f2b8..." (Merkle root, used as governance_hash)
|
|
125
|
+
# merkle_tree: {"algorithm": "sha256", "leaf_count": 5, "leaves": [...]}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Or use the instrumentor for triple-emit with Merkle:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
event = instrumentor.multi_resource_governance_proof(
|
|
132
|
+
resources=[
|
|
133
|
+
("policy", "policy.refund-limits", "Refund max: $500..."),
|
|
134
|
+
("prompt", "prompt.customer-support-v3", "You are a helpful..."),
|
|
135
|
+
("tool", "tool.order-lookup", '{"name": "order-lookup"}'),
|
|
136
|
+
("context", "context.env-config", '{"env": "production"}'),
|
|
137
|
+
("lineage", "lineage.upstream-orders", '{"datasets": ["orders"]}'),
|
|
138
|
+
],
|
|
139
|
+
data_classification="confidential",
|
|
140
|
+
)
|
|
141
|
+
# governance_hash is the Merkle root
|
|
142
|
+
# hash_type is "merkle-sha256"
|
|
143
|
+
# governance_merkle_tree contains per-resource leaf hashes
|
|
144
|
+
# OTel span event carries aigp.governance.merkle.leaf_count
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Single-resource calls continue to produce flat SHA-256 hashes for full backward compatibility.
|
|
148
|
+
|
|
149
|
+
### Baggage Propagation (Agent-to-Agent)
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from aigp.baggage import AIGPBaggage
|
|
153
|
+
|
|
154
|
+
# Calling agent: inject governance context
|
|
155
|
+
ctx = AIGPBaggage.inject(
|
|
156
|
+
policy_name="policy.trading-limits",
|
|
157
|
+
data_classification="confidential",
|
|
158
|
+
org_id="org.finco",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Receiving agent: extract governance context
|
|
162
|
+
extracted = AIGPBaggage.extract()
|
|
163
|
+
# {'aigp.policy.name': 'policy.trading-limits', ...}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### W3C tracestate Vendor Key
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from aigp.tracestate import AIGPTraceState
|
|
170
|
+
|
|
171
|
+
# Encode AIGP into tracestate
|
|
172
|
+
tracestate = AIGPTraceState.inject_into_tracestate(
|
|
173
|
+
existing_tracestate="dd=s:1",
|
|
174
|
+
data_classification="confidential",
|
|
175
|
+
policy_name="policy.trading-limits",
|
|
176
|
+
policy_version=4,
|
|
177
|
+
)
|
|
178
|
+
# "aigp=cls:con;pol:policy.trading-limits;ver:4,dd=s:1"
|
|
179
|
+
|
|
180
|
+
# Decode on receiving side
|
|
181
|
+
context = AIGPTraceState.extract_from_tracestate(tracestate)
|
|
182
|
+
# {'data_classification': 'confidential', 'policy_name': 'policy.trading-limits', ...}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### OpenLineage Facet Builder
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from aigp.openlineage import build_openlineage_run_event
|
|
189
|
+
from aigp.events import compute_merkle_governance_hash, create_aigp_event
|
|
190
|
+
|
|
191
|
+
# Context + lineage resources as governed inputs
|
|
192
|
+
resources = [
|
|
193
|
+
("policy", "policy.fair-lending", policy_content),
|
|
194
|
+
("prompt", "prompt.scoring-v3", prompt_content),
|
|
195
|
+
("context", "context.env-config", env_config_json),
|
|
196
|
+
("lineage", "lineage.upstream-orders", lineage_snapshot_json),
|
|
197
|
+
]
|
|
198
|
+
root, tree = compute_merkle_governance_hash(resources)
|
|
199
|
+
|
|
200
|
+
aigp_event = create_aigp_event(
|
|
201
|
+
event_type="GOVERNANCE_PROOF",
|
|
202
|
+
event_category="governance-proof",
|
|
203
|
+
agent_id="agent.credit-scorer-v2",
|
|
204
|
+
trace_id="abc123...",
|
|
205
|
+
governance_hash=root,
|
|
206
|
+
hash_type="merkle-sha256",
|
|
207
|
+
governance_merkle_tree=tree,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Build OpenLineage RunEvent (zero OL dependency)
|
|
211
|
+
ol_event = build_openlineage_run_event(
|
|
212
|
+
aigp_event,
|
|
213
|
+
job_namespace="finco.scoring",
|
|
214
|
+
job_name="credit-scorer-v2.invoke",
|
|
215
|
+
)
|
|
216
|
+
# Send to any OpenLineage-compatible lineage backend
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Modules
|
|
220
|
+
|
|
221
|
+
| Module | Purpose |
|
|
222
|
+
|--------|---------|
|
|
223
|
+
| `aigp.instrumentor` | Core triple-emit bridge (`AIGPInstrumentor`) |
|
|
224
|
+
| `aigp.attributes` | `aigp.*` semantic attribute constants |
|
|
225
|
+
| `aigp.events` | AIGP event creation, hash computation, and Merkle tree |
|
|
226
|
+
| `aigp.openlineage` | OpenLineage facet builder (zero OL dependency) |
|
|
227
|
+
| `aigp.baggage` | OTel Baggage propagation for A2A calls |
|
|
228
|
+
| `aigp.tracestate` | W3C tracestate vendor key encode/decode |
|
|
229
|
+
|
|
230
|
+
## Running Tests
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
cd sdks/python
|
|
234
|
+
pip install opentelemetry-api opentelemetry-sdk pytest
|
|
235
|
+
PYTHONPATH=. pytest tests/ -v
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Running the End-to-End Example
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
cd sdks/python
|
|
242
|
+
PYTHONPATH=. python examples/end_to_end.py
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Related Documentation
|
|
246
|
+
|
|
247
|
+
- [AIGP Specification](../../spec/aigp-spec.md) (Sections 11.4-11.7)
|
|
248
|
+
- [AIGP OTel Semantic Conventions](../../integrations/opentelemetry/semantic-conventions.md)
|
|
249
|
+
- [OTel Collector Reference Config](../../integrations/opentelemetry/collector-config.yaml)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIGP — AI Governance Proof
|
|
3
|
+
==========================
|
|
4
|
+
|
|
5
|
+
Open standard for proving your AI agents used the approved
|
|
6
|
+
policies, prompts, and tools — every single time.
|
|
7
|
+
|
|
8
|
+
Quick Start::
|
|
9
|
+
|
|
10
|
+
pip install aigp-python sandarb
|
|
11
|
+
|
|
12
|
+
from aigp import configure, aigp
|
|
13
|
+
from sandarb import SandarbBackend
|
|
14
|
+
|
|
15
|
+
configure(
|
|
16
|
+
backend=SandarbBackend("https://api.sandarb.ai", token="..."),
|
|
17
|
+
agent_id="agent.my-bot-v1",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
@aigp(policy="policy.trading-limits")
|
|
21
|
+
def process_trade(order: dict, governance=None):
|
|
22
|
+
if governance.denied:
|
|
23
|
+
return {"error": governance.denial_reason}
|
|
24
|
+
return execute(order)
|
|
25
|
+
|
|
26
|
+
What AIGP does:
|
|
27
|
+
- Proves governance was delivered (Merkle proofs, cryptographic hashes)
|
|
28
|
+
- Emits standardized events (INJECT_SUCCESS, TOOL_INVOKED, A2A_CALL, ...)
|
|
29
|
+
- Transports via OpenTelemetry (dual-emit to governance store + observability)
|
|
30
|
+
- Stays vendor-neutral — any GovernanceBackend can plug in
|
|
31
|
+
|
|
32
|
+
What AIGP does NOT do:
|
|
33
|
+
- Dictate how governance works — that's the backend's job
|
|
34
|
+
- Provide policies, prompts, or tools — those come from your governance server
|
|
35
|
+
|
|
36
|
+
Website: https://open-aigp.org
|
|
37
|
+
GitHub: https://github.com/open-aigp/aigp
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# ── Core: what most developers need ──────────────────────────────────
|
|
41
|
+
|
|
42
|
+
from aigp.decorators import (
|
|
43
|
+
configure,
|
|
44
|
+
aigp,
|
|
45
|
+
aigp_action,
|
|
46
|
+
a2a_traced,
|
|
47
|
+
audit_action,
|
|
48
|
+
GovernanceBackend,
|
|
49
|
+
GovernanceResult,
|
|
50
|
+
GovernanceError,
|
|
51
|
+
GovernedActionContext,
|
|
52
|
+
get_backend,
|
|
53
|
+
get_instrumentor,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# ── Events & Proof ────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
from aigp.instrumentor import AIGPInstrumentor
|
|
59
|
+
from aigp.events import (
|
|
60
|
+
create_aigp_event,
|
|
61
|
+
compute_governance_hash,
|
|
62
|
+
compute_leaf_hash,
|
|
63
|
+
compute_merkle_governance_hash,
|
|
64
|
+
sign_event,
|
|
65
|
+
verify_event_signature,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# ── Context propagation (OTel integration) ────────────────────────────
|
|
69
|
+
|
|
70
|
+
from aigp.attributes import AIGPAttributes
|
|
71
|
+
from aigp.baggage import AIGPBaggage
|
|
72
|
+
from aigp.tracestate import AIGPTraceState
|
|
73
|
+
|
|
74
|
+
# ── OpenLineage integration ───────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
from aigp.openlineage import (
|
|
77
|
+
build_governance_run_facet,
|
|
78
|
+
build_resource_input_facets,
|
|
79
|
+
build_openlineage_run_event,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# ── CloudEvents transport ─────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
from aigp.cloudevents import (
|
|
85
|
+
wrap_as_cloudevent,
|
|
86
|
+
unwrap_from_cloudevent,
|
|
87
|
+
build_ce_headers,
|
|
88
|
+
ce_type_from_event_type,
|
|
89
|
+
event_type_from_ce_type,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
__version__ = "1.0.0"
|
|
93
|
+
__all__ = [
|
|
94
|
+
# ── Start here ──
|
|
95
|
+
"configure",
|
|
96
|
+
"aigp",
|
|
97
|
+
"aigp_action",
|
|
98
|
+
"a2a_traced",
|
|
99
|
+
"audit_action",
|
|
100
|
+
"GovernanceBackend",
|
|
101
|
+
"GovernanceResult",
|
|
102
|
+
"GovernanceError",
|
|
103
|
+
"GovernedActionContext",
|
|
104
|
+
"get_backend",
|
|
105
|
+
"get_instrumentor",
|
|
106
|
+
# ── Events & Proof ──
|
|
107
|
+
"AIGPInstrumentor",
|
|
108
|
+
"create_aigp_event",
|
|
109
|
+
"compute_governance_hash",
|
|
110
|
+
"compute_leaf_hash",
|
|
111
|
+
"compute_merkle_governance_hash",
|
|
112
|
+
"sign_event",
|
|
113
|
+
"verify_event_signature",
|
|
114
|
+
# ── Context propagation ──
|
|
115
|
+
"AIGPAttributes",
|
|
116
|
+
"AIGPBaggage",
|
|
117
|
+
"AIGPTraceState",
|
|
118
|
+
# ── OpenLineage ──
|
|
119
|
+
"build_governance_run_facet",
|
|
120
|
+
"build_resource_input_facets",
|
|
121
|
+
"build_openlineage_run_event",
|
|
122
|
+
# ── CloudEvents ──
|
|
123
|
+
"wrap_as_cloudevent",
|
|
124
|
+
"unwrap_from_cloudevent",
|
|
125
|
+
"build_ce_headers",
|
|
126
|
+
"ce_type_from_event_type",
|
|
127
|
+
"event_type_from_ce_type",
|
|
128
|
+
]
|