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.
Files changed (44) hide show
  1. {trodo_python-2.5.0 → trodo_python-2.6.0}/PKG-INFO +1 -1
  2. {trodo_python-2.5.0 → trodo_python-2.6.0}/pyproject.toml +1 -1
  3. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/processor.py +5 -5
  4. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/wrap_agent.py +38 -14
  5. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/PKG-INFO +1 -1
  6. {trodo_python-2.5.0 → trodo_python-2.6.0}/README.md +0 -0
  7. {trodo_python-2.5.0 → trodo_python-2.6.0}/setup.cfg +0 -0
  8. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_anon_distinct_id.py +0 -0
  9. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_auto_instrument_fixes.py +0 -0
  10. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_cross_process_session.py +0 -0
  11. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_end_run.py +0 -0
  12. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_processor_methods.py +0 -0
  13. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_register_otel.py +0 -0
  14. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_start_run.py +0 -0
  15. {trodo_python-2.5.0 → trodo_python-2.6.0}/tests/test_wrap_agent_unchanged.py +0 -0
  16. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/__init__.py +0 -0
  17. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/__init__.py +0 -0
  18. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/async_client.py +0 -0
  19. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/endpoints.py +0 -0
  20. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/api/http_client.py +0 -0
  21. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/auto/__init__.py +0 -0
  22. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/auto/auto_event_manager.py +0 -0
  23. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/client.py +0 -0
  24. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/__init__.py +0 -0
  25. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/group_manager.py +0 -0
  26. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/managers/people_manager.py +0 -0
  27. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/__init__.py +0 -0
  28. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/auto_instrument.py +0 -0
  29. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/context.py +0 -0
  30. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/helpers.py +0 -0
  31. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/register.py +0 -0
  32. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/otel/transport.py +0 -0
  33. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/__init__.py +0 -0
  34. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/batch_flusher.py +0 -0
  35. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/queue/event_queue.py +0 -0
  36. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/__init__.py +0 -0
  37. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/server_session.py +0 -0
  38. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/session/session_manager.py +0 -0
  39. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/types.py +0 -0
  40. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo/user_context.py +0 -0
  41. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/SOURCES.txt +0 -0
  42. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/dependency_links.txt +0 -0
  43. {trodo_python-2.5.0 → trodo_python-2.6.0}/trodo_python.egg-info/requires.txt +0 -0
  44. {trodo_python-2.5.0 → trodo_python-2.6.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: 2.5.0
3
+ Version: 2.6.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "trodo-python"
7
- version = "2.5.0"
7
+ version = "2.6.0"
8
8
  description = "Trodo Analytics SDK for Python — server-side event tracking"
9
9
  readme = "README.md"
10
10
  license = { text = "ISC" }
@@ -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
- def _truncate(value: Any, max_len: int = 64_000) -> Optional[str]:
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 = _truncate(value)
177
+ self.input = _prepare_value(value)
154
178
 
155
179
  def set_output(self, value: Any) -> None:
156
- self.output = _truncate(value)
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 = _truncate(value)
204
+ self.input = _prepare_value(value)
181
205
 
182
206
  def set_output(self, value: Any) -> None:
183
- self.output = _truncate(value)
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=_truncate(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"] = _truncate(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 = _truncate(input) if input is not None else None
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 = _truncate(input) if input is not None else None
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trodo-python
3
- Version: 2.5.0
3
+ Version: 2.6.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
File without changes
File without changes