agenta 0.27.6a3__py3-none-any.whl → 0.27.7__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 (61) hide show
  1. agenta/cli/main.py +4 -51
  2. agenta/client/backend/__init__.py +63 -0
  3. agenta/client/backend/apps/client.py +12 -58
  4. agenta/client/backend/client.py +22 -22
  5. agenta/client/backend/core/http_client.py +15 -7
  6. agenta/client/backend/evaluations/client.py +0 -11
  7. agenta/client/backend/observability/client.py +4 -4
  8. agenta/client/backend/observability_v_1/__init__.py +5 -0
  9. agenta/client/backend/observability_v_1/client.py +560 -0
  10. agenta/client/backend/observability_v_1/types/__init__.py +6 -0
  11. agenta/client/backend/observability_v_1/types/format.py +5 -0
  12. agenta/client/backend/observability_v_1/types/query_traces_response.py +11 -0
  13. agenta/client/backend/testsets/client.py +8 -40
  14. agenta/client/backend/types/__init__.py +58 -0
  15. agenta/client/backend/types/agenta_node_dto.py +48 -0
  16. agenta/client/backend/types/agenta_node_dto_nodes_value.py +6 -0
  17. agenta/client/backend/types/agenta_nodes_response.py +30 -0
  18. agenta/client/backend/types/agenta_root_dto.py +30 -0
  19. agenta/client/backend/types/agenta_roots_response.py +30 -0
  20. agenta/client/backend/types/agenta_tree_dto.py +30 -0
  21. agenta/client/backend/types/agenta_trees_response.py +30 -0
  22. agenta/client/backend/types/collect_status_response.py +22 -0
  23. agenta/client/backend/types/exception_dto.py +26 -0
  24. agenta/client/backend/types/link_dto.py +24 -0
  25. agenta/client/backend/types/node_dto.py +24 -0
  26. agenta/client/backend/types/node_type.py +19 -0
  27. agenta/client/backend/types/o_tel_context_dto.py +22 -0
  28. agenta/client/backend/types/o_tel_event_dto.py +23 -0
  29. agenta/client/backend/types/o_tel_extra_dto.py +26 -0
  30. agenta/client/backend/types/o_tel_link_dto.py +23 -0
  31. agenta/client/backend/types/o_tel_span_dto.py +37 -0
  32. agenta/client/backend/types/o_tel_span_kind.py +15 -0
  33. agenta/client/backend/types/o_tel_spans_response.py +24 -0
  34. agenta/client/backend/types/o_tel_status_code.py +8 -0
  35. agenta/client/backend/types/parent_dto.py +21 -0
  36. agenta/client/backend/types/root_dto.py +21 -0
  37. agenta/client/backend/types/span_dto.py +54 -0
  38. agenta/client/backend/types/span_dto_nodes_value.py +9 -0
  39. agenta/client/backend/types/status_code.py +5 -0
  40. agenta/client/backend/types/status_dto.py +23 -0
  41. agenta/client/backend/types/time_dto.py +23 -0
  42. agenta/client/backend/types/tree_dto.py +23 -0
  43. agenta/client/backend/types/tree_type.py +5 -0
  44. agenta/client/backend/variants/client.py +24 -16
  45. agenta/sdk/__init__.py +2 -0
  46. agenta/sdk/agenta_init.py +4 -9
  47. agenta/sdk/decorators/routing.py +34 -53
  48. agenta/sdk/litellm/litellm.py +30 -75
  49. agenta/sdk/middleware/auth.py +10 -7
  50. agenta/sdk/tracing/context.py +6 -6
  51. agenta/sdk/tracing/inline.py +48 -151
  52. agenta/sdk/tracing/processors.py +1 -3
  53. agenta/sdk/tracing/tracing.py +1 -5
  54. agenta/sdk/types.py +5 -2
  55. agenta/sdk/utils/exceptions.py +15 -9
  56. agenta/sdk/utils/logging.py +5 -1
  57. {agenta-0.27.6a3.dist-info → agenta-0.27.7.dist-info}/METADATA +1 -1
  58. {agenta-0.27.6a3.dist-info → agenta-0.27.7.dist-info}/RECORD +60 -27
  59. agenta/sdk/utils/debug.py +0 -68
  60. {agenta-0.27.6a3.dist-info → agenta-0.27.7.dist-info}/WHEEL +0 -0
  61. {agenta-0.27.6a3.dist-info → agenta-0.27.7.dist-info}/entry_points.txt +0 -0
@@ -38,7 +38,7 @@ from agenta.sdk.types import (
38
38
  import agenta as ag
39
39
 
40
40
 
41
- AGENTA_USE_CORS = str(environ.get("AGENTA_USE_CORS", False)).lower() in (
41
+ AGENTA_USE_CORS = str(environ.get("AGENTA_USE_CORS", "true")).lower() in (
42
42
  "true",
43
43
  "1",
44
44
  "t",
@@ -48,22 +48,12 @@ app = FastAPI()
48
48
  log.setLevel("DEBUG")
49
49
 
50
50
 
51
- if AGENTA_USE_CORS:
52
- app.add_middleware(
53
- CORSMiddleware,
54
- allow_origins=["*"],
55
- allow_methods=["*"],
56
- allow_headers=["Authorization"],
57
- )
58
-
59
51
  _MIDDLEWARES = True
60
52
 
61
53
 
62
54
  app.include_router(router, prefix="")
63
55
 
64
56
 
65
-
66
-
67
57
  class PathValidator(BaseModel):
68
58
  url: HttpUrl
69
59
 
@@ -141,12 +131,19 @@ class entrypoint:
141
131
  resource_type="application",
142
132
  )
143
133
 
134
+ if AGENTA_USE_CORS:
135
+ app.add_middleware(
136
+ CORSMiddleware,
137
+ allow_origins=["*"],
138
+ allow_methods=["*"],
139
+ allow_headers=["*"],
140
+ allow_credentials=True,
141
+ )
142
+
144
143
  _MIDDLEWARES = False
145
144
 
146
145
  except: # pylint: disable=bare-except
147
- log.error("------------------------------------")
148
- log.error("Agenta SDK - failed to secure route: %s", route_path)
149
- log.error("------------------------------------")
146
+ log.warning("Agenta SDK - failed to secure route: %s", route_path)
150
147
  ### --- Update Middleware --- #
151
148
 
152
149
  DEFAULT_PATH = "generate"
@@ -358,9 +355,7 @@ class entrypoint:
358
355
  *args,
359
356
  **func_params,
360
357
  ):
361
- log.info("---------------------------")
362
- log.info(f"Agenta SDK - running route: {repr(self.route_path or '/')}")
363
- log.info("---------------------------")
358
+ log.info("Agenta SDK - handling route: %s", repr(self.route_path or "/"))
364
359
 
365
360
  tracing_context.set(routing_context.get())
366
361
 
@@ -378,36 +373,32 @@ class entrypoint:
378
373
 
379
374
  async def handle_success(self, result: Any, inline_trace: bool):
380
375
  data = None
381
- trace = dict()
376
+ tree = None
382
377
 
383
378
  with suppress():
384
379
  data = self.patch_result(result)
385
380
 
386
381
  if inline_trace:
387
- trace = await self.fetch_inline_trace(inline_trace)
382
+ tree = await self.fetch_inline_trace(inline_trace)
388
383
 
389
384
  log.info(f"----------------------------------")
390
385
  log.info(f"Agenta SDK - exiting with success: 200")
391
386
  log.info(f"----------------------------------")
392
387
 
393
- return BaseResponse(data=data, trace=trace)
388
+ return BaseResponse(data=data, tree=tree)
394
389
 
395
390
  def handle_failure(self, error: Exception):
396
- log.error("--------------------------------------------------")
397
- log.error("Agenta SDK - handling application exception below:")
398
- log.error("--------------------------------------------------")
399
- log.error(format_exc().strip("\n"))
400
- log.error("--------------------------------------------------")
391
+ log.warning("--------------------------------------------------")
392
+ log.warning("Agenta SDK - handling application exception below:")
393
+ log.warning("--------------------------------------------------")
394
+ log.warning(format_exc().strip("\n"))
395
+ log.warning("--------------------------------------------------")
401
396
 
402
397
  status_code = error.status_code if hasattr(error, "status_code") else 500
403
398
  message = str(error)
404
399
  stacktrace = format_exception(error, value=error, tb=error.__traceback__) # type: ignore
405
400
  detail = {"message": message, "stacktrace": stacktrace}
406
401
 
407
- log.error(f"----------------------------------")
408
- log.error(f"Agenta SDK - exiting with failure: {status_code}")
409
- log.error(f"----------------------------------")
410
-
411
402
  raise HTTPException(status_code=status_code, detail=detail)
412
403
 
413
404
  def patch_result(self, result: Any):
@@ -684,10 +675,7 @@ class entrypoint:
684
675
 
685
676
  loop = get_event_loop()
686
677
 
687
- with routing_context_manager(
688
- config=args_config_params,
689
- environment="terminal",
690
- ):
678
+ with routing_context_manager(config=args_config_params):
691
679
  result = loop.run_until_complete(
692
680
  self.execute_function(
693
681
  func,
@@ -696,30 +684,23 @@ class entrypoint:
696
684
  )
697
685
  )
698
686
 
699
- SHOW_DETAILS = True
700
- SHOW_DATA = False
701
- SHOW_TRACE = False
702
-
703
687
  if result.trace:
704
688
  log.info("\n========= Result =========\n")
705
689
 
706
690
  log.info(f"trace_id: {result.trace['trace_id']}")
707
- if SHOW_DETAILS:
708
- log.info(f"latency: {result.trace.get('latency')}")
709
- log.info(f"cost: {result.trace.get('cost')}")
710
- log.info(f"usage: {list(result.trace.get('usage', {}).values())}")
711
-
712
- if SHOW_DATA:
713
- log.info(" ")
714
- log.info(f"data:")
715
- log.info(dumps(result.data, indent=2))
716
-
717
- if SHOW_TRACE:
718
- log.info(" ")
719
- log.info(f"trace:")
720
- log.info(f"----------------")
721
- log.info(dumps(result.trace.get("spans", []), indent=2))
722
- log.info(f"----------------")
691
+ log.info(f"latency: {result.trace.get('latency')}")
692
+ log.info(f"cost: {result.trace.get('cost')}")
693
+ log.info(f"usage: {list(result.trace.get('usage', {}).values())}")
694
+
695
+ log.info(" ")
696
+ log.info("data:")
697
+ log.info(dumps(result.data, indent=2))
698
+
699
+ log.info(" ")
700
+ log.info("trace:")
701
+ log.info("----------------")
702
+ log.info(dumps(result.trace.get("spans", []), indent=2))
703
+ log.info("----------------")
723
704
 
724
705
  log.info("\n==========================\n")
725
706
 
@@ -60,7 +60,11 @@ def litellm_handler():
60
60
  )
61
61
 
62
62
  if not self.span:
63
- log.error("LiteLLM callback error: span not found.")
63
+ log.warning("Agenta SDK - litellm tracing failed")
64
+ return
65
+
66
+ if not self.span.is_recording():
67
+ log.error("Agenta SDK - litellm span not recording.")
64
68
  return
65
69
 
66
70
  self.span.set_attributes(
@@ -86,43 +90,11 @@ def litellm_handler():
86
90
  end_time,
87
91
  ):
88
92
  if not self.span:
89
- log.error("LiteLLM callback error: span not found.")
93
+ log.warning("Agenta SDK - litellm tracing failed")
90
94
  return
91
95
 
92
- try:
93
- result = []
94
- for choice in response_obj.choices:
95
- message = choice.message.__dict__
96
- result.append(message)
97
-
98
- outputs = {"completion": result}
99
- self.span.set_attributes(
100
- attributes={"outputs": outputs},
101
- namespace="data",
102
- )
103
-
104
- except Exception as e:
105
- pass
106
-
107
- self.span.set_attributes(
108
- attributes={"total": kwargs.get("response_cost")},
109
- namespace="metrics.unit.costs",
110
- )
111
-
112
- self.span.set_attributes(
113
- attributes=(
114
- {
115
- "prompt": response_obj.usage.prompt_tokens,
116
- "completion": response_obj.usage.completion_tokens,
117
- "total": response_obj.usage.total_tokens,
118
- }
119
- ),
120
- namespace="metrics.unit.tokens",
121
- )
122
-
123
- self.span.set_status(status="OK")
124
-
125
- self.span.end()
96
+ if not self.span.is_recording():
97
+ return
126
98
 
127
99
  def log_success_event(
128
100
  self,
@@ -131,8 +103,14 @@ def litellm_handler():
131
103
  start_time,
132
104
  end_time,
133
105
  ):
106
+ if kwargs.get("stream"):
107
+ return
108
+
134
109
  if not self.span:
135
- log.error("LiteLLM callback error: span not found.")
110
+ log.warning("Agenta SDK - litellm tracing failed")
111
+ return
112
+
113
+ if not self.span.is_recording():
136
114
  return
137
115
 
138
116
  try:
@@ -178,7 +156,10 @@ def litellm_handler():
178
156
  end_time,
179
157
  ):
180
158
  if not self.span:
181
- log.error("LiteLLM callback error: span not found.")
159
+ log.warning("Agenta SDK - litellm tracing failed")
160
+ return
161
+
162
+ if not self.span.is_recording():
182
163
  return
183
164
 
184
165
  self.span.record_exception(kwargs["exception"])
@@ -195,43 +176,11 @@ def litellm_handler():
195
176
  end_time,
196
177
  ):
197
178
  if not self.span:
198
- log.error("LiteLLM callback error: span not found.")
179
+ log.warning("Agenta SDK - litellm tracing failed")
199
180
  return
200
181
 
201
- try:
202
- result = []
203
- for choice in response_obj.choices:
204
- message = choice.message.__dict__
205
- result.append(message)
206
-
207
- outputs = {"completion": result}
208
- self.span.set_attributes(
209
- attributes={"outputs": outputs},
210
- namespace="data",
211
- )
212
-
213
- except Exception as e:
214
- pass
215
-
216
- self.span.set_attributes(
217
- attributes={"total": kwargs.get("response_cost")},
218
- namespace="metrics.unit.costs",
219
- )
220
-
221
- self.span.set_attributes(
222
- attributes=(
223
- {
224
- "prompt": response_obj.usage.prompt_tokens,
225
- "completion": response_obj.usage.completion_tokens,
226
- "total": response_obj.usage.total_tokens,
227
- }
228
- ),
229
- namespace="metrics.unit.tokens",
230
- )
231
-
232
- self.span.set_status(status="OK")
233
-
234
- self.span.end()
182
+ if not self.span.is_recording():
183
+ return
235
184
 
236
185
  async def async_log_success_event(
237
186
  self,
@@ -241,7 +190,10 @@ def litellm_handler():
241
190
  end_time,
242
191
  ):
243
192
  if not self.span:
244
- log.error("LiteLLM callback error: span not found.")
193
+ log.warning("Agenta SDK - litellm tracing failed")
194
+ return
195
+
196
+ if not self.span.is_recording():
245
197
  return
246
198
 
247
199
  try:
@@ -287,7 +239,10 @@ def litellm_handler():
287
239
  end_time,
288
240
  ):
289
241
  if not self.span:
290
- log.error("LiteLLM callback error: span not found.")
242
+ log.warning("Agenta SDK - litellm tracing failed")
243
+ return
244
+
245
+ if not self.span.is_recording():
291
246
  return
292
247
 
293
248
  self.span.record_exception(kwargs["exception"])
@@ -27,6 +27,8 @@ AGENTA_SDK_AUTH_CACHE = str(environ.get("AGENTA_SDK_AUTH_CACHE", True)).lower()
27
27
  "t",
28
28
  )
29
29
 
30
+ AGENTA_SDK_AUTH_CACHE = False
31
+
30
32
  AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED = str(
31
33
  environ.get("AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED", False)
32
34
  ).lower() in ("true", "1", "t")
@@ -61,7 +63,6 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
61
63
  self,
62
64
  request: Request,
63
65
  call_next: Callable,
64
- project_id: Optional[UUID] = None,
65
66
  ):
66
67
  if AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED:
67
68
  return await call_next(request)
@@ -83,6 +84,8 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
83
84
  "resource_id": self.resource_id,
84
85
  }
85
86
 
87
+ project_id = request.query_params.get("project_id")
88
+
86
89
  if project_id:
87
90
  params["project_id"] = project_id
88
91
 
@@ -125,7 +128,7 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
125
128
 
126
129
  cache.put(_hash, policy)
127
130
 
128
- if policy.get("effect") == "deny":
131
+ if not policy or policy.get("effect") == "deny":
129
132
  return Deny()
130
133
 
131
134
  request.state.credentials = policy.get("credentials")
@@ -133,10 +136,10 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
133
136
  return await call_next(request)
134
137
 
135
138
  except: # pylint: disable=bare-except
136
- log.error("------------------------------------------------------")
137
- log.error("Agenta SDK - handling auth middleware exception below:")
138
- log.error("------------------------------------------------------")
139
- log.error(format_exc().strip("\n"))
140
- log.error("------------------------------------------------------")
139
+ log.warning("------------------------------------------------------")
140
+ log.warning("Agenta SDK - handling auth middleware exception below:")
141
+ log.warning("------------------------------------------------------")
142
+ log.warning(format_exc().strip("\n"))
143
+ log.warning("------------------------------------------------------")
141
144
 
142
145
  return Deny()
@@ -14,11 +14,11 @@ def tracing_context_manager():
14
14
  token = tracing_context.set(_tracing_context)
15
15
  try:
16
16
  yield
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("----------------------------------------------")
17
+ except: # pylint: disable=bare-except
18
+ log.warning("----------------------------------------------")
19
+ log.warning("Agenta SDK - handling tracing exception below:")
20
+ log.warning("----------------------------------------------")
21
+ log.warning(format_exc().strip("\n"))
22
+ log.warning("----------------------------------------------")
23
23
  finally:
24
24
  tracing_context.reset(token)
@@ -41,7 +41,6 @@ from uuid import UUID
41
41
  class TimeDTO(BaseModel):
42
42
  start: datetime
43
43
  end: datetime
44
- span: int
45
44
 
46
45
 
47
46
  class StatusCode(Enum):
@@ -846,12 +845,9 @@ def parse_from_otel_span_dto(
846
845
  else None
847
846
  )
848
847
 
849
- duration = (otel_span_dto.end_time - otel_span_dto.start_time).total_seconds()
850
-
851
848
  time = TimeDTO(
852
849
  start=otel_span_dto.start_time,
853
850
  end=otel_span_dto.end_time,
854
- span=round(duration * 1_000_000), # microseconds
855
851
  )
856
852
 
857
853
  status = StatusDTO(
@@ -863,6 +859,13 @@ def parse_from_otel_span_dto(
863
859
 
864
860
  data, metrics, meta, tags, refs = _parse_from_attributes(otel_span_dto)
865
861
 
862
+ duration = (otel_span_dto.end_time - otel_span_dto.start_time).total_seconds()
863
+
864
+ if metrics is None:
865
+ metrics = dict()
866
+
867
+ metrics["acc.duration.total"] = round(duration * 1_000, 3) # milliseconds
868
+
866
869
  root_id = str(tree_id)
867
870
  if refs is not None:
868
871
  root_id = refs.get("scenario.id", root_id)
@@ -903,9 +906,9 @@ def parse_to_agenta_span_dto(
903
906
  if span_dto.data:
904
907
  span_dto.data = _unmarshal_attributes(span_dto.data)
905
908
 
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
+ if "outputs" in span_dto.data:
910
+ if "__default__" in span_dto.data["outputs"]:
911
+ span_dto.data["outputs"] = span_dto.data["outputs"]["__default__"]
909
912
 
910
913
  # METRICS
911
914
  if span_dto.metrics:
@@ -934,6 +937,17 @@ def parse_to_agenta_span_dto(
934
937
  else:
935
938
  parse_to_agenta_span_dto(v)
936
939
 
940
+ # MASK LINKS FOR NOW
941
+ span_dto.links = None
942
+ # ------------------
943
+
944
+ # MASK LIFECYCLE FOR NOW
945
+ # span_dto.lifecycle = None
946
+ if span_dto.lifecycle:
947
+ span_dto.lifecycle.updated_at = None
948
+ span_dto.lifecycle.updated_by_id = None
949
+ # ----------------------
950
+
937
951
  return span_dto
938
952
 
939
953
 
@@ -945,6 +959,8 @@ def parse_to_agenta_span_dto(
945
959
  from litellm import cost_calculator
946
960
  from opentelemetry.sdk.trace import ReadableSpan
947
961
 
962
+ from agenta.sdk.types import AgentaNodeDto, AgentaNodesResponse
963
+
948
964
 
949
965
  def parse_inline_trace(
950
966
  spans: Dict[str, ReadableSpan],
@@ -992,51 +1008,19 @@ def parse_inline_trace(
992
1008
  ### services.observability.service.query() ###
993
1009
  ##############################################
994
1010
 
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
-
1011
+ spans = [
1012
+ loads(
1013
+ span_dto.model_dump_json(
1014
+ exclude_none=True,
1015
+ exclude_defaults=True,
1016
+ )
1017
+ )
1018
+ for span_dto in agenta_span_dtos
1019
+ ]
1020
+ inline_trace = AgentaNodesResponse(
1021
+ version="1.0.0",
1022
+ nodes=[AgentaNodeDto(**span) for span in spans],
1023
+ ).model_dump(exclude_none=True, exclude_unset=True)
1040
1024
  return inline_trace
1041
1025
 
1042
1026
 
@@ -1120,98 +1104,6 @@ class LlmTokens(BaseModel):
1120
1104
  total_tokens: Optional[int] = 0
1121
1105
 
1122
1106
 
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
-
1215
1107
  TYPES_WITH_COSTS = [
1216
1108
  "embedding",
1217
1109
  "query",
@@ -1229,13 +1121,15 @@ def calculate_costs(span_idx: Dict[str, SpanDTO]):
1229
1121
  and span.meta
1230
1122
  and span.metrics
1231
1123
  ):
1124
+ model = span.meta.get("response.model")
1125
+ prompt_tokens = span.metrics.get("unit.tokens.prompt", 0.0)
1126
+ completion_tokens = span.metrics.get("unit.tokens.completion", 0.0)
1127
+
1232
1128
  try:
1233
1129
  costs = cost_calculator.cost_per_token(
1234
- model=span.meta.get("response.model"),
1235
- prompt_tokens=span.metrics.get("unit.tokens.prompt", 0.0),
1236
- completion_tokens=span.metrics.get("unit.tokens.completion", 0.0),
1237
- call_type=span.node.type.name.lower(),
1238
- response_time_ms=span.time.span // 1_000,
1130
+ model=model,
1131
+ prompt_tokens=prompt_tokens,
1132
+ completion_tokens=completion_tokens,
1239
1133
  )
1240
1134
 
1241
1135
  if not costs:
@@ -1248,5 +1142,8 @@ def calculate_costs(span_idx: Dict[str, SpanDTO]):
1248
1142
  span.metrics["unit.costs.completion"] = completion_cost
1249
1143
  span.metrics["unit.costs.total"] = total_cost
1250
1144
 
1251
- except:
1252
- pass
1145
+ except: # pylint: disable=bare-except
1146
+ print("Failed to calculate costs:")
1147
+ print(
1148
+ f"model={model}, prompt_tokens={prompt_tokens}, completion_tokens={completion_tokens}"
1149
+ )
@@ -91,9 +91,7 @@ class TraceProcessor(BatchSpanProcessor):
91
91
  ret = super().force_flush(timeout_millis)
92
92
 
93
93
  if not ret:
94
- log.error("--------------------------------------------")
95
- log.error("Agenta SDK - skipping export due to timeout.")
96
- log.error("--------------------------------------------")
94
+ log.warning("Agenta SDK - skipping export due to timeout.")
97
95
 
98
96
  def is_ready(
99
97
  self,