trodo-python 2.5.0__tar.gz → 2.6.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.
- {trodo_python-2.5.0 → trodo_python-2.6.0}/PKG-INFO +1 -1
- {trodo_python-2.5.0 → trodo_python-2.6.0}/pyproject.toml +1 -1
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/processor.py +5 -5
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/wrap_agent.py +38 -14
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/PKG-INFO +1 -1
- {trodo_python-2.5.0 → trodo_python-2.6.0}/README.md +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/setup.cfg +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_anon_distinct_id.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_auto_instrument_fixes.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_cross_process_session.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_end_run.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_processor_methods.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_register_otel.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_start_run.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_wrap_agent_unchanged.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/async_client.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/endpoints.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/http_client.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/auto/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/auto/auto_event_manager.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/client.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/group_manager.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/people_manager.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/auto_instrument.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/context.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/helpers.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/register.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/transport.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/batch_flusher.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/event_queue.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/__init__.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/server_session.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/session_manager.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/types.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/user_context.py +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/SOURCES.txt +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/dependency_links.txt +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/requires.txt +0 -0
- {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import threading
|
|
11
11
|
from dataclasses import dataclass, asdict
|
|
12
|
-
from typing import Any, Dict, List, Optional
|
|
12
|
+
from typing import Any, Dict, List, Optional, Union
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@dataclass
|
|
@@ -20,8 +20,8 @@ class TrodoRun:
|
|
|
20
20
|
conversation_id: Optional[str] = None
|
|
21
21
|
parent_run_id: Optional[str] = None
|
|
22
22
|
status: str = "ok" # 'running' | 'ok' | 'error'
|
|
23
|
-
input: Optional[str] = None
|
|
24
|
-
output: Optional[str] = None
|
|
23
|
+
input: Optional[Union[str, Dict[str, Any]]] = None
|
|
24
|
+
output: Optional[Union[str, Dict[str, Any]]] = None
|
|
25
25
|
started_at: Optional[str] = None
|
|
26
26
|
ended_at: Optional[str] = None
|
|
27
27
|
duration_ms: Optional[int] = None
|
|
@@ -50,8 +50,8 @@ class TrodoSpan:
|
|
|
50
50
|
started_at: Optional[str] = None
|
|
51
51
|
ended_at: Optional[str] = None
|
|
52
52
|
duration_ms: Optional[int] = None
|
|
53
|
-
input: Optional[str] = None
|
|
54
|
-
output: Optional[str] = None
|
|
53
|
+
input: Optional[Union[str, Dict[str, Any]]] = None
|
|
54
|
+
output: Optional[Union[str, Dict[str, Any]]] = None
|
|
55
55
|
error_type: Optional[str] = None
|
|
56
56
|
error_message: Optional[str] = None
|
|
57
57
|
model: Optional[str] = None
|
|
@@ -28,7 +28,7 @@ import json
|
|
|
28
28
|
import time
|
|
29
29
|
import uuid
|
|
30
30
|
from datetime import datetime, timezone
|
|
31
|
-
from typing import Any, Callable, Dict, Optional
|
|
31
|
+
from typing import Any, Callable, Dict, Optional, Union
|
|
32
32
|
|
|
33
33
|
from .context import ActiveSpanContext, get_active_context, run_with_context
|
|
34
34
|
from .processor import TrodoSpanProcessor, TrodoRun, TrodoSpan
|
|
@@ -62,7 +62,11 @@ def _now_iso() -> str:
|
|
|
62
62
|
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
_MAX_VALUE_LEN = 1_000_000 # 1 MB
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _truncate(value: Any, max_len: int = _MAX_VALUE_LEN) -> Optional[str]:
|
|
69
|
+
"""Coerce to string and truncate. Use for string-only contexts (OTel attrs, error summaries)."""
|
|
66
70
|
if value is None:
|
|
67
71
|
return None
|
|
68
72
|
if isinstance(value, str):
|
|
@@ -75,6 +79,26 @@ def _truncate(value: Any, max_len: int = 64_000) -> Optional[str]:
|
|
|
75
79
|
return s[:max_len] if len(s) > max_len else s
|
|
76
80
|
|
|
77
81
|
|
|
82
|
+
def _prepare_value(value: Any, max_len: int = _MAX_VALUE_LEN) -> Optional[Union[str, Dict[str, Any]]]:
|
|
83
|
+
"""Prepare a value for storage in the JSONB input/output column.
|
|
84
|
+
|
|
85
|
+
Dicts/lists pass through as-is (stored as JSONB objects/arrays).
|
|
86
|
+
Strings are truncated at max_len.
|
|
87
|
+
Everything else is JSON-serialised then truncated.
|
|
88
|
+
"""
|
|
89
|
+
if value is None:
|
|
90
|
+
return None
|
|
91
|
+
if isinstance(value, dict):
|
|
92
|
+
return value
|
|
93
|
+
if isinstance(value, str):
|
|
94
|
+
return value[:max_len] if len(value) > max_len else value
|
|
95
|
+
try:
|
|
96
|
+
s = json.dumps(value, default=str)
|
|
97
|
+
except Exception:
|
|
98
|
+
s = str(value)
|
|
99
|
+
return s[:max_len] if len(s) > max_len else s
|
|
100
|
+
|
|
101
|
+
|
|
78
102
|
def current_run_id() -> Optional[str]:
|
|
79
103
|
"""Return the run_id of the currently active agent run, if any."""
|
|
80
104
|
ctx = get_active_context()
|
|
@@ -145,15 +169,15 @@ class RunHandle:
|
|
|
145
169
|
# Always populated — wrap_agent mints anon if caller didn't pass one
|
|
146
170
|
# so downstream ``trodo.feedback(distinct_id=...)`` always has a target.
|
|
147
171
|
self.distinct_id = distinct_id
|
|
148
|
-
self.input: Optional[str] = None
|
|
149
|
-
self.output: Optional[str] = None
|
|
172
|
+
self.input: Optional[Union[str, Dict[str, Any]]] = None
|
|
173
|
+
self.output: Optional[Union[str, Dict[str, Any]]] = None
|
|
150
174
|
self.metadata: Dict[str, Any] = {}
|
|
151
175
|
|
|
152
176
|
def set_input(self, value: Any) -> None:
|
|
153
|
-
self.input =
|
|
177
|
+
self.input = _prepare_value(value)
|
|
154
178
|
|
|
155
179
|
def set_output(self, value: Any) -> None:
|
|
156
|
-
self.output =
|
|
180
|
+
self.output = _prepare_value(value)
|
|
157
181
|
|
|
158
182
|
def set_metadata(self, **kwargs: Any) -> None:
|
|
159
183
|
self.metadata.update(kwargs)
|
|
@@ -165,8 +189,8 @@ class SpanHandle:
|
|
|
165
189
|
def __init__(self, span_id: str, name: str) -> None:
|
|
166
190
|
self.span_id = span_id
|
|
167
191
|
self.name = name
|
|
168
|
-
self.input: Optional[str] = None
|
|
169
|
-
self.output: Optional[str] = None
|
|
192
|
+
self.input: Optional[Union[str, Dict[str, Any]]] = None
|
|
193
|
+
self.output: Optional[Union[str, Dict[str, Any]]] = None
|
|
170
194
|
self.attributes: Dict[str, Any] = {}
|
|
171
195
|
self.model: Optional[str] = None
|
|
172
196
|
self.provider: Optional[str] = None
|
|
@@ -177,10 +201,10 @@ class SpanHandle:
|
|
|
177
201
|
self.tool_name: Optional[str] = None
|
|
178
202
|
|
|
179
203
|
def set_input(self, value: Any) -> None:
|
|
180
|
-
self.input =
|
|
204
|
+
self.input = _prepare_value(value)
|
|
181
205
|
|
|
182
206
|
def set_output(self, value: Any) -> None:
|
|
183
|
-
self.output =
|
|
207
|
+
self.output = _prepare_value(value)
|
|
184
208
|
|
|
185
209
|
def set_attribute(self, key: str, value: Any) -> None:
|
|
186
210
|
self.attributes[key] = value
|
|
@@ -247,7 +271,7 @@ def start_run(
|
|
|
247
271
|
conversation_id=conversation_id,
|
|
248
272
|
parent_run_id=parent_run_id,
|
|
249
273
|
status="running",
|
|
250
|
-
input=
|
|
274
|
+
input=_prepare_value(input),
|
|
251
275
|
started_at=_now_iso(),
|
|
252
276
|
metadata=metadata,
|
|
253
277
|
)
|
|
@@ -279,7 +303,7 @@ def end_run(
|
|
|
279
303
|
**agg,
|
|
280
304
|
}
|
|
281
305
|
if output is not None:
|
|
282
|
-
payload["output"] =
|
|
306
|
+
payload["output"] = _prepare_value(output)
|
|
283
307
|
if error_summary is not None:
|
|
284
308
|
payload["error_summary"] = _truncate(error_summary, 4_000)
|
|
285
309
|
if metadata is not None:
|
|
@@ -493,7 +517,7 @@ class join_run:
|
|
|
493
517
|
self._parent_span_id = parent_span_id
|
|
494
518
|
self._name = name
|
|
495
519
|
self._kind = kind
|
|
496
|
-
self._input =
|
|
520
|
+
self._input = _prepare_value(input) if input is not None else None
|
|
497
521
|
self._attributes = attributes
|
|
498
522
|
self._ctx_mgr: Optional[run_with_context] = None
|
|
499
523
|
self._started_ms: float = 0.0
|
|
@@ -580,7 +604,7 @@ class span:
|
|
|
580
604
|
) -> None:
|
|
581
605
|
self._name = name
|
|
582
606
|
self._kind = kind
|
|
583
|
-
self._input =
|
|
607
|
+
self._input = _prepare_value(input) if input is not None else None
|
|
584
608
|
self._attributes = attributes
|
|
585
609
|
self._ctx_mgr: Optional[run_with_context] = None
|
|
586
610
|
self._started_ms: float = 0.0
|
|
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
|