agenta 0.27.0__py3-none-any.whl → 0.27.0a0__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 (68) hide show
  1. agenta/__init__.py +3 -23
  2. agenta/cli/helper.py +1 -5
  3. agenta/client/backend/__init__.py +0 -14
  4. agenta/client/backend/apps/client.py +20 -28
  5. agenta/client/backend/client.py +2 -25
  6. agenta/client/backend/containers/client.py +1 -5
  7. agenta/client/backend/core/__init__.py +1 -2
  8. agenta/client/backend/core/client_wrapper.py +6 -6
  9. agenta/client/backend/core/file.py +11 -33
  10. agenta/client/backend/core/http_client.py +18 -24
  11. agenta/client/backend/core/pydantic_utilities.py +29 -144
  12. agenta/client/backend/core/request_options.py +0 -3
  13. agenta/client/backend/core/serialization.py +42 -139
  14. agenta/client/backend/evaluations/client.py +2 -7
  15. agenta/client/backend/evaluators/client.py +1 -349
  16. agenta/client/backend/observability/client.py +2 -11
  17. agenta/client/backend/testsets/client.py +10 -10
  18. agenta/client/backend/types/__init__.py +0 -14
  19. agenta/client/backend/types/app.py +0 -1
  20. agenta/client/backend/types/app_variant_response.py +1 -3
  21. agenta/client/backend/types/create_span.py +2 -3
  22. agenta/client/backend/types/environment_output.py +0 -1
  23. agenta/client/backend/types/environment_output_extended.py +0 -1
  24. agenta/client/backend/types/evaluation.py +2 -1
  25. agenta/client/backend/types/evaluator.py +0 -2
  26. agenta/client/backend/types/evaluator_config.py +0 -1
  27. agenta/client/backend/types/human_evaluation.py +2 -1
  28. agenta/client/backend/types/llm_tokens.py +2 -2
  29. agenta/client/backend/types/span.py +0 -1
  30. agenta/client/backend/types/span_detail.py +1 -7
  31. agenta/client/backend/types/test_set_output_response.py +2 -5
  32. agenta/client/backend/types/trace_detail.py +1 -7
  33. agenta/client/backend/types/with_pagination.py +2 -4
  34. agenta/client/backend/variants/client.py +273 -1566
  35. agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
  36. agenta/sdk/__init__.py +5 -21
  37. agenta/sdk/agenta_init.py +29 -34
  38. agenta/sdk/config_manager.py +205 -0
  39. agenta/sdk/context/routing.py +5 -6
  40. agenta/sdk/decorators/routing.py +146 -158
  41. agenta/sdk/decorators/tracing.py +239 -206
  42. agenta/sdk/litellm/litellm.py +36 -47
  43. agenta/sdk/tracing/attributes.py +47 -7
  44. agenta/sdk/tracing/context.py +2 -5
  45. agenta/sdk/tracing/conventions.py +19 -25
  46. agenta/sdk/tracing/exporters.py +5 -17
  47. agenta/sdk/tracing/inline.py +146 -92
  48. agenta/sdk/tracing/processors.py +13 -65
  49. agenta/sdk/tracing/spans.py +4 -16
  50. agenta/sdk/tracing/tracing.py +65 -124
  51. agenta/sdk/types.py +2 -61
  52. agenta/sdk/utils/exceptions.py +5 -38
  53. {agenta-0.27.0.dist-info → agenta-0.27.0a0.dist-info}/METADATA +1 -1
  54. {agenta-0.27.0.dist-info → agenta-0.27.0a0.dist-info}/RECORD +56 -67
  55. agenta/client/backend/types/config_dto.py +0 -32
  56. agenta/client/backend/types/config_response_model.py +0 -32
  57. agenta/client/backend/types/evaluator_mapping_output_interface.py +0 -21
  58. agenta/client/backend/types/evaluator_output_interface.py +0 -21
  59. agenta/client/backend/types/lifecycle_dto.py +0 -24
  60. agenta/client/backend/types/reference_dto.py +0 -23
  61. agenta/client/backend/types/reference_request_model.py +0 -23
  62. agenta/sdk/managers/__init__.py +0 -6
  63. agenta/sdk/managers/config.py +0 -318
  64. agenta/sdk/managers/deployment.py +0 -45
  65. agenta/sdk/managers/shared.py +0 -639
  66. agenta/sdk/managers/variant.py +0 -182
  67. {agenta-0.27.0.dist-info → agenta-0.27.0a0.dist-info}/WHEEL +0 -0
  68. {agenta-0.27.0.dist-info → agenta-0.27.0a0.dist-info}/entry_points.txt +0 -0
@@ -93,19 +93,14 @@ def _marshal(
93
93
  return marshalled
94
94
 
95
95
 
96
- def _encode_key(
97
- namespace: Optional[str] = None,
98
- key: str = "",
99
- ) -> str:
96
+ def _encode_key(namespace: Optional[str] = None, key: str = "") -> str:
100
97
  if namespace is None:
101
98
  return key
102
99
 
103
100
  return f"ag.{namespace}.{key}"
104
101
 
105
102
 
106
- def _encode_value(
107
- value: Any,
108
- ) -> Optional[Attribute]:
103
+ def _encode_value(value: Any) -> Optional[Attribute]:
109
104
  if value is None:
110
105
  return None
111
106
 
@@ -139,3 +134,48 @@ def serialize(
139
134
  }
140
135
 
141
136
  return _attributes
137
+
138
+
139
+ """
140
+ def _decode_key(namespace: Optional[str] = None, key: str = "") -> str:
141
+ if namespace is None:
142
+ return key
143
+
144
+ return key.replace(f"ag.{namespace}.", "")
145
+ """
146
+
147
+ """
148
+ def _decode_value(value: Attribute) -> Any:
149
+ if isinstance(value, (int, float, bool, bytes)):
150
+ return value
151
+
152
+ if isinstance(value, str):
153
+ if value == "@ag.type=none:":
154
+ return None
155
+
156
+ if value.startswith("@ag.type=json:"):
157
+ encoded = value[len("@ag.type=json:") :]
158
+ value = loads(encoded)
159
+ return value
160
+
161
+ return value
162
+
163
+ return value
164
+ """
165
+
166
+ """
167
+ def deserialize(
168
+ *,
169
+ namespace: str,
170
+ attributes: Dict[str, Any],
171
+ max_depth: Optional[int] = None,
172
+ ) -> Dict[str, Any]:
173
+ if not isinstance(attributes, dict):
174
+ return {}
175
+
176
+ return {
177
+ _decode_key(namespace, key): _decode_value(value)
178
+ for key, value in attributes
179
+ if key != _decode_key(namespace, key)
180
+ }
181
+ """
@@ -15,10 +15,7 @@ def tracing_context_manager():
15
15
  try:
16
16
  yield
17
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("----------------------------------------------")
18
+ log.error(f"Error with tracing context: {_tracing_context}")
19
+ log.error(f"Exception: {format_exc()}")
23
20
  finally:
24
21
  tracing_context.reset(token)
@@ -1,31 +1,25 @@
1
- from enum import Enum
2
- from re import fullmatch
1
+ from typing import Literal
3
2
 
4
3
  from opentelemetry.trace import SpanKind
5
4
 
6
-
7
- class Reference(str, Enum):
8
- #
9
- VARIANT_ID = "variant.id"
10
- VARIANT_SLUG = "variant.slug"
11
- VARIANT_VERSION = "variant.version"
12
- #
13
- ENVIRONMENT_ID = "environment.id"
14
- ENVIRONMENT_SLUG = "environment.slug"
15
- ENVIRONMENT_VERSION = "environment.version"
16
- #
17
- APPLICATION_ID = "application.id"
18
- APPLICATION_SLUG = "application.slug"
19
- #
20
-
21
-
22
- _PATTERN = r"[A-Za-z0-9._-]+"
23
-
24
-
25
- def is_valid_attribute_key(
26
- string: str,
27
- ):
28
- return bool(fullmatch(_PATTERN, string))
5
+ Namespace = Literal[
6
+ "data.inputs",
7
+ "data.internals",
8
+ "data.outputs",
9
+ "metrics.scores",
10
+ "metrics.unit.costs",
11
+ "metrics.unit.tokens",
12
+ "meta.configuration",
13
+ "meta.version",
14
+ "tags",
15
+ "refs",
16
+ ]
17
+
18
+ Code = Literal[
19
+ "OK",
20
+ "UNSET",
21
+ "ERROR",
22
+ ]
29
23
 
30
24
 
31
25
  def parse_span_kind(type: str) -> SpanKind:
@@ -1,12 +1,14 @@
1
1
  from typing import Sequence, Dict, List
2
2
 
3
- from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
4
3
  from opentelemetry.sdk.trace.export import (
5
4
  ConsoleSpanExporter,
6
5
  SpanExporter,
7
6
  SpanExportResult,
8
7
  ReadableSpan,
9
8
  )
9
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
10
+ OTLPSpanExporter,
11
+ )
10
12
 
11
13
  from agenta.sdk.utils.exceptions import suppress
12
14
 
@@ -38,28 +40,14 @@ class InlineTraceExporter(SpanExporter):
38
40
  def force_flush(self, timeout_millis: int = 30000) -> bool:
39
41
  return True
40
42
 
41
- def is_ready(
42
- self,
43
- trace_id: int,
44
- ) -> bool:
45
- is_ready = trace_id in self._registry
46
-
47
- return is_ready
48
-
49
- def fetch(
50
- self,
51
- trace_id: int,
52
- ) -> List[ReadableSpan]:
43
+ def fetch(self, trace_id: int) -> List[ReadableSpan]:
53
44
  trace = self._registry.get(trace_id, [])
54
45
 
55
- if trace_id in self._registry:
56
- del self._registry[trace_id]
46
+ del self._registry[trace_id]
57
47
 
58
48
  return trace
59
49
 
60
50
 
61
- OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
62
-
63
51
  ConsoleExporter = ConsoleSpanExporter
64
52
  InlineExporter = InlineTraceExporter
65
53
  OTLPExporter = OTLPSpanExporter
@@ -11,11 +11,82 @@ from enum import Enum
11
11
  from collections import OrderedDict
12
12
 
13
13
 
14
- class ProjectScopeDTO(BaseModel):
14
+ NOF_CHARS = 8
15
+
16
+
17
+ def _p_id(id):
18
+ return repr(str(id)[:NOF_CHARS])
19
+
20
+
21
+ def _p_osa(o):
22
+ elements = []
23
+
24
+ for i in OrderedDict(sorted(o.items())).items():
25
+ if not i[0].startswith("_"):
26
+ if i[1].__class__.__module__ != "builtins":
27
+ if repr(i[1]).startswith("<"):
28
+ elements.append(f"{i[0]}: {i[1].name}")
29
+ elif repr(i[1]).startswith("UUID("):
30
+ elements.append(f"{i[0]}: {_p_id(i[1])}")
31
+ else:
32
+ elements.append(f"{i[0]}: {i[1].__str__()}")
33
+ else:
34
+ if isinstance(i[1], list):
35
+ elements.append(
36
+ f"{i[0]}: [" + ", ".join([el.__str__() for el in i[1]]) + "]"
37
+ )
38
+ elif isinstance(i[1], dict):
39
+ elements.append(f"{i[0]}: {{{_p_osa(i[1])}}}")
40
+ else:
41
+ if i[1] is not None:
42
+ if i[0] == "slug":
43
+ elements.append(f"{i[0]}: {repr(i[1][:8])}")
44
+ else:
45
+ elements.append(f"{i[0]}: {repr(i[1])}")
46
+
47
+ return ", ".join(elements)
48
+
49
+
50
+ def _p_ora(o, open="{", close="}", sep=": ", foo=repr):
51
+ if o.__class__.__module__ != "builtins":
52
+ if o.__class__.__name__ == "UUID":
53
+ return repr(o)
54
+ if isinstance(o, Enum):
55
+ return o
56
+ if isinstance(o, datetime):
57
+ return o.isoformat()
58
+ return f"{o.__class__.__name__}({_p_ora(o.__dict__, open='', close='', sep='=', foo=lambda x : x)})"
59
+ elif isinstance(o, list):
60
+ return f"[{', '.join([repr(el) for el in o])}]"
61
+ elif isinstance(o, dict):
62
+ o = OrderedDict(sorted(o.items()))
63
+ return f"{open}{', '.join([f'{foo(elk)}{sep}{_p_ora(elv)}' for elk, elv in o.items()])}{close}"
64
+ else:
65
+ if o is not None:
66
+ return repr(o)
67
+
68
+
69
+ def _str(o):
70
+ return f"{{{_p_osa(o.__dict__)}}}"
71
+
72
+
73
+ def _repr(o):
74
+ return _p_ora(o)
75
+
76
+
77
+ class DisplayBase(BaseModel):
78
+ def __str__(self):
79
+ return _str(self)
80
+
81
+ def __repr__(self):
82
+ return _repr(self)
83
+
84
+
85
+ class ProjectScopeDTO(DisplayBase):
15
86
  project_id: UUID
16
87
 
17
88
 
18
- class LifecycleDTO(BaseModel):
89
+ class LifecycleDTO(DisplayBase):
19
90
  created_at: datetime
20
91
  updated_at: Optional[datetime] = None
21
92
 
@@ -31,14 +102,14 @@ class LifecycleDTO(BaseModel):
31
102
  ### services.observability.dtos ###
32
103
  ### --------------------------- ###
33
104
 
34
- from typing import List, Dict, Any, Union, Optional
105
+ from typing import List, Dict, Any, Union, Optional, Sequence
35
106
 
36
107
  from enum import Enum
37
108
  from datetime import datetime
38
109
  from uuid import UUID
39
110
 
40
111
 
41
- class TimeDTO(BaseModel):
112
+ class TimeDTO(DisplayBase):
42
113
  start: datetime
43
114
  end: datetime
44
115
  span: int
@@ -50,7 +121,7 @@ class StatusCode(Enum):
50
121
  ERROR = "ERROR"
51
122
 
52
123
 
53
- class StatusDTO(BaseModel):
124
+ class StatusDTO(DisplayBase):
54
125
  code: StatusCode
55
126
  message: Optional[str] = None
56
127
  stacktrace: Optional[str] = None
@@ -60,6 +131,14 @@ AttributeValueType = Any
60
131
  Attributes = Dict[str, AttributeValueType]
61
132
 
62
133
 
134
+ class AttributesDTO(DisplayBase):
135
+ data: Optional[Attributes] = None
136
+ metrics: Optional[Attributes] = None
137
+ meta: Optional[Attributes] = None
138
+ tags: Optional[Attributes] = None
139
+ semconv: Optional[Attributes] = None
140
+
141
+
63
142
  class TreeType(Enum):
64
143
  # --- VARIANTS --- #
65
144
  INVOCATION = "invocation"
@@ -84,16 +163,16 @@ class NodeType(Enum):
84
163
  # --- VARIANTS --- #
85
164
 
86
165
 
87
- class RootDTO(BaseModel):
166
+ class RootDTO(DisplayBase):
88
167
  id: UUID
89
168
 
90
169
 
91
- class TreeDTO(BaseModel):
170
+ class TreeDTO(DisplayBase):
92
171
  id: UUID
93
172
  type: Optional[TreeType] = None
94
173
 
95
174
 
96
- class NodeDTO(BaseModel):
175
+ class NodeDTO(DisplayBase):
97
176
  id: UUID
98
177
  type: Optional[NodeType] = None
99
178
  name: str
@@ -106,13 +185,13 @@ Tags = Dict[str, str]
106
185
  Refs = Dict[str, str]
107
186
 
108
187
 
109
- class LinkDTO(BaseModel):
188
+ class LinkDTO(DisplayBase):
110
189
  type: str
111
190
  id: UUID
112
191
  tree_id: Optional[UUID] = None
113
192
 
114
193
 
115
- class ParentDTO(BaseModel):
194
+ class ParentDTO(DisplayBase):
116
195
  id: UUID
117
196
 
118
197
 
@@ -134,25 +213,25 @@ class OTelStatusCode(Enum):
134
213
  STATUS_CODE_UNSET = "STATUS_CODE_UNSET"
135
214
 
136
215
 
137
- class OTelContextDTO(BaseModel):
216
+ class OTelContextDTO(DisplayBase):
138
217
  trace_id: str
139
218
  span_id: str
140
219
 
141
220
 
142
- class OTelEventDTO(BaseModel):
221
+ class OTelEventDTO(DisplayBase):
143
222
  name: str
144
223
  timestamp: datetime
145
224
 
146
225
  attributes: Optional[Attributes] = None
147
226
 
148
227
 
149
- class OTelLinkDTO(BaseModel):
228
+ class OTelLinkDTO(DisplayBase):
150
229
  context: OTelContextDTO
151
230
 
152
231
  attributes: Optional[Attributes] = None
153
232
 
154
233
 
155
- class OTelExtraDTO(BaseModel):
234
+ class OTelExtraDTO(DisplayBase):
156
235
  kind: Optional[str] = None
157
236
 
158
237
  attributes: Optional[Attributes] = None
@@ -160,10 +239,10 @@ class OTelExtraDTO(BaseModel):
160
239
  links: Optional[List[OTelLinkDTO]] = None
161
240
 
162
241
 
163
- class SpanDTO(BaseModel):
164
- scope: Optional[ProjectScopeDTO] = None
242
+ class SpanDTO(DisplayBase):
243
+ scope: ProjectScopeDTO
165
244
 
166
- lifecycle: Optional[LifecycleDTO] = None
245
+ lifecycle: LifecycleDTO
167
246
 
168
247
  root: RootDTO
169
248
  tree: TreeDTO
@@ -187,7 +266,30 @@ class SpanDTO(BaseModel):
187
266
  nodes: Optional[Dict[str, Union["SpanDTO", List["SpanDTO"]]]] = None
188
267
 
189
268
 
190
- class OTelSpanDTO(BaseModel):
269
+ class SpanCreateDTO(DisplayBase):
270
+ scope: ProjectScopeDTO
271
+
272
+ root: RootDTO
273
+ tree: TreeDTO
274
+ node: NodeDTO
275
+
276
+ parent: Optional[ParentDTO] = None
277
+
278
+ time: TimeDTO
279
+ status: StatusDTO
280
+
281
+ data: Optional[Data] = None
282
+ metrics: Optional[Metrics] = None
283
+ meta: Optional[Metadata] = None
284
+ tags: Optional[Tags] = None
285
+ refs: Optional[Refs] = None
286
+
287
+ links: Optional[List[LinkDTO]] = None
288
+
289
+ otel: Optional[OTelExtraDTO] = None
290
+
291
+
292
+ class OTelSpanDTO(DisplayBase):
191
293
  context: OTelContextDTO
192
294
 
193
295
  name: str
@@ -219,20 +321,20 @@ from typing import List, Dict, OrderedDict
219
321
 
220
322
 
221
323
  def parse_span_dtos_to_span_idx(
222
- span_dtos: List[SpanDTO],
223
- ) -> Dict[str, SpanDTO]:
324
+ span_dtos: List[SpanCreateDTO],
325
+ ) -> Dict[str, SpanCreateDTO]:
224
326
  span_idx = {span_dto.node.id: span_dto for span_dto in span_dtos}
225
327
 
226
328
  return span_idx
227
329
 
228
330
 
229
331
  def parse_span_idx_to_span_id_tree(
230
- span_idx: Dict[str, SpanDTO],
332
+ span_idx: Dict[str, SpanCreateDTO],
231
333
  ) -> OrderedDict:
232
334
  span_id_tree = OrderedDict()
233
335
  index = {}
234
336
 
235
- def push(span_dto: SpanDTO) -> None:
337
+ def push(span_dto: SpanCreateDTO) -> None:
236
338
  if span_dto.parent is None:
237
339
  span_id_tree[span_dto.node.id] = OrderedDict()
238
340
  index[span_dto.node.id] = span_id_tree[span_dto.node.id]
@@ -248,15 +350,15 @@ def parse_span_idx_to_span_id_tree(
248
350
 
249
351
  def cumulate_costs(
250
352
  spans_id_tree: OrderedDict,
251
- spans_idx: Dict[str, SpanDTO],
353
+ spans_idx: Dict[str, SpanCreateDTO],
252
354
  ) -> None:
253
- def _get_unit(span: SpanDTO):
355
+ def _get_unit(span: SpanCreateDTO):
254
356
  if span.metrics is not None:
255
357
  return span.metrics.get("unit.costs.total", 0.0)
256
358
 
257
359
  return 0.0
258
360
 
259
- def _get_acc(span: SpanDTO):
361
+ def _get_acc(span: SpanCreateDTO):
260
362
  if span.metrics is not None:
261
363
  return span.metrics.get("acc.costs.total", 0.0)
262
364
 
@@ -265,7 +367,7 @@ def cumulate_costs(
265
367
  def _acc(a: float, b: float):
266
368
  return a + b
267
369
 
268
- def _set(span: SpanDTO, cost: float):
370
+ def _set(span: SpanCreateDTO, cost: float):
269
371
  if span.metrics is None:
270
372
  span.metrics = {}
271
373
 
@@ -279,7 +381,7 @@ def cumulate_tokens(
279
381
  spans_id_tree: OrderedDict,
280
382
  spans_idx: Dict[str, dict],
281
383
  ) -> None:
282
- def _get_unit(span: SpanDTO):
384
+ def _get_unit(span: SpanCreateDTO):
283
385
  _tokens = {
284
386
  "prompt": 0.0,
285
387
  "completion": 0.0,
@@ -295,7 +397,7 @@ def cumulate_tokens(
295
397
 
296
398
  return _tokens
297
399
 
298
- def _get_acc(span: SpanDTO):
400
+ def _get_acc(span: SpanCreateDTO):
299
401
  _tokens = {
300
402
  "prompt": 0.0,
301
403
  "completion": 0.0,
@@ -318,7 +420,7 @@ def cumulate_tokens(
318
420
  "total": a.get("total", 0.0) + b.get("total", 0.0),
319
421
  }
320
422
 
321
- def _set(span: SpanDTO, tokens: dict):
423
+ def _set(span: SpanCreateDTO, tokens: dict):
322
424
  if span.metrics is None:
323
425
  span.metrics = {}
324
426
 
@@ -340,7 +442,7 @@ def cumulate_tokens(
340
442
 
341
443
  def _cumulate_tree_dfs(
342
444
  spans_id_tree: OrderedDict,
343
- spans_idx: Dict[str, SpanDTO],
445
+ spans_idx: Dict[str, SpanCreateDTO],
344
446
  get_unit_metric,
345
447
  get_acc_metric,
346
448
  accumulate_metric,
@@ -412,12 +514,9 @@ def _connect_tree_dfs(
412
514
  ### apis.fastapi.observability.opentelemetry.semconv ###
413
515
  ### ------------------------------------------------ ###
414
516
 
415
- from json import loads
416
-
417
517
  VERSION = "0.4.1"
418
518
 
419
519
  V_0_4_1_ATTRIBUTES_EXACT = [
420
- # OPENLLMETRY
421
520
  ("gen_ai.system", "ag.meta.system"),
422
521
  ("gen_ai.request.base_url", "ag.meta.request.base_url"),
423
522
  ("gen_ai.request.endpoint", "ag.meta.request.endpoint"),
@@ -442,35 +541,12 @@ V_0_4_1_ATTRIBUTES_EXACT = [
442
541
  ("db.vector.query.top_k", "ag.meta.request.top_k"),
443
542
  ("pinecone.query.top_k", "ag.meta.request.top_k"),
444
543
  ("traceloop.span.kind", "ag.type.node"),
445
- ("traceloop.entity.name", "ag.node.name"),
446
- # OPENINFERENCE
447
- ("output.value", "ag.data.outputs"),
448
- ("input.value", "ag.data.inputs"),
449
- ("embedding.model_name", "ag.meta.request.model"),
450
- ("llm.invocation_parameters", "ag.meta.request"),
451
- ("llm.model_name", "ag.meta.request.model"),
452
- ("llm.provider", "ag.meta.provider"),
453
- ("llm.system", "ag.meta.system"),
454
544
  ]
455
545
  V_0_4_1_ATTRIBUTES_PREFIX = [
456
- # OPENLLMETRY
457
546
  ("gen_ai.prompt", "ag.data.inputs.prompt"),
458
547
  ("gen_ai.completion", "ag.data.outputs.completion"),
459
- ("llm.request.functions", "ag.data.inputs.functions"),
460
- ("llm.request.tools", "ag.data.inputs.tools"),
461
- # OPENINFERENCE
462
- ("llm.token_count", "ag.metrics.unit.tokens"),
463
- ("llm.input_messages", "ag.data.inputs.prompt"),
464
- ("llm.output_messages", "ag.data.outputs.completion"),
465
548
  ]
466
549
 
467
- V_0_4_1_ATTRIBUTES_DYNAMIC = [
468
- # OPENLLMETRY
469
- ("traceloop.entity.input", lambda x: ("ag.data.inputs", loads(x).get("inputs"))),
470
- ("traceloop.entity.output", lambda x: ("ag.data.outputs", loads(x).get("outputs"))),
471
- ]
472
-
473
-
474
550
  V_0_4_1_MAPS = {
475
551
  "attributes": {
476
552
  "exact": {
@@ -481,9 +557,6 @@ V_0_4_1_MAPS = {
481
557
  "from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
482
558
  "to": {agenta: otel for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
483
559
  },
484
- "dynamic": {
485
- "from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_DYNAMIC[::-1]}
486
- },
487
560
  },
488
561
  }
489
562
  V_0_4_1_KEYS = {
@@ -496,9 +569,6 @@ V_0_4_1_KEYS = {
496
569
  "from": list(V_0_4_1_MAPS["attributes"]["prefix"]["from"].keys()),
497
570
  "to": list(V_0_4_1_MAPS["attributes"]["prefix"]["to"].keys()),
498
571
  },
499
- "dynamic": {
500
- "from": list(V_0_4_1_MAPS["attributes"]["dynamic"]["from"].keys()),
501
- },
502
572
  },
503
573
  }
504
574
 
@@ -512,7 +582,6 @@ KEYS = {
512
582
 
513
583
  CODEX = {"maps": MAPS[VERSION], "keys": KEYS[VERSION]}
514
584
 
515
-
516
585
  ### ------------------------------------------------ ###
517
586
  ### apis.fastapi.observability.opentelemetry.semconv ###
518
587
  ########################################################
@@ -686,18 +755,6 @@ def _parse_from_semconv(
686
755
 
687
756
  del attributes[old_key]
688
757
 
689
- for dynamic_key in CODEX["keys"]["attributes"]["dynamic"]["from"]:
690
- if old_key == dynamic_key:
691
- try:
692
- new_key, new_value = CODEX["maps"]["attributes"]["dynamic"][
693
- "from"
694
- ][dynamic_key](value)
695
-
696
- attributes[new_key] = new_value
697
-
698
- except: # pylint: disable=bare-except
699
- pass
700
-
701
758
 
702
759
  def _parse_from_links(
703
760
  otel_span_dto: OTelSpanDTO,
@@ -800,8 +857,11 @@ def _parse_from_attributes(
800
857
 
801
858
 
802
859
  def parse_from_otel_span_dto(
860
+ project_id: str,
803
861
  otel_span_dto: OTelSpanDTO,
804
862
  ) -> SpanDTO:
863
+ scope = ProjectScopeDTO(project_id=UUID(project_id))
864
+
805
865
  lifecyle = LifecycleDTO(
806
866
  created_at=datetime.now(),
807
867
  )
@@ -821,15 +881,11 @@ def parse_from_otel_span_dto(
821
881
 
822
882
  node_id = UUID(tree_id.hex[16:] + otel_span_dto.context.span_id[2:])
823
883
 
824
- node_type = NodeType.TASK
825
- try:
826
- node_type = NodeType(types.get("node", "").lower())
827
- except: # pylint: disable=bare-except
828
- pass
884
+ node_type: str = types.get("node")
829
885
 
830
886
  node = NodeDTO(
831
887
  id=node_id,
832
- type=node_type,
888
+ type=node_type.lower() if node_type else None,
833
889
  name=otel_span_dto.name,
834
890
  )
835
891
 
@@ -877,6 +933,7 @@ def parse_from_otel_span_dto(
877
933
  )
878
934
 
879
935
  span_dto = SpanDTO(
936
+ scope=scope,
880
937
  lifecycle=lifecyle,
881
938
  root=root,
882
939
  tree=tree,
@@ -947,6 +1004,7 @@ from opentelemetry.sdk.trace import ReadableSpan
947
1004
 
948
1005
 
949
1006
  def parse_inline_trace(
1007
+ project_id: str,
950
1008
  spans: Dict[str, ReadableSpan],
951
1009
  ):
952
1010
  otel_span_dtos = _parse_readable_spans(spans)
@@ -955,7 +1013,8 @@ def parse_inline_trace(
955
1013
  ### apis.fastapi.observability.api.otlp_collect_traces() ###
956
1014
  ### ---------------------------------------------------- ###
957
1015
  span_dtos = [
958
- parse_from_otel_span_dto(otel_span_dto) for otel_span_dto in otel_span_dtos
1016
+ parse_from_otel_span_dto(project_id, otel_span_dto)
1017
+ for otel_span_dto in otel_span_dtos
959
1018
  ]
960
1019
  ### ---------------------------------------------------- ###
961
1020
  ### apis.fastapi.observability.api.otlp_collect_traces() ###
@@ -973,7 +1032,7 @@ def parse_inline_trace(
973
1032
  ###############################################
974
1033
  ### services.observability.service.ingest() ###
975
1034
  ### --------------------------------------- ###
976
- calculate_costs(span_idx)
1035
+ calculate_cost(span_idx)
977
1036
  cumulate_costs(span_id_tree, span_idx)
978
1037
  cumulate_tokens(span_id_tree, span_idx)
979
1038
  ### --------------------------------------- ###
@@ -1195,7 +1254,7 @@ def _parse_to_legacy_span(span: SpanDTO) -> CreateSpan:
1195
1254
  ),
1196
1255
  #
1197
1256
  app_id=(
1198
- span.refs.get("application", {}).get("id", "missing-app-id")
1257
+ span.refs.get("application_id", "missing-app-id")
1199
1258
  if span.refs
1200
1259
  else "missing-app-id"
1201
1260
  ),
@@ -1212,7 +1271,7 @@ def _parse_to_legacy_span(span: SpanDTO) -> CreateSpan:
1212
1271
  return legacy_span
1213
1272
 
1214
1273
 
1215
- TYPES_WITH_COSTS = [
1274
+ PAYING_TYPES = [
1216
1275
  "embedding",
1217
1276
  "query",
1218
1277
  "completion",
@@ -1221,14 +1280,9 @@ TYPES_WITH_COSTS = [
1221
1280
  ]
1222
1281
 
1223
1282
 
1224
- def calculate_costs(span_idx: Dict[str, SpanDTO]):
1283
+ def calculate_cost(span_idx: Dict[str, SpanCreateDTO]):
1225
1284
  for span in span_idx.values():
1226
- if (
1227
- span.node.type
1228
- and span.node.type.name.lower() in TYPES_WITH_COSTS
1229
- and span.meta
1230
- and span.metrics
1231
- ):
1285
+ if span.node.type.name.lower() in PAYING_TYPES and span.meta and span.metrics:
1232
1286
  try:
1233
1287
  costs = cost_calculator.cost_per_token(
1234
1288
  model=span.meta.get("response.model"),