agenta 0.27.0__py3-none-any.whl → 0.27.0a1__py3-none-any.whl

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.

Potentially problematic release.


This version of agenta might be problematic. Click here for more details.

Files changed (68) hide show
  1. agenta/__init__.py +3 -22
  2. agenta/cli/helper.py +1 -5
  3. agenta/client/backend/__init__.py +0 -14
  4. agenta/client/backend/apps/client.py +20 -28
  5. agenta/client/backend/client.py +2 -25
  6. agenta/client/backend/containers/client.py +1 -5
  7. agenta/client/backend/core/__init__.py +1 -2
  8. agenta/client/backend/core/client_wrapper.py +6 -6
  9. agenta/client/backend/core/file.py +11 -33
  10. agenta/client/backend/core/http_client.py +18 -24
  11. agenta/client/backend/core/pydantic_utilities.py +29 -144
  12. agenta/client/backend/core/request_options.py +0 -3
  13. agenta/client/backend/core/serialization.py +42 -139
  14. agenta/client/backend/evaluations/client.py +2 -7
  15. agenta/client/backend/evaluators/client.py +1 -349
  16. agenta/client/backend/observability/client.py +2 -11
  17. agenta/client/backend/testsets/client.py +10 -10
  18. agenta/client/backend/types/__init__.py +0 -14
  19. agenta/client/backend/types/app.py +0 -1
  20. agenta/client/backend/types/app_variant_response.py +1 -3
  21. agenta/client/backend/types/create_span.py +2 -3
  22. agenta/client/backend/types/environment_output.py +0 -1
  23. agenta/client/backend/types/environment_output_extended.py +0 -1
  24. agenta/client/backend/types/evaluation.py +2 -1
  25. agenta/client/backend/types/evaluator.py +0 -2
  26. agenta/client/backend/types/evaluator_config.py +0 -1
  27. agenta/client/backend/types/human_evaluation.py +2 -1
  28. agenta/client/backend/types/llm_tokens.py +2 -2
  29. agenta/client/backend/types/span.py +0 -1
  30. agenta/client/backend/types/span_detail.py +1 -7
  31. agenta/client/backend/types/test_set_output_response.py +2 -5
  32. agenta/client/backend/types/trace_detail.py +1 -7
  33. agenta/client/backend/types/with_pagination.py +2 -4
  34. agenta/client/backend/variants/client.py +273 -1566
  35. agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
  36. agenta/sdk/__init__.py +5 -20
  37. agenta/sdk/agenta_init.py +26 -30
  38. agenta/sdk/config_manager.py +205 -0
  39. agenta/sdk/context/routing.py +5 -6
  40. agenta/sdk/decorators/routing.py +135 -142
  41. agenta/sdk/decorators/tracing.py +245 -206
  42. agenta/sdk/litellm/litellm.py +36 -47
  43. agenta/sdk/tracing/attributes.py +2 -7
  44. agenta/sdk/tracing/context.py +2 -5
  45. agenta/sdk/tracing/conventions.py +8 -10
  46. agenta/sdk/tracing/exporters.py +6 -15
  47. agenta/sdk/tracing/inline.py +98 -70
  48. agenta/sdk/tracing/processors.py +14 -55
  49. agenta/sdk/tracing/spans.py +4 -16
  50. agenta/sdk/tracing/tracing.py +50 -54
  51. agenta/sdk/types.py +2 -61
  52. agenta/sdk/utils/exceptions.py +1 -31
  53. {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/METADATA +1 -1
  54. {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/RECORD +56 -67
  55. agenta/client/backend/types/config_dto.py +0 -32
  56. agenta/client/backend/types/config_response_model.py +0 -32
  57. agenta/client/backend/types/evaluator_mapping_output_interface.py +0 -21
  58. agenta/client/backend/types/evaluator_output_interface.py +0 -21
  59. agenta/client/backend/types/lifecycle_dto.py +0 -24
  60. agenta/client/backend/types/reference_dto.py +0 -23
  61. agenta/client/backend/types/reference_request_model.py +0 -23
  62. agenta/sdk/managers/__init__.py +0 -6
  63. agenta/sdk/managers/config.py +0 -318
  64. agenta/sdk/managers/deployment.py +0 -45
  65. agenta/sdk/managers/shared.py +0 -639
  66. agenta/sdk/managers/variant.py +0 -182
  67. {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/WHEEL +0 -0
  68. {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/entry_points.txt +0 -0
@@ -15,10 +15,7 @@ def tracing_context_manager():
15
15
  try:
16
16
  yield
17
17
  except Exception as e:
18
- log.error("----------------------------------------------")
19
- log.error("Agenta SDK - handling tracing exception below:")
20
- log.error("----------------------------------------------")
21
- log.error(format_exc().strip("\n"))
22
- log.error("----------------------------------------------")
18
+ log.error(f"Error with tracing context: {_tracing_context}")
19
+ log.error(f"Exception: {format_exc()}")
23
20
  finally:
24
21
  tracing_context.reset(token)
@@ -1,7 +1,14 @@
1
+ from opentelemetry.trace import SpanKind
2
+
1
3
  from enum import Enum
4
+
2
5
  from re import fullmatch
3
6
 
4
- from opentelemetry.trace import SpanKind
7
+ _PATTERN = r"[A-Za-z0-9._-]+"
8
+
9
+
10
+ def is_valid_attribute_key(string):
11
+ return bool(fullmatch(_PATTERN, string))
5
12
 
6
13
 
7
14
  class Reference(str, Enum):
@@ -19,15 +26,6 @@ class Reference(str, Enum):
19
26
  #
20
27
 
21
28
 
22
- _PATTERN = r"[A-Za-z0-9._-]+"
23
-
24
-
25
- def is_valid_attribute_key(
26
- string: str,
27
- ):
28
- return bool(fullmatch(_PATTERN, string))
29
-
30
-
31
29
  def parse_span_kind(type: str) -> SpanKind:
32
30
  kind = SpanKind.INTERNAL
33
31
  if type in [
@@ -1,12 +1,14 @@
1
1
  from typing import Sequence, Dict, List
2
2
 
3
- from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
4
3
  from opentelemetry.sdk.trace.export import (
5
4
  ConsoleSpanExporter,
6
5
  SpanExporter,
7
6
  SpanExportResult,
8
7
  ReadableSpan,
9
8
  )
9
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
10
+ OTLPSpanExporter,
11
+ )
10
12
 
11
13
  from agenta.sdk.utils.exceptions import suppress
12
14
 
@@ -38,28 +40,17 @@ class InlineTraceExporter(SpanExporter):
38
40
  def force_flush(self, timeout_millis: int = 30000) -> bool:
39
41
  return True
40
42
 
41
- def is_ready(
42
- self,
43
- trace_id: int,
44
- ) -> bool:
45
- is_ready = trace_id in self._registry
46
-
47
- return is_ready
48
-
49
- def fetch(
50
- self,
51
- trace_id: int,
52
- ) -> List[ReadableSpan]:
43
+ def fetch(self, trace_id: int) -> List[ReadableSpan]:
53
44
  trace = self._registry.get(trace_id, [])
54
45
 
55
- if trace_id in self._registry:
56
- del self._registry[trace_id]
46
+ del self._registry[trace_id]
57
47
 
58
48
  return trace
59
49
 
60
50
 
61
51
  OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
62
52
 
53
+
63
54
  ConsoleExporter = ConsoleSpanExporter
64
55
  InlineExporter = InlineTraceExporter
65
56
  OTLPExporter = OTLPSpanExporter
@@ -11,11 +11,82 @@ from enum import Enum
11
11
  from collections import OrderedDict
12
12
 
13
13
 
14
- class ProjectScopeDTO(BaseModel):
14
+ NOF_CHARS = 8
15
+
16
+
17
+ def _p_id(id):
18
+ return repr(str(id)[:NOF_CHARS])
19
+
20
+
21
+ def _p_osa(o):
22
+ elements = []
23
+
24
+ for i in OrderedDict(sorted(o.items())).items():
25
+ if not i[0].startswith("_"):
26
+ if i[1].__class__.__module__ != "builtins":
27
+ if repr(i[1]).startswith("<"):
28
+ elements.append(f"{i[0]}: {i[1].name}")
29
+ elif repr(i[1]).startswith("UUID("):
30
+ elements.append(f"{i[0]}: {_p_id(i[1])}")
31
+ else:
32
+ elements.append(f"{i[0]}: {i[1].__str__()}")
33
+ else:
34
+ if isinstance(i[1], list):
35
+ elements.append(
36
+ f"{i[0]}: [" + ", ".join([el.__str__() for el in i[1]]) + "]"
37
+ )
38
+ elif isinstance(i[1], dict):
39
+ elements.append(f"{i[0]}: {{{_p_osa(i[1])}}}")
40
+ else:
41
+ if i[1] is not None:
42
+ if i[0] == "slug":
43
+ elements.append(f"{i[0]}: {repr(i[1][:8])}")
44
+ else:
45
+ elements.append(f"{i[0]}: {repr(i[1])}")
46
+
47
+ return ", ".join(elements)
48
+
49
+
50
+ def _p_ora(o, open="{", close="}", sep=": ", foo=repr):
51
+ if o.__class__.__module__ != "builtins":
52
+ if o.__class__.__name__ == "UUID":
53
+ return repr(o)
54
+ if isinstance(o, Enum):
55
+ return o
56
+ if isinstance(o, datetime):
57
+ return o.isoformat()
58
+ return f"{o.__class__.__name__}({_p_ora(o.__dict__, open='', close='', sep='=', foo=lambda x : x)})"
59
+ elif isinstance(o, list):
60
+ return f"[{', '.join([repr(el) for el in o])}]"
61
+ elif isinstance(o, dict):
62
+ o = OrderedDict(sorted(o.items()))
63
+ return f"{open}{', '.join([f'{foo(elk)}{sep}{_p_ora(elv)}' for elk, elv in o.items()])}{close}"
64
+ else:
65
+ if o is not None:
66
+ return repr(o)
67
+
68
+
69
+ def _str(o):
70
+ return f"{{{_p_osa(o.__dict__)}}}"
71
+
72
+
73
+ def _repr(o):
74
+ return _p_ora(o)
75
+
76
+
77
+ class DisplayBase(BaseModel):
78
+ def __str__(self):
79
+ return _str(self)
80
+
81
+ def __repr__(self):
82
+ return _repr(self)
83
+
84
+
85
+ class ProjectScopeDTO(DisplayBase):
15
86
  project_id: UUID
16
87
 
17
88
 
18
- class LifecycleDTO(BaseModel):
89
+ class LifecycleDTO(DisplayBase):
19
90
  created_at: datetime
20
91
  updated_at: Optional[datetime] = None
21
92
 
@@ -31,14 +102,14 @@ class LifecycleDTO(BaseModel):
31
102
  ### services.observability.dtos ###
32
103
  ### --------------------------- ###
33
104
 
34
- from typing import List, Dict, Any, Union, Optional
105
+ from typing import List, Dict, Any, Union, Optional, Sequence
35
106
 
36
107
  from enum import Enum
37
108
  from datetime import datetime
38
109
  from uuid import UUID
39
110
 
40
111
 
41
- class TimeDTO(BaseModel):
112
+ class TimeDTO(DisplayBase):
42
113
  start: datetime
43
114
  end: datetime
44
115
  span: int
@@ -50,7 +121,7 @@ class StatusCode(Enum):
50
121
  ERROR = "ERROR"
51
122
 
52
123
 
53
- class StatusDTO(BaseModel):
124
+ class StatusDTO(DisplayBase):
54
125
  code: StatusCode
55
126
  message: Optional[str] = None
56
127
  stacktrace: Optional[str] = None
@@ -84,16 +155,16 @@ class NodeType(Enum):
84
155
  # --- VARIANTS --- #
85
156
 
86
157
 
87
- class RootDTO(BaseModel):
158
+ class RootDTO(DisplayBase):
88
159
  id: UUID
89
160
 
90
161
 
91
- class TreeDTO(BaseModel):
162
+ class TreeDTO(DisplayBase):
92
163
  id: UUID
93
164
  type: Optional[TreeType] = None
94
165
 
95
166
 
96
- class NodeDTO(BaseModel):
167
+ class NodeDTO(DisplayBase):
97
168
  id: UUID
98
169
  type: Optional[NodeType] = None
99
170
  name: str
@@ -106,13 +177,13 @@ Tags = Dict[str, str]
106
177
  Refs = Dict[str, str]
107
178
 
108
179
 
109
- class LinkDTO(BaseModel):
180
+ class LinkDTO(DisplayBase):
110
181
  type: str
111
182
  id: UUID
112
183
  tree_id: Optional[UUID] = None
113
184
 
114
185
 
115
- class ParentDTO(BaseModel):
186
+ class ParentDTO(DisplayBase):
116
187
  id: UUID
117
188
 
118
189
 
@@ -134,25 +205,25 @@ class OTelStatusCode(Enum):
134
205
  STATUS_CODE_UNSET = "STATUS_CODE_UNSET"
135
206
 
136
207
 
137
- class OTelContextDTO(BaseModel):
208
+ class OTelContextDTO(DisplayBase):
138
209
  trace_id: str
139
210
  span_id: str
140
211
 
141
212
 
142
- class OTelEventDTO(BaseModel):
213
+ class OTelEventDTO(DisplayBase):
143
214
  name: str
144
215
  timestamp: datetime
145
216
 
146
217
  attributes: Optional[Attributes] = None
147
218
 
148
219
 
149
- class OTelLinkDTO(BaseModel):
220
+ class OTelLinkDTO(DisplayBase):
150
221
  context: OTelContextDTO
151
222
 
152
223
  attributes: Optional[Attributes] = None
153
224
 
154
225
 
155
- class OTelExtraDTO(BaseModel):
226
+ class OTelExtraDTO(DisplayBase):
156
227
  kind: Optional[str] = None
157
228
 
158
229
  attributes: Optional[Attributes] = None
@@ -160,8 +231,8 @@ class OTelExtraDTO(BaseModel):
160
231
  links: Optional[List[OTelLinkDTO]] = None
161
232
 
162
233
 
163
- class SpanDTO(BaseModel):
164
- scope: Optional[ProjectScopeDTO] = None
234
+ class SpanDTO(DisplayBase):
235
+ scope: ProjectScopeDTO
165
236
 
166
237
  lifecycle: Optional[LifecycleDTO] = None
167
238
 
@@ -187,7 +258,7 @@ class SpanDTO(BaseModel):
187
258
  nodes: Optional[Dict[str, Union["SpanDTO", List["SpanDTO"]]]] = None
188
259
 
189
260
 
190
- class OTelSpanDTO(BaseModel):
261
+ class OTelSpanDTO(DisplayBase):
191
262
  context: OTelContextDTO
192
263
 
193
264
  name: str
@@ -412,12 +483,9 @@ def _connect_tree_dfs(
412
483
  ### apis.fastapi.observability.opentelemetry.semconv ###
413
484
  ### ------------------------------------------------ ###
414
485
 
415
- from json import loads
416
-
417
486
  VERSION = "0.4.1"
418
487
 
419
488
  V_0_4_1_ATTRIBUTES_EXACT = [
420
- # OPENLLMETRY
421
489
  ("gen_ai.system", "ag.meta.system"),
422
490
  ("gen_ai.request.base_url", "ag.meta.request.base_url"),
423
491
  ("gen_ai.request.endpoint", "ag.meta.request.endpoint"),
@@ -442,35 +510,12 @@ V_0_4_1_ATTRIBUTES_EXACT = [
442
510
  ("db.vector.query.top_k", "ag.meta.request.top_k"),
443
511
  ("pinecone.query.top_k", "ag.meta.request.top_k"),
444
512
  ("traceloop.span.kind", "ag.type.node"),
445
- ("traceloop.entity.name", "ag.node.name"),
446
- # OPENINFERENCE
447
- ("output.value", "ag.data.outputs"),
448
- ("input.value", "ag.data.inputs"),
449
- ("embedding.model_name", "ag.meta.request.model"),
450
- ("llm.invocation_parameters", "ag.meta.request"),
451
- ("llm.model_name", "ag.meta.request.model"),
452
- ("llm.provider", "ag.meta.provider"),
453
- ("llm.system", "ag.meta.system"),
454
513
  ]
455
514
  V_0_4_1_ATTRIBUTES_PREFIX = [
456
- # OPENLLMETRY
457
515
  ("gen_ai.prompt", "ag.data.inputs.prompt"),
458
516
  ("gen_ai.completion", "ag.data.outputs.completion"),
459
- ("llm.request.functions", "ag.data.inputs.functions"),
460
- ("llm.request.tools", "ag.data.inputs.tools"),
461
- # OPENINFERENCE
462
- ("llm.token_count", "ag.metrics.unit.tokens"),
463
- ("llm.input_messages", "ag.data.inputs.prompt"),
464
- ("llm.output_messages", "ag.data.outputs.completion"),
465
517
  ]
466
518
 
467
- V_0_4_1_ATTRIBUTES_DYNAMIC = [
468
- # OPENLLMETRY
469
- ("traceloop.entity.input", lambda x: ("ag.data.inputs", loads(x).get("inputs"))),
470
- ("traceloop.entity.output", lambda x: ("ag.data.outputs", loads(x).get("outputs"))),
471
- ]
472
-
473
-
474
519
  V_0_4_1_MAPS = {
475
520
  "attributes": {
476
521
  "exact": {
@@ -481,9 +526,6 @@ V_0_4_1_MAPS = {
481
526
  "from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
482
527
  "to": {agenta: otel for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
483
528
  },
484
- "dynamic": {
485
- "from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_DYNAMIC[::-1]}
486
- },
487
529
  },
488
530
  }
489
531
  V_0_4_1_KEYS = {
@@ -496,9 +538,6 @@ V_0_4_1_KEYS = {
496
538
  "from": list(V_0_4_1_MAPS["attributes"]["prefix"]["from"].keys()),
497
539
  "to": list(V_0_4_1_MAPS["attributes"]["prefix"]["to"].keys()),
498
540
  },
499
- "dynamic": {
500
- "from": list(V_0_4_1_MAPS["attributes"]["dynamic"]["from"].keys()),
501
- },
502
541
  },
503
542
  }
504
543
 
@@ -512,7 +551,6 @@ KEYS = {
512
551
 
513
552
  CODEX = {"maps": MAPS[VERSION], "keys": KEYS[VERSION]}
514
553
 
515
-
516
554
  ### ------------------------------------------------ ###
517
555
  ### apis.fastapi.observability.opentelemetry.semconv ###
518
556
  ########################################################
@@ -686,18 +724,6 @@ def _parse_from_semconv(
686
724
 
687
725
  del attributes[old_key]
688
726
 
689
- for dynamic_key in CODEX["keys"]["attributes"]["dynamic"]["from"]:
690
- if old_key == dynamic_key:
691
- try:
692
- new_key, new_value = CODEX["maps"]["attributes"]["dynamic"][
693
- "from"
694
- ][dynamic_key](value)
695
-
696
- attributes[new_key] = new_value
697
-
698
- except: # pylint: disable=bare-except
699
- pass
700
-
701
727
 
702
728
  def _parse_from_links(
703
729
  otel_span_dto: OTelSpanDTO,
@@ -800,8 +826,11 @@ def _parse_from_attributes(
800
826
 
801
827
 
802
828
  def parse_from_otel_span_dto(
829
+ project_id: str,
803
830
  otel_span_dto: OTelSpanDTO,
804
831
  ) -> SpanDTO:
832
+ scope = ProjectScopeDTO(project_id=UUID(project_id))
833
+
805
834
  lifecyle = LifecycleDTO(
806
835
  created_at=datetime.now(),
807
836
  )
@@ -821,15 +850,11 @@ def parse_from_otel_span_dto(
821
850
 
822
851
  node_id = UUID(tree_id.hex[16:] + otel_span_dto.context.span_id[2:])
823
852
 
824
- node_type = NodeType.TASK
825
- try:
826
- node_type = NodeType(types.get("node", "").lower())
827
- except: # pylint: disable=bare-except
828
- pass
853
+ node_type: str = types.get("node")
829
854
 
830
855
  node = NodeDTO(
831
856
  id=node_id,
832
- type=node_type,
857
+ type=node_type.lower() if node_type else None,
833
858
  name=otel_span_dto.name,
834
859
  )
835
860
 
@@ -877,6 +902,7 @@ def parse_from_otel_span_dto(
877
902
  )
878
903
 
879
904
  span_dto = SpanDTO(
905
+ scope=scope,
880
906
  lifecycle=lifecyle,
881
907
  root=root,
882
908
  tree=tree,
@@ -947,6 +973,7 @@ from opentelemetry.sdk.trace import ReadableSpan
947
973
 
948
974
 
949
975
  def parse_inline_trace(
976
+ project_id: str,
950
977
  spans: Dict[str, ReadableSpan],
951
978
  ):
952
979
  otel_span_dtos = _parse_readable_spans(spans)
@@ -955,7 +982,8 @@ def parse_inline_trace(
955
982
  ### apis.fastapi.observability.api.otlp_collect_traces() ###
956
983
  ### ---------------------------------------------------- ###
957
984
  span_dtos = [
958
- parse_from_otel_span_dto(otel_span_dto) for otel_span_dto in otel_span_dtos
985
+ parse_from_otel_span_dto(project_id, otel_span_dto)
986
+ for otel_span_dto in otel_span_dtos
959
987
  ]
960
988
  ### ---------------------------------------------------- ###
961
989
  ### apis.fastapi.observability.api.otlp_collect_traces() ###
@@ -1195,7 +1223,7 @@ def _parse_to_legacy_span(span: SpanDTO) -> CreateSpan:
1195
1223
  ),
1196
1224
  #
1197
1225
  app_id=(
1198
- span.refs.get("application", {}).get("id", "missing-app-id")
1226
+ span.refs.get("application.id", "missing-app-id")
1199
1227
  if span.refs
1200
1228
  else "missing-app-id"
1201
1229
  ),
@@ -1,4 +1,5 @@
1
- from typing import Optional, Dict, List
1
+ from typing import Optional, Dict
2
+ from traceback import format_exc
2
3
 
3
4
  from opentelemetry.context import Context
4
5
  from opentelemetry.sdk.trace import Span
@@ -6,8 +7,8 @@ from opentelemetry.sdk.trace.export import (
6
7
  SpanExporter,
7
8
  ReadableSpan,
8
9
  BatchSpanProcessor,
10
+ _DEFAULT_EXPORT_TIMEOUT_MILLIS,
9
11
  _DEFAULT_MAX_QUEUE_SIZE,
10
- _DEFAULT_MAX_EXPORT_BATCH_SIZE,
11
12
  )
12
13
 
13
14
  from agenta.sdk.utils.logging import log
@@ -28,21 +29,16 @@ class TraceProcessor(BatchSpanProcessor):
28
29
  super().__init__(
29
30
  span_exporter,
30
31
  _DEFAULT_MAX_QUEUE_SIZE,
31
- 12 * 60 * 60 * 1000, # 12 hours
32
- _DEFAULT_MAX_EXPORT_BATCH_SIZE,
32
+ 60 * 60 * 1000, # 1 hour
33
+ _DEFAULT_MAX_QUEUE_SIZE,
33
34
  500, # < 1 second (0.5 seconds)
34
35
  )
35
36
 
36
37
  self._registry = dict()
37
38
  self._exporter = span_exporter
38
39
  self.references = references or dict()
39
- self.spans: Dict[int, List[ReadableSpan]] = dict()
40
40
 
41
- def on_start(
42
- self,
43
- span: Span,
44
- parent_context: Optional[Context] = None,
45
- ) -> None:
41
+ def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None:
46
42
  # ADD LINKS FROM CONTEXT, HERE
47
43
 
48
44
  for key in self.references.keys():
@@ -53,41 +49,15 @@ class TraceProcessor(BatchSpanProcessor):
53
49
 
54
50
  self._registry[span.context.trace_id][span.context.span_id] = True
55
51
 
56
- def on_end(
57
- self,
58
- span: ReadableSpan,
59
- ):
60
- if self.done:
61
- return
62
-
63
- if span.context.trace_id not in self.spans:
64
- self.spans[span.context.trace_id] = list()
65
-
66
- self.spans[span.context.trace_id].append(span)
52
+ def on_end(self, span: ReadableSpan):
53
+ super().on_end(span)
67
54
 
68
55
  del self._registry[span.context.trace_id][span.context.span_id]
69
56
 
70
- if len(self._registry[span.context.trace_id]) == 0:
71
- self.export(span.context.trace_id)
72
-
73
- def export(
74
- self,
75
- trace_id: int,
76
- ):
77
- spans = self.spans[trace_id]
78
-
79
- for span in spans:
80
- self.queue.appendleft(span)
81
-
82
- with self.condition:
83
- self.condition.notify()
84
-
85
- del self.spans[trace_id]
57
+ if self.is_ready(span.get_span_context().trace_id):
58
+ self.force_flush()
86
59
 
87
- def force_flush(
88
- self,
89
- timeout_millis: int = None,
90
- ) -> bool:
60
+ def force_flush(self, timeout_millis: int = None) -> bool:
91
61
  ret = super().force_flush(timeout_millis)
92
62
 
93
63
  if not ret:
@@ -95,23 +65,12 @@ class TraceProcessor(BatchSpanProcessor):
95
65
  log.error("Agenta SDK - skipping export due to timeout.")
96
66
  log.error("--------------------------------------------")
97
67
 
98
- def is_ready(
99
- self,
100
- trace_id: Optional[int] = None,
101
- ) -> bool:
102
- is_ready = True
103
-
104
- try:
105
- is_ready = self._exporter.is_ready(trace_id)
106
- except: # pylint: disable=bare-except
107
- pass
68
+ def is_ready(self, trace_id: Optional[int] = None) -> bool:
69
+ is_ready = not len(self._registry.get(trace_id, {}))
108
70
 
109
71
  return is_ready
110
72
 
111
- def fetch(
112
- self,
113
- trace_id: Optional[int] = None,
114
- ) -> Dict[str, ReadableSpan]:
73
+ def fetch(self, trace_id: Optional[int] = None) -> Dict[str, ReadableSpan]:
115
74
  trace = self._exporter.fetch(trace_id) # type: ignore
116
75
 
117
76
  return trace
@@ -8,10 +8,7 @@ from agenta.sdk.tracing.attributes import serialize
8
8
 
9
9
 
10
10
  class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
11
- def __init__(
12
- self,
13
- span: Span,
14
- ) -> None:
11
+ def __init__(self, span: Span) -> None:
15
12
  super().__init__( # INHERITANCE FOR TYPING ONLY
16
13
  name=span.name,
17
14
  context=span.context,
@@ -41,10 +38,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
41
38
  def is_recording(self) -> bool:
42
39
  return self._span.is_recording()
43
40
 
44
- def update_name(
45
- self,
46
- name: str,
47
- ) -> None:
41
+ def update_name(self, name: str) -> None:
48
42
  self._span.update_name(name)
49
43
 
50
44
  def set_status(
@@ -52,10 +46,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
52
46
  status: Union[Status, StatusCode],
53
47
  description: Optional[str] = None,
54
48
  ) -> None:
55
- self._span.set_status(
56
- status=status,
57
- description=description,
58
- )
49
+ self._span.set_status(status=status, description=description)
59
50
 
60
51
  def end(self) -> None:
61
52
  self._span.end()
@@ -82,10 +73,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
82
73
  value: Any,
83
74
  namespace: Optional[str] = None,
84
75
  ) -> None:
85
- self.set_attributes(
86
- attributes={key: value},
87
- namespace=namespace,
88
- )
76
+ self.set_attributes({key: value}, namespace)
89
77
 
90
78
  def add_event(
91
79
  self,