trodo-python 2.10.8__tar.gz → 2.10.9__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.
- {trodo_python-2.10.8 → trodo_python-2.10.9}/PKG-INFO +1 -1
- {trodo_python-2.10.8 → trodo_python-2.10.9}/pyproject.toml +1 -1
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_auto_instrument_fixes.py +50 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/__init__.py +1 -1
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/auto_instrument.py +49 -7
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo_python.egg-info/PKG-INFO +1 -1
- {trodo_python-2.10.8 → trodo_python-2.10.9}/README.md +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/setup.cfg +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_anon_distinct_id 2.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_anon_distinct_id.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_cross_process_session.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_end_run.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_error_enrichment.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_llm_usage_cost.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_processor_methods.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_register_otel.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_start_run.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/tests/test_wrap_agent_unchanged.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/api/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/api/async_client.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/api/endpoints.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/api/http_client.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/auto/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/auto/auto_event_manager.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/client.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/managers/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/managers/group_manager.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/managers/people_manager.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/context.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/helpers.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/processor.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/register.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/transport.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/otel/wrap_agent.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/queue/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/queue/batch_flusher.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/queue/event_queue.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/session/__init__.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/session/server_session.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/session/session_manager.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/types.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo/user_context.py +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo_python.egg-info/SOURCES.txt +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo_python.egg-info/dependency_links.txt +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo_python.egg-info/requires.txt +0 -0
- {trodo_python-2.10.8 → trodo_python-2.10.9}/trodo_python.egg-info/top_level.txt +0 -0
|
@@ -109,3 +109,53 @@ class TestOnStartStamping:
|
|
|
109
109
|
def test_drops_span_when_no_run_id_anywhere(self):
|
|
110
110
|
otel = _fake_otel_span(start_ns=1, end_ns=2, attrs={})
|
|
111
111
|
assert otel_span_to_trodo_span(otel) is None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TestVercelAiContentMapping:
|
|
115
|
+
"""Regression: the bridge read input/output only from gen_ai.*/llm.*, so
|
|
116
|
+
Vercel AI SDK spans (ai.* convention) landed with input/output = None and
|
|
117
|
+
the prompt/response stranded in attributes -> nothing embedded or scored."""
|
|
118
|
+
|
|
119
|
+
def _span(self, name, attrs):
|
|
120
|
+
s = _fake_otel_span(start_ns=1_000_000_000, end_ns=2_000_000_000, attrs=attrs)
|
|
121
|
+
s.name = name
|
|
122
|
+
return s
|
|
123
|
+
|
|
124
|
+
def test_maps_ai_prompt_messages_and_response_text(self):
|
|
125
|
+
otel = self._span(
|
|
126
|
+
"ai.streamText.doStream",
|
|
127
|
+
{
|
|
128
|
+
"trodo.run_id": RUN_ID,
|
|
129
|
+
"gen_ai.system": "openrouter",
|
|
130
|
+
"ai.model.id": "gemini-2.5-flash-lite",
|
|
131
|
+
"ai.usage.promptTokens": 766,
|
|
132
|
+
"ai.usage.completionTokens": 5,
|
|
133
|
+
"ai.prompt.messages": '[{"role":"user","content":"gaming monitor specs"}]',
|
|
134
|
+
"ai.response.text": "Here are some gaming monitors...",
|
|
135
|
+
},
|
|
136
|
+
)
|
|
137
|
+
span = otel_span_to_trodo_span(otel)
|
|
138
|
+
assert span is not None
|
|
139
|
+
assert span.kind == "llm"
|
|
140
|
+
assert "gaming monitor specs" in span.input
|
|
141
|
+
assert "gaming monitors" in span.output
|
|
142
|
+
assert span.model == "gemini-2.5-flash-lite"
|
|
143
|
+
assert span.input_tokens == 766
|
|
144
|
+
assert span.output_tokens == 5
|
|
145
|
+
|
|
146
|
+
def test_maps_ai_toolcall_args_and_result(self):
|
|
147
|
+
otel = self._span(
|
|
148
|
+
"ai.toolCall",
|
|
149
|
+
{
|
|
150
|
+
"trodo.run_id": RUN_ID,
|
|
151
|
+
"ai.toolCall.name": "create_object",
|
|
152
|
+
"ai.toolCall.args": '{"isValid":true}',
|
|
153
|
+
"ai.toolCall.result": '{"ok":1}',
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
span = otel_span_to_trodo_span(otel)
|
|
157
|
+
assert span is not None
|
|
158
|
+
assert span.kind == "tool"
|
|
159
|
+
assert span.tool_name == "create_object"
|
|
160
|
+
assert span.input == '{"isValid":true}'
|
|
161
|
+
assert span.output == '{"ok":1}'
|
|
@@ -45,9 +45,19 @@ def _trunc(s: Any, max_len: int) -> Optional[str]:
|
|
|
45
45
|
def _infer_kind(attrs: Dict[str, Any]) -> str:
|
|
46
46
|
if not attrs:
|
|
47
47
|
return "generic"
|
|
48
|
-
|
|
48
|
+
# Vercel AI SDK tool spans (`ai.toolCall`) carry ai.toolCall.name, not
|
|
49
|
+
# gen_ai.tool.name — without this they landed as 'generic'.
|
|
50
|
+
if attrs.get("gen_ai.tool.name") or attrs.get("ai.toolCall.name") or attrs.get("ai.functionCall.name"):
|
|
49
51
|
return "tool"
|
|
50
|
-
if
|
|
52
|
+
if (
|
|
53
|
+
attrs.get("gen_ai.operation.name")
|
|
54
|
+
or attrs.get("gen_ai.request.model")
|
|
55
|
+
or attrs.get("gen_ai.response.model")
|
|
56
|
+
or attrs.get("ai.model.id")
|
|
57
|
+
or attrs.get("ai.response.model")
|
|
58
|
+
or attrs.get("gen_ai.usage.input_tokens") is not None
|
|
59
|
+
or attrs.get("ai.usage.promptTokens") is not None
|
|
60
|
+
):
|
|
51
61
|
return "llm"
|
|
52
62
|
if attrs.get("db.system") or attrs.get("retrieval.query"):
|
|
53
63
|
return "retrieval"
|
|
@@ -178,20 +188,52 @@ def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
|
178
188
|
attrs.get("gen_ai.usage.input_tokens")
|
|
179
189
|
or attrs.get("gen_ai.usage.prompt_tokens")
|
|
180
190
|
or attrs.get("llm.usage.prompt_tokens")
|
|
191
|
+
or attrs.get("ai.usage.promptTokens")
|
|
192
|
+
or attrs.get("ai.usage.inputTokens")
|
|
181
193
|
)
|
|
182
194
|
out_toks = (
|
|
183
195
|
attrs.get("gen_ai.usage.output_tokens")
|
|
184
196
|
or attrs.get("gen_ai.usage.completion_tokens")
|
|
185
197
|
or attrs.get("llm.usage.completion_tokens")
|
|
198
|
+
or attrs.get("ai.usage.completionTokens")
|
|
199
|
+
or attrs.get("ai.usage.outputTokens")
|
|
186
200
|
)
|
|
187
201
|
model = (
|
|
188
202
|
attrs.get("gen_ai.request.model")
|
|
189
203
|
or attrs.get("gen_ai.response.model")
|
|
190
204
|
or attrs.get("llm.request.model")
|
|
205
|
+
or attrs.get("ai.model.id")
|
|
206
|
+
or attrs.get("ai.response.model")
|
|
207
|
+
)
|
|
208
|
+
provider = attrs.get("gen_ai.system") or attrs.get("llm.vendor") or attrs.get("ai.model.provider")
|
|
209
|
+
# Vercel AI SDK uses the `ai.*` convention, NOT gen_ai.prompt/completion:
|
|
210
|
+
# ai.prompt.messages / ai.prompt (input), ai.response.text / ai.response.object
|
|
211
|
+
# (output), ai.toolCall.args / ai.toolCall.result (tool spans). Omitting these
|
|
212
|
+
# left input/output empty -> NULL in the DB -> nothing embedded or scored.
|
|
213
|
+
prompt = (
|
|
214
|
+
attrs.get("gen_ai.prompt")
|
|
215
|
+
or attrs.get("llm.prompts")
|
|
216
|
+
or attrs.get("ai.prompt")
|
|
217
|
+
or attrs.get("ai.prompt.messages")
|
|
218
|
+
or attrs.get("ai.toolCall.args")
|
|
219
|
+
or attrs.get("input.value")
|
|
220
|
+
)
|
|
221
|
+
completion = (
|
|
222
|
+
attrs.get("gen_ai.completion")
|
|
223
|
+
or attrs.get("llm.completion")
|
|
224
|
+
or attrs.get("ai.response.text")
|
|
225
|
+
or attrs.get("ai.response.object")
|
|
226
|
+
or attrs.get("ai.toolCall.result")
|
|
227
|
+
or attrs.get("output.value")
|
|
228
|
+
)
|
|
229
|
+
tool_name = (
|
|
230
|
+
attrs.get("gen_ai.tool.name")
|
|
231
|
+
or attrs.get("ai.toolCall.name")
|
|
232
|
+
or attrs.get("ai.functionCall.name")
|
|
191
233
|
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
234
|
+
temperature = attrs.get("gen_ai.request.temperature")
|
|
235
|
+
if temperature is None:
|
|
236
|
+
temperature = attrs.get("ai.settings.temperature")
|
|
195
237
|
|
|
196
238
|
return TrodoSpan(
|
|
197
239
|
span_id=span_id,
|
|
@@ -212,8 +254,8 @@ def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
|
212
254
|
provider=provider,
|
|
213
255
|
input_tokens=int(in_toks) if in_toks is not None else None,
|
|
214
256
|
output_tokens=int(out_toks) if out_toks is not None else None,
|
|
215
|
-
temperature=
|
|
216
|
-
tool_name=
|
|
257
|
+
temperature=temperature,
|
|
258
|
+
tool_name=tool_name,
|
|
217
259
|
input=prompt,
|
|
218
260
|
output=completion,
|
|
219
261
|
attributes=attrs or None,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|