agenta 0.27.7__py3-none-any.whl → 0.27.7a0__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.
- agenta/cli/main.py +51 -4
- agenta/client/backend/__init__.py +0 -63
- agenta/client/backend/apps/client.py +58 -12
- agenta/client/backend/client.py +22 -22
- agenta/client/backend/core/http_client.py +7 -15
- agenta/client/backend/evaluations/client.py +11 -0
- agenta/client/backend/observability/client.py +4 -4
- agenta/client/backend/testsets/client.py +40 -8
- agenta/client/backend/types/__init__.py +0 -58
- agenta/client/backend/variants/client.py +16 -24
- agenta/sdk/__init__.py +0 -2
- agenta/sdk/agenta_init.py +9 -4
- agenta/sdk/decorators/routing.py +42 -24
- agenta/sdk/litellm/litellm.py +75 -30
- agenta/sdk/middleware/auth.py +6 -9
- agenta/sdk/tracing/context.py +6 -6
- agenta/sdk/tracing/inline.py +151 -48
- agenta/sdk/tracing/processors.py +3 -1
- agenta/sdk/tracing/tracing.py +5 -1
- agenta/sdk/types.py +2 -5
- agenta/sdk/utils/debug.py +68 -0
- agenta/sdk/utils/exceptions.py +9 -15
- agenta/sdk/utils/logging.py +1 -5
- {agenta-0.27.7.dist-info → agenta-0.27.7a0.dist-info}/METADATA +1 -1
- {agenta-0.27.7.dist-info → agenta-0.27.7a0.dist-info}/RECORD +27 -60
- agenta/client/backend/observability_v_1/__init__.py +0 -5
- agenta/client/backend/observability_v_1/client.py +0 -560
- agenta/client/backend/observability_v_1/types/__init__.py +0 -6
- agenta/client/backend/observability_v_1/types/format.py +0 -5
- agenta/client/backend/observability_v_1/types/query_traces_response.py +0 -11
- agenta/client/backend/types/agenta_node_dto.py +0 -48
- agenta/client/backend/types/agenta_node_dto_nodes_value.py +0 -6
- agenta/client/backend/types/agenta_nodes_response.py +0 -30
- agenta/client/backend/types/agenta_root_dto.py +0 -30
- agenta/client/backend/types/agenta_roots_response.py +0 -30
- agenta/client/backend/types/agenta_tree_dto.py +0 -30
- agenta/client/backend/types/agenta_trees_response.py +0 -30
- agenta/client/backend/types/collect_status_response.py +0 -22
- agenta/client/backend/types/exception_dto.py +0 -26
- agenta/client/backend/types/link_dto.py +0 -24
- agenta/client/backend/types/node_dto.py +0 -24
- agenta/client/backend/types/node_type.py +0 -19
- agenta/client/backend/types/o_tel_context_dto.py +0 -22
- agenta/client/backend/types/o_tel_event_dto.py +0 -23
- agenta/client/backend/types/o_tel_extra_dto.py +0 -26
- agenta/client/backend/types/o_tel_link_dto.py +0 -23
- agenta/client/backend/types/o_tel_span_dto.py +0 -37
- agenta/client/backend/types/o_tel_span_kind.py +0 -15
- agenta/client/backend/types/o_tel_spans_response.py +0 -24
- agenta/client/backend/types/o_tel_status_code.py +0 -8
- agenta/client/backend/types/parent_dto.py +0 -21
- agenta/client/backend/types/root_dto.py +0 -21
- agenta/client/backend/types/span_dto.py +0 -54
- agenta/client/backend/types/span_dto_nodes_value.py +0 -9
- agenta/client/backend/types/status_code.py +0 -5
- agenta/client/backend/types/status_dto.py +0 -23
- agenta/client/backend/types/time_dto.py +0 -23
- agenta/client/backend/types/tree_dto.py +0 -23
- agenta/client/backend/types/tree_type.py +0 -5
- {agenta-0.27.7.dist-info → agenta-0.27.7a0.dist-info}/WHEEL +0 -0
- {agenta-0.27.7.dist-info → agenta-0.27.7a0.dist-info}/entry_points.txt +0 -0
agenta/sdk/decorators/routing.py
CHANGED
|
@@ -143,7 +143,9 @@ class entrypoint:
|
|
|
143
143
|
_MIDDLEWARES = False
|
|
144
144
|
|
|
145
145
|
except: # pylint: disable=bare-except
|
|
146
|
-
log.
|
|
146
|
+
log.error("------------------------------------")
|
|
147
|
+
log.error("Agenta SDK - failed to secure route: %s", route_path)
|
|
148
|
+
log.error("------------------------------------")
|
|
147
149
|
### --- Update Middleware --- #
|
|
148
150
|
|
|
149
151
|
DEFAULT_PATH = "generate"
|
|
@@ -355,7 +357,9 @@ class entrypoint:
|
|
|
355
357
|
*args,
|
|
356
358
|
**func_params,
|
|
357
359
|
):
|
|
358
|
-
log.info("
|
|
360
|
+
log.info("---------------------------")
|
|
361
|
+
log.info(f"Agenta SDK - running route: {repr(self.route_path or '/')}")
|
|
362
|
+
log.info("---------------------------")
|
|
359
363
|
|
|
360
364
|
tracing_context.set(routing_context.get())
|
|
361
365
|
|
|
@@ -373,32 +377,36 @@ class entrypoint:
|
|
|
373
377
|
|
|
374
378
|
async def handle_success(self, result: Any, inline_trace: bool):
|
|
375
379
|
data = None
|
|
376
|
-
|
|
380
|
+
trace = dict()
|
|
377
381
|
|
|
378
382
|
with suppress():
|
|
379
383
|
data = self.patch_result(result)
|
|
380
384
|
|
|
381
385
|
if inline_trace:
|
|
382
|
-
|
|
386
|
+
trace = await self.fetch_inline_trace(inline_trace)
|
|
383
387
|
|
|
384
388
|
log.info(f"----------------------------------")
|
|
385
389
|
log.info(f"Agenta SDK - exiting with success: 200")
|
|
386
390
|
log.info(f"----------------------------------")
|
|
387
391
|
|
|
388
|
-
return BaseResponse(data=data,
|
|
392
|
+
return BaseResponse(data=data, trace=trace)
|
|
389
393
|
|
|
390
394
|
def handle_failure(self, error: Exception):
|
|
391
|
-
log.
|
|
392
|
-
log.
|
|
393
|
-
log.
|
|
394
|
-
log.
|
|
395
|
-
log.
|
|
395
|
+
log.error("--------------------------------------------------")
|
|
396
|
+
log.error("Agenta SDK - handling application exception below:")
|
|
397
|
+
log.error("--------------------------------------------------")
|
|
398
|
+
log.error(format_exc().strip("\n"))
|
|
399
|
+
log.error("--------------------------------------------------")
|
|
396
400
|
|
|
397
401
|
status_code = error.status_code if hasattr(error, "status_code") else 500
|
|
398
402
|
message = str(error)
|
|
399
403
|
stacktrace = format_exception(error, value=error, tb=error.__traceback__) # type: ignore
|
|
400
404
|
detail = {"message": message, "stacktrace": stacktrace}
|
|
401
405
|
|
|
406
|
+
log.error(f"----------------------------------")
|
|
407
|
+
log.error(f"Agenta SDK - exiting with failure: {status_code}")
|
|
408
|
+
log.error(f"----------------------------------")
|
|
409
|
+
|
|
402
410
|
raise HTTPException(status_code=status_code, detail=detail)
|
|
403
411
|
|
|
404
412
|
def patch_result(self, result: Any):
|
|
@@ -675,7 +683,10 @@ class entrypoint:
|
|
|
675
683
|
|
|
676
684
|
loop = get_event_loop()
|
|
677
685
|
|
|
678
|
-
with routing_context_manager(
|
|
686
|
+
with routing_context_manager(
|
|
687
|
+
config=args_config_params,
|
|
688
|
+
environment="terminal",
|
|
689
|
+
):
|
|
679
690
|
result = loop.run_until_complete(
|
|
680
691
|
self.execute_function(
|
|
681
692
|
func,
|
|
@@ -684,23 +695,30 @@ class entrypoint:
|
|
|
684
695
|
)
|
|
685
696
|
)
|
|
686
697
|
|
|
698
|
+
SHOW_DETAILS = True
|
|
699
|
+
SHOW_DATA = False
|
|
700
|
+
SHOW_TRACE = False
|
|
701
|
+
|
|
687
702
|
if result.trace:
|
|
688
703
|
log.info("\n========= Result =========\n")
|
|
689
704
|
|
|
690
705
|
log.info(f"trace_id: {result.trace['trace_id']}")
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
706
|
+
if SHOW_DETAILS:
|
|
707
|
+
log.info(f"latency: {result.trace.get('latency')}")
|
|
708
|
+
log.info(f"cost: {result.trace.get('cost')}")
|
|
709
|
+
log.info(f"usage: {list(result.trace.get('usage', {}).values())}")
|
|
710
|
+
|
|
711
|
+
if SHOW_DATA:
|
|
712
|
+
log.info(" ")
|
|
713
|
+
log.info(f"data:")
|
|
714
|
+
log.info(dumps(result.data, indent=2))
|
|
715
|
+
|
|
716
|
+
if SHOW_TRACE:
|
|
717
|
+
log.info(" ")
|
|
718
|
+
log.info(f"trace:")
|
|
719
|
+
log.info(f"----------------")
|
|
720
|
+
log.info(dumps(result.trace.get("spans", []), indent=2))
|
|
721
|
+
log.info(f"----------------")
|
|
704
722
|
|
|
705
723
|
log.info("\n==========================\n")
|
|
706
724
|
|
agenta/sdk/litellm/litellm.py
CHANGED
|
@@ -60,11 +60,7 @@ def litellm_handler():
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
if not self.span:
|
|
63
|
-
log.
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
if not self.span.is_recording():
|
|
67
|
-
log.error("Agenta SDK - litellm span not recording.")
|
|
63
|
+
log.error("LiteLLM callback error: span not found.")
|
|
68
64
|
return
|
|
69
65
|
|
|
70
66
|
self.span.set_attributes(
|
|
@@ -90,11 +86,43 @@ def litellm_handler():
|
|
|
90
86
|
end_time,
|
|
91
87
|
):
|
|
92
88
|
if not self.span:
|
|
93
|
-
log.
|
|
89
|
+
log.error("LiteLLM callback error: span not found.")
|
|
94
90
|
return
|
|
95
91
|
|
|
96
|
-
|
|
97
|
-
|
|
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()
|
|
98
126
|
|
|
99
127
|
def log_success_event(
|
|
100
128
|
self,
|
|
@@ -103,14 +131,8 @@ def litellm_handler():
|
|
|
103
131
|
start_time,
|
|
104
132
|
end_time,
|
|
105
133
|
):
|
|
106
|
-
if kwargs.get("stream"):
|
|
107
|
-
return
|
|
108
|
-
|
|
109
134
|
if not self.span:
|
|
110
|
-
log.
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
if not self.span.is_recording():
|
|
135
|
+
log.error("LiteLLM callback error: span not found.")
|
|
114
136
|
return
|
|
115
137
|
|
|
116
138
|
try:
|
|
@@ -156,10 +178,7 @@ def litellm_handler():
|
|
|
156
178
|
end_time,
|
|
157
179
|
):
|
|
158
180
|
if not self.span:
|
|
159
|
-
log.
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
if not self.span.is_recording():
|
|
181
|
+
log.error("LiteLLM callback error: span not found.")
|
|
163
182
|
return
|
|
164
183
|
|
|
165
184
|
self.span.record_exception(kwargs["exception"])
|
|
@@ -176,11 +195,43 @@ def litellm_handler():
|
|
|
176
195
|
end_time,
|
|
177
196
|
):
|
|
178
197
|
if not self.span:
|
|
179
|
-
log.
|
|
198
|
+
log.error("LiteLLM callback error: span not found.")
|
|
180
199
|
return
|
|
181
200
|
|
|
182
|
-
|
|
183
|
-
|
|
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()
|
|
184
235
|
|
|
185
236
|
async def async_log_success_event(
|
|
186
237
|
self,
|
|
@@ -190,10 +241,7 @@ def litellm_handler():
|
|
|
190
241
|
end_time,
|
|
191
242
|
):
|
|
192
243
|
if not self.span:
|
|
193
|
-
log.
|
|
194
|
-
return
|
|
195
|
-
|
|
196
|
-
if not self.span.is_recording():
|
|
244
|
+
log.error("LiteLLM callback error: span not found.")
|
|
197
245
|
return
|
|
198
246
|
|
|
199
247
|
try:
|
|
@@ -239,10 +287,7 @@ def litellm_handler():
|
|
|
239
287
|
end_time,
|
|
240
288
|
):
|
|
241
289
|
if not self.span:
|
|
242
|
-
log.
|
|
243
|
-
return
|
|
244
|
-
|
|
245
|
-
if not self.span.is_recording():
|
|
290
|
+
log.error("LiteLLM callback error: span not found.")
|
|
246
291
|
return
|
|
247
292
|
|
|
248
293
|
self.span.record_exception(kwargs["exception"])
|
agenta/sdk/middleware/auth.py
CHANGED
|
@@ -27,8 +27,6 @@ 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
|
-
|
|
32
30
|
AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED = str(
|
|
33
31
|
environ.get("AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED", False)
|
|
34
32
|
).lower() in ("true", "1", "t")
|
|
@@ -63,6 +61,7 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
|
|
|
63
61
|
self,
|
|
64
62
|
request: Request,
|
|
65
63
|
call_next: Callable,
|
|
64
|
+
project_id: Optional[UUID] = None,
|
|
66
65
|
):
|
|
67
66
|
if AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED:
|
|
68
67
|
return await call_next(request)
|
|
@@ -84,8 +83,6 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
|
|
|
84
83
|
"resource_id": self.resource_id,
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
project_id = request.query_params.get("project_id")
|
|
88
|
-
|
|
89
86
|
if project_id:
|
|
90
87
|
params["project_id"] = project_id
|
|
91
88
|
|
|
@@ -136,10 +133,10 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
|
|
|
136
133
|
return await call_next(request)
|
|
137
134
|
|
|
138
135
|
except: # pylint: disable=bare-except
|
|
139
|
-
log.
|
|
140
|
-
log.
|
|
141
|
-
log.
|
|
142
|
-
log.
|
|
143
|
-
log.
|
|
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("------------------------------------------------------")
|
|
144
141
|
|
|
145
142
|
return Deny()
|
agenta/sdk/tracing/context.py
CHANGED
|
@@ -14,11 +14,11 @@ def tracing_context_manager():
|
|
|
14
14
|
token = tracing_context.set(_tracing_context)
|
|
15
15
|
try:
|
|
16
16
|
yield
|
|
17
|
-
except
|
|
18
|
-
log.
|
|
19
|
-
log.
|
|
20
|
-
log.
|
|
21
|
-
log.
|
|
22
|
-
log.
|
|
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("----------------------------------------------")
|
|
23
23
|
finally:
|
|
24
24
|
tracing_context.reset(token)
|
agenta/sdk/tracing/inline.py
CHANGED
|
@@ -41,6 +41,7 @@ from uuid import UUID
|
|
|
41
41
|
class TimeDTO(BaseModel):
|
|
42
42
|
start: datetime
|
|
43
43
|
end: datetime
|
|
44
|
+
span: int
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
class StatusCode(Enum):
|
|
@@ -845,9 +846,12 @@ def parse_from_otel_span_dto(
|
|
|
845
846
|
else None
|
|
846
847
|
)
|
|
847
848
|
|
|
849
|
+
duration = (otel_span_dto.end_time - otel_span_dto.start_time).total_seconds()
|
|
850
|
+
|
|
848
851
|
time = TimeDTO(
|
|
849
852
|
start=otel_span_dto.start_time,
|
|
850
853
|
end=otel_span_dto.end_time,
|
|
854
|
+
span=round(duration * 1_000_000), # microseconds
|
|
851
855
|
)
|
|
852
856
|
|
|
853
857
|
status = StatusDTO(
|
|
@@ -859,13 +863,6 @@ def parse_from_otel_span_dto(
|
|
|
859
863
|
|
|
860
864
|
data, metrics, meta, tags, refs = _parse_from_attributes(otel_span_dto)
|
|
861
865
|
|
|
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
|
-
|
|
869
866
|
root_id = str(tree_id)
|
|
870
867
|
if refs is not None:
|
|
871
868
|
root_id = refs.get("scenario.id", root_id)
|
|
@@ -906,9 +903,9 @@ def parse_to_agenta_span_dto(
|
|
|
906
903
|
if span_dto.data:
|
|
907
904
|
span_dto.data = _unmarshal_attributes(span_dto.data)
|
|
908
905
|
|
|
909
|
-
if "outputs" in span_dto.data:
|
|
910
|
-
|
|
911
|
-
|
|
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__"]
|
|
912
909
|
|
|
913
910
|
# METRICS
|
|
914
911
|
if span_dto.metrics:
|
|
@@ -937,17 +934,6 @@ def parse_to_agenta_span_dto(
|
|
|
937
934
|
else:
|
|
938
935
|
parse_to_agenta_span_dto(v)
|
|
939
936
|
|
|
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
|
-
|
|
951
937
|
return span_dto
|
|
952
938
|
|
|
953
939
|
|
|
@@ -959,8 +945,6 @@ def parse_to_agenta_span_dto(
|
|
|
959
945
|
from litellm import cost_calculator
|
|
960
946
|
from opentelemetry.sdk.trace import ReadableSpan
|
|
961
947
|
|
|
962
|
-
from agenta.sdk.types import AgentaNodeDto, AgentaNodesResponse
|
|
963
|
-
|
|
964
948
|
|
|
965
949
|
def parse_inline_trace(
|
|
966
950
|
spans: Dict[str, ReadableSpan],
|
|
@@ -1008,19 +992,51 @@ def parse_inline_trace(
|
|
|
1008
992
|
### services.observability.service.query() ###
|
|
1009
993
|
##############################################
|
|
1010
994
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
)
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
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
|
+
|
|
1024
1040
|
return inline_trace
|
|
1025
1041
|
|
|
1026
1042
|
|
|
@@ -1104,6 +1120,98 @@ class LlmTokens(BaseModel):
|
|
|
1104
1120
|
total_tokens: Optional[int] = 0
|
|
1105
1121
|
|
|
1106
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
|
+
|
|
1107
1215
|
TYPES_WITH_COSTS = [
|
|
1108
1216
|
"embedding",
|
|
1109
1217
|
"query",
|
|
@@ -1121,15 +1229,13 @@ def calculate_costs(span_idx: Dict[str, SpanDTO]):
|
|
|
1121
1229
|
and span.meta
|
|
1122
1230
|
and span.metrics
|
|
1123
1231
|
):
|
|
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
|
-
|
|
1128
1232
|
try:
|
|
1129
1233
|
costs = cost_calculator.cost_per_token(
|
|
1130
|
-
model=model,
|
|
1131
|
-
prompt_tokens=
|
|
1132
|
-
completion_tokens=
|
|
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,
|
|
1133
1239
|
)
|
|
1134
1240
|
|
|
1135
1241
|
if not costs:
|
|
@@ -1142,8 +1248,5 @@ def calculate_costs(span_idx: Dict[str, SpanDTO]):
|
|
|
1142
1248
|
span.metrics["unit.costs.completion"] = completion_cost
|
|
1143
1249
|
span.metrics["unit.costs.total"] = total_cost
|
|
1144
1250
|
|
|
1145
|
-
except:
|
|
1146
|
-
|
|
1147
|
-
print(
|
|
1148
|
-
f"model={model}, prompt_tokens={prompt_tokens}, completion_tokens={completion_tokens}"
|
|
1149
|
-
)
|
|
1251
|
+
except:
|
|
1252
|
+
pass
|
agenta/sdk/tracing/processors.py
CHANGED
|
@@ -91,7 +91,9 @@ class TraceProcessor(BatchSpanProcessor):
|
|
|
91
91
|
ret = super().force_flush(timeout_millis)
|
|
92
92
|
|
|
93
93
|
if not ret:
|
|
94
|
-
log.
|
|
94
|
+
log.error("--------------------------------------------")
|
|
95
|
+
log.error("Agenta SDK - skipping export due to timeout.")
|
|
96
|
+
log.error("--------------------------------------------")
|
|
95
97
|
|
|
96
98
|
def is_ready(
|
|
97
99
|
self,
|
agenta/sdk/tracing/tracing.py
CHANGED
|
@@ -90,6 +90,7 @@ class Tracing(metaclass=Singleton):
|
|
|
90
90
|
self.otlp_url,
|
|
91
91
|
)
|
|
92
92
|
log.info("--------------------------------------------")
|
|
93
|
+
|
|
93
94
|
check(
|
|
94
95
|
self.otlp_url,
|
|
95
96
|
headers=self.headers,
|
|
@@ -105,10 +106,13 @@ class Tracing(metaclass=Singleton):
|
|
|
105
106
|
)
|
|
106
107
|
|
|
107
108
|
self.tracer_provider.add_span_processor(_otlp)
|
|
109
|
+
|
|
108
110
|
log.info("Success: traces will be exported.")
|
|
109
111
|
log.info("--------------------------------------------")
|
|
112
|
+
|
|
110
113
|
except: # pylint: disable=bare-except
|
|
111
|
-
log.warning("
|
|
114
|
+
log.warning("Failure: traces will not be exported.")
|
|
115
|
+
log.warning("--------------------------------------------")
|
|
112
116
|
|
|
113
117
|
# GLOBAL TRACER PROVIDER -- INSTRUMENTATION LIBRARIES
|
|
114
118
|
set_tracer_provider(self.tracer_provider)
|
agenta/sdk/types.py
CHANGED
|
@@ -4,9 +4,6 @@ from typing import Dict, List, Optional, Any, Union
|
|
|
4
4
|
|
|
5
5
|
from pydantic import ConfigDict, BaseModel, HttpUrl
|
|
6
6
|
|
|
7
|
-
from agenta.client.backend.types.agenta_node_dto import AgentaNodeDto
|
|
8
|
-
from agenta.client.backend.types.agenta_nodes_response import AgentaNodesResponse
|
|
9
|
-
|
|
10
7
|
|
|
11
8
|
@dataclass
|
|
12
9
|
class MultipleChoice:
|
|
@@ -26,9 +23,9 @@ class LLMTokenUsage(BaseModel):
|
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
class BaseResponse(BaseModel):
|
|
29
|
-
version: Optional[str] = "
|
|
26
|
+
version: Optional[str] = "2.0"
|
|
30
27
|
data: Optional[Union[str, Dict[str, Any]]] = None
|
|
31
|
-
|
|
28
|
+
trace: Optional[Dict[str, Any]] = None
|
|
32
29
|
|
|
33
30
|
|
|
34
31
|
class DictInput(dict):
|