actaclad-agentguard 1.1.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.
- actaclad_agentguard-1.1.0/PKG-INFO +200 -0
- actaclad_agentguard-1.1.0/README.md +180 -0
- actaclad_agentguard-1.1.0/actaclad_agentguard.egg-info/PKG-INFO +200 -0
- actaclad_agentguard-1.1.0/actaclad_agentguard.egg-info/SOURCES.txt +16 -0
- actaclad_agentguard-1.1.0/actaclad_agentguard.egg-info/dependency_links.txt +1 -0
- actaclad_agentguard-1.1.0/actaclad_agentguard.egg-info/requires.txt +18 -0
- actaclad_agentguard-1.1.0/actaclad_agentguard.egg-info/top_level.txt +2 -0
- actaclad_agentguard-1.1.0/agentguard/__init__.py +3 -0
- actaclad_agentguard-1.1.0/agentguard/_config.py +34 -0
- actaclad_agentguard-1.1.0/agentguard/_dimensions.py +38 -0
- actaclad_agentguard-1.1.0/agentguard/_filtering.py +55 -0
- actaclad_agentguard-1.1.0/agentguard/_gemini.py +234 -0
- actaclad_agentguard-1.1.0/agentguard/_tracing.py +367 -0
- actaclad_agentguard-1.1.0/agentguard_sdk/__init__.py +23 -0
- actaclad_agentguard-1.1.0/agentguard_sdk/client.py +125 -0
- actaclad_agentguard-1.1.0/agentguard_sdk/langchain.py +43 -0
- actaclad_agentguard-1.1.0/pyproject.toml +40 -0
- actaclad_agentguard-1.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: actaclad-agentguard
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Agent Guard observability SDK for Python
|
|
5
|
+
Author: Agent Guard
|
|
6
|
+
Project-URL: Homepage, https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
10
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
|
|
11
|
+
Requires-Dist: traceloop-sdk>=0.33.0; python_version >= "3.10"
|
|
12
|
+
Provides-Extra: auto
|
|
13
|
+
Requires-Dist: traceloop-sdk>=0.33.0; python_version >= "3.10" and extra == "auto"
|
|
14
|
+
Provides-Extra: legacy
|
|
15
|
+
Requires-Dist: langfuse>=2.0.0; extra == "legacy"
|
|
16
|
+
Provides-Extra: langchain
|
|
17
|
+
Requires-Dist: langchain-core>=0.2.0; extra == "langchain"
|
|
18
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == "langchain"
|
|
19
|
+
Requires-Dist: langfuse>=2.0.0; extra == "langchain"
|
|
20
|
+
|
|
21
|
+
# AgentGuard SDK for Python
|
|
22
|
+
|
|
23
|
+
Install the package:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install agentguard
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The distribution is named `agentguard` and exposes the onboarding API as
|
|
30
|
+
`import agentguard`.
|
|
31
|
+
|
|
32
|
+
### Python version
|
|
33
|
+
|
|
34
|
+
- **Python 3.10+** — full auto-instrumentation. `pip install agentguard` pulls
|
|
35
|
+
`traceloop-sdk`, so OpenAI / Anthropic / Gemini calls are traced with no
|
|
36
|
+
per-call code.
|
|
37
|
+
- **Python 3.8 / 3.9** — installs and runs in **manual mode**. `traceloop-sdk`
|
|
38
|
+
requires 3.10, so it is skipped automatically (PEP 508 marker) and the SDK
|
|
39
|
+
falls back to manual export. Auto-instrumentation of providers is **not**
|
|
40
|
+
available; use `track()` and `record_generation()`. Gemini **sync** is still
|
|
41
|
+
traced by the SDK on 3.9; Gemini **batch** always uses `record_generation()`
|
|
42
|
+
(see below). To force the extra explicitly on 3.10+:
|
|
43
|
+
`pip install "agentguard[auto]"`.
|
|
44
|
+
|
|
45
|
+
You normally leave `AGENTGUARD_MODE=auto` (the default) — the SDK downgrades to
|
|
46
|
+
manual only when traceloop is unavailable. `context()` / `track()` are optional
|
|
47
|
+
enrichment on top of either mode, not a switch into manual mode.
|
|
48
|
+
|
|
49
|
+
## Environment
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
AGENTGUARD_HOST=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
53
|
+
AGENTGUARD_PUBLIC_KEY=pk-lf-...
|
|
54
|
+
AGENTGUARD_SECRET_KEY=sk-lf-...
|
|
55
|
+
APP_ENV=production
|
|
56
|
+
AGENTGUARD_MODE=auto
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Optional:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Drop infrastructure spans (DB, HTTP client, framework) at the exporter and
|
|
63
|
+
# keep only LLM/observation spans — reduces storage/egress. Default: false
|
|
64
|
+
# (full end-to-end agent traces are preserved).
|
|
65
|
+
AGENTGUARD_DROP_INFRA_SPANS=true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Compatibility env vars are also accepted:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
AGENTGUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
72
|
+
AGENT_GUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
73
|
+
AGENT_GUARD_PUBLIC_KEY=pk-lf-...
|
|
74
|
+
AGENT_GUARD_SECRET_KEY=sk-lf-...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use API keys from an existing AgentGuard project. The Python SDK does not create
|
|
78
|
+
console organizations or projects; create or select the project in the console,
|
|
79
|
+
then copy its public and secret keys into the environment.
|
|
80
|
+
|
|
81
|
+
## Layer 1 — Base Observability
|
|
82
|
+
|
|
83
|
+
Initialize once at startup before creating LLM clients:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import agentguard
|
|
87
|
+
|
|
88
|
+
agentguard.init(service_name="my-service")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then make LLM calls exactly as before:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from openai import OpenAI
|
|
95
|
+
|
|
96
|
+
resp = OpenAI().chat.completions.create(
|
|
97
|
+
model="gpt-4o",
|
|
98
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Optional Cohere/Mistral instrumentor warnings during startup are ignored by the
|
|
103
|
+
SDK. They do not block OpenAI or Gemini tracing when those clients are installed
|
|
104
|
+
and initialized after `agentguard.init()`.
|
|
105
|
+
|
|
106
|
+
## Layer 2 — Tenant Context
|
|
107
|
+
|
|
108
|
+
Set business/channel once per request:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
with agentguard.context(
|
|
112
|
+
business_id="caratlane",
|
|
113
|
+
channel="instagram_dm",
|
|
114
|
+
session_id=conversation_id,
|
|
115
|
+
):
|
|
116
|
+
handle_message(message)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Layer 3 — Feature Attribution
|
|
120
|
+
|
|
121
|
+
Wrap each feature-level LLM call:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
def handle_message(message):
|
|
125
|
+
with agentguard.track("sentiment"):
|
|
126
|
+
sentiment = run_sentiment(message)
|
|
127
|
+
|
|
128
|
+
with agentguard.track("reply"):
|
|
129
|
+
reply = run_reply(message)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`track()` emits groupable tags and filterable metadata:
|
|
133
|
+
|
|
134
|
+
- `business:*`
|
|
135
|
+
- `channel:*`
|
|
136
|
+
- `feature:*`
|
|
137
|
+
- `biz_channel:*`
|
|
138
|
+
- `biz_feat:*`
|
|
139
|
+
- `chan_feat:*`
|
|
140
|
+
- `biz_chan_feat:*`
|
|
141
|
+
|
|
142
|
+
## Gemini — sync vs batch
|
|
143
|
+
|
|
144
|
+
**Sync** calls (`client.models.generate_content(...)`) auto-trace on Python 3.9+.
|
|
145
|
+
**Batch** calls (`client.batches.create(...)`) are asynchronous — there are no
|
|
146
|
+
tokens at submit time, so auto-instrumentation cannot capture them. Record the
|
|
147
|
+
cost with `record_generation()` when you fetch the results:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
for line in batch_results: # each line carries usage_metadata
|
|
151
|
+
um = line.response.usage_metadata
|
|
152
|
+
agentguard.record_generation(
|
|
153
|
+
feature="transcription",
|
|
154
|
+
model="gemini-2.5-flash", # must be in the pricing table or cost shows 0
|
|
155
|
+
input_tokens=um.prompt_token_count,
|
|
156
|
+
output_tokens=um.candidates_token_count,
|
|
157
|
+
) # business/channel/session inherit the surrounding context()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`record_generation()` also covers any call auto-instrumentation can't reach —
|
|
161
|
+
custom/REST providers or an SDK without an instrumentor. Cost is computed
|
|
162
|
+
server-side from the model name; standard models work out of the box, new or
|
|
163
|
+
custom model names are added once in the AgentGuard console.
|
|
164
|
+
|
|
165
|
+
## Manual Smoke Test
|
|
166
|
+
|
|
167
|
+
Use `manual` mode to test export without real LLM calls:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
AGENTGUARD_MODE=manual python examples/smoke_test_agentguard.py \
|
|
171
|
+
--business-id caratlane \
|
|
172
|
+
--channel instagram_dm \
|
|
173
|
+
--flow-id checkout-flow \
|
|
174
|
+
--feature-id sentiment
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
PowerShell:
|
|
178
|
+
|
|
179
|
+
```powershell
|
|
180
|
+
$env:AGENTGUARD_MODE="manual"
|
|
181
|
+
python examples/smoke_test_agentguard.py `
|
|
182
|
+
--business-id caratlane `
|
|
183
|
+
--channel instagram_dm `
|
|
184
|
+
--flow-id checkout-flow `
|
|
185
|
+
--feature-id sentiment
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Legacy API Compatibility
|
|
189
|
+
|
|
190
|
+
The older `agentguard_sdk` module is still included:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from agentguard_sdk import AgentGuard
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
New onboarding docs should use:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
import agentguard
|
|
200
|
+
```
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# AgentGuard SDK for Python
|
|
2
|
+
|
|
3
|
+
Install the package:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install agentguard
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The distribution is named `agentguard` and exposes the onboarding API as
|
|
10
|
+
`import agentguard`.
|
|
11
|
+
|
|
12
|
+
### Python version
|
|
13
|
+
|
|
14
|
+
- **Python 3.10+** — full auto-instrumentation. `pip install agentguard` pulls
|
|
15
|
+
`traceloop-sdk`, so OpenAI / Anthropic / Gemini calls are traced with no
|
|
16
|
+
per-call code.
|
|
17
|
+
- **Python 3.8 / 3.9** — installs and runs in **manual mode**. `traceloop-sdk`
|
|
18
|
+
requires 3.10, so it is skipped automatically (PEP 508 marker) and the SDK
|
|
19
|
+
falls back to manual export. Auto-instrumentation of providers is **not**
|
|
20
|
+
available; use `track()` and `record_generation()`. Gemini **sync** is still
|
|
21
|
+
traced by the SDK on 3.9; Gemini **batch** always uses `record_generation()`
|
|
22
|
+
(see below). To force the extra explicitly on 3.10+:
|
|
23
|
+
`pip install "agentguard[auto]"`.
|
|
24
|
+
|
|
25
|
+
You normally leave `AGENTGUARD_MODE=auto` (the default) — the SDK downgrades to
|
|
26
|
+
manual only when traceloop is unavailable. `context()` / `track()` are optional
|
|
27
|
+
enrichment on top of either mode, not a switch into manual mode.
|
|
28
|
+
|
|
29
|
+
## Environment
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
AGENTGUARD_HOST=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
33
|
+
AGENTGUARD_PUBLIC_KEY=pk-lf-...
|
|
34
|
+
AGENTGUARD_SECRET_KEY=sk-lf-...
|
|
35
|
+
APP_ENV=production
|
|
36
|
+
AGENTGUARD_MODE=auto
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Optional:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Drop infrastructure spans (DB, HTTP client, framework) at the exporter and
|
|
43
|
+
# keep only LLM/observation spans — reduces storage/egress. Default: false
|
|
44
|
+
# (full end-to-end agent traces are preserved).
|
|
45
|
+
AGENTGUARD_DROP_INFRA_SPANS=true
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Compatibility env vars are also accepted:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
AGENTGUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
52
|
+
AGENT_GUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
53
|
+
AGENT_GUARD_PUBLIC_KEY=pk-lf-...
|
|
54
|
+
AGENT_GUARD_SECRET_KEY=sk-lf-...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Use API keys from an existing AgentGuard project. The Python SDK does not create
|
|
58
|
+
console organizations or projects; create or select the project in the console,
|
|
59
|
+
then copy its public and secret keys into the environment.
|
|
60
|
+
|
|
61
|
+
## Layer 1 — Base Observability
|
|
62
|
+
|
|
63
|
+
Initialize once at startup before creating LLM clients:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import agentguard
|
|
67
|
+
|
|
68
|
+
agentguard.init(service_name="my-service")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then make LLM calls exactly as before:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from openai import OpenAI
|
|
75
|
+
|
|
76
|
+
resp = OpenAI().chat.completions.create(
|
|
77
|
+
model="gpt-4o",
|
|
78
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Optional Cohere/Mistral instrumentor warnings during startup are ignored by the
|
|
83
|
+
SDK. They do not block OpenAI or Gemini tracing when those clients are installed
|
|
84
|
+
and initialized after `agentguard.init()`.
|
|
85
|
+
|
|
86
|
+
## Layer 2 — Tenant Context
|
|
87
|
+
|
|
88
|
+
Set business/channel once per request:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
with agentguard.context(
|
|
92
|
+
business_id="caratlane",
|
|
93
|
+
channel="instagram_dm",
|
|
94
|
+
session_id=conversation_id,
|
|
95
|
+
):
|
|
96
|
+
handle_message(message)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Layer 3 — Feature Attribution
|
|
100
|
+
|
|
101
|
+
Wrap each feature-level LLM call:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
def handle_message(message):
|
|
105
|
+
with agentguard.track("sentiment"):
|
|
106
|
+
sentiment = run_sentiment(message)
|
|
107
|
+
|
|
108
|
+
with agentguard.track("reply"):
|
|
109
|
+
reply = run_reply(message)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`track()` emits groupable tags and filterable metadata:
|
|
113
|
+
|
|
114
|
+
- `business:*`
|
|
115
|
+
- `channel:*`
|
|
116
|
+
- `feature:*`
|
|
117
|
+
- `biz_channel:*`
|
|
118
|
+
- `biz_feat:*`
|
|
119
|
+
- `chan_feat:*`
|
|
120
|
+
- `biz_chan_feat:*`
|
|
121
|
+
|
|
122
|
+
## Gemini — sync vs batch
|
|
123
|
+
|
|
124
|
+
**Sync** calls (`client.models.generate_content(...)`) auto-trace on Python 3.9+.
|
|
125
|
+
**Batch** calls (`client.batches.create(...)`) are asynchronous — there are no
|
|
126
|
+
tokens at submit time, so auto-instrumentation cannot capture them. Record the
|
|
127
|
+
cost with `record_generation()` when you fetch the results:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
for line in batch_results: # each line carries usage_metadata
|
|
131
|
+
um = line.response.usage_metadata
|
|
132
|
+
agentguard.record_generation(
|
|
133
|
+
feature="transcription",
|
|
134
|
+
model="gemini-2.5-flash", # must be in the pricing table or cost shows 0
|
|
135
|
+
input_tokens=um.prompt_token_count,
|
|
136
|
+
output_tokens=um.candidates_token_count,
|
|
137
|
+
) # business/channel/session inherit the surrounding context()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`record_generation()` also covers any call auto-instrumentation can't reach —
|
|
141
|
+
custom/REST providers or an SDK without an instrumentor. Cost is computed
|
|
142
|
+
server-side from the model name; standard models work out of the box, new or
|
|
143
|
+
custom model names are added once in the AgentGuard console.
|
|
144
|
+
|
|
145
|
+
## Manual Smoke Test
|
|
146
|
+
|
|
147
|
+
Use `manual` mode to test export without real LLM calls:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
AGENTGUARD_MODE=manual python examples/smoke_test_agentguard.py \
|
|
151
|
+
--business-id caratlane \
|
|
152
|
+
--channel instagram_dm \
|
|
153
|
+
--flow-id checkout-flow \
|
|
154
|
+
--feature-id sentiment
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
PowerShell:
|
|
158
|
+
|
|
159
|
+
```powershell
|
|
160
|
+
$env:AGENTGUARD_MODE="manual"
|
|
161
|
+
python examples/smoke_test_agentguard.py `
|
|
162
|
+
--business-id caratlane `
|
|
163
|
+
--channel instagram_dm `
|
|
164
|
+
--flow-id checkout-flow `
|
|
165
|
+
--feature-id sentiment
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Legacy API Compatibility
|
|
169
|
+
|
|
170
|
+
The older `agentguard_sdk` module is still included:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from agentguard_sdk import AgentGuard
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
New onboarding docs should use:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import agentguard
|
|
180
|
+
```
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: actaclad-agentguard
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Agent Guard observability SDK for Python
|
|
5
|
+
Author: Agent Guard
|
|
6
|
+
Project-URL: Homepage, https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
10
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
|
|
11
|
+
Requires-Dist: traceloop-sdk>=0.33.0; python_version >= "3.10"
|
|
12
|
+
Provides-Extra: auto
|
|
13
|
+
Requires-Dist: traceloop-sdk>=0.33.0; python_version >= "3.10" and extra == "auto"
|
|
14
|
+
Provides-Extra: legacy
|
|
15
|
+
Requires-Dist: langfuse>=2.0.0; extra == "legacy"
|
|
16
|
+
Provides-Extra: langchain
|
|
17
|
+
Requires-Dist: langchain-core>=0.2.0; extra == "langchain"
|
|
18
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == "langchain"
|
|
19
|
+
Requires-Dist: langfuse>=2.0.0; extra == "langchain"
|
|
20
|
+
|
|
21
|
+
# AgentGuard SDK for Python
|
|
22
|
+
|
|
23
|
+
Install the package:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install agentguard
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The distribution is named `agentguard` and exposes the onboarding API as
|
|
30
|
+
`import agentguard`.
|
|
31
|
+
|
|
32
|
+
### Python version
|
|
33
|
+
|
|
34
|
+
- **Python 3.10+** — full auto-instrumentation. `pip install agentguard` pulls
|
|
35
|
+
`traceloop-sdk`, so OpenAI / Anthropic / Gemini calls are traced with no
|
|
36
|
+
per-call code.
|
|
37
|
+
- **Python 3.8 / 3.9** — installs and runs in **manual mode**. `traceloop-sdk`
|
|
38
|
+
requires 3.10, so it is skipped automatically (PEP 508 marker) and the SDK
|
|
39
|
+
falls back to manual export. Auto-instrumentation of providers is **not**
|
|
40
|
+
available; use `track()` and `record_generation()`. Gemini **sync** is still
|
|
41
|
+
traced by the SDK on 3.9; Gemini **batch** always uses `record_generation()`
|
|
42
|
+
(see below). To force the extra explicitly on 3.10+:
|
|
43
|
+
`pip install "agentguard[auto]"`.
|
|
44
|
+
|
|
45
|
+
You normally leave `AGENTGUARD_MODE=auto` (the default) — the SDK downgrades to
|
|
46
|
+
manual only when traceloop is unavailable. `context()` / `track()` are optional
|
|
47
|
+
enrichment on top of either mode, not a switch into manual mode.
|
|
48
|
+
|
|
49
|
+
## Environment
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
AGENTGUARD_HOST=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
53
|
+
AGENTGUARD_PUBLIC_KEY=pk-lf-...
|
|
54
|
+
AGENTGUARD_SECRET_KEY=sk-lf-...
|
|
55
|
+
APP_ENV=production
|
|
56
|
+
AGENTGUARD_MODE=auto
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Optional:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Drop infrastructure spans (DB, HTTP client, framework) at the exporter and
|
|
63
|
+
# keep only LLM/observation spans — reduces storage/egress. Default: false
|
|
64
|
+
# (full end-to-end agent traces are preserved).
|
|
65
|
+
AGENTGUARD_DROP_INFRA_SPANS=true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Compatibility env vars are also accepted:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
AGENTGUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
72
|
+
AGENT_GUARD_BASE_URL=https://agentgaurd-a0acc6egbhced0dc.centralindia-01.azurewebsites.net
|
|
73
|
+
AGENT_GUARD_PUBLIC_KEY=pk-lf-...
|
|
74
|
+
AGENT_GUARD_SECRET_KEY=sk-lf-...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use API keys from an existing AgentGuard project. The Python SDK does not create
|
|
78
|
+
console organizations or projects; create or select the project in the console,
|
|
79
|
+
then copy its public and secret keys into the environment.
|
|
80
|
+
|
|
81
|
+
## Layer 1 — Base Observability
|
|
82
|
+
|
|
83
|
+
Initialize once at startup before creating LLM clients:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import agentguard
|
|
87
|
+
|
|
88
|
+
agentguard.init(service_name="my-service")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then make LLM calls exactly as before:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from openai import OpenAI
|
|
95
|
+
|
|
96
|
+
resp = OpenAI().chat.completions.create(
|
|
97
|
+
model="gpt-4o",
|
|
98
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Optional Cohere/Mistral instrumentor warnings during startup are ignored by the
|
|
103
|
+
SDK. They do not block OpenAI or Gemini tracing when those clients are installed
|
|
104
|
+
and initialized after `agentguard.init()`.
|
|
105
|
+
|
|
106
|
+
## Layer 2 — Tenant Context
|
|
107
|
+
|
|
108
|
+
Set business/channel once per request:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
with agentguard.context(
|
|
112
|
+
business_id="caratlane",
|
|
113
|
+
channel="instagram_dm",
|
|
114
|
+
session_id=conversation_id,
|
|
115
|
+
):
|
|
116
|
+
handle_message(message)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Layer 3 — Feature Attribution
|
|
120
|
+
|
|
121
|
+
Wrap each feature-level LLM call:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
def handle_message(message):
|
|
125
|
+
with agentguard.track("sentiment"):
|
|
126
|
+
sentiment = run_sentiment(message)
|
|
127
|
+
|
|
128
|
+
with agentguard.track("reply"):
|
|
129
|
+
reply = run_reply(message)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`track()` emits groupable tags and filterable metadata:
|
|
133
|
+
|
|
134
|
+
- `business:*`
|
|
135
|
+
- `channel:*`
|
|
136
|
+
- `feature:*`
|
|
137
|
+
- `biz_channel:*`
|
|
138
|
+
- `biz_feat:*`
|
|
139
|
+
- `chan_feat:*`
|
|
140
|
+
- `biz_chan_feat:*`
|
|
141
|
+
|
|
142
|
+
## Gemini — sync vs batch
|
|
143
|
+
|
|
144
|
+
**Sync** calls (`client.models.generate_content(...)`) auto-trace on Python 3.9+.
|
|
145
|
+
**Batch** calls (`client.batches.create(...)`) are asynchronous — there are no
|
|
146
|
+
tokens at submit time, so auto-instrumentation cannot capture them. Record the
|
|
147
|
+
cost with `record_generation()` when you fetch the results:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
for line in batch_results: # each line carries usage_metadata
|
|
151
|
+
um = line.response.usage_metadata
|
|
152
|
+
agentguard.record_generation(
|
|
153
|
+
feature="transcription",
|
|
154
|
+
model="gemini-2.5-flash", # must be in the pricing table or cost shows 0
|
|
155
|
+
input_tokens=um.prompt_token_count,
|
|
156
|
+
output_tokens=um.candidates_token_count,
|
|
157
|
+
) # business/channel/session inherit the surrounding context()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`record_generation()` also covers any call auto-instrumentation can't reach —
|
|
161
|
+
custom/REST providers or an SDK without an instrumentor. Cost is computed
|
|
162
|
+
server-side from the model name; standard models work out of the box, new or
|
|
163
|
+
custom model names are added once in the AgentGuard console.
|
|
164
|
+
|
|
165
|
+
## Manual Smoke Test
|
|
166
|
+
|
|
167
|
+
Use `manual` mode to test export without real LLM calls:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
AGENTGUARD_MODE=manual python examples/smoke_test_agentguard.py \
|
|
171
|
+
--business-id caratlane \
|
|
172
|
+
--channel instagram_dm \
|
|
173
|
+
--flow-id checkout-flow \
|
|
174
|
+
--feature-id sentiment
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
PowerShell:
|
|
178
|
+
|
|
179
|
+
```powershell
|
|
180
|
+
$env:AGENTGUARD_MODE="manual"
|
|
181
|
+
python examples/smoke_test_agentguard.py `
|
|
182
|
+
--business-id caratlane `
|
|
183
|
+
--channel instagram_dm `
|
|
184
|
+
--flow-id checkout-flow `
|
|
185
|
+
--feature-id sentiment
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Legacy API Compatibility
|
|
189
|
+
|
|
190
|
+
The older `agentguard_sdk` module is still included:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from agentguard_sdk import AgentGuard
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
New onboarding docs should use:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
import agentguard
|
|
200
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
actaclad_agentguard.egg-info/PKG-INFO
|
|
4
|
+
actaclad_agentguard.egg-info/SOURCES.txt
|
|
5
|
+
actaclad_agentguard.egg-info/dependency_links.txt
|
|
6
|
+
actaclad_agentguard.egg-info/requires.txt
|
|
7
|
+
actaclad_agentguard.egg-info/top_level.txt
|
|
8
|
+
agentguard/__init__.py
|
|
9
|
+
agentguard/_config.py
|
|
10
|
+
agentguard/_dimensions.py
|
|
11
|
+
agentguard/_filtering.py
|
|
12
|
+
agentguard/_gemini.py
|
|
13
|
+
agentguard/_tracing.py
|
|
14
|
+
agentguard_sdk/__init__.py
|
|
15
|
+
agentguard_sdk/client.py
|
|
16
|
+
agentguard_sdk/langchain.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
opentelemetry-sdk>=1.20.0
|
|
2
|
+
opentelemetry-exporter-otlp-proto-http>=1.20.0
|
|
3
|
+
|
|
4
|
+
[:python_version >= "3.10"]
|
|
5
|
+
traceloop-sdk>=0.33.0
|
|
6
|
+
|
|
7
|
+
[auto]
|
|
8
|
+
|
|
9
|
+
[auto:python_version >= "3.10"]
|
|
10
|
+
traceloop-sdk>=0.33.0
|
|
11
|
+
|
|
12
|
+
[langchain]
|
|
13
|
+
langchain-core>=0.2.0
|
|
14
|
+
langchain-openai>=0.1.0
|
|
15
|
+
langfuse>=2.0.0
|
|
16
|
+
|
|
17
|
+
[legacy]
|
|
18
|
+
langfuse>=2.0.0
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _bool(value, default=False):
|
|
5
|
+
if value is None:
|
|
6
|
+
return default
|
|
7
|
+
return value.strip().lower() in {"1", "true", "yes", "on"}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Settings:
|
|
11
|
+
service_name = os.getenv("AGENTGUARD_SERVICE_NAME") or os.getenv(
|
|
12
|
+
"SERVICE_NAME", "my-service"
|
|
13
|
+
)
|
|
14
|
+
app_env = os.getenv("APP_ENV", "production")
|
|
15
|
+
mode = (os.getenv("AGENTGUARD_MODE", "auto") or "auto").strip().lower()
|
|
16
|
+
capture_content = _bool(os.getenv("AGENTGUARD_CAPTURE_CONTENT"), False)
|
|
17
|
+
# When true, only LLM/observation spans are exported; infra spans (DB, HTTP
|
|
18
|
+
# client, framework) are dropped at the exporter to reduce storage/egress.
|
|
19
|
+
# Default false to preserve full end-to-end agent traces.
|
|
20
|
+
drop_infra_spans = _bool(os.getenv("AGENTGUARD_DROP_INFRA_SPANS"), False)
|
|
21
|
+
host = (
|
|
22
|
+
os.getenv("AGENTGUARD_HOST")
|
|
23
|
+
or os.getenv("AGENTGUARD_BASE_URL")
|
|
24
|
+
or os.getenv("AGENT_GUARD_BASE_URL")
|
|
25
|
+
)
|
|
26
|
+
public_key = os.getenv("AGENTGUARD_PUBLIC_KEY") or os.getenv(
|
|
27
|
+
"AGENT_GUARD_PUBLIC_KEY"
|
|
28
|
+
)
|
|
29
|
+
secret_key = os.getenv("AGENTGUARD_SECRET_KEY") or os.getenv(
|
|
30
|
+
"AGENT_GUARD_SECRET_KEY"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
settings = Settings()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def slug(value: str) -> str:
|
|
8
|
+
text = re.sub(r"[^a-z0-9]+", "-", (value or "").strip().lower()).strip("-")
|
|
9
|
+
return text or "unknown"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def call_tags(business: str, channel: str, feature: str) -> list[str]:
|
|
13
|
+
business_slug = slug(business)
|
|
14
|
+
channel_slug = slug(channel)
|
|
15
|
+
feature_slug = slug(feature)
|
|
16
|
+
return [
|
|
17
|
+
f"business:{business_slug}",
|
|
18
|
+
f"channel:{channel_slug}",
|
|
19
|
+
f"feature:{feature_slug}",
|
|
20
|
+
f"biz_channel:{business_slug}__{channel_slug}",
|
|
21
|
+
f"biz_feat:{business_slug}__{feature_slug}",
|
|
22
|
+
f"chan_feat:{channel_slug}__{feature_slug}",
|
|
23
|
+
f"biz_chan_feat:{business_slug}__{channel_slug}__{feature_slug}",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def metadata(
|
|
28
|
+
business: str,
|
|
29
|
+
channel: str,
|
|
30
|
+
env: str,
|
|
31
|
+
feature: Optional[str] = None,
|
|
32
|
+
**extra,
|
|
33
|
+
) -> dict:
|
|
34
|
+
result = {"business_id": business, "channel_name": channel, "env": env}
|
|
35
|
+
if feature:
|
|
36
|
+
result["feature_name"] = feature
|
|
37
|
+
result.update({key: value for key, value in extra.items() if value is not None})
|
|
38
|
+
return result
|