agentracer 0.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.
- agentracer-0.1.0/.github/workflows/workflow.yml +53 -0
- agentracer-0.1.0/.gitignore +5 -0
- agentracer-0.1.0/LICENSE +21 -0
- agentracer-0.1.0/PKG-INFO +567 -0
- agentracer-0.1.0/README.md +528 -0
- agentracer-0.1.0/agentracer/__init__.py +303 -0
- agentracer-0.1.0/agentracer/anthropic.py +192 -0
- agentracer-0.1.0/agentracer/gemini.py +89 -0
- agentracer-0.1.0/agentracer/openai.py +200 -0
- agentracer-0.1.0/agentracer/py.typed +0 -0
- agentracer-0.1.0/pyproject.toml +43 -0
- agentracer-0.1.0/tests/__init__.py +0 -0
- agentracer-0.1.0/tests/test_anthropic.py +125 -0
- agentracer-0.1.0/tests/test_core.py +159 -0
- agentracer-0.1.0/tests/test_gemini.py +110 -0
- agentracer-0.1.0/tests/test_openai.py +133 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
name: Run tests
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: pip install -e ".[dev]"
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: pytest tests/ -v
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
name: Build and publish
|
|
33
|
+
needs: test
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment: pypi
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- name: Set up Python
|
|
40
|
+
uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: "3.12"
|
|
43
|
+
|
|
44
|
+
- name: Install build tools
|
|
45
|
+
run: pip install build
|
|
46
|
+
|
|
47
|
+
- name: Build package
|
|
48
|
+
run: python -m build
|
|
49
|
+
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
52
|
+
with:
|
|
53
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
agentracer-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Agentracer
|
|
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,567 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentracer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight AI incident detection. Catch cost spikes, latency anomalies, and prompt bloat before they hit your users.
|
|
5
|
+
Project-URL: Homepage, https://agentracer.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/aqib-ilyas/agentracer-python
|
|
7
|
+
Project-URL: Documentation, https://agentracer.dev/docs
|
|
8
|
+
Author-email: Agentracer <hello@agentracer.dev>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,anthropic,cost-tracking,gemini,llm,observability,openai
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: httpx>=0.24.0
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: anthropic>=0.18.0; extra == 'all'
|
|
27
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == 'all'
|
|
28
|
+
Requires-Dist: openai>=1.0.0; extra == 'all'
|
|
29
|
+
Provides-Extra: anthropic
|
|
30
|
+
Requires-Dist: anthropic>=0.18.0; extra == 'anthropic'
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
34
|
+
Provides-Extra: gemini
|
|
35
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == 'gemini'
|
|
36
|
+
Provides-Extra: openai
|
|
37
|
+
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# Agentracer Python SDK
|
|
41
|
+
|
|
42
|
+
Lightweight AI observability. Catch cost spikes, latency anomalies, and prompt bloat before they hit your users.
|
|
43
|
+
|
|
44
|
+
[](https://pypi.org/project/agentracer/)
|
|
45
|
+
[](https://www.python.org/downloads/)
|
|
46
|
+
[](https://opensource.org/licenses/MIT)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install agentracer
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
With provider-specific extras:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# OpenAI support
|
|
58
|
+
pip install agentracer[openai]
|
|
59
|
+
|
|
60
|
+
# Anthropic support
|
|
61
|
+
pip install agentracer[anthropic]
|
|
62
|
+
|
|
63
|
+
# Google Gemini support
|
|
64
|
+
pip install agentracer[gemini]
|
|
65
|
+
|
|
66
|
+
# All providers
|
|
67
|
+
pip install agentracer[all]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import agentracer
|
|
74
|
+
|
|
75
|
+
# Initialize once at app startup
|
|
76
|
+
agentracer.init(
|
|
77
|
+
tracker_api_key="at_your_api_key",
|
|
78
|
+
project_id="your_project_id",
|
|
79
|
+
environment="production"
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
### OpenAI
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from agentracer.openai import openai
|
|
89
|
+
|
|
90
|
+
# Use exactly like the normal OpenAI client
|
|
91
|
+
response = openai.chat.completions.create(
|
|
92
|
+
model="gpt-4o",
|
|
93
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
94
|
+
feature_tag="chatbot" # optional: tag this call
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Anthropic
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from agentracer.anthropic import anthropic
|
|
102
|
+
|
|
103
|
+
response = anthropic.messages.create(
|
|
104
|
+
model="claude-sonnet-4-20250514",
|
|
105
|
+
max_tokens=1024,
|
|
106
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
107
|
+
feature_tag="summarizer" # optional: tag this call
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Google Gemini
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import google.generativeai as genai
|
|
115
|
+
from agentracer.gemini import gemini
|
|
116
|
+
|
|
117
|
+
# Configure your API key as usual
|
|
118
|
+
genai.configure(api_key="your-gemini-api-key")
|
|
119
|
+
|
|
120
|
+
model = gemini.GenerativeModel("gemini-1.5-pro")
|
|
121
|
+
response = model.generate_content(
|
|
122
|
+
"Hello!",
|
|
123
|
+
feature_tag="content-gen" # optional: tag this call
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Custom Client Configuration
|
|
128
|
+
|
|
129
|
+
The default imports (`openai`, `anthropic`) create clients using environment variables. To pass custom configuration like `api_key` or `base_url`, use the class constructors:
|
|
130
|
+
|
|
131
|
+
### OpenAI
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from agentracer.openai import TrackedOpenAI
|
|
135
|
+
|
|
136
|
+
openai = TrackedOpenAI(api_key="sk-...", base_url="https://custom.api/v1")
|
|
137
|
+
|
|
138
|
+
response = openai.chat.completions.create(
|
|
139
|
+
model="gpt-4o",
|
|
140
|
+
messages=[{"role": "user", "content": "Hello!"}]
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Anthropic
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from agentracer.anthropic import TrackedAnthropic
|
|
148
|
+
|
|
149
|
+
anthropic = TrackedAnthropic(api_key="sk-ant-...")
|
|
150
|
+
|
|
151
|
+
response = anthropic.messages.create(
|
|
152
|
+
model="claude-sonnet-4-20250514",
|
|
153
|
+
max_tokens=1024,
|
|
154
|
+
messages=[{"role": "user", "content": "Hello!"}]
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Async Support
|
|
159
|
+
|
|
160
|
+
For async applications, use the async client wrappers:
|
|
161
|
+
|
|
162
|
+
### Async OpenAI
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from agentracer.openai import TrackedAsyncOpenAI
|
|
166
|
+
|
|
167
|
+
client = TrackedAsyncOpenAI()
|
|
168
|
+
|
|
169
|
+
async def chat(message: str):
|
|
170
|
+
response = await client.chat.completions.create(
|
|
171
|
+
model="gpt-4o",
|
|
172
|
+
messages=[{"role": "user", "content": message}],
|
|
173
|
+
feature_tag="async-chatbot"
|
|
174
|
+
)
|
|
175
|
+
return response.choices[0].message.content
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Async Anthropic
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from agentracer.anthropic import TrackedAsyncAnthropic
|
|
182
|
+
|
|
183
|
+
client = TrackedAsyncAnthropic()
|
|
184
|
+
|
|
185
|
+
async def chat(message: str):
|
|
186
|
+
response = await client.messages.create(
|
|
187
|
+
model="claude-sonnet-4-20250514",
|
|
188
|
+
max_tokens=1024,
|
|
189
|
+
messages=[{"role": "user", "content": message}],
|
|
190
|
+
feature_tag="async-summarizer"
|
|
191
|
+
)
|
|
192
|
+
return response.content[0].text
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Streaming
|
|
196
|
+
|
|
197
|
+
All providers support streaming. Token usage is automatically tracked after the stream completes.
|
|
198
|
+
|
|
199
|
+
### OpenAI Streaming
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from agentracer.openai import openai
|
|
203
|
+
|
|
204
|
+
stream = openai.chat.completions.create(
|
|
205
|
+
model="gpt-4o",
|
|
206
|
+
messages=[{"role": "user", "content": "Write a poem"}],
|
|
207
|
+
stream=True,
|
|
208
|
+
feature_tag="poet"
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
for chunk in stream:
|
|
212
|
+
content = chunk.choices[0].delta.content
|
|
213
|
+
if content:
|
|
214
|
+
print(content, end="")
|
|
215
|
+
# Telemetry is sent automatically after the stream ends
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Anthropic Streaming
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
from agentracer.anthropic import anthropic
|
|
222
|
+
|
|
223
|
+
stream = anthropic.messages.create(
|
|
224
|
+
model="claude-sonnet-4-20250514",
|
|
225
|
+
max_tokens=1024,
|
|
226
|
+
messages=[{"role": "user", "content": "Write a poem"}],
|
|
227
|
+
stream=True,
|
|
228
|
+
feature_tag="poet"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
for event in stream:
|
|
232
|
+
if event.type == "content_block_delta":
|
|
233
|
+
print(event.delta.text, end="")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Gemini Streaming
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from agentracer.gemini import gemini
|
|
240
|
+
|
|
241
|
+
model = gemini.GenerativeModel("gemini-1.5-pro")
|
|
242
|
+
|
|
243
|
+
stream = model.generate_content(
|
|
244
|
+
"Write a poem",
|
|
245
|
+
stream=True,
|
|
246
|
+
feature_tag="poet"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
for chunk in stream:
|
|
250
|
+
print(chunk.text, end="")
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
> Streaming works transparently -- usage is captured from the final chunk (OpenAI), SSE events (Anthropic), or chunk metadata (Gemini), then sent as a single telemetry event after the stream finishes.
|
|
254
|
+
|
|
255
|
+
## Feature Tags
|
|
256
|
+
|
|
257
|
+
Feature tags let you group and track costs by feature across your application. There are three ways to apply them:
|
|
258
|
+
|
|
259
|
+
### 1. Inline (per-call)
|
|
260
|
+
|
|
261
|
+
Pass `feature_tag` directly on any tracked call:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
response = openai.chat.completions.create(
|
|
265
|
+
model="gpt-4o",
|
|
266
|
+
messages=[{"role": "user", "content": "Summarize this"}],
|
|
267
|
+
feature_tag="summarizer"
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 2. Decorator
|
|
272
|
+
|
|
273
|
+
Use the `@observe` decorator to tag all LLM calls inside a function:
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
import agentracer
|
|
277
|
+
|
|
278
|
+
@agentracer.observe(feature_tag="chatbot")
|
|
279
|
+
def handle_chat(message: str):
|
|
280
|
+
response = openai.chat.completions.create(
|
|
281
|
+
model="gpt-4o",
|
|
282
|
+
messages=[{"role": "user", "content": message}]
|
|
283
|
+
)
|
|
284
|
+
return response
|
|
285
|
+
|
|
286
|
+
# Async functions work too
|
|
287
|
+
@agentracer.observe(feature_tag="async-chatbot")
|
|
288
|
+
async def handle_chat_async(message: str):
|
|
289
|
+
response = await client.chat.completions.create(
|
|
290
|
+
model="gpt-4o",
|
|
291
|
+
messages=[{"role": "user", "content": message}]
|
|
292
|
+
)
|
|
293
|
+
return response
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 3. Context Manager
|
|
297
|
+
|
|
298
|
+
Use `feature_context` for block-level tagging:
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from agentracer import feature_context
|
|
302
|
+
|
|
303
|
+
with feature_context("report-generator"):
|
|
304
|
+
# All LLM calls in this block get tagged "report-generator"
|
|
305
|
+
summary = openai.chat.completions.create(
|
|
306
|
+
model="gpt-4o",
|
|
307
|
+
messages=[{"role": "user", "content": "Summarize the data"}]
|
|
308
|
+
)
|
|
309
|
+
analysis = anthropic.messages.create(
|
|
310
|
+
model="claude-sonnet-4-20250514",
|
|
311
|
+
max_tokens=2048,
|
|
312
|
+
messages=[{"role": "user", "content": "Analyze trends"}]
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Agent Runs
|
|
317
|
+
|
|
318
|
+
Track multi-step agent workflows as a single run with `AgentRun`. Each LLM call inside the run is automatically recorded as a step.
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
from agentracer import AgentRun
|
|
322
|
+
from agentracer.openai import openai
|
|
323
|
+
|
|
324
|
+
with AgentRun(run_name="research-agent", feature_tag="research") as run:
|
|
325
|
+
# Step 1: Plan
|
|
326
|
+
plan = openai.chat.completions.create(
|
|
327
|
+
model="gpt-4o",
|
|
328
|
+
messages=[{"role": "user", "content": "Plan a research outline"}]
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Step 2: Execute
|
|
332
|
+
result = openai.chat.completions.create(
|
|
333
|
+
model="gpt-4o",
|
|
334
|
+
messages=[{"role": "user", "content": f"Research: {plan.choices[0].message.content}"}]
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# Step 3: Summarize
|
|
338
|
+
summary = openai.chat.completions.create(
|
|
339
|
+
model="gpt-4o-mini",
|
|
340
|
+
messages=[{"role": "user", "content": f"Summarize: {result.choices[0].message.content}"}]
|
|
341
|
+
)
|
|
342
|
+
# All 3 steps are tracked under a single run with timing, tokens, and status
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Async Agent Runs
|
|
346
|
+
|
|
347
|
+
`AgentRun` also works as an async context manager:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from agentracer import AgentRun
|
|
351
|
+
from agentracer.openai import TrackedAsyncOpenAI
|
|
352
|
+
|
|
353
|
+
client = TrackedAsyncOpenAI()
|
|
354
|
+
|
|
355
|
+
async def run_agent(query: str):
|
|
356
|
+
async with AgentRun(run_name="async-agent", feature_tag="agent") as run:
|
|
357
|
+
response = await client.chat.completions.create(
|
|
358
|
+
model="gpt-4o",
|
|
359
|
+
messages=[{"role": "user", "content": query}]
|
|
360
|
+
)
|
|
361
|
+
return response.choices[0].message.content
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### AgentRun Parameters
|
|
365
|
+
|
|
366
|
+
| Parameter | Type | Default | Description |
|
|
367
|
+
|-----------|------|---------|-------------|
|
|
368
|
+
| `run_name` | `str` | `None` | Name for this run (shown in dashboard) |
|
|
369
|
+
| `feature_tag` | `str` | `"unknown"` | Feature tag applied to all steps |
|
|
370
|
+
| `end_user_id` | `str` | `None` | ID of the end user triggering this run |
|
|
371
|
+
| `run_id` | `str` | auto-generated | Custom run ID (UUID v4 generated if omitted) |
|
|
372
|
+
|
|
373
|
+
### What gets tracked per run
|
|
374
|
+
|
|
375
|
+
- **Start/end timestamps** and total duration
|
|
376
|
+
- **Status**: `completed` or `failed` (auto-detected from exceptions)
|
|
377
|
+
- **Each step**: model, provider, tokens, latency, success/failure
|
|
378
|
+
- **Aggregates**: total steps, total tokens, total cost, total latency
|
|
379
|
+
|
|
380
|
+
## Manual Tracking
|
|
381
|
+
|
|
382
|
+
For custom integrations or providers not yet supported, use `track()` directly:
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
import agentracer
|
|
386
|
+
|
|
387
|
+
agentracer.track(
|
|
388
|
+
model="gpt-4o",
|
|
389
|
+
input_tokens=150,
|
|
390
|
+
output_tokens=300,
|
|
391
|
+
latency_ms=420.5,
|
|
392
|
+
feature_tag="custom-pipeline",
|
|
393
|
+
provider="openai",
|
|
394
|
+
end_user_id="user-123", # optional: track per-user costs
|
|
395
|
+
cached_tokens=50, # optional: cached/prompt-cache tokens
|
|
396
|
+
)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## FastAPI Example
|
|
400
|
+
|
|
401
|
+
```python
|
|
402
|
+
from fastapi import FastAPI
|
|
403
|
+
import agentracer
|
|
404
|
+
from agentracer.openai import TrackedAsyncOpenAI
|
|
405
|
+
|
|
406
|
+
app = FastAPI()
|
|
407
|
+
client = TrackedAsyncOpenAI()
|
|
408
|
+
|
|
409
|
+
agentracer.init(
|
|
410
|
+
tracker_api_key="at_your_api_key",
|
|
411
|
+
project_id="your_project_id",
|
|
412
|
+
environment="production"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
@app.post("/chat")
|
|
416
|
+
@agentracer.observe(feature_tag="chatbot")
|
|
417
|
+
async def chat(message: str):
|
|
418
|
+
response = await client.chat.completions.create(
|
|
419
|
+
model="gpt-4o",
|
|
420
|
+
messages=[{"role": "user", "content": message}]
|
|
421
|
+
)
|
|
422
|
+
return {"reply": response.choices[0].message.content}
|
|
423
|
+
|
|
424
|
+
@app.post("/summarize")
|
|
425
|
+
async def summarize(text: str):
|
|
426
|
+
with agentracer.feature_context("summarizer"):
|
|
427
|
+
response = await client.chat.completions.create(
|
|
428
|
+
model="gpt-4o-mini",
|
|
429
|
+
messages=[{"role": "user", "content": f"Summarize: {text}"}]
|
|
430
|
+
)
|
|
431
|
+
return {"summary": response.choices[0].message.content}
|
|
432
|
+
|
|
433
|
+
@app.post("/agent")
|
|
434
|
+
async def agent(query: str):
|
|
435
|
+
async with agentracer.AgentRun(run_name="qa-agent", feature_tag="agent") as run:
|
|
436
|
+
response = await client.chat.completions.create(
|
|
437
|
+
model="gpt-4o",
|
|
438
|
+
messages=[{"role": "user", "content": query}]
|
|
439
|
+
)
|
|
440
|
+
return {"answer": response.choices[0].message.content}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Django Example
|
|
444
|
+
|
|
445
|
+
```python
|
|
446
|
+
# settings.py
|
|
447
|
+
import agentracer
|
|
448
|
+
|
|
449
|
+
agentracer.init(
|
|
450
|
+
tracker_api_key="at_your_api_key",
|
|
451
|
+
project_id="your_project_id",
|
|
452
|
+
environment="production"
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
# views.py
|
|
456
|
+
from agentracer.openai import openai
|
|
457
|
+
from agentracer import feature_context, AgentRun
|
|
458
|
+
|
|
459
|
+
def chat_view(request):
|
|
460
|
+
message = request.POST.get("message")
|
|
461
|
+
|
|
462
|
+
with feature_context("django-chatbot"):
|
|
463
|
+
response = openai.chat.completions.create(
|
|
464
|
+
model="gpt-4o",
|
|
465
|
+
messages=[{"role": "user", "content": message}]
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
return JsonResponse({"reply": response.choices[0].message.content})
|
|
469
|
+
|
|
470
|
+
def agent_view(request):
|
|
471
|
+
query = request.POST.get("query")
|
|
472
|
+
|
|
473
|
+
with AgentRun(run_name="django-agent", feature_tag="agent"):
|
|
474
|
+
response = openai.chat.completions.create(
|
|
475
|
+
model="gpt-4o",
|
|
476
|
+
messages=[{"role": "user", "content": query}]
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
return JsonResponse({"answer": response.choices[0].message.content})
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Configuration
|
|
483
|
+
|
|
484
|
+
```python
|
|
485
|
+
agentracer.init(
|
|
486
|
+
tracker_api_key="at_your_api_key", # Required: your API key from the dashboard
|
|
487
|
+
project_id="your_project_id", # Required: your project ID
|
|
488
|
+
environment="production", # Optional: environment name (default: "production")
|
|
489
|
+
host="https://api.agentracer.dev", # Optional: API host (default: production)
|
|
490
|
+
debug=False, # Optional: enable debug logging (default: False)
|
|
491
|
+
enabled=True # Optional: enable/disable tracking (default: True)
|
|
492
|
+
)
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
| Parameter | Type | Default | Description |
|
|
496
|
+
|-----------|------|---------|-------------|
|
|
497
|
+
| `tracker_api_key` | `str` | *required* | Your API key from the Agentracer dashboard |
|
|
498
|
+
| `project_id` | `str` | *required* | Your project ID |
|
|
499
|
+
| `environment` | `str` | `"production"` | Environment name (e.g., `"staging"`, `"development"`) |
|
|
500
|
+
| `host` | `str` | `"https://api.agentracer.dev"` | API endpoint |
|
|
501
|
+
| `debug` | `bool` | `False` | Print telemetry payloads to console |
|
|
502
|
+
| `enabled` | `bool` | `True` | Set to `False` to disable all tracking |
|
|
503
|
+
|
|
504
|
+
## What We Track
|
|
505
|
+
|
|
506
|
+
Every LLM call automatically captures:
|
|
507
|
+
|
|
508
|
+
| Field | Description |
|
|
509
|
+
|-------|-------------|
|
|
510
|
+
| `project_id` | Your project identifier |
|
|
511
|
+
| `provider` | LLM provider (`openai`, `anthropic`, `gemini`, `custom`) |
|
|
512
|
+
| `model` | Model name (e.g., `gpt-4o`, `claude-sonnet-4-20250514`) |
|
|
513
|
+
| `feature_tag` | Feature label for cost grouping |
|
|
514
|
+
| `input_tokens` | Number of input/prompt tokens |
|
|
515
|
+
| `output_tokens` | Number of output/completion tokens |
|
|
516
|
+
| `cached_tokens` | Prompt-cached tokens (OpenAI, Anthropic, Gemini) |
|
|
517
|
+
| `latency_ms` | Request latency in milliseconds |
|
|
518
|
+
| `success` | Whether the call succeeded |
|
|
519
|
+
| `error_type` | Exception class name on failure |
|
|
520
|
+
| `environment` | Deployment environment |
|
|
521
|
+
| `end_user_id` | End user identifier (when provided) |
|
|
522
|
+
|
|
523
|
+
We **never** capture prompts, responses, or any PII. Only metadata and usage metrics.
|
|
524
|
+
|
|
525
|
+
## Troubleshooting
|
|
526
|
+
|
|
527
|
+
### Telemetry not appearing in the dashboard
|
|
528
|
+
|
|
529
|
+
1. **Check your API key and project ID** -- ensure they match what's in your [dashboard](https://agentracer.dev/dashboard).
|
|
530
|
+
2. **Enable debug mode** to see what's being sent:
|
|
531
|
+
```python
|
|
532
|
+
agentracer.init(
|
|
533
|
+
tracker_api_key="at_your_api_key",
|
|
534
|
+
project_id="your_project_id",
|
|
535
|
+
debug=True
|
|
536
|
+
)
|
|
537
|
+
```
|
|
538
|
+
3. **Check that tracking is enabled** -- make sure you haven't set `enabled=False`.
|
|
539
|
+
4. **Verify network connectivity** -- the SDK sends data to `https://api.agentracer.dev/api/ingest`.
|
|
540
|
+
|
|
541
|
+
### Import errors for provider modules
|
|
542
|
+
|
|
543
|
+
If you see `ImportError: openai package not installed`, install the provider extra:
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
pip install agentracer[openai]
|
|
547
|
+
# or
|
|
548
|
+
pip install agentracer[anthropic]
|
|
549
|
+
# or
|
|
550
|
+
pip install agentracer[gemini]
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Feature tags showing as "unknown"
|
|
554
|
+
|
|
555
|
+
Make sure you're setting feature tags using one of the three methods:
|
|
556
|
+
|
|
557
|
+
- Inline: `feature_tag="my-feature"` on the call
|
|
558
|
+
- Decorator: `@agentracer.observe(feature_tag="my-feature")`
|
|
559
|
+
- Context manager: `with agentracer.feature_context("my-feature"):`
|
|
560
|
+
|
|
561
|
+
### SDK not throwing errors
|
|
562
|
+
|
|
563
|
+
This is by design. The SDK uses a fire-and-forget pattern and silently catches all exceptions to ensure it never impacts your application's performance or reliability.
|
|
564
|
+
|
|
565
|
+
## License
|
|
566
|
+
|
|
567
|
+
MIT
|