agenta 0.27.6a2__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 +41 -56
  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.6a2.dist-info → agenta-0.27.7.dist-info}/METADATA +1 -1
  58. {agenta-0.27.6a2.dist-info → agenta-0.27.7.dist-info}/RECORD +60 -27
  59. agenta/sdk/utils/debug.py +0 -68
  60. {agenta-0.27.6a2.dist-info → agenta-0.27.7.dist-info}/WHEEL +0 -0
  61. {agenta-0.27.6a2.dist-info → agenta-0.27.7.dist-info}/entry_points.txt +0 -0
@@ -37,27 +37,21 @@ from agenta.sdk.types import (
37
37
 
38
38
  import agenta as ag
39
39
 
40
- app = FastAPI()
41
-
42
- origins = [
43
- "*",
44
- ]
45
40
 
46
- app.add_middleware(
47
- CORSMiddleware,
48
- allow_origins=origins,
49
- allow_credentials=True,
50
- allow_methods=["*"],
51
- allow_headers=["*"],
41
+ AGENTA_USE_CORS = str(environ.get("AGENTA_USE_CORS", "true")).lower() in (
42
+ "true",
43
+ "1",
44
+ "t",
52
45
  )
53
46
 
54
- _MIDDLEWARES = True
47
+ app = FastAPI()
48
+ log.setLevel("DEBUG")
55
49
 
56
50
 
57
- app.include_router(router, prefix="")
51
+ _MIDDLEWARES = True
58
52
 
59
53
 
60
- log.setLevel("DEBUG")
54
+ app.include_router(router, prefix="")
61
55
 
62
56
 
63
57
  class PathValidator(BaseModel):
@@ -137,12 +131,19 @@ class entrypoint:
137
131
  resource_type="application",
138
132
  )
139
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
+
140
143
  _MIDDLEWARES = False
141
144
 
142
145
  except: # pylint: disable=bare-except
143
- log.error("------------------------------------")
144
- log.error("Agenta SDK - failed to secure route: %s", route_path)
145
- log.error("------------------------------------")
146
+ log.warning("Agenta SDK - failed to secure route: %s", route_path)
146
147
  ### --- Update Middleware --- #
147
148
 
148
149
  DEFAULT_PATH = "generate"
@@ -354,9 +355,7 @@ class entrypoint:
354
355
  *args,
355
356
  **func_params,
356
357
  ):
357
- log.info("---------------------------")
358
- log.info(f"Agenta SDK - running route: {repr(self.route_path or '/')}")
359
- log.info("---------------------------")
358
+ log.info("Agenta SDK - handling route: %s", repr(self.route_path or "/"))
360
359
 
361
360
  tracing_context.set(routing_context.get())
362
361
 
@@ -374,36 +373,32 @@ class entrypoint:
374
373
 
375
374
  async def handle_success(self, result: Any, inline_trace: bool):
376
375
  data = None
377
- trace = dict()
376
+ tree = None
378
377
 
379
378
  with suppress():
380
379
  data = self.patch_result(result)
381
380
 
382
381
  if inline_trace:
383
- trace = await self.fetch_inline_trace(inline_trace)
382
+ tree = await self.fetch_inline_trace(inline_trace)
384
383
 
385
384
  log.info(f"----------------------------------")
386
385
  log.info(f"Agenta SDK - exiting with success: 200")
387
386
  log.info(f"----------------------------------")
388
387
 
389
- return BaseResponse(data=data, trace=trace)
388
+ return BaseResponse(data=data, tree=tree)
390
389
 
391
390
  def handle_failure(self, error: Exception):
392
- log.error("--------------------------------------------------")
393
- log.error("Agenta SDK - handling application exception below:")
394
- log.error("--------------------------------------------------")
395
- log.error(format_exc().strip("\n"))
396
- 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("--------------------------------------------------")
397
396
 
398
397
  status_code = error.status_code if hasattr(error, "status_code") else 500
399
398
  message = str(error)
400
399
  stacktrace = format_exception(error, value=error, tb=error.__traceback__) # type: ignore
401
400
  detail = {"message": message, "stacktrace": stacktrace}
402
401
 
403
- log.error(f"----------------------------------")
404
- log.error(f"Agenta SDK - exiting with failure: {status_code}")
405
- log.error(f"----------------------------------")
406
-
407
402
  raise HTTPException(status_code=status_code, detail=detail)
408
403
 
409
404
  def patch_result(self, result: Any):
@@ -680,10 +675,7 @@ class entrypoint:
680
675
 
681
676
  loop = get_event_loop()
682
677
 
683
- with routing_context_manager(
684
- config=args_config_params,
685
- environment="terminal",
686
- ):
678
+ with routing_context_manager(config=args_config_params):
687
679
  result = loop.run_until_complete(
688
680
  self.execute_function(
689
681
  func,
@@ -692,30 +684,23 @@ class entrypoint:
692
684
  )
693
685
  )
694
686
 
695
- SHOW_DETAILS = True
696
- SHOW_DATA = False
697
- SHOW_TRACE = False
698
-
699
687
  if result.trace:
700
688
  log.info("\n========= Result =========\n")
701
689
 
702
690
  log.info(f"trace_id: {result.trace['trace_id']}")
703
- if SHOW_DETAILS:
704
- log.info(f"latency: {result.trace.get('latency')}")
705
- log.info(f"cost: {result.trace.get('cost')}")
706
- log.info(f"usage: {list(result.trace.get('usage', {}).values())}")
707
-
708
- if SHOW_DATA:
709
- log.info(" ")
710
- log.info(f"data:")
711
- log.info(dumps(result.data, indent=2))
712
-
713
- if SHOW_TRACE:
714
- log.info(" ")
715
- log.info(f"trace:")
716
- log.info(f"----------------")
717
- log.info(dumps(result.trace.get("spans", []), indent=2))
718
- 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("----------------")
719
704
 
720
705
  log.info("\n==========================\n")
721
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,