trodo-python 1.2.0__tar.gz → 2.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.
Files changed (35) hide show
  1. {trodo_python-1.2.0 → trodo_python-2.1.0}/PKG-INFO +155 -3
  2. {trodo_python-1.2.0 → trodo_python-2.1.0}/README.md +154 -2
  3. {trodo_python-1.2.0 → trodo_python-2.1.0}/pyproject.toml +1 -1
  4. trodo_python-2.1.0/trodo/__init__.py +430 -0
  5. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/api/endpoints.py +5 -1
  6. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/api/http_client.py +30 -2
  7. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/client.py +193 -112
  8. trodo_python-2.1.0/trodo/otel/__init__.py +21 -0
  9. trodo_python-2.1.0/trodo/otel/auto_instrument.py +281 -0
  10. trodo_python-2.1.0/trodo/otel/context.py +44 -0
  11. trodo_python-2.1.0/trodo/otel/helpers.py +407 -0
  12. trodo_python-2.1.0/trodo/otel/processor.py +165 -0
  13. trodo_python-2.1.0/trodo/otel/wrap_agent.py +438 -0
  14. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/types.py +12 -68
  15. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo_python.egg-info/PKG-INFO +155 -3
  16. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo_python.egg-info/SOURCES.txt +6 -0
  17. trodo_python-1.2.0/trodo/__init__.py +0 -177
  18. {trodo_python-1.2.0 → trodo_python-2.1.0}/setup.cfg +0 -0
  19. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/api/__init__.py +0 -0
  20. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/api/async_client.py +0 -0
  21. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/auto/__init__.py +0 -0
  22. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/auto/auto_event_manager.py +0 -0
  23. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/managers/__init__.py +0 -0
  24. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/managers/group_manager.py +0 -0
  25. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/managers/people_manager.py +0 -0
  26. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/queue/__init__.py +0 -0
  27. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/queue/batch_flusher.py +0 -0
  28. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/queue/event_queue.py +0 -0
  29. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/session/__init__.py +0 -0
  30. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/session/server_session.py +0 -0
  31. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/session/session_manager.py +0 -0
  32. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo/user_context.py +0 -0
  33. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo_python.egg-info/dependency_links.txt +0 -0
  34. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo_python.egg-info/requires.txt +0 -0
  35. {trodo_python-1.2.0 → trodo_python-2.1.0}/trodo_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trodo-python
3
- Version: 1.2.0
3
+ Version: 2.1.0
4
4
  Summary: Trodo Analytics SDK for Python — server-side event tracking
5
5
  License: ISC
6
6
  Keywords: analytics,tracking,trodo,server-side
@@ -136,9 +136,160 @@ trodo.set_group('user-123', 'company', 'acme')
136
136
 
137
137
  ---
138
138
 
139
- ## Agent Analytics
139
+ ## AI Agent Tracing (recommended)
140
140
 
141
- Track every step of your LLM agents. Each call counts as one event toward your plan limit.
141
+ One wrap around your agent captures every LLM call, tool call, and
142
+ nested step as a tree of spans — token counts, costs, inputs, outputs,
143
+ errors. Works with any stack: OpenAI, Anthropic, LangChain, LlamaIndex,
144
+ Gemini, raw HTTP, custom tools. Cost is derived server-side from
145
+ `(provider, model)` — the SDK only sends tokens.
146
+
147
+ ### 30-second quickstart
148
+
149
+ ```python
150
+ import trodo
151
+ trodo.init(site_id='your-site-id') # auto-instrument on by default
152
+
153
+ with trodo.wrap_agent('customer-support',
154
+ distinct_id=user_id,
155
+ conversation_id=session_id) as run:
156
+ run.set_input({'query': 'where did sales drop'})
157
+ answer = agent.run(query) # OpenAI/Anthropic/LangChain auto-captured
158
+ run.set_output(answer)
159
+ ```
160
+
161
+ Open the Agent Runs dashboard — the row shows tokens in/out, cost,
162
+ span count, tool count, error count, plus the full trace tree.
163
+
164
+ ### Auto-instrumentation
165
+
166
+ `trodo.init()` calls `enable_auto_instrument()` which registers every
167
+ installed OpenTelemetry instrumentor. No extra code required.
168
+
169
+ | Framework | Install |
170
+ |-----------|---------|
171
+ | OpenAI | `pip install opentelemetry-instrumentation-openai` |
172
+ | Anthropic | `pip install opentelemetry-instrumentation-anthropic` |
173
+ | LangChain | `pip install opentelemetry-instrumentation-langchain` |
174
+ | LlamaIndex | `pip install opentelemetry-instrumentation-llama-index` |
175
+ | Google Gemini | `pip install opentelemetry-instrumentation-google-generativeai` |
176
+ | Vertex AI | `pip install opentelemetry-instrumentation-vertexai` |
177
+ | Bedrock | `pip install opentelemetry-instrumentation-bedrock` |
178
+ | Cohere | `pip install opentelemetry-instrumentation-cohere` |
179
+ | Mistral | `pip install opentelemetry-instrumentation-mistralai` |
180
+ | Haystack | `pip install opentelemetry-instrumentation-haystack` |
181
+ | httpx / requests | bundled — generic HTTP spans for raw-HTTP callers |
182
+
183
+ Opt out with `trodo.init(site_id=..., auto_instrument=False)`.
184
+
185
+ ### Span helpers
186
+
187
+ Typed function wrappers for custom code — every call becomes a span
188
+ with the args auto-captured as `input`, return value as `output`,
189
+ exception as `error`. Dual-form: helper **and** decorator.
190
+
191
+ ```python
192
+ # trace — generic span
193
+ prepared = trodo.trace('prepare', prepare_fn)(payload)
194
+
195
+ @trodo.trace('step')
196
+ def step(): ...
197
+
198
+ # tool — tool span (auto tool_name, kind='tool')
199
+ run_funnel = trodo.tool('run_funnel_query', run_funnel_query)
200
+ result = run_funnel(team_id=1, preset='day7')
201
+
202
+ @trodo.tool(name='fetch_user')
203
+ async def fetch_user(uid): ...
204
+
205
+ # llm — LLM span, auto-extracts OpenAI / Anthropic / Gemini usage
206
+ answer = trodo.llm(
207
+ 'answer', call_openai, model='gpt-4o-mini', provider='openai',
208
+ )(messages)
209
+ # Records input_tokens / output_tokens from response['usage'].
210
+
211
+ # retrieval — vector search / RAG retriever span
212
+ search = trodo.retrieval('vector_search', vector_search)
213
+ docs = search(query)
214
+ ```
215
+
216
+ ### Raw-HTTP escape hatches
217
+
218
+ If your LLM client isn't OTel-instrumented and you can't wrap it as a
219
+ function, record a span post-hoc:
220
+
221
+ ```python
222
+ resp = httpx.post(url, json=body).json()
223
+ trodo.track_llm_call(
224
+ model='gemini-2.5-flash', provider='google',
225
+ input_tokens=resp['usageMetadata']['promptTokenCount'],
226
+ output_tokens=resp['usageMetadata']['candidatesTokenCount'],
227
+ prompt=body, completion=resp,
228
+ )
229
+ ```
230
+
231
+ For advanced cases, get a raw OTel tracer — the Trodo processor is
232
+ already subscribed:
233
+
234
+ ```python
235
+ tracer = trodo.get_tracer('my.module')
236
+ with tracer.start_as_current_span('custom') as sp:
237
+ sp.set_attribute('gen_ai.system', 'my-llm')
238
+ ```
239
+
240
+ ### Cross-service runs
241
+
242
+ When one service calls another, the downstream service **joins** the
243
+ caller's run instead of creating its own. All spans nest under a single
244
+ timeline in the dashboard.
245
+
246
+ ```python
247
+ # Caller (FastAPI / Flask / Django / …) — outbound:
248
+ import httpx
249
+ httpx.post(url, headers=trodo.propagation_headers(), json=body)
250
+
251
+ # Downstream (FastAPI):
252
+ from fastapi import FastAPI
253
+ app = FastAPI()
254
+ app.middleware('http')(trodo.fastapi_middleware())
255
+ # Every LLM call / @tool / trace helper inside handlers now nests under
256
+ # the caller's run — no extra wiring.
257
+
258
+ # Or manually:
259
+ with trodo.join_run(
260
+ run_id=headers['x-trodo-run-id'],
261
+ parent_span_id=headers['x-trodo-parent-span-id'],
262
+ ):
263
+ ...
264
+ ```
265
+
266
+ ### Conversation binding & feedback
267
+
268
+ ```python
269
+ with trodo.wrap_agent(
270
+ 'chat', distinct_id=user_id, conversation_id=session_id,
271
+ ) as run:
272
+ ...
273
+ # Later:
274
+ trodo.feedback(run.run_id, satisfaction='positive', rating=5)
275
+ ```
276
+
277
+ ### Cookbook
278
+
279
+ Runnable scenarios that double as integration tests live in
280
+ `sandbox/scenarios/` — `span_helpers.py`, `raw_http.py`,
281
+ `custom_tools.py`, `cross_service.py`, `concurrent_100.py`,
282
+ `long_run.py`, plus opt-in `openai_auto.py`, `anthropic_auto.py`,
283
+ `langchain_chain.py`. Run them with
284
+ `python -m sandbox.run_all` from the SDK root.
285
+
286
+ ---
287
+
288
+ ## Agent Analytics (legacy event-based API)
289
+
290
+ The older per-event API below is still supported but superseded by
291
+ `wrap_agent` + span helpers above. Use it only if you're already wired
292
+ into it; new integrations should prefer the tracing API.
142
293
 
143
294
  **Before you start:** register your agent in **Integrations → AI Agents** in the dashboard to get an `agent_id` (`agt_xxxxxxxx`).
144
295
 
@@ -161,6 +312,7 @@ trodo.track_agent_call(AgentCallProps(
161
312
  provider='anthropic',
162
313
  system_prompt_version='v2', # optional — track prompt iterations
163
314
  distinct_id=user_id, # optional — link to a Trodo user
315
+ metadata={'thread_source': 'slack', 'locale': 'en'}, # optional — agent_calls.metadata JSONB
164
316
  ))
165
317
  ```
166
318
 
@@ -109,9 +109,160 @@ trodo.set_group('user-123', 'company', 'acme')
109
109
 
110
110
  ---
111
111
 
112
- ## Agent Analytics
112
+ ## AI Agent Tracing (recommended)
113
113
 
114
- Track every step of your LLM agents. Each call counts as one event toward your plan limit.
114
+ One wrap around your agent captures every LLM call, tool call, and
115
+ nested step as a tree of spans — token counts, costs, inputs, outputs,
116
+ errors. Works with any stack: OpenAI, Anthropic, LangChain, LlamaIndex,
117
+ Gemini, raw HTTP, custom tools. Cost is derived server-side from
118
+ `(provider, model)` — the SDK only sends tokens.
119
+
120
+ ### 30-second quickstart
121
+
122
+ ```python
123
+ import trodo
124
+ trodo.init(site_id='your-site-id') # auto-instrument on by default
125
+
126
+ with trodo.wrap_agent('customer-support',
127
+ distinct_id=user_id,
128
+ conversation_id=session_id) as run:
129
+ run.set_input({'query': 'where did sales drop'})
130
+ answer = agent.run(query) # OpenAI/Anthropic/LangChain auto-captured
131
+ run.set_output(answer)
132
+ ```
133
+
134
+ Open the Agent Runs dashboard — the row shows tokens in/out, cost,
135
+ span count, tool count, error count, plus the full trace tree.
136
+
137
+ ### Auto-instrumentation
138
+
139
+ `trodo.init()` calls `enable_auto_instrument()` which registers every
140
+ installed OpenTelemetry instrumentor. No extra code required.
141
+
142
+ | Framework | Install |
143
+ |-----------|---------|
144
+ | OpenAI | `pip install opentelemetry-instrumentation-openai` |
145
+ | Anthropic | `pip install opentelemetry-instrumentation-anthropic` |
146
+ | LangChain | `pip install opentelemetry-instrumentation-langchain` |
147
+ | LlamaIndex | `pip install opentelemetry-instrumentation-llama-index` |
148
+ | Google Gemini | `pip install opentelemetry-instrumentation-google-generativeai` |
149
+ | Vertex AI | `pip install opentelemetry-instrumentation-vertexai` |
150
+ | Bedrock | `pip install opentelemetry-instrumentation-bedrock` |
151
+ | Cohere | `pip install opentelemetry-instrumentation-cohere` |
152
+ | Mistral | `pip install opentelemetry-instrumentation-mistralai` |
153
+ | Haystack | `pip install opentelemetry-instrumentation-haystack` |
154
+ | httpx / requests | bundled — generic HTTP spans for raw-HTTP callers |
155
+
156
+ Opt out with `trodo.init(site_id=..., auto_instrument=False)`.
157
+
158
+ ### Span helpers
159
+
160
+ Typed function wrappers for custom code — every call becomes a span
161
+ with the args auto-captured as `input`, return value as `output`,
162
+ exception as `error`. Dual-form: helper **and** decorator.
163
+
164
+ ```python
165
+ # trace — generic span
166
+ prepared = trodo.trace('prepare', prepare_fn)(payload)
167
+
168
+ @trodo.trace('step')
169
+ def step(): ...
170
+
171
+ # tool — tool span (auto tool_name, kind='tool')
172
+ run_funnel = trodo.tool('run_funnel_query', run_funnel_query)
173
+ result = run_funnel(team_id=1, preset='day7')
174
+
175
+ @trodo.tool(name='fetch_user')
176
+ async def fetch_user(uid): ...
177
+
178
+ # llm — LLM span, auto-extracts OpenAI / Anthropic / Gemini usage
179
+ answer = trodo.llm(
180
+ 'answer', call_openai, model='gpt-4o-mini', provider='openai',
181
+ )(messages)
182
+ # Records input_tokens / output_tokens from response['usage'].
183
+
184
+ # retrieval — vector search / RAG retriever span
185
+ search = trodo.retrieval('vector_search', vector_search)
186
+ docs = search(query)
187
+ ```
188
+
189
+ ### Raw-HTTP escape hatches
190
+
191
+ If your LLM client isn't OTel-instrumented and you can't wrap it as a
192
+ function, record a span post-hoc:
193
+
194
+ ```python
195
+ resp = httpx.post(url, json=body).json()
196
+ trodo.track_llm_call(
197
+ model='gemini-2.5-flash', provider='google',
198
+ input_tokens=resp['usageMetadata']['promptTokenCount'],
199
+ output_tokens=resp['usageMetadata']['candidatesTokenCount'],
200
+ prompt=body, completion=resp,
201
+ )
202
+ ```
203
+
204
+ For advanced cases, get a raw OTel tracer — the Trodo processor is
205
+ already subscribed:
206
+
207
+ ```python
208
+ tracer = trodo.get_tracer('my.module')
209
+ with tracer.start_as_current_span('custom') as sp:
210
+ sp.set_attribute('gen_ai.system', 'my-llm')
211
+ ```
212
+
213
+ ### Cross-service runs
214
+
215
+ When one service calls another, the downstream service **joins** the
216
+ caller's run instead of creating its own. All spans nest under a single
217
+ timeline in the dashboard.
218
+
219
+ ```python
220
+ # Caller (FastAPI / Flask / Django / …) — outbound:
221
+ import httpx
222
+ httpx.post(url, headers=trodo.propagation_headers(), json=body)
223
+
224
+ # Downstream (FastAPI):
225
+ from fastapi import FastAPI
226
+ app = FastAPI()
227
+ app.middleware('http')(trodo.fastapi_middleware())
228
+ # Every LLM call / @tool / trace helper inside handlers now nests under
229
+ # the caller's run — no extra wiring.
230
+
231
+ # Or manually:
232
+ with trodo.join_run(
233
+ run_id=headers['x-trodo-run-id'],
234
+ parent_span_id=headers['x-trodo-parent-span-id'],
235
+ ):
236
+ ...
237
+ ```
238
+
239
+ ### Conversation binding & feedback
240
+
241
+ ```python
242
+ with trodo.wrap_agent(
243
+ 'chat', distinct_id=user_id, conversation_id=session_id,
244
+ ) as run:
245
+ ...
246
+ # Later:
247
+ trodo.feedback(run.run_id, satisfaction='positive', rating=5)
248
+ ```
249
+
250
+ ### Cookbook
251
+
252
+ Runnable scenarios that double as integration tests live in
253
+ `sandbox/scenarios/` — `span_helpers.py`, `raw_http.py`,
254
+ `custom_tools.py`, `cross_service.py`, `concurrent_100.py`,
255
+ `long_run.py`, plus opt-in `openai_auto.py`, `anthropic_auto.py`,
256
+ `langchain_chain.py`. Run them with
257
+ `python -m sandbox.run_all` from the SDK root.
258
+
259
+ ---
260
+
261
+ ## Agent Analytics (legacy event-based API)
262
+
263
+ The older per-event API below is still supported but superseded by
264
+ `wrap_agent` + span helpers above. Use it only if you're already wired
265
+ into it; new integrations should prefer the tracing API.
115
266
 
116
267
  **Before you start:** register your agent in **Integrations → AI Agents** in the dashboard to get an `agent_id` (`agt_xxxxxxxx`).
117
268
 
@@ -134,6 +285,7 @@ trodo.track_agent_call(AgentCallProps(
134
285
  provider='anthropic',
135
286
  system_prompt_version='v2', # optional — track prompt iterations
136
287
  distinct_id=user_id, # optional — link to a Trodo user
288
+ metadata={'thread_source': 'slack', 'locale': 'en'}, # optional — agent_calls.metadata JSONB
137
289
  ))
138
290
  ```
139
291
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "trodo-python"
7
- version = "1.2.0"
7
+ version = "2.1.0"
8
8
  description = "Trodo Analytics SDK for Python — server-side event tracking"
9
9
  readme = "README.md"
10
10
  license = { text = "ISC" }