agenta 0.27.4a1__py3-none-any.whl → 0.27.5a1__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 (54) hide show
  1. agenta/__init__.py +29 -6
  2. agenta/client/backend/__init__.py +0 -63
  3. agenta/client/backend/client.py +22 -22
  4. agenta/client/backend/core/http_client.py +7 -15
  5. agenta/client/backend/observability/client.py +4 -4
  6. agenta/client/backend/types/__init__.py +0 -58
  7. agenta/client/backend/variants/client.py +16 -24
  8. agenta/sdk/__init__.py +8 -6
  9. agenta/sdk/agenta_init.py +10 -3
  10. agenta/sdk/decorators/routing.py +1 -1
  11. agenta/sdk/decorators/tracing.py +31 -7
  12. agenta/sdk/litellm/litellm.py +36 -25
  13. agenta/sdk/middleware/auth.py +14 -8
  14. agenta/sdk/tracing/inline.py +140 -29
  15. agenta/sdk/tracing/tracing.py +7 -1
  16. agenta/sdk/types.py +2 -5
  17. {agenta-0.27.4a1.dist-info → agenta-0.27.5a1.dist-info}/METADATA +1 -4
  18. {agenta-0.27.4a1.dist-info → agenta-0.27.5a1.dist-info}/RECORD +20 -54
  19. agenta/client/backend/observability_v_1/__init__.py +0 -5
  20. agenta/client/backend/observability_v_1/client.py +0 -560
  21. agenta/client/backend/observability_v_1/types/__init__.py +0 -6
  22. agenta/client/backend/observability_v_1/types/format.py +0 -5
  23. agenta/client/backend/observability_v_1/types/query_traces_response.py +0 -11
  24. agenta/client/backend/types/agenta_node_dto.py +0 -48
  25. agenta/client/backend/types/agenta_node_dto_nodes_value.py +0 -6
  26. agenta/client/backend/types/agenta_nodes_response.py +0 -30
  27. agenta/client/backend/types/agenta_root_dto.py +0 -30
  28. agenta/client/backend/types/agenta_roots_response.py +0 -30
  29. agenta/client/backend/types/agenta_tree_dto.py +0 -30
  30. agenta/client/backend/types/agenta_trees_response.py +0 -30
  31. agenta/client/backend/types/collect_status_response.py +0 -22
  32. agenta/client/backend/types/exception_dto.py +0 -26
  33. agenta/client/backend/types/link_dto.py +0 -24
  34. agenta/client/backend/types/node_dto.py +0 -24
  35. agenta/client/backend/types/node_type.py +0 -19
  36. agenta/client/backend/types/o_tel_context_dto.py +0 -22
  37. agenta/client/backend/types/o_tel_event_dto.py +0 -23
  38. agenta/client/backend/types/o_tel_extra_dto.py +0 -26
  39. agenta/client/backend/types/o_tel_link_dto.py +0 -23
  40. agenta/client/backend/types/o_tel_span_dto.py +0 -37
  41. agenta/client/backend/types/o_tel_span_kind.py +0 -15
  42. agenta/client/backend/types/o_tel_spans_response.py +0 -24
  43. agenta/client/backend/types/o_tel_status_code.py +0 -8
  44. agenta/client/backend/types/parent_dto.py +0 -21
  45. agenta/client/backend/types/root_dto.py +0 -21
  46. agenta/client/backend/types/span_dto.py +0 -54
  47. agenta/client/backend/types/span_dto_nodes_value.py +0 -9
  48. agenta/client/backend/types/status_code.py +0 -5
  49. agenta/client/backend/types/status_dto.py +0 -23
  50. agenta/client/backend/types/time_dto.py +0 -23
  51. agenta/client/backend/types/tree_dto.py +0 -23
  52. agenta/client/backend/types/tree_type.py +0 -5
  53. {agenta-0.27.4a1.dist-info → agenta-0.27.5a1.dist-info}/WHEEL +0 -0
  54. {agenta-0.27.4a1.dist-info → agenta-0.27.5a1.dist-info}/entry_points.txt +0 -0
@@ -1104,14 +1104,14 @@ class VariantsClient:
1104
1104
  def configs_delete(
1105
1105
  self,
1106
1106
  *,
1107
- variant_ref: ReferenceRequestModel,
1107
+ variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1108
1108
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1109
1109
  request_options: typing.Optional[RequestOptions] = None,
1110
1110
  ) -> int:
1111
1111
  """
1112
1112
  Parameters
1113
1113
  ----------
1114
- variant_ref : ReferenceRequestModel
1114
+ variant_ref : typing.Optional[ReferenceRequestModel]
1115
1115
 
1116
1116
  application_ref : typing.Optional[ReferenceRequestModel]
1117
1117
 
@@ -1125,15 +1125,13 @@ class VariantsClient:
1125
1125
 
1126
1126
  Examples
1127
1127
  --------
1128
- from agenta import AgentaApi, ReferenceRequestModel
1128
+ from agenta import AgentaApi
1129
1129
 
1130
1130
  client = AgentaApi(
1131
1131
  api_key="YOUR_API_KEY",
1132
1132
  base_url="https://yourhost.com/path/to/api",
1133
1133
  )
1134
- client.variants.configs_delete(
1135
- variant_ref=ReferenceRequestModel(),
1136
- )
1134
+ client.variants.configs_delete()
1137
1135
  """
1138
1136
  _response = self._client_wrapper.httpx_client.request(
1139
1137
  "variants/configs/delete",
@@ -1246,14 +1244,14 @@ class VariantsClient:
1246
1244
  def configs_history(
1247
1245
  self,
1248
1246
  *,
1249
- variant_ref: ReferenceRequestModel,
1247
+ variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1250
1248
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1251
1249
  request_options: typing.Optional[RequestOptions] = None,
1252
1250
  ) -> typing.List[ConfigResponseModel]:
1253
1251
  """
1254
1252
  Parameters
1255
1253
  ----------
1256
- variant_ref : ReferenceRequestModel
1254
+ variant_ref : typing.Optional[ReferenceRequestModel]
1257
1255
 
1258
1256
  application_ref : typing.Optional[ReferenceRequestModel]
1259
1257
 
@@ -1267,15 +1265,13 @@ class VariantsClient:
1267
1265
 
1268
1266
  Examples
1269
1267
  --------
1270
- from agenta import AgentaApi, ReferenceRequestModel
1268
+ from agenta import AgentaApi
1271
1269
 
1272
1270
  client = AgentaApi(
1273
1271
  api_key="YOUR_API_KEY",
1274
1272
  base_url="https://yourhost.com/path/to/api",
1275
1273
  )
1276
- client.variants.configs_history(
1277
- variant_ref=ReferenceRequestModel(),
1278
- )
1274
+ client.variants.configs_history()
1279
1275
  """
1280
1276
  _response = self._client_wrapper.httpx_client.request(
1281
1277
  "variants/configs/history",
@@ -2508,14 +2504,14 @@ class AsyncVariantsClient:
2508
2504
  async def configs_delete(
2509
2505
  self,
2510
2506
  *,
2511
- variant_ref: ReferenceRequestModel,
2507
+ variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2512
2508
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2513
2509
  request_options: typing.Optional[RequestOptions] = None,
2514
2510
  ) -> int:
2515
2511
  """
2516
2512
  Parameters
2517
2513
  ----------
2518
- variant_ref : ReferenceRequestModel
2514
+ variant_ref : typing.Optional[ReferenceRequestModel]
2519
2515
 
2520
2516
  application_ref : typing.Optional[ReferenceRequestModel]
2521
2517
 
@@ -2531,7 +2527,7 @@ class AsyncVariantsClient:
2531
2527
  --------
2532
2528
  import asyncio
2533
2529
 
2534
- from agenta import AsyncAgentaApi, ReferenceRequestModel
2530
+ from agenta import AsyncAgentaApi
2535
2531
 
2536
2532
  client = AsyncAgentaApi(
2537
2533
  api_key="YOUR_API_KEY",
@@ -2540,9 +2536,7 @@ class AsyncVariantsClient:
2540
2536
 
2541
2537
 
2542
2538
  async def main() -> None:
2543
- await client.variants.configs_delete(
2544
- variant_ref=ReferenceRequestModel(),
2545
- )
2539
+ await client.variants.configs_delete()
2546
2540
 
2547
2541
 
2548
2542
  asyncio.run(main())
@@ -2666,14 +2660,14 @@ class AsyncVariantsClient:
2666
2660
  async def configs_history(
2667
2661
  self,
2668
2662
  *,
2669
- variant_ref: ReferenceRequestModel,
2663
+ variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2670
2664
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2671
2665
  request_options: typing.Optional[RequestOptions] = None,
2672
2666
  ) -> typing.List[ConfigResponseModel]:
2673
2667
  """
2674
2668
  Parameters
2675
2669
  ----------
2676
- variant_ref : ReferenceRequestModel
2670
+ variant_ref : typing.Optional[ReferenceRequestModel]
2677
2671
 
2678
2672
  application_ref : typing.Optional[ReferenceRequestModel]
2679
2673
 
@@ -2689,7 +2683,7 @@ class AsyncVariantsClient:
2689
2683
  --------
2690
2684
  import asyncio
2691
2685
 
2692
- from agenta import AsyncAgentaApi, ReferenceRequestModel
2686
+ from agenta import AsyncAgentaApi
2693
2687
 
2694
2688
  client = AsyncAgentaApi(
2695
2689
  api_key="YOUR_API_KEY",
@@ -2698,9 +2692,7 @@ class AsyncVariantsClient:
2698
2692
 
2699
2693
 
2700
2694
  async def main() -> None:
2701
- await client.variants.configs_history(
2702
- variant_ref=ReferenceRequestModel(),
2703
- )
2695
+ await client.variants.configs_history()
2704
2696
 
2705
2697
 
2706
2698
  asyncio.run(main())
agenta/sdk/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, Callable, Any
2
2
 
3
3
  from .utils.preinit import PreInitObject # always the first import!
4
4
 
@@ -17,8 +17,6 @@ from .types import (
17
17
  FileInputURL,
18
18
  BinaryParam,
19
19
  Prompt,
20
- AgentaNodeDto,
21
- AgentaNodesResponse,
22
20
  )
23
21
 
24
22
  from .tracing import Tracing, get_tracer
@@ -45,17 +43,21 @@ tracer = get_tracer(tracing)
45
43
 
46
44
  def init(
47
45
  host: Optional[str] = None,
48
- app_id: Optional[str] = None,
49
46
  api_key: Optional[str] = None,
50
47
  config_fname: Optional[str] = None,
48
+ redact: Optional[Callable[..., Any]] = None,
49
+ redact_on_error: Optional[bool] = True,
50
+ # DEPRECATING
51
+ app_id: Optional[str] = None,
51
52
  ):
52
- global api, async_api, tracing, tracer
53
+ global api, async_api, tracing, tracer # pylint: disable=global-statement
53
54
 
54
55
  _init(
55
56
  host=host,
56
57
  api_key=api_key,
57
58
  config_fname=config_fname,
58
- # DEPRECATING
59
+ redact=redact,
60
+ redact_on_error=redact_on_error,
59
61
  app_id=app_id,
60
62
  )
61
63
 
agenta/sdk/agenta_init.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import toml
3
3
  from os import getenv
4
- from typing import Optional
4
+ from typing import Optional, Callable, Any
5
5
  from importlib.metadata import version
6
6
 
7
7
  from agenta.sdk.utils.logging import log
@@ -36,6 +36,8 @@ class AgentaSingleton:
36
36
  host: Optional[str] = None,
37
37
  api_key: Optional[str] = None,
38
38
  config_fname: Optional[str] = None,
39
+ redact: Optional[Callable[..., Any]] = None,
40
+ redact_on_error: Optional[bool] = True,
39
41
  # DEPRECATING
40
42
  app_id: Optional[str] = None,
41
43
  ) -> None:
@@ -91,6 +93,8 @@ class AgentaSingleton:
91
93
 
92
94
  self.tracing = Tracing(
93
95
  url=f"{self.host}/api/observability/v1/otlp/traces", # type: ignore
96
+ redact=redact,
97
+ redact_on_error=redact_on_error,
94
98
  )
95
99
 
96
100
  self.tracing.configure(
@@ -258,7 +262,9 @@ def init(
258
262
  host: Optional[str] = None,
259
263
  api_key: Optional[str] = None,
260
264
  config_fname: Optional[str] = None,
261
- # DEPRECATED
265
+ redact: Optional[Callable[..., Any]] = None,
266
+ redact_on_error: Optional[bool] = True,
267
+ # DEPRECATING
262
268
  app_id: Optional[str] = None,
263
269
  ):
264
270
  """Main function to initialize the agenta sdk.
@@ -289,7 +295,8 @@ def init(
289
295
  host=host,
290
296
  api_key=api_key,
291
297
  config_fname=config_fname,
292
- # DEPRECATED
298
+ redact=redact,
299
+ redact_on_error=redact_on_error,
293
300
  app_id=app_id,
294
301
  )
295
302
 
@@ -386,7 +386,7 @@ class entrypoint:
386
386
  log.info(f"Agenta SDK - exiting with success: 200")
387
387
  log.info(f"----------------------------------")
388
388
 
389
- return BaseResponse(data=data, tree=trace)
389
+ return BaseResponse(data=data, trace=trace)
390
390
 
391
391
  def handle_failure(self, error: Exception):
392
392
  log.error("--------------------------------------------------")
@@ -19,6 +19,8 @@ class instrument: # pylint: disable=invalid-name
19
19
  config: Optional[Dict[str, Any]] = None,
20
20
  ignore_inputs: Optional[bool] = None,
21
21
  ignore_outputs: Optional[bool] = None,
22
+ redact: Optional[Callable[..., Any]] = None,
23
+ redact_on_error: Optional[bool] = True,
22
24
  max_depth: Optional[int] = 2,
23
25
  # DEPRECATING
24
26
  kind: str = "task",
@@ -29,6 +31,8 @@ class instrument: # pylint: disable=invalid-name
29
31
  self.config = config
30
32
  self.ignore_inputs = ignore_inputs
31
33
  self.ignore_outputs = ignore_outputs
34
+ self.redact = redact
35
+ self.redact_on_error = redact_on_error
32
36
  self.max_depth = max_depth
33
37
 
34
38
  def __call__(self, func: Callable[..., Any]):
@@ -109,12 +113,10 @@ class instrument: # pylint: disable=invalid-name
109
113
  )
110
114
 
111
115
  _inputs = self._redact(
112
- self._parse(
113
- func,
114
- *args,
115
- **kwargs,
116
- ),
117
- self.ignore_inputs,
116
+ name=span.name,
117
+ field="inputs",
118
+ io=self._parse(func, *args, **kwargs),
119
+ ignore=self.ignore_inputs,
118
120
  )
119
121
  span.set_attributes(
120
122
  attributes={"inputs": _inputs},
@@ -153,7 +155,12 @@ class instrument: # pylint: disable=invalid-name
153
155
  namespace="metrics.unit.tokens",
154
156
  )
155
157
 
156
- _outputs = self._redact(self._patch(result), self.ignore_outputs)
158
+ _outputs = self._redact(
159
+ name=span.name,
160
+ field="outputs",
161
+ io=self._patch(result),
162
+ ignore=self.ignore_outputs,
163
+ )
157
164
  span.set_attributes(
158
165
  attributes={"outputs": _outputs},
159
166
  namespace="data",
@@ -192,6 +199,9 @@ class instrument: # pylint: disable=invalid-name
192
199
 
193
200
  def _redact(
194
201
  self,
202
+ *,
203
+ name: str,
204
+ field: str,
195
205
  io: Dict[str, Any],
196
206
  ignore: Union[List[str], bool] = False,
197
207
  ) -> Dict[str, Any]:
@@ -220,6 +230,20 @@ class instrument: # pylint: disable=invalid-name
220
230
  )
221
231
  }
222
232
 
233
+ if self.redact is not None:
234
+ try:
235
+ io = self.redact(name, field, io)
236
+ except: # pylint: disable=bare-except
237
+ if self.redact_on_error:
238
+ io = {}
239
+
240
+ if ag.tracing.redact is not None:
241
+ try:
242
+ io = ag.tracing.redact(name, field, io)
243
+ except: # pylint: disable=bare-except
244
+ if ag.tracing.redact_on_error:
245
+ io = {}
246
+
223
247
  return io
224
248
 
225
249
  def _patch(
@@ -89,16 +89,20 @@ def litellm_handler():
89
89
  log.error("LiteLLM callback error: span not found.")
90
90
  return
91
91
 
92
- result = kwargs.get("complete_streaming_response")
92
+ try:
93
+ result = []
94
+ for choice in response_obj.choices:
95
+ message = choice.message.__dict__
96
+ result.append(message)
93
97
 
94
- outputs = (
95
- {"__default__": result} if not isinstance(result, dict) else result
96
- )
98
+ outputs = {"completion": result}
99
+ self.span.set_attributes(
100
+ attributes={"outputs": outputs},
101
+ namespace="data",
102
+ )
97
103
 
98
- self.span.set_attributes(
99
- attributes={"outputs": outputs},
100
- namespace="data",
101
- )
104
+ except Exception as e:
105
+ pass
102
106
 
103
107
  self.span.set_attributes(
104
108
  attributes={"total": kwargs.get("response_cost")},
@@ -194,16 +198,20 @@ def litellm_handler():
194
198
  log.error("LiteLLM callback error: span not found.")
195
199
  return
196
200
 
197
- result = kwargs.get("complete_streaming_response")
201
+ try:
202
+ result = []
203
+ for choice in response_obj.choices:
204
+ message = choice.message.__dict__
205
+ result.append(message)
198
206
 
199
- outputs = (
200
- {"__default__": result} if not isinstance(result, dict) else result
201
- )
207
+ outputs = {"completion": result}
208
+ self.span.set_attributes(
209
+ attributes={"outputs": outputs},
210
+ namespace="data",
211
+ )
202
212
 
203
- self.span.set_attributes(
204
- attributes={"outputs": outputs},
205
- namespace="data",
206
- )
213
+ except Exception as e:
214
+ pass
207
215
 
208
216
  self.span.set_attributes(
209
217
  attributes={"total": kwargs.get("response_cost")},
@@ -236,17 +244,20 @@ def litellm_handler():
236
244
  log.error("LiteLLM callback error: span not found.")
237
245
  return
238
246
 
239
- # result = kwargs.get("complete_streaming_response")
240
- result = response_obj.choices[0].message.content
247
+ try:
248
+ result = []
249
+ for choice in response_obj.choices:
250
+ message = choice.message.__dict__
251
+ result.append(message)
241
252
 
242
- outputs = (
243
- {"__default__": result} if not isinstance(result, dict) else result
244
- )
253
+ outputs = {"completion": result}
254
+ self.span.set_attributes(
255
+ attributes={"outputs": outputs},
256
+ namespace="data",
257
+ )
245
258
 
246
- self.span.set_attributes(
247
- attributes={"outputs": outputs},
248
- namespace="data",
249
- )
259
+ except Exception as e:
260
+ pass
250
261
 
251
262
  self.span.set_attributes(
252
263
  attributes={"total": kwargs.get("response_cost")},
@@ -21,6 +21,12 @@ AGENTA_SDK_AUTH_CACHE_TTL = environ.get(
21
21
  15 * 60, # 15 minutes
22
22
  )
23
23
 
24
+ AGENTA_SDK_AUTH_CACHE = str(environ.get("AGENTA_SDK_AUTH_CACHE", True)).lower() in (
25
+ "true",
26
+ "1",
27
+ "t",
28
+ )
29
+
24
30
  AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED = str(
25
31
  environ.get("AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED", False)
26
32
  ).lower() in ("true", "1", "t")
@@ -89,9 +95,11 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
89
95
  sort_keys=True,
90
96
  )
91
97
 
92
- cached_policy = cache.get(_hash)
98
+ policy = None
99
+ if AGENTA_SDK_AUTH_CACHE:
100
+ policy = cache.get(_hash)
93
101
 
94
- if not cached_policy:
102
+ if not policy:
95
103
  async with httpx.AsyncClient() as client:
96
104
  response = await client.get(
97
105
  f"{self.host}/api/permissions/verify",
@@ -110,19 +118,17 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
110
118
  cache.put(_hash, {"effect": "deny"})
111
119
  return Deny()
112
120
 
113
- cached_policy = {
121
+ policy = {
114
122
  "effect": "allow",
115
123
  "credentials": auth.get("credentials"),
116
124
  }
117
125
 
118
- cache.put(_hash, cached_policy)
126
+ cache.put(_hash, policy)
119
127
 
120
- if cached_policy.get("effect") == "deny":
128
+ if policy.get("effect") == "deny":
121
129
  return Deny()
122
130
 
123
- request.state.credentials = cached_policy.get("credentials")
124
-
125
- print(f"credentials: {request.state.credentials}")
131
+ request.state.credentials = policy.get("credentials")
126
132
 
127
133
  return await call_next(request)
128
134
 
@@ -903,9 +903,9 @@ def parse_to_agenta_span_dto(
903
903
  if span_dto.data:
904
904
  span_dto.data = _unmarshal_attributes(span_dto.data)
905
905
 
906
- if "outputs" in span_dto.data:
907
- if "__default__" in span_dto.data["outputs"]:
908
- span_dto.data["outputs"] = span_dto.data["outputs"]["__default__"]
906
+ # if "outputs" in span_dto.data:
907
+ # if "__default__" in span_dto.data["outputs"]:
908
+ # span_dto.data["outputs"] = span_dto.data["outputs"]["__default__"]
909
909
 
910
910
  # METRICS
911
911
  if span_dto.metrics:
@@ -934,17 +934,6 @@ def parse_to_agenta_span_dto(
934
934
  else:
935
935
  parse_to_agenta_span_dto(v)
936
936
 
937
- # MASK LINKS FOR NOW
938
- span_dto.links = None
939
- # ------------------
940
-
941
- # MASK LIFECYCLE FOR NOW
942
- # span_dto.lifecycle = None
943
- if span_dto.lifecycle:
944
- span_dto.lifecycle.updated_at = None
945
- span_dto.lifecycle.updated_by_id = None
946
- # ----------------------
947
-
948
937
  return span_dto
949
938
 
950
939
 
@@ -956,8 +945,6 @@ def parse_to_agenta_span_dto(
956
945
  from litellm import cost_calculator
957
946
  from opentelemetry.sdk.trace import ReadableSpan
958
947
 
959
- from agenta.sdk.types import AgentaNodeDto, AgentaNodesResponse
960
-
961
948
 
962
949
  def parse_inline_trace(
963
950
  spans: Dict[str, ReadableSpan],
@@ -1005,19 +992,51 @@ def parse_inline_trace(
1005
992
  ### services.observability.service.query() ###
1006
993
  ##############################################
1007
994
 
1008
- spans = [
1009
- loads(
1010
- span_dto.model_dump_json(
1011
- exclude_none=True,
1012
- exclude_defaults=True,
1013
- )
1014
- )
1015
- for span_dto in agenta_span_dtos
1016
- ]
1017
- inline_trace = AgentaNodesResponse(
1018
- version="1.0.0",
1019
- nodes=[AgentaNodeDto(**span) for span in spans],
1020
- ).model_dump(exclude_none=True, exclude_unset=True)
995
+ LEGACY = True
996
+ inline_trace = None
997
+
998
+ if LEGACY:
999
+ legacy_spans = [
1000
+ _parse_to_legacy_span(span_dto) for span_dto in span_idx.values()
1001
+ ]
1002
+
1003
+ root_span = agenta_span_dtos[0]
1004
+
1005
+ trace_id = root_span.root.id.hex
1006
+ latency = root_span.time.span / 1_000_000
1007
+ cost = root_span.metrics.get("acc", {}).get("costs", {}).get("total", 0.0)
1008
+ tokens = {
1009
+ "prompt_tokens": root_span.metrics.get("acc", {})
1010
+ .get("tokens", {})
1011
+ .get("prompt", 0),
1012
+ "completion_tokens": root_span.metrics.get("acc", {})
1013
+ .get("tokens", {})
1014
+ .get("completion", 0),
1015
+ "total_tokens": root_span.metrics.get("acc", {})
1016
+ .get("tokens", {})
1017
+ .get("total", 0),
1018
+ }
1019
+
1020
+ spans = [
1021
+ loads(span.model_dump_json(exclude_none=True)) for span in legacy_spans
1022
+ ]
1023
+
1024
+ inline_trace = {
1025
+ "trace_id": trace_id,
1026
+ "latency": latency,
1027
+ "cost": cost,
1028
+ "usage": tokens,
1029
+ "spans": spans,
1030
+ }
1031
+
1032
+ else:
1033
+ spans = [
1034
+ loads(span_dto.model_dump_json(exclude_none=True))
1035
+ for span_dto in agenta_span_dtos
1036
+ ]
1037
+
1038
+ inline_trace = spans # turn into Agenta Model ?
1039
+
1021
1040
  return inline_trace
1022
1041
 
1023
1042
 
@@ -1101,6 +1120,98 @@ class LlmTokens(BaseModel):
1101
1120
  total_tokens: Optional[int] = 0
1102
1121
 
1103
1122
 
1123
+ class CreateSpan(BaseModel):
1124
+ id: str
1125
+ app_id: str
1126
+ variant_id: Optional[str] = None
1127
+ variant_name: Optional[str] = None
1128
+ inputs: Optional[Dict[str, Optional[Any]]] = None
1129
+ internals: Optional[Dict[str, Optional[Any]]] = None
1130
+ outputs: Optional[Union[str, Dict[str, Optional[Any]], List[Any]]] = None
1131
+ config: Optional[Dict[str, Optional[Any]]] = None
1132
+ environment: Optional[str] = None
1133
+ tags: Optional[List[str]] = None
1134
+ token_consumption: Optional[int] = None
1135
+ name: str
1136
+ parent_span_id: Optional[str] = None
1137
+ attributes: Optional[Dict[str, Optional[Any]]] = None
1138
+ spankind: str
1139
+ status: str
1140
+ user: Optional[str] = None
1141
+ start_time: datetime
1142
+ end_time: datetime
1143
+ tokens: Optional[LlmTokens] = None
1144
+ cost: Optional[float] = None
1145
+
1146
+
1147
+ def _parse_to_legacy_span(span: SpanDTO) -> CreateSpan:
1148
+ attributes = None
1149
+ if span.otel:
1150
+ attributes = span.otel.attributes or {}
1151
+
1152
+ if span.otel.events:
1153
+ for event in span.otel.events:
1154
+ if event.name == "exception":
1155
+ attributes.update(**event.attributes)
1156
+
1157
+ legacy_span = CreateSpan(
1158
+ id=span.node.id.hex[:24],
1159
+ spankind=span.node.type,
1160
+ name=span.node.name,
1161
+ #
1162
+ status=span.status.code.name,
1163
+ #
1164
+ start_time=span.time.start,
1165
+ end_time=span.time.end,
1166
+ #
1167
+ parent_span_id=span.parent.id.hex[:24] if span.parent else None,
1168
+ #
1169
+ inputs=span.data.get("inputs") if span.data else {},
1170
+ internals=span.data.get("internals") if span.data else {},
1171
+ outputs=span.data.get("outputs") if span.data else {},
1172
+ #
1173
+ environment=span.meta.get("environment") if span.meta else None,
1174
+ config=span.meta.get("configuration") if span.meta else None,
1175
+ #
1176
+ tokens=(
1177
+ LlmTokens(
1178
+ prompt_tokens=span.metrics.get("acc", {})
1179
+ .get("tokens", {})
1180
+ .get("prompt", 0.0),
1181
+ completion_tokens=span.metrics.get("acc", {})
1182
+ .get("tokens", {})
1183
+ .get("completion", 0.0),
1184
+ total_tokens=span.metrics.get("acc", {})
1185
+ .get("tokens", {})
1186
+ .get("total", 0.0),
1187
+ )
1188
+ if span.metrics
1189
+ else None
1190
+ ),
1191
+ cost=(
1192
+ span.metrics.get("acc", {}).get("costs", {}).get("total", 0.0)
1193
+ if span.metrics
1194
+ else None
1195
+ ),
1196
+ #
1197
+ app_id=(
1198
+ span.refs.get("application", {}).get("id", "missing-app-id")
1199
+ if span.refs
1200
+ else "missing-app-id"
1201
+ ),
1202
+ #
1203
+ attributes=attributes,
1204
+ #
1205
+ variant_id=None,
1206
+ variant_name=None,
1207
+ tags=None,
1208
+ token_consumption=None,
1209
+ user=None,
1210
+ )
1211
+
1212
+ return legacy_span
1213
+
1214
+
1104
1215
  TYPES_WITH_COSTS = [
1105
1216
  "embedding",
1106
1217
  "query",
@@ -1,4 +1,4 @@
1
- from typing import Optional, Any, Dict
1
+ from typing import Optional, Any, Dict, Callable
2
2
  from enum import Enum
3
3
 
4
4
  from httpx import get as check
@@ -32,6 +32,8 @@ class Tracing(metaclass=Singleton):
32
32
  def __init__(
33
33
  self,
34
34
  url: str,
35
+ redact: Optional[Callable[..., Any]] = None,
36
+ redact_on_error: Optional[bool] = True,
35
37
  ) -> None:
36
38
  # ENDPOINT (OTLP)
37
39
  self.otlp_url = url
@@ -49,6 +51,10 @@ class Tracing(metaclass=Singleton):
49
51
  # INLINE SPANS for INLINE TRACES (INLINE PROCESSOR)
50
52
  self.inline_spans: Dict[str, Any] = dict()
51
53
 
54
+ # REDACT
55
+ self.redact = redact
56
+ self.redact_on_error = redact_on_error
57
+
52
58
  # PUBLIC
53
59
 
54
60
  def configure(