agenta 0.12.3__py3-none-any.whl → 0.32.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 (244) hide show
  1. agenta/__init__.py +64 -7
  2. agenta/cli/helper.py +7 -3
  3. agenta/cli/main.py +15 -50
  4. agenta/cli/variant_commands.py +50 -29
  5. agenta/client/Readme.md +72 -64
  6. agenta/client/api.py +2 -2
  7. agenta/client/backend/__init__.py +193 -22
  8. agenta/client/backend/access_control/__init__.py +1 -0
  9. agenta/client/backend/access_control/client.py +167 -0
  10. agenta/client/backend/apps/__init__.py +1 -0
  11. agenta/client/backend/apps/client.py +1691 -0
  12. agenta/client/backend/bases/__init__.py +1 -0
  13. agenta/client/backend/bases/client.py +190 -0
  14. agenta/client/backend/client.py +2508 -5712
  15. agenta/client/backend/configs/__init__.py +1 -0
  16. agenta/client/backend/configs/client.py +604 -0
  17. agenta/client/backend/containers/__init__.py +5 -0
  18. agenta/client/backend/containers/client.py +648 -0
  19. agenta/client/backend/containers/types/__init__.py +5 -0
  20. agenta/client/backend/{types → containers/types}/container_templates_response.py +1 -2
  21. agenta/client/backend/core/__init__.py +30 -0
  22. agenta/client/backend/core/client_wrapper.py +42 -9
  23. agenta/client/backend/core/file.py +70 -0
  24. agenta/client/backend/core/http_client.py +575 -0
  25. agenta/client/backend/core/jsonable_encoder.py +33 -39
  26. agenta/client/backend/core/pydantic_utilities.py +325 -0
  27. agenta/client/backend/core/query_encoder.py +60 -0
  28. agenta/client/backend/core/remove_none_from_dict.py +2 -2
  29. agenta/client/backend/core/request_options.py +35 -0
  30. agenta/client/backend/core/serialization.py +276 -0
  31. agenta/client/backend/environments/__init__.py +1 -0
  32. agenta/client/backend/environments/client.py +196 -0
  33. agenta/client/backend/evaluations/__init__.py +1 -0
  34. agenta/client/backend/evaluations/client.py +1469 -0
  35. agenta/client/backend/evaluators/__init__.py +1 -0
  36. agenta/client/backend/evaluators/client.py +1283 -0
  37. agenta/client/backend/observability/__init__.py +1 -0
  38. agenta/client/backend/observability/client.py +1286 -0
  39. agenta/client/backend/observability_v_1/__init__.py +5 -0
  40. agenta/client/backend/observability_v_1/client.py +763 -0
  41. agenta/client/backend/observability_v_1/types/__init__.py +7 -0
  42. agenta/client/backend/observability_v_1/types/format.py +5 -0
  43. agenta/client/backend/observability_v_1/types/query_analytics_response.py +7 -0
  44. agenta/client/backend/observability_v_1/types/query_traces_response.py +11 -0
  45. agenta/client/backend/scopes/__init__.py +1 -0
  46. agenta/client/backend/scopes/client.py +114 -0
  47. agenta/client/backend/testsets/__init__.py +1 -0
  48. agenta/client/backend/testsets/client.py +1284 -0
  49. agenta/client/backend/types/__init__.py +154 -26
  50. agenta/client/backend/types/agenta_node_dto.py +48 -0
  51. agenta/client/backend/types/agenta_node_dto_nodes_value.py +6 -0
  52. agenta/client/backend/types/agenta_nodes_response.py +30 -0
  53. agenta/client/backend/types/agenta_root_dto.py +30 -0
  54. agenta/client/backend/types/agenta_roots_response.py +30 -0
  55. agenta/client/backend/types/agenta_tree_dto.py +30 -0
  56. agenta/client/backend/types/agenta_trees_response.py +30 -0
  57. agenta/client/backend/types/aggregated_result.py +16 -31
  58. agenta/client/backend/types/aggregated_result_evaluator_config.py +8 -0
  59. agenta/client/backend/types/analytics_response.py +24 -0
  60. agenta/client/backend/types/app.py +17 -30
  61. agenta/client/backend/types/app_variant_response.py +36 -0
  62. agenta/client/backend/types/app_variant_revision.py +17 -32
  63. agenta/client/backend/types/base_output.py +13 -28
  64. agenta/client/backend/types/body_import_testset.py +15 -31
  65. agenta/client/backend/types/bucket_dto.py +26 -0
  66. agenta/client/backend/types/collect_status_response.py +22 -0
  67. agenta/client/backend/types/config_db.py +16 -31
  68. agenta/client/backend/types/config_dto.py +32 -0
  69. agenta/client/backend/types/config_response_model.py +32 -0
  70. agenta/client/backend/types/correct_answer.py +22 -0
  71. agenta/client/backend/types/create_app_output.py +13 -28
  72. agenta/client/backend/types/create_span.py +45 -0
  73. agenta/client/backend/types/create_trace_response.py +22 -0
  74. agenta/client/backend/types/docker_env_vars.py +13 -28
  75. agenta/client/backend/types/environment_output.py +22 -34
  76. agenta/client/backend/types/environment_output_extended.py +31 -0
  77. agenta/client/backend/types/environment_revision.py +26 -0
  78. agenta/client/backend/types/error.py +22 -0
  79. agenta/client/backend/types/evaluation.py +22 -33
  80. agenta/client/backend/types/evaluation_scenario.py +18 -33
  81. agenta/client/backend/types/evaluation_scenario_input.py +16 -31
  82. agenta/client/backend/types/evaluation_scenario_output.py +17 -30
  83. agenta/client/backend/types/evaluation_scenario_result.py +14 -29
  84. agenta/client/backend/types/evaluation_scenario_score_update.py +21 -0
  85. agenta/client/backend/types/evaluation_status_enum.py +11 -29
  86. agenta/client/backend/types/evaluation_type.py +3 -21
  87. agenta/client/backend/types/evaluator.py +20 -31
  88. agenta/client/backend/types/evaluator_config.py +21 -33
  89. agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
  90. agenta/client/backend/types/evaluator_output_interface.py +21 -0
  91. agenta/client/backend/types/exception_dto.py +26 -0
  92. agenta/client/backend/types/get_config_response.py +23 -0
  93. agenta/client/backend/types/header_dto.py +22 -0
  94. agenta/client/backend/types/http_validation_error.py +14 -29
  95. agenta/client/backend/types/human_evaluation.py +18 -34
  96. agenta/client/backend/types/human_evaluation_scenario.py +22 -38
  97. agenta/client/backend/types/human_evaluation_scenario_input.py +13 -28
  98. agenta/client/backend/types/human_evaluation_scenario_output.py +13 -28
  99. agenta/client/backend/types/human_evaluation_scenario_update.py +30 -0
  100. agenta/client/backend/types/human_evaluation_update.py +22 -0
  101. agenta/client/backend/types/image.py +18 -32
  102. agenta/client/backend/types/invite_request.py +16 -30
  103. agenta/client/backend/types/legacy_analytics_response.py +29 -0
  104. agenta/client/backend/types/legacy_data_point.py +27 -0
  105. agenta/client/backend/types/lifecycle_dto.py +24 -0
  106. agenta/client/backend/types/link_dto.py +24 -0
  107. agenta/client/backend/types/list_api_keys_response.py +24 -0
  108. agenta/client/backend/types/llm_run_rate_limit.py +13 -28
  109. agenta/client/backend/types/llm_tokens.py +23 -0
  110. agenta/client/backend/types/metrics_dto.py +24 -0
  111. agenta/client/backend/types/new_human_evaluation.py +27 -0
  112. agenta/client/backend/types/new_testset.py +16 -31
  113. agenta/client/backend/types/node_dto.py +24 -0
  114. agenta/client/backend/types/node_type.py +19 -0
  115. agenta/client/backend/types/o_tel_context_dto.py +22 -0
  116. agenta/client/backend/types/o_tel_event_dto.py +23 -0
  117. agenta/client/backend/types/o_tel_extra_dto.py +26 -0
  118. agenta/client/backend/types/o_tel_link_dto.py +23 -0
  119. agenta/client/backend/types/o_tel_span_dto.py +37 -0
  120. agenta/client/backend/types/o_tel_span_kind.py +15 -0
  121. agenta/client/backend/types/o_tel_spans_response.py +24 -0
  122. agenta/client/backend/types/o_tel_status_code.py +8 -0
  123. agenta/client/backend/types/organization.py +22 -35
  124. agenta/client/backend/types/organization_output.py +13 -28
  125. agenta/client/backend/types/outputs.py +5 -0
  126. agenta/client/backend/types/parent_dto.py +21 -0
  127. agenta/client/backend/types/permission.py +41 -0
  128. agenta/client/backend/types/projects_response.py +28 -0
  129. agenta/client/backend/types/provider_key_dto.py +23 -0
  130. agenta/client/backend/types/provider_kind.py +21 -0
  131. agenta/client/backend/types/reference_dto.py +23 -0
  132. agenta/client/backend/types/reference_request_model.py +23 -0
  133. agenta/client/backend/types/result.py +18 -31
  134. agenta/client/backend/types/root_dto.py +21 -0
  135. agenta/client/backend/types/{human_evaluation_scenario_score.py → score.py} +1 -1
  136. agenta/client/backend/types/secret_dto.py +24 -0
  137. agenta/client/backend/types/{human_evaluation_scenario_update_score.py → secret_kind.py} +1 -1
  138. agenta/client/backend/types/secret_response_dto.py +27 -0
  139. agenta/client/backend/types/simple_evaluation_output.py +13 -28
  140. agenta/client/backend/types/span.py +39 -49
  141. agenta/client/backend/types/span_detail.py +44 -0
  142. agenta/client/backend/types/span_dto.py +54 -0
  143. agenta/client/backend/types/span_dto_nodes_value.py +9 -0
  144. agenta/client/backend/types/span_status_code.py +5 -0
  145. agenta/client/backend/types/span_variant.py +23 -0
  146. agenta/client/backend/types/status_code.py +5 -0
  147. agenta/client/backend/types/status_dto.py +23 -0
  148. agenta/client/backend/types/template.py +14 -29
  149. agenta/client/backend/types/template_image_info.py +21 -35
  150. agenta/client/backend/types/test_set_output_response.py +20 -33
  151. agenta/client/backend/types/test_set_simple_response.py +13 -28
  152. agenta/client/backend/types/time_dto.py +23 -0
  153. agenta/client/backend/types/trace_detail.py +44 -0
  154. agenta/client/backend/types/tree_dto.py +23 -0
  155. agenta/client/backend/types/tree_type.py +5 -0
  156. agenta/client/backend/types/update_app_output.py +22 -0
  157. agenta/client/backend/types/uri.py +13 -28
  158. agenta/client/backend/types/validation_error.py +13 -28
  159. agenta/client/backend/types/variant_action.py +14 -29
  160. agenta/client/backend/types/variant_action_enum.py +1 -19
  161. agenta/client/backend/types/with_pagination.py +26 -0
  162. agenta/client/backend/types/workspace_member_response.py +23 -0
  163. agenta/client/backend/types/workspace_permission.py +25 -0
  164. agenta/client/backend/types/workspace_response.py +29 -0
  165. agenta/client/backend/types/workspace_role.py +15 -0
  166. agenta/client/backend/types/workspace_role_response.py +23 -0
  167. agenta/client/backend/variants/__init__.py +5 -0
  168. agenta/client/backend/variants/client.py +2814 -0
  169. agenta/client/backend/variants/types/__init__.py +7 -0
  170. agenta/client/backend/variants/types/add_variant_from_base_and_config_response.py +8 -0
  171. agenta/client/backend/vault/__init__.py +1 -0
  172. agenta/client/backend/vault/client.py +685 -0
  173. agenta/client/client.py +1 -1
  174. agenta/config.py +0 -2
  175. agenta/config.toml +0 -1
  176. agenta/docker/docker-assets/Dockerfile.cloud.template +2 -1
  177. agenta/docker/docker-assets/Dockerfile.template +2 -1
  178. agenta/docker/docker_utils.py +11 -12
  179. agenta/sdk/__init__.py +58 -7
  180. agenta/sdk/agenta_init.py +182 -164
  181. agenta/sdk/assets.py +95 -0
  182. agenta/sdk/client.py +56 -0
  183. agenta/sdk/context/__init__.py +0 -0
  184. agenta/sdk/context/exporting.py +25 -0
  185. agenta/sdk/context/routing.py +27 -0
  186. agenta/sdk/context/tracing.py +28 -0
  187. agenta/sdk/decorators/__init__.py +0 -0
  188. agenta/sdk/decorators/routing.py +576 -0
  189. agenta/sdk/decorators/tracing.py +296 -0
  190. agenta/sdk/litellm/__init__.py +1 -0
  191. agenta/sdk/litellm/litellm.py +314 -0
  192. agenta/sdk/litellm/mockllm.py +27 -0
  193. agenta/sdk/litellm/mocks/__init__.py +26 -0
  194. agenta/sdk/managers/__init__.py +6 -0
  195. agenta/sdk/managers/config.py +208 -0
  196. agenta/sdk/managers/deployment.py +45 -0
  197. agenta/sdk/managers/secrets.py +38 -0
  198. agenta/sdk/managers/shared.py +639 -0
  199. agenta/sdk/managers/variant.py +182 -0
  200. agenta/sdk/managers/vault.py +16 -0
  201. agenta/sdk/middleware/__init__.py +0 -0
  202. agenta/sdk/middleware/auth.py +180 -0
  203. agenta/sdk/middleware/cache.py +47 -0
  204. agenta/sdk/middleware/config.py +255 -0
  205. agenta/sdk/middleware/cors.py +29 -0
  206. agenta/sdk/middleware/inline.py +38 -0
  207. agenta/sdk/middleware/mock.py +33 -0
  208. agenta/sdk/middleware/otel.py +40 -0
  209. agenta/sdk/middleware/vault.py +145 -0
  210. agenta/sdk/router.py +0 -7
  211. agenta/sdk/tracing/__init__.py +1 -0
  212. agenta/sdk/tracing/attributes.py +141 -0
  213. agenta/sdk/tracing/conventions.py +49 -0
  214. agenta/sdk/tracing/exporters.py +103 -0
  215. agenta/sdk/tracing/inline.py +1146 -0
  216. agenta/sdk/tracing/processors.py +121 -0
  217. agenta/sdk/tracing/spans.py +136 -0
  218. agenta/sdk/tracing/tracing.py +237 -0
  219. agenta/sdk/types.py +478 -74
  220. agenta/sdk/utils/__init__.py +0 -0
  221. agenta/sdk/utils/constants.py +1 -0
  222. agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
  223. agenta/sdk/utils/exceptions.py +59 -0
  224. agenta/sdk/utils/globals.py +6 -10
  225. agenta/sdk/utils/helpers.py +8 -0
  226. agenta/sdk/utils/logging.py +21 -0
  227. agenta/sdk/utils/singleton.py +13 -0
  228. agenta/sdk/utils/timing.py +58 -0
  229. {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/METADATA +98 -151
  230. agenta-0.32.0a1.dist-info/RECORD +263 -0
  231. {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/WHEEL +1 -1
  232. agenta/client/backend/types/add_variant_from_base_and_config_response.py +0 -7
  233. agenta/client/backend/types/app_variant_output.py +0 -47
  234. agenta/client/backend/types/app_variant_output_extended.py +0 -50
  235. agenta/client/backend/types/delete_evaluation.py +0 -36
  236. agenta/client/backend/types/evaluation_webhook.py +0 -36
  237. agenta/client/backend/types/feedback.py +0 -40
  238. agenta/client/backend/types/get_config_reponse.py +0 -39
  239. agenta/client/backend/types/list_api_keys_output.py +0 -39
  240. agenta/client/backend/types/trace.py +0 -48
  241. agenta/sdk/agenta_decorator.py +0 -443
  242. agenta/sdk/context.py +0 -41
  243. agenta-0.12.3.dist-info/RECORD +0 -114
  244. {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,121 @@
1
+ from typing import Optional, Dict, List
2
+
3
+ from opentelemetry.baggage import get_all as get_baggage
4
+ from opentelemetry.context import Context
5
+ from opentelemetry.sdk.trace import Span
6
+ from opentelemetry.sdk.trace.export import (
7
+ SpanExporter,
8
+ ReadableSpan,
9
+ BatchSpanProcessor,
10
+ _DEFAULT_MAX_QUEUE_SIZE,
11
+ _DEFAULT_MAX_EXPORT_BATCH_SIZE,
12
+ )
13
+
14
+ from agenta.sdk.utils.logging import log
15
+ from agenta.sdk.tracing.conventions import Reference
16
+
17
+
18
+ class TraceProcessor(BatchSpanProcessor):
19
+ def __init__(
20
+ self,
21
+ span_exporter: SpanExporter,
22
+ references: Dict[str, str] = None,
23
+ max_queue_size: int = None,
24
+ schedule_delay_millis: float = None,
25
+ max_export_batch_size: int = None,
26
+ export_timeout_millis: float = None,
27
+ ):
28
+ super().__init__(
29
+ span_exporter,
30
+ _DEFAULT_MAX_QUEUE_SIZE,
31
+ 12 * 60 * 60 * 1000, # 12 hours
32
+ _DEFAULT_MAX_EXPORT_BATCH_SIZE,
33
+ 500, # < 1 second (0.5 seconds)
34
+ )
35
+
36
+ self._registry = dict()
37
+ self._exporter = span_exporter
38
+ self.references = references or dict()
39
+ self.spans: Dict[int, List[ReadableSpan]] = dict()
40
+
41
+ def on_start(
42
+ self,
43
+ span: Span,
44
+ parent_context: Optional[Context] = None,
45
+ ) -> None:
46
+ baggage = get_baggage(parent_context)
47
+
48
+ for key in self.references.keys():
49
+ span.set_attribute(f"ag.refs.{key}", self.references[key])
50
+
51
+ for key in baggage.keys():
52
+ if key.startswith("ag.refs."):
53
+ _key = key.replace("ag.refs.", "")
54
+ if _key in [_.value for _ in Reference.__members__.values()]:
55
+ span.set_attribute(key, baggage[key])
56
+
57
+ if span.context.trace_id not in self._registry:
58
+ self._registry[span.context.trace_id] = dict()
59
+
60
+ self._registry[span.context.trace_id][span.context.span_id] = True
61
+
62
+ def on_end(
63
+ self,
64
+ span: ReadableSpan,
65
+ ):
66
+ if self.done:
67
+ return
68
+
69
+ if span.context.trace_id not in self.spans:
70
+ self.spans[span.context.trace_id] = list()
71
+
72
+ self.spans[span.context.trace_id].append(span)
73
+
74
+ del self._registry[span.context.trace_id][span.context.span_id]
75
+
76
+ if len(self._registry[span.context.trace_id]) == 0:
77
+ self.export(span.context.trace_id)
78
+
79
+ def export(
80
+ self,
81
+ trace_id: int,
82
+ ):
83
+ spans = self.spans[trace_id]
84
+
85
+ for span in spans:
86
+ self.queue.appendleft(span)
87
+
88
+ with self.condition:
89
+ self.condition.notify()
90
+
91
+ del self.spans[trace_id]
92
+
93
+ def force_flush(
94
+ self,
95
+ timeout_millis: int = None,
96
+ ) -> bool:
97
+ ret = super().force_flush(timeout_millis)
98
+
99
+ if not ret:
100
+ log.warning("Agenta - Skipping export due to timeout.")
101
+
102
+ def is_ready(
103
+ self,
104
+ trace_id: Optional[int] = None,
105
+ ) -> bool:
106
+ is_ready = True
107
+
108
+ try:
109
+ is_ready = self._exporter.is_ready(trace_id)
110
+ except: # pylint: disable=bare-except
111
+ pass
112
+
113
+ return is_ready
114
+
115
+ def fetch(
116
+ self,
117
+ trace_id: Optional[int] = None,
118
+ ) -> Dict[str, ReadableSpan]:
119
+ trace = self._exporter.fetch(trace_id) # type: ignore
120
+
121
+ return trace
@@ -0,0 +1,136 @@
1
+ from typing import Optional, Union, Any, Dict
2
+
3
+ from opentelemetry.trace import SpanContext
4
+ from opentelemetry.trace.status import Status, StatusCode
5
+ from opentelemetry.sdk.trace import Span
6
+
7
+ from agenta.sdk.tracing.attributes import serialize
8
+
9
+
10
+ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
11
+ def __init__(
12
+ self,
13
+ span: Span,
14
+ ) -> None:
15
+ super().__init__( # INHERITANCE FOR TYPING ONLY
16
+ name=span.name,
17
+ context=span.context,
18
+ parent=span.parent,
19
+ sampler=span._sampler,
20
+ trace_config=span._trace_config,
21
+ resource=span.resource,
22
+ attributes=span.attributes,
23
+ events=span.events,
24
+ links=span.links,
25
+ kind=span.kind,
26
+ span_processor=span._span_processor,
27
+ instrumentation_info=span.instrumentation_info,
28
+ record_exception=span._record_exception,
29
+ set_status_on_exception=span._set_status_on_exception,
30
+ limits=span._limits,
31
+ instrumentation_scope=span.instrumentation_scope,
32
+ )
33
+
34
+ self._span = span
35
+
36
+ ## --- PROXY METHODS --- ##
37
+
38
+ def get_span_context(self):
39
+ return self._span.get_span_context()
40
+
41
+ def is_recording(self) -> bool:
42
+ return self._span.is_recording()
43
+
44
+ def update_name(
45
+ self,
46
+ name: str,
47
+ ) -> None:
48
+ self._span.update_name(name)
49
+
50
+ def set_status(
51
+ self,
52
+ status: Union[Status, StatusCode],
53
+ description: Optional[str] = None,
54
+ ) -> None:
55
+ self._span.set_status(
56
+ status=status,
57
+ description=description,
58
+ )
59
+
60
+ def end(self) -> None:
61
+ self._span.end()
62
+
63
+ ## --- CUSTOM METHODS W/ ATTRIBUTES SERALIZATION --- ##
64
+
65
+ def set_attributes(
66
+ self,
67
+ attributes: Dict[str, Any],
68
+ namespace: Optional[str] = None,
69
+ max_depth: Optional[int] = None,
70
+ ) -> None:
71
+ self._span.set_attributes(
72
+ attributes=serialize(
73
+ namespace=namespace,
74
+ attributes=attributes,
75
+ max_depth=max_depth,
76
+ )
77
+ )
78
+
79
+ def set_attribute(
80
+ self,
81
+ key: str,
82
+ value: Any,
83
+ namespace: Optional[str] = None,
84
+ ) -> None:
85
+ self.set_attributes(
86
+ attributes={key: value},
87
+ namespace=namespace,
88
+ )
89
+
90
+ def add_event(
91
+ self,
92
+ name: str,
93
+ attributes: Optional[Dict[str, Any]] = None,
94
+ timestamp: Optional[int] = None,
95
+ namespace: Optional[str] = None,
96
+ ) -> None:
97
+ self._span.add_event(
98
+ name=name,
99
+ attributes=serialize(
100
+ namespace=namespace,
101
+ attributes=attributes,
102
+ ),
103
+ timestamp=timestamp,
104
+ )
105
+
106
+ def add_link(
107
+ self,
108
+ context: SpanContext,
109
+ attributes: Optional[Dict[str, Any]] = None,
110
+ namespace: Optional[str] = None,
111
+ ) -> None:
112
+ self._span.add_link(
113
+ context=context,
114
+ attributes=serialize(
115
+ namespace=namespace,
116
+ attributes=attributes,
117
+ ),
118
+ )
119
+
120
+ def record_exception(
121
+ self,
122
+ exception: BaseException,
123
+ attributes: Optional[Dict[str, Any]] = None,
124
+ timestamp: Optional[int] = None,
125
+ escaped: bool = False,
126
+ namespace: Optional[str] = None,
127
+ ) -> None:
128
+ self._span.record_exception(
129
+ exception=exception,
130
+ attributes=serialize(
131
+ namespace=namespace,
132
+ attributes=attributes,
133
+ ),
134
+ timestamp=timestamp,
135
+ escaped=escaped,
136
+ )
@@ -0,0 +1,237 @@
1
+ from typing import Optional, Any, Dict, Callable
2
+ from enum import Enum
3
+
4
+ from httpx import get as check
5
+
6
+ from opentelemetry.trace import (
7
+ get_current_span,
8
+ set_tracer_provider,
9
+ get_tracer_provider,
10
+ Status,
11
+ StatusCode,
12
+ )
13
+ from opentelemetry.sdk.trace import Span, Tracer, TracerProvider
14
+ from opentelemetry.sdk.resources import Resource
15
+
16
+ from agenta.sdk.utils.singleton import Singleton
17
+ from agenta.sdk.utils.exceptions import suppress
18
+ from agenta.sdk.utils.logging import log
19
+ from agenta.sdk.tracing.processors import TraceProcessor
20
+ from agenta.sdk.tracing.exporters import InlineExporter, OTLPExporter
21
+ from agenta.sdk.tracing.spans import CustomSpan
22
+ from agenta.sdk.tracing.inline import parse_inline_trace
23
+ from agenta.sdk.tracing.conventions import Reference, is_valid_attribute_key
24
+
25
+
26
+ class Tracing(metaclass=Singleton):
27
+ VERSION = "0.1.0"
28
+
29
+ Status = Status
30
+ StatusCode = StatusCode
31
+
32
+ def __init__(
33
+ self,
34
+ url: str,
35
+ redact: Optional[Callable[..., Any]] = None,
36
+ redact_on_error: Optional[bool] = True,
37
+ ) -> None:
38
+ # ENDPOINT (OTLP)
39
+ self.otlp_url = url
40
+ # HEADERS (OTLP)
41
+ self.headers: Dict[str, str] = dict()
42
+ # REFERENCES
43
+ self.references: Dict[str, str] = dict()
44
+ # CREDENTIALS
45
+ self.credentials: Dict[int, str] = dict()
46
+
47
+ # TRACER PROVIDER
48
+ self.tracer_provider: Optional[TracerProvider] = None
49
+ # TRACE PROCESSORS -- INLINE
50
+ self.inline: Optional[TraceProcessor] = None
51
+ # TRACER
52
+ self.tracer: Optional[Tracer] = None
53
+ # INLINE SPANS for INLINE TRACES (INLINE PROCESSOR)
54
+ self.inline_spans: Dict[str, Any] = dict()
55
+
56
+ # REDACT
57
+ self.redact = redact
58
+ self.redact_on_error = redact_on_error
59
+
60
+ # PUBLIC
61
+
62
+ def configure(
63
+ self,
64
+ api_key: Optional[str] = None,
65
+ service_id: Optional[str] = None,
66
+ # DEPRECATING
67
+ app_id: Optional[str] = None,
68
+ ):
69
+ # HEADERS (OTLP)
70
+ if api_key:
71
+ self.headers["Authorization"] = f"ApiKey {api_key}"
72
+ # REFERENCES
73
+ if service_id:
74
+ self.references["service.id"] = service_id
75
+ if app_id:
76
+ self.references["application.id"] = app_id
77
+
78
+ # TRACER PROVIDER
79
+ self.tracer_provider = TracerProvider(
80
+ resource=Resource(attributes={"service.name": "agenta-sdk"})
81
+ )
82
+ # TRACE PROCESSORS -- INLINE
83
+ self.inline = TraceProcessor(
84
+ InlineExporter(
85
+ registry=self.inline_spans,
86
+ ),
87
+ references=self.references,
88
+ )
89
+ self.tracer_provider.add_span_processor(self.inline)
90
+ # TRACE PROCESSORS -- OTLP
91
+ try:
92
+ log.info(
93
+ "Agenta - OLTP URL: %s",
94
+ self.otlp_url,
95
+ )
96
+ # check(
97
+ # self.otlp_url,
98
+ # headers=self.headers,
99
+ # timeout=1,
100
+ # )
101
+
102
+ _otlp = TraceProcessor(
103
+ OTLPExporter(
104
+ endpoint=self.otlp_url,
105
+ headers=self.headers,
106
+ credentials=self.credentials,
107
+ ),
108
+ references=self.references,
109
+ )
110
+
111
+ self.tracer_provider.add_span_processor(_otlp)
112
+ except: # pylint: disable=bare-except
113
+ log.warning("Agenta - OLTP unreachable, skipping exports.")
114
+
115
+ # GLOBAL TRACER PROVIDER -- INSTRUMENTATION LIBRARIES
116
+ set_tracer_provider(self.tracer_provider)
117
+ # TRACER
118
+ self.tracer: Tracer = self.tracer_provider.get_tracer("agenta.tracer")
119
+
120
+ def get_current_span(self):
121
+ _span = None
122
+
123
+ with suppress():
124
+ _span = get_current_span()
125
+
126
+ if _span.is_recording():
127
+ return CustomSpan(_span)
128
+
129
+ return _span
130
+
131
+ def store_internals(
132
+ self,
133
+ attributes: Dict[str, Any],
134
+ span: Optional[Span] = None,
135
+ ):
136
+ with suppress():
137
+ if span is None:
138
+ span = self.get_current_span()
139
+
140
+ span.set_attributes(
141
+ attributes={"internals": attributes},
142
+ namespace="data",
143
+ )
144
+
145
+ def store_refs(
146
+ self,
147
+ refs: Dict[str, str],
148
+ span: Optional[Span] = None,
149
+ ):
150
+ with suppress():
151
+ if span is None:
152
+ span = self.get_current_span()
153
+
154
+ for key in refs.keys():
155
+ if key in [_.value for _ in Reference.__members__.values()]:
156
+ # ADD REFERENCE TO THIS SPAN
157
+ span.set_attribute(
158
+ key.value if isinstance(key, Enum) else key,
159
+ refs[key],
160
+ namespace="refs",
161
+ )
162
+
163
+ # AND TO ALL SPANS CREATED AFTER THIS ONE
164
+ self.references[key] = refs[key]
165
+ # TODO: THIS SHOULD BE REPLACED BY A TRACE CONTEXT !!!
166
+
167
+ def store_meta(
168
+ self,
169
+ meta: Dict[str, Any],
170
+ span: Optional[Span] = None,
171
+ ):
172
+ with suppress():
173
+ if span is None:
174
+ span = self.get_current_span()
175
+
176
+ for key in meta.keys():
177
+ if is_valid_attribute_key(key):
178
+ span.set_attribute(
179
+ key,
180
+ meta[key],
181
+ namespace="meta",
182
+ )
183
+
184
+ def store_metrics(
185
+ self,
186
+ metrics: Dict[str, Any],
187
+ span: Optional[Span] = None,
188
+ ):
189
+ with suppress():
190
+ if span is None:
191
+ span = self.get_current_span()
192
+
193
+ for key in metrics.keys():
194
+ if is_valid_attribute_key(key):
195
+ span.set_attribute(
196
+ key,
197
+ metrics[key],
198
+ namespace="metrics",
199
+ )
200
+
201
+ def is_inline_trace_ready(
202
+ self,
203
+ trace_id: Optional[int] = None,
204
+ ) -> bool:
205
+ is_ready = True
206
+
207
+ with suppress():
208
+ if trace_id is not None:
209
+ is_ready = self.inline.is_ready(trace_id)
210
+
211
+ return is_ready
212
+
213
+ def get_inline_trace(
214
+ self,
215
+ trace_id: Optional[int] = None,
216
+ ) -> Dict[str, Any]:
217
+ _inline_trace = {}
218
+
219
+ with suppress():
220
+ is_ready = self.inline.is_ready(trace_id)
221
+
222
+ if is_ready is True:
223
+ otel_spans = self.inline.fetch(trace_id)
224
+
225
+ if otel_spans:
226
+ _inline_trace = parse_inline_trace(otel_spans)
227
+
228
+ return _inline_trace
229
+
230
+
231
+ def get_tracer(
232
+ tracing: Tracing,
233
+ ) -> Tracer:
234
+ if tracing is None or tracing.tracer is None or tracing.tracer_provider is None:
235
+ return get_tracer_provider().get_tracer("default.tracer")
236
+
237
+ return tracing.tracer