agenta 0.52.6__py3-none-any.whl → 0.63.2__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.
Files changed (271) hide show
  1. agenta/__init__.py +12 -3
  2. agenta/client/__init__.py +4 -4
  3. agenta/client/backend/__init__.py +4 -4
  4. agenta/client/backend/api_keys/client.py +2 -2
  5. agenta/client/backend/billing/client.py +2 -2
  6. agenta/client/backend/billing/raw_client.py +2 -2
  7. agenta/client/backend/client.py +56 -48
  8. agenta/client/backend/core/client_wrapper.py +2 -2
  9. agenta/client/backend/core/file.py +3 -1
  10. agenta/client/backend/core/http_client.py +3 -3
  11. agenta/client/backend/core/pydantic_utilities.py +13 -3
  12. agenta/client/backend/human_evaluations/client.py +2 -2
  13. agenta/client/backend/human_evaluations/raw_client.py +2 -2
  14. agenta/client/backend/organization/client.py +46 -34
  15. agenta/client/backend/organization/raw_client.py +32 -26
  16. agenta/client/backend/raw_client.py +26 -26
  17. agenta/client/backend/testsets/client.py +18 -18
  18. agenta/client/backend/testsets/raw_client.py +30 -30
  19. agenta/client/backend/types/__init__.py +4 -4
  20. agenta/client/backend/types/account_request.py +3 -1
  21. agenta/client/backend/types/account_response.py +3 -1
  22. agenta/client/backend/types/agenta_node_dto.py +3 -1
  23. agenta/client/backend/types/agenta_nodes_response.py +3 -1
  24. agenta/client/backend/types/agenta_root_dto.py +3 -1
  25. agenta/client/backend/types/agenta_roots_response.py +3 -1
  26. agenta/client/backend/types/agenta_tree_dto.py +3 -1
  27. agenta/client/backend/types/agenta_trees_response.py +3 -1
  28. agenta/client/backend/types/aggregated_result.py +3 -1
  29. agenta/client/backend/types/analytics_response.py +3 -1
  30. agenta/client/backend/types/annotation.py +6 -4
  31. agenta/client/backend/types/annotation_create.py +3 -1
  32. agenta/client/backend/types/annotation_edit.py +3 -1
  33. agenta/client/backend/types/annotation_link.py +3 -1
  34. agenta/client/backend/types/annotation_link_response.py +3 -1
  35. agenta/client/backend/types/annotation_query.py +3 -1
  36. agenta/client/backend/types/annotation_query_request.py +3 -1
  37. agenta/client/backend/types/annotation_reference.py +3 -1
  38. agenta/client/backend/types/annotation_references.py +3 -1
  39. agenta/client/backend/types/annotation_response.py +3 -1
  40. agenta/client/backend/types/annotations_response.py +3 -1
  41. agenta/client/backend/types/app.py +3 -1
  42. agenta/client/backend/types/app_variant_response.py +3 -1
  43. agenta/client/backend/types/app_variant_revision.py +3 -1
  44. agenta/client/backend/types/artifact.py +6 -4
  45. agenta/client/backend/types/base_output.py +3 -1
  46. agenta/client/backend/types/body_fetch_workflow_revision.py +3 -1
  47. agenta/client/backend/types/body_import_testset.py +3 -1
  48. agenta/client/backend/types/bucket_dto.py +3 -1
  49. agenta/client/backend/types/collect_status_response.py +3 -1
  50. agenta/client/backend/types/config_db.py +3 -1
  51. agenta/client/backend/types/config_dto.py +3 -1
  52. agenta/client/backend/types/config_response_model.py +3 -1
  53. agenta/client/backend/types/correct_answer.py +3 -1
  54. agenta/client/backend/types/create_app_output.py +3 -1
  55. agenta/client/backend/types/custom_model_settings_dto.py +3 -1
  56. agenta/client/backend/types/custom_provider_dto.py +3 -1
  57. agenta/client/backend/types/custom_provider_kind.py +1 -1
  58. agenta/client/backend/types/custom_provider_settings_dto.py +3 -1
  59. agenta/client/backend/types/delete_evaluation.py +3 -1
  60. agenta/client/backend/types/environment_output.py +3 -1
  61. agenta/client/backend/types/environment_output_extended.py +3 -1
  62. agenta/client/backend/types/environment_revision.py +3 -1
  63. agenta/client/backend/types/error.py +3 -1
  64. agenta/client/backend/types/evaluation.py +3 -1
  65. agenta/client/backend/types/evaluation_scenario.py +3 -1
  66. agenta/client/backend/types/evaluation_scenario_input.py +3 -1
  67. agenta/client/backend/types/evaluation_scenario_output.py +3 -1
  68. agenta/client/backend/types/evaluation_scenario_result.py +3 -1
  69. agenta/client/backend/types/evaluator.py +6 -4
  70. agenta/client/backend/types/evaluator_config.py +6 -4
  71. agenta/client/backend/types/evaluator_flags.py +3 -1
  72. agenta/client/backend/types/evaluator_mapping_output_interface.py +3 -1
  73. agenta/client/backend/types/evaluator_output_interface.py +3 -1
  74. agenta/client/backend/types/evaluator_query.py +3 -1
  75. agenta/client/backend/types/evaluator_query_request.py +3 -1
  76. agenta/client/backend/types/evaluator_request.py +3 -1
  77. agenta/client/backend/types/evaluator_response.py +3 -1
  78. agenta/client/backend/types/evaluators_response.py +3 -1
  79. agenta/client/backend/types/exception_dto.py +3 -1
  80. agenta/client/backend/types/extended_o_tel_tracing_response.py +3 -1
  81. agenta/client/backend/types/get_config_response.py +3 -1
  82. agenta/client/backend/types/header.py +3 -1
  83. agenta/client/backend/types/http_validation_error.py +3 -1
  84. agenta/client/backend/types/human_evaluation.py +3 -1
  85. agenta/client/backend/types/human_evaluation_scenario.py +3 -1
  86. agenta/client/backend/types/human_evaluation_scenario_input.py +3 -1
  87. agenta/client/backend/types/human_evaluation_scenario_output.py +3 -1
  88. agenta/client/backend/types/invite_request.py +3 -1
  89. agenta/client/backend/types/legacy_analytics_response.py +3 -1
  90. agenta/client/backend/types/legacy_data_point.py +3 -1
  91. agenta/client/backend/types/legacy_evaluator.py +3 -1
  92. agenta/client/backend/types/legacy_scope_request.py +3 -1
  93. agenta/client/backend/types/legacy_scopes_response.py +3 -1
  94. agenta/client/backend/types/legacy_subscription_request.py +3 -1
  95. agenta/client/backend/types/legacy_user_request.py +3 -1
  96. agenta/client/backend/types/legacy_user_response.py +3 -1
  97. agenta/client/backend/types/lifecycle_dto.py +3 -1
  98. agenta/client/backend/types/link_dto.py +3 -1
  99. agenta/client/backend/types/list_api_keys_response.py +3 -1
  100. agenta/client/backend/types/llm_run_rate_limit.py +3 -1
  101. agenta/client/backend/types/meta_request.py +3 -1
  102. agenta/client/backend/types/metrics_dto.py +3 -1
  103. agenta/client/backend/types/new_testset.py +3 -1
  104. agenta/client/backend/types/node_dto.py +3 -1
  105. agenta/client/backend/types/o_tel_context_dto.py +3 -1
  106. agenta/client/backend/types/o_tel_event.py +6 -4
  107. agenta/client/backend/types/o_tel_event_dto.py +3 -1
  108. agenta/client/backend/types/o_tel_extra_dto.py +3 -1
  109. agenta/client/backend/types/o_tel_flat_span.py +6 -4
  110. agenta/client/backend/types/o_tel_link.py +6 -4
  111. agenta/client/backend/types/o_tel_link_dto.py +3 -1
  112. agenta/client/backend/types/o_tel_links_response.py +3 -1
  113. agenta/client/backend/types/o_tel_span.py +1 -1
  114. agenta/client/backend/types/o_tel_span_dto.py +3 -1
  115. agenta/client/backend/types/o_tel_spans_tree.py +3 -1
  116. agenta/client/backend/types/o_tel_tracing_data_response.py +3 -1
  117. agenta/client/backend/types/o_tel_tracing_request.py +3 -1
  118. agenta/client/backend/types/o_tel_tracing_response.py +3 -1
  119. agenta/client/backend/types/organization.py +3 -1
  120. agenta/client/backend/types/organization_details.py +3 -1
  121. agenta/client/backend/types/organization_membership_request.py +3 -1
  122. agenta/client/backend/types/organization_output.py +3 -1
  123. agenta/client/backend/types/organization_request.py +3 -1
  124. agenta/client/backend/types/parent_dto.py +3 -1
  125. agenta/client/backend/types/project_membership_request.py +3 -1
  126. agenta/client/backend/types/project_request.py +3 -1
  127. agenta/client/backend/types/project_scope.py +3 -1
  128. agenta/client/backend/types/projects_response.py +3 -1
  129. agenta/client/backend/types/reference.py +6 -4
  130. agenta/client/backend/types/reference_dto.py +3 -1
  131. agenta/client/backend/types/reference_request_model.py +3 -1
  132. agenta/client/backend/types/result.py +3 -1
  133. agenta/client/backend/types/root_dto.py +3 -1
  134. agenta/client/backend/types/scopes_response_model.py +3 -1
  135. agenta/client/backend/types/secret_dto.py +3 -1
  136. agenta/client/backend/types/secret_response_dto.py +3 -1
  137. agenta/client/backend/types/simple_evaluation_output.py +3 -1
  138. agenta/client/backend/types/span_dto.py +6 -4
  139. agenta/client/backend/types/standard_provider_dto.py +3 -1
  140. agenta/client/backend/types/standard_provider_settings_dto.py +3 -1
  141. agenta/client/backend/types/status_dto.py +3 -1
  142. agenta/client/backend/types/tags_request.py +3 -1
  143. agenta/client/backend/types/testcase_response.py +6 -4
  144. agenta/client/backend/types/testset.py +6 -4
  145. agenta/client/backend/types/{test_set_output_response.py → testset_output_response.py} +4 -2
  146. agenta/client/backend/types/testset_request.py +3 -1
  147. agenta/client/backend/types/testset_response.py +3 -1
  148. agenta/client/backend/types/{test_set_simple_response.py → testset_simple_response.py} +4 -2
  149. agenta/client/backend/types/testsets_response.py +3 -1
  150. agenta/client/backend/types/time_dto.py +3 -1
  151. agenta/client/backend/types/tree_dto.py +3 -1
  152. agenta/client/backend/types/update_app_output.py +3 -1
  153. agenta/client/backend/types/user_request.py +3 -1
  154. agenta/client/backend/types/validation_error.py +3 -1
  155. agenta/client/backend/types/workflow_artifact.py +6 -4
  156. agenta/client/backend/types/workflow_data.py +3 -1
  157. agenta/client/backend/types/workflow_flags.py +3 -1
  158. agenta/client/backend/types/workflow_request.py +3 -1
  159. agenta/client/backend/types/workflow_response.py +3 -1
  160. agenta/client/backend/types/workflow_revision.py +6 -4
  161. agenta/client/backend/types/workflow_revision_request.py +3 -1
  162. agenta/client/backend/types/workflow_revision_response.py +3 -1
  163. agenta/client/backend/types/workflow_revisions_response.py +3 -1
  164. agenta/client/backend/types/workflow_variant.py +6 -4
  165. agenta/client/backend/types/workflow_variant_request.py +3 -1
  166. agenta/client/backend/types/workflow_variant_response.py +3 -1
  167. agenta/client/backend/types/workflow_variants_response.py +3 -1
  168. agenta/client/backend/types/workflows_response.py +3 -1
  169. agenta/client/backend/types/workspace.py +3 -1
  170. agenta/client/backend/types/workspace_member_response.py +3 -1
  171. agenta/client/backend/types/workspace_membership_request.py +3 -1
  172. agenta/client/backend/types/workspace_permission.py +3 -1
  173. agenta/client/backend/types/workspace_request.py +3 -1
  174. agenta/client/backend/types/workspace_response.py +3 -1
  175. agenta/client/backend/vault/raw_client.py +4 -4
  176. agenta/client/backend/workspace/client.py +2 -2
  177. agenta/client/client.py +102 -88
  178. agenta/sdk/__init__.py +52 -3
  179. agenta/sdk/agenta_init.py +43 -16
  180. agenta/sdk/assets.py +23 -15
  181. agenta/sdk/context/serving.py +20 -8
  182. agenta/sdk/context/tracing.py +40 -22
  183. agenta/sdk/contexts/__init__.py +0 -0
  184. agenta/sdk/contexts/routing.py +38 -0
  185. agenta/sdk/contexts/running.py +57 -0
  186. agenta/sdk/contexts/tracing.py +86 -0
  187. agenta/sdk/decorators/__init__.py +1 -0
  188. agenta/sdk/decorators/routing.py +284 -0
  189. agenta/sdk/decorators/running.py +692 -98
  190. agenta/sdk/decorators/serving.py +20 -21
  191. agenta/sdk/decorators/tracing.py +176 -131
  192. agenta/sdk/engines/__init__.py +0 -0
  193. agenta/sdk/engines/running/__init__.py +0 -0
  194. agenta/sdk/engines/running/utils.py +17 -0
  195. agenta/sdk/engines/tracing/__init__.py +1 -0
  196. agenta/sdk/engines/tracing/attributes.py +185 -0
  197. agenta/sdk/engines/tracing/conventions.py +49 -0
  198. agenta/sdk/engines/tracing/exporters.py +130 -0
  199. agenta/sdk/engines/tracing/inline.py +1154 -0
  200. agenta/sdk/engines/tracing/processors.py +190 -0
  201. agenta/sdk/engines/tracing/propagation.py +102 -0
  202. agenta/sdk/engines/tracing/spans.py +136 -0
  203. agenta/sdk/engines/tracing/tracing.py +324 -0
  204. agenta/sdk/evaluations/__init__.py +2 -0
  205. agenta/sdk/evaluations/metrics.py +37 -0
  206. agenta/sdk/evaluations/preview/__init__.py +0 -0
  207. agenta/sdk/evaluations/preview/evaluate.py +765 -0
  208. agenta/sdk/evaluations/preview/utils.py +861 -0
  209. agenta/sdk/evaluations/results.py +66 -0
  210. agenta/sdk/evaluations/runs.py +153 -0
  211. agenta/sdk/evaluations/scenarios.py +48 -0
  212. agenta/sdk/litellm/litellm.py +12 -0
  213. agenta/sdk/litellm/mockllm.py +6 -8
  214. agenta/sdk/litellm/mocks/__init__.py +5 -5
  215. agenta/sdk/managers/applications.py +304 -0
  216. agenta/sdk/managers/config.py +2 -2
  217. agenta/sdk/managers/evaluations.py +0 -0
  218. agenta/sdk/managers/evaluators.py +303 -0
  219. agenta/sdk/managers/secrets.py +161 -24
  220. agenta/sdk/managers/shared.py +3 -1
  221. agenta/sdk/managers/testsets.py +441 -0
  222. agenta/sdk/managers/vault.py +3 -3
  223. agenta/sdk/middleware/auth.py +0 -176
  224. agenta/sdk/middleware/config.py +27 -9
  225. agenta/sdk/middleware/vault.py +204 -9
  226. agenta/sdk/middlewares/__init__.py +0 -0
  227. agenta/sdk/middlewares/routing/__init__.py +0 -0
  228. agenta/sdk/middlewares/routing/auth.py +263 -0
  229. agenta/sdk/middlewares/routing/cors.py +30 -0
  230. agenta/sdk/middlewares/routing/otel.py +29 -0
  231. agenta/sdk/middlewares/running/__init__.py +0 -0
  232. agenta/sdk/middlewares/running/normalizer.py +321 -0
  233. agenta/sdk/middlewares/running/resolver.py +161 -0
  234. agenta/sdk/middlewares/running/vault.py +140 -0
  235. agenta/sdk/models/__init__.py +0 -0
  236. agenta/sdk/models/blobs.py +33 -0
  237. agenta/sdk/models/evaluations.py +119 -0
  238. agenta/sdk/models/git.py +126 -0
  239. agenta/sdk/models/shared.py +167 -0
  240. agenta/sdk/models/testsets.py +163 -0
  241. agenta/sdk/models/tracing.py +202 -0
  242. agenta/sdk/models/workflows.py +753 -0
  243. agenta/sdk/tracing/attributes.py +4 -4
  244. agenta/sdk/tracing/exporters.py +67 -17
  245. agenta/sdk/tracing/inline.py +37 -45
  246. agenta/sdk/tracing/processors.py +97 -0
  247. agenta/sdk/tracing/propagation.py +3 -1
  248. agenta/sdk/tracing/spans.py +4 -0
  249. agenta/sdk/tracing/tracing.py +13 -15
  250. agenta/sdk/types.py +222 -22
  251. agenta/sdk/utils/cache.py +1 -1
  252. agenta/sdk/utils/client.py +38 -0
  253. agenta/sdk/utils/helpers.py +13 -12
  254. agenta/sdk/utils/logging.py +18 -78
  255. agenta/sdk/utils/references.py +23 -0
  256. agenta/sdk/workflows/builtin.py +600 -0
  257. agenta/sdk/workflows/configurations.py +22 -0
  258. agenta/sdk/workflows/errors.py +292 -0
  259. agenta/sdk/workflows/handlers.py +1791 -0
  260. agenta/sdk/workflows/interfaces.py +948 -0
  261. agenta/sdk/workflows/sandbox.py +118 -0
  262. agenta/sdk/workflows/utils.py +303 -6
  263. {agenta-0.52.6.dist-info → agenta-0.63.2.dist-info}/METADATA +37 -33
  264. agenta-0.63.2.dist-info/RECORD +421 -0
  265. {agenta-0.52.6.dist-info → agenta-0.63.2.dist-info}/WHEEL +1 -1
  266. agenta/sdk/middleware/adapt.py +0 -253
  267. agenta/sdk/middleware/base.py +0 -40
  268. agenta/sdk/middleware/flags.py +0 -40
  269. agenta/sdk/workflows/types.py +0 -472
  270. agenta-0.52.6.dist-info/RECORD +0 -371
  271. /agenta/sdk/{workflows → engines/running}/registry.py +0 -0
@@ -6,7 +6,7 @@ PrimitivesSequence = Sequence[Primitive]
6
6
  Attribute = Union[Primitive, PrimitivesSequence]
7
7
 
8
8
 
9
- def _marshal(
9
+ def _marshall(
10
10
  unmarshalled: Dict[str, Any],
11
11
  *,
12
12
  parent_key: Optional[str] = "",
@@ -59,7 +59,7 @@ def _marshal(
59
59
  dict_key = child_key
60
60
 
61
61
  marshalled.update(
62
- _marshal(
62
+ _marshall(
63
63
  value,
64
64
  parent_key=dict_key,
65
65
  depth=depth + 1,
@@ -76,7 +76,7 @@ def _marshal(
76
76
 
77
77
  if isinstance(item, (dict, list)):
78
78
  marshalled.update(
79
- _marshal(
79
+ _marshall(
80
80
  item,
81
81
  parent_key=list_key,
82
82
  depth=depth + 1,
@@ -177,7 +177,7 @@ def serialize(
177
177
  k: v
178
178
  for k, v in {
179
179
  _encode_key(namespace, key): _encode_value(value)
180
- for key, value in _marshal(attributes, max_depth=max_depth).items()
180
+ for key, value in _marshall(attributes, max_depth=max_depth).items()
181
181
  }.items()
182
182
  if v is not None
183
183
  }
@@ -1,4 +1,7 @@
1
- from typing import Sequence, Dict, List, Optional
1
+ from typing import Sequence, Dict, List, Optional, Any
2
+ from threading import Thread
3
+ from os import environ
4
+ from uuid import UUID
2
5
 
3
6
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
4
7
  from opentelemetry.sdk.trace.export import (
@@ -8,18 +11,21 @@ from opentelemetry.sdk.trace.export import (
8
11
  ReadableSpan,
9
12
  )
10
13
 
14
+ from agenta.sdk.utils.constants import TRUTHY
11
15
  from agenta.sdk.utils.logging import get_module_logger
12
16
  from agenta.sdk.utils.exceptions import suppress
13
17
  from agenta.sdk.utils.cache import TTLLRUCache
14
- from agenta.sdk.context.tracing import (
15
- tracing_exporter_context_manager,
16
- tracing_exporter_context,
17
- TracingExporterContext,
18
+ from agenta.sdk.contexts.tracing import (
19
+ otlp_context_manager,
20
+ otlp_context,
21
+ OTLPContext,
18
22
  )
19
23
 
20
24
 
21
25
  log = get_module_logger(__name__)
22
26
 
27
+ _ASYNC_EXPORT = environ.get("AGENTA_OTLP_ASYNC_EXPORT", "true").lower() in TRUTHY
28
+
23
29
 
24
30
  class InlineTraceExporter(SpanExporter):
25
31
  def __init__(
@@ -45,6 +51,8 @@ class InlineTraceExporter(SpanExporter):
45
51
 
46
52
  self._registry[trace_id].append(span)
47
53
 
54
+ return
55
+
48
56
  def shutdown(self) -> None:
49
57
  self._shutdown = True
50
58
 
@@ -84,7 +92,7 @@ class OTLPExporter(OTLPSpanExporter):
84
92
  self.credentials = credentials
85
93
 
86
94
  def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
87
- grouped_spans: Dict[str, List[str]] = {}
95
+ grouped_spans: Dict[Optional[str], List[ReadableSpan]] = dict()
88
96
 
89
97
  for span in spans:
90
98
  trace_id = span.get_span_context().trace_id
@@ -94,18 +102,28 @@ class OTLPExporter(OTLPSpanExporter):
94
102
  credentials = self.credentials.get(trace_id)
95
103
 
96
104
  if credentials not in grouped_spans:
97
- grouped_spans[credentials] = []
105
+ grouped_spans[credentials] = list()
98
106
 
99
107
  grouped_spans[credentials].append(span)
100
108
 
101
109
  serialized_spans = []
102
110
 
103
111
  for credentials, _spans in grouped_spans.items():
104
- with tracing_exporter_context_manager(
105
- context=TracingExporterContext(
112
+ with otlp_context_manager(
113
+ context=OTLPContext(
106
114
  credentials=credentials,
107
115
  )
108
116
  ):
117
+ for _span in _spans:
118
+ trace_id = _span.get_span_context().trace_id
119
+ span_id = _span.get_span_context().span_id
120
+
121
+ # log.debug(
122
+ # "[SPAN] [EXPORT]",
123
+ # trace_id=UUID(int=trace_id).hex,
124
+ # span_id=UUID(int=span_id).hex[-16:],
125
+ # )
126
+
109
127
  serialized_spans.append(super().export(_spans))
110
128
 
111
129
  if all(serialized_spans):
@@ -114,16 +132,48 @@ class OTLPExporter(OTLPSpanExporter):
114
132
  return SpanExportResult.FAILURE
115
133
 
116
134
  def _export(self, serialized_data: bytes, timeout_sec: Optional[float] = None):
117
- credentials = tracing_exporter_context.get().credentials
135
+ try:
136
+ credentials = otlp_context.get().credentials
137
+
138
+ if credentials:
139
+ self._session.headers.update({"Authorization": credentials})
140
+
141
+ def __export():
142
+ with suppress():
143
+ resp = None
144
+ if timeout_sec is not None:
145
+ resp = super(OTLPExporter, self)._export(
146
+ serialized_data,
147
+ timeout_sec,
148
+ )
149
+ else:
150
+ resp = super(OTLPExporter, self)._export(
151
+ serialized_data,
152
+ )
153
+
154
+ # log.debug(
155
+ # "[SPAN] [_EXPORT]",
156
+ # data=serialized_data,
157
+ # resp=resp,
158
+ # )
159
+
160
+ if _ASYNC_EXPORT is True:
161
+ # log.debug("[SPAN] [ASYNC.X]", credentials=(credentials is not None))
162
+ thread = Thread(target=__export, daemon=False)
163
+ thread.start()
164
+ else:
165
+ # log.debug("[SPAN] [ SYNC.X]", credentials=(credentials is not None))
166
+ return __export()
118
167
 
119
- if credentials:
120
- self._session.headers.update({"Authorization": credentials})
168
+ except Exception as e:
169
+ log.error(f"Export failed with error: {e}", exc_info=True)
121
170
 
122
- with suppress():
123
- if timeout_sec is not None:
124
- return super()._export(serialized_data, timeout_sec)
125
- else:
126
- return super()._export(serialized_data)
171
+ finally:
172
+
173
+ class Response:
174
+ ok = True
175
+
176
+ return Response()
127
177
 
128
178
 
129
179
  ConsoleExporter = ConsoleSpanExporter
@@ -532,11 +532,11 @@ from json import loads, JSONDecodeError, dumps
532
532
  from copy import copy
533
533
 
534
534
 
535
- def _unmarshal_attributes(
535
+ def _unmarshall_attributes(
536
536
  marshalled: Dict[str, Any],
537
537
  ) -> Dict[str, Any]:
538
538
  """
539
- Unmarshals a dictionary of marshalled attributes into a nested dictionary
539
+ Unmarshalls a dictionary of marshalled attributes into a nested dictionary
540
540
 
541
541
  Example:
542
542
  marshalled = {
@@ -566,42 +566,34 @@ def _unmarshal_attributes(
566
566
 
567
567
  for key, value in marshalled.items():
568
568
  keys = key.split(".")
569
-
570
- level = unmarshalled
571
-
572
- for i, part in enumerate(keys[:-1]):
573
- if part.isdigit():
574
- part = int(part)
575
-
576
- if not isinstance(level, list):
577
- level = []
578
-
579
- while len(level) <= part:
580
- level.append({})
581
-
582
- level = level[part]
583
-
569
+ current = unmarshalled
570
+
571
+ for i, key in enumerate(keys):
572
+ is_last = i == len(keys) - 1
573
+ next_key = keys[i + 1] if not is_last else None
574
+ is_index = key.isdigit()
575
+ key = int(key) if is_index else key
576
+
577
+ if is_last:
578
+ if isinstance(current, list) and isinstance(key, int):
579
+ while len(current) <= key:
580
+ current.append(None)
581
+ current[key] = value
582
+ elif isinstance(current, dict):
583
+ current[key] = value
584
584
  else:
585
- if part not in level:
586
- level[part] = {} if not keys[i + 1].isdigit() else []
587
-
588
- level = level[part]
589
-
590
- last_key = keys[-1]
591
-
592
- if last_key.isdigit():
593
- last_key = int(last_key)
594
-
595
- if not isinstance(level, list):
596
- level = []
597
-
598
- while len(level) <= last_key:
599
- level.append(None)
600
-
601
- level[last_key] = value
602
-
603
- else:
604
- level[last_key] = value
585
+ next_is_index = next_key.isdigit() if next_key else False
586
+
587
+ if isinstance(current, list) and isinstance(key, int):
588
+ while len(current) <= key:
589
+ current.append([] if next_is_index else {})
590
+ if current[key] is None:
591
+ current[key] = [] if next_is_index else {}
592
+ current = current[key]
593
+ elif isinstance(current, dict):
594
+ if key not in current:
595
+ current[key] = [] if next_is_index else {}
596
+ current = current[key]
605
597
 
606
598
  return unmarshalled
607
599
 
@@ -750,7 +742,7 @@ def _parse_from_attributes(
750
742
  for key in _data.keys():
751
743
  del otel_span_dto.attributes[_encode_key("data", key)]
752
744
 
753
- # _data = _unmarshal_attributes(_data)
745
+ # _data = _unmarshall_attributes(_data)
754
746
  _data = _data if _data else None
755
747
 
756
748
  # METRICS
@@ -759,7 +751,7 @@ def _parse_from_attributes(
759
751
  for key in _metrics.keys():
760
752
  del otel_span_dto.attributes[_encode_key("metrics", key)]
761
753
 
762
- # _metrics = _unmarshal_attributes(_metrics)
754
+ # _metrics = _unmarshall_attributes(_metrics)
763
755
  _metrics = _metrics if _metrics else None
764
756
 
765
757
  # META
@@ -768,7 +760,7 @@ def _parse_from_attributes(
768
760
  for key in _meta.keys():
769
761
  del otel_span_dto.attributes[_encode_key("meta", key)]
770
762
 
771
- # _meta = _unmarshal_attributes(_meta)
763
+ # _meta = _unmarshall_attributes(_meta)
772
764
  _meta = _meta if _meta else None
773
765
 
774
766
  # TAGS
@@ -904,7 +896,7 @@ def parse_to_agenta_span_dto(
904
896
  ) -> SpanDTO:
905
897
  # DATA
906
898
  if span_dto.data:
907
- span_dto.data = _unmarshal_attributes(span_dto.data)
899
+ span_dto.data = _unmarshall_attributes(span_dto.data)
908
900
 
909
901
  if "outputs" in span_dto.data:
910
902
  if "__default__" in span_dto.data["outputs"]:
@@ -912,19 +904,19 @@ def parse_to_agenta_span_dto(
912
904
 
913
905
  # METRICS
914
906
  if span_dto.metrics:
915
- span_dto.metrics = _unmarshal_attributes(span_dto.metrics)
907
+ span_dto.metrics = _unmarshall_attributes(span_dto.metrics)
916
908
 
917
909
  # META
918
910
  if span_dto.meta:
919
- span_dto.meta = _unmarshal_attributes(span_dto.meta)
911
+ span_dto.meta = _unmarshall_attributes(span_dto.meta)
920
912
 
921
913
  # TAGS
922
914
  if span_dto.tags:
923
- span_dto.tags = _unmarshal_attributes(span_dto.tags)
915
+ span_dto.tags = _unmarshall_attributes(span_dto.tags)
924
916
 
925
917
  # REFS
926
918
  if span_dto.refs:
927
- span_dto.refs = _unmarshal_attributes(span_dto.refs)
919
+ span_dto.refs = _unmarshall_attributes(span_dto.refs)
928
920
 
929
921
  if isinstance(span_dto.links, list):
930
922
  for link in span_dto.links:
@@ -1,5 +1,7 @@
1
1
  from typing import Optional, Dict, List
2
2
  from threading import Lock
3
+ from json import dumps
4
+ from uuid import UUID
3
5
 
4
6
  from opentelemetry.baggage import get_all as get_baggage
5
7
  from opentelemetry.context import Context
@@ -9,10 +11,13 @@ from opentelemetry.sdk.trace.export import (
9
11
  ReadableSpan,
10
12
  BatchSpanProcessor,
11
13
  )
14
+ from opentelemetry.trace import SpanContext
12
15
 
13
16
  from agenta.sdk.utils.logging import get_module_logger
14
17
  from agenta.sdk.tracing.conventions import Reference
15
18
 
19
+ from agenta.sdk.contexts.tracing import TracingContext
20
+
16
21
  log = get_module_logger(__name__)
17
22
 
18
23
 
@@ -50,6 +55,15 @@ class TraceProcessor(SpanProcessor):
50
55
  span: Span,
51
56
  parent_context: Optional[Context] = None,
52
57
  ) -> None:
58
+ trace_id = span.context.trace_id
59
+ span_id = span.context.span_id
60
+
61
+ # log.debug(
62
+ # "[SPAN] [START] ",
63
+ # trace_id=UUID(int=trace_id).hex,
64
+ # span_id=UUID(int=span_id).hex[-16:],
65
+ # )
66
+
53
67
  for key in self.references.keys():
54
68
  span.set_attribute(f"ag.refs.{key}", self.references[key])
55
69
 
@@ -61,6 +75,83 @@ class TraceProcessor(SpanProcessor):
61
75
  if _key in [_.value for _ in Reference.__members__.values()]:
62
76
  span.set_attribute(key, baggage[key])
63
77
 
78
+ context = TracingContext.get()
79
+
80
+ trace_type = span.attributes.get("trace_type") if span.attributes else None
81
+
82
+ context.annotate = (
83
+ context.annotate
84
+ or (context.type == "annotation")
85
+ or (trace_type == "annotation")
86
+ )
87
+ context.type = (
88
+ (str(trace_type) if trace_type else None)
89
+ or context.type
90
+ or ("annotation" if context.annotate else "invocation")
91
+ )
92
+
93
+ span.set_attribute("ag.type.tree", context.type)
94
+
95
+ if context.flags:
96
+ for key in context.flags.keys():
97
+ span.set_attribute(f"ag.flags.{key}", context.flags[key])
98
+ # if context.tags:
99
+ # for key in context.tags.keys():
100
+ # span.set_attribute(f"ag.tags.{key}", context.tags[key])
101
+ # if context.meta:
102
+ # span.set_attribute(f"ag.meta.", dumps(context.meta))
103
+
104
+ # --- DISTRIBUTED
105
+ if not self.inline:
106
+ if context.links:
107
+ for key, link in context.links.items():
108
+ try:
109
+ link = link.model_dump(mode="json", exclude_none=True)
110
+ except: # pylint: disable=bare-except
111
+ pass
112
+ if not isinstance(link, dict):
113
+ continue
114
+ if not link.get("trace_id") or not link.get("span_id"):
115
+ continue
116
+
117
+ span.add_link(
118
+ context=SpanContext(
119
+ trace_id=int(str(link.get("trace_id")), 16),
120
+ span_id=int(str(link.get("span_id")), 16),
121
+ is_remote=True,
122
+ ),
123
+ attributes=dict(
124
+ key=str(key),
125
+ ),
126
+ )
127
+
128
+ if context.references:
129
+ for key, ref in context.references.items():
130
+ try:
131
+ ref = ref.model_dump(mode="json", exclude_none=True)
132
+ except: # pylint: disable=bare-except
133
+ pass
134
+ if not isinstance(ref, dict):
135
+ continue
136
+ if not ref.get("id") and not ref.get("slug") and not ref.get("version"):
137
+ continue
138
+
139
+ if ref.get("id"):
140
+ span.set_attribute(
141
+ f"ag.refs.{key}.id",
142
+ str(ref.get("id")),
143
+ )
144
+ if ref.get("slug"):
145
+ span.set_attribute(
146
+ f"ag.refs.{key}.slug",
147
+ str(ref.get("slug")),
148
+ )
149
+ if ref.get("version"):
150
+ span.set_attribute(
151
+ f"ag.refs.{key}.version",
152
+ str(ref.get("version")),
153
+ )
154
+
64
155
  trace_id = span.context.trace_id
65
156
  span_id = span.context.span_id
66
157
 
@@ -74,6 +165,12 @@ class TraceProcessor(SpanProcessor):
74
165
  trace_id = span.context.trace_id
75
166
  span_id = span.context.span_id
76
167
 
168
+ # log.debug(
169
+ # "[SPAN] [END] ",
170
+ # trace_id=UUID(int=trace_id).hex,
171
+ # span_id=UUID(int=span_id).hex[-16:],
172
+ # )
173
+
77
174
  self._spans.setdefault(trace_id, []).append(span)
78
175
  self._registry.setdefault(trace_id, {})
79
176
  self._registry[trace_id].pop(span_id, None)
@@ -6,6 +6,8 @@ from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapProp
6
6
  from opentelemetry.baggage import set_baggage
7
7
  from opentelemetry.context import get_current
8
8
 
9
+ from agenta.sdk.contexts.tracing import TracingContext
10
+
9
11
  import agenta as ag
10
12
 
11
13
 
@@ -72,7 +74,7 @@ def inject(
72
74
 
73
75
  _context = get_current()
74
76
 
75
- ctx = ag.sdk.context.tracing.tracing_context.get()
77
+ ctx = TracingContext.get()
76
78
 
77
79
  # --- Inject traceparent --- #
78
80
  try:
@@ -35,6 +35,10 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
35
35
 
36
36
  ## --- PROXY METHODS --- ##
37
37
 
38
+ @property
39
+ def name(self) -> str:
40
+ return self._span.name
41
+
38
42
  def get_span_context(self):
39
43
  return self._span.get_span_context()
40
44
 
@@ -52,8 +52,6 @@ class Link(BaseModel):
52
52
 
53
53
 
54
54
  class Tracing(metaclass=Singleton):
55
- VERSION = "0.1.0"
56
-
57
55
  Status = Status
58
56
  StatusCode = StatusCode
59
57
 
@@ -101,19 +99,6 @@ class Tracing(metaclass=Singleton):
101
99
  resource=Resource(attributes={"service.name": "agenta-sdk"})
102
100
  )
103
101
 
104
- # --- INLINE
105
- if inline:
106
- # TRACE PROCESSORS -- INLINE
107
- self.inline = TraceProcessor(
108
- InlineExporter(
109
- registry=self.inline_spans,
110
- ),
111
- references=self.references,
112
- inline=inline,
113
- )
114
- self.tracer_provider.add_span_processor(self.inline)
115
- # --- INLINE
116
-
117
102
  # TRACE PROCESSORS -- OTLP
118
103
  try:
119
104
  log.info("Agenta - OLTP URL: %s", self.otlp_url)
@@ -131,6 +116,19 @@ class Tracing(metaclass=Singleton):
131
116
  except: # pylint: disable=bare-except
132
117
  log.warning("Agenta - OLTP unreachable, skipping exports.")
133
118
 
119
+ # --- INLINE
120
+ if inline:
121
+ # TRACE PROCESSORS -- INLINE
122
+ self.inline = TraceProcessor(
123
+ InlineExporter(
124
+ registry=self.inline_spans,
125
+ ),
126
+ references=self.references,
127
+ inline=inline,
128
+ )
129
+ self.tracer_provider.add_span_processor(self.inline)
130
+ # --- INLINE
131
+
134
132
  # GLOBAL TRACER PROVIDER -- INSTRUMENTATION LIBRARIES
135
133
  set_tracer_provider(self.tracer_provider)
136
134
  # TRACER