agenta 0.26.0a0__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.
- agenta/__init__.py +6 -7
- agenta/client/backend/client.py +22 -14
- agenta/client/backend/core/http_client.py +23 -15
- agenta/sdk/__init__.py +27 -6
- agenta/sdk/agenta_init.py +73 -26
- agenta/sdk/config_manager.py +2 -2
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/routing.py +25 -0
- agenta/sdk/context/tracing.py +3 -0
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +137 -124
- agenta/sdk/decorators/tracing.py +228 -76
- agenta/sdk/litellm/__init__.py +1 -0
- agenta/sdk/litellm/litellm.py +277 -0
- agenta/sdk/router.py +0 -7
- agenta/sdk/tracing/__init__.py +1 -0
- agenta/sdk/tracing/attributes.py +181 -0
- agenta/sdk/tracing/context.py +21 -0
- agenta/sdk/tracing/conventions.py +43 -0
- agenta/sdk/tracing/exporters.py +53 -0
- agenta/sdk/tracing/inline.py +1306 -0
- agenta/sdk/tracing/processors.py +65 -0
- agenta/sdk/tracing/spans.py +124 -0
- agenta/sdk/tracing/tracing.py +174 -0
- agenta/sdk/types.py +0 -12
- agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
- agenta/sdk/utils/debug.py +5 -5
- agenta/sdk/utils/exceptions.py +19 -0
- agenta/sdk/utils/globals.py +3 -5
- agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
- agenta/sdk/utils/singleton.py +13 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/METADATA +5 -1
- {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/RECORD +35 -25
- agenta/sdk/context.py +0 -41
- agenta/sdk/decorators/base.py +0 -10
- agenta/sdk/tracing/callbacks.py +0 -187
- agenta/sdk/tracing/llm_tracing.py +0 -617
- agenta/sdk/tracing/tasks_manager.py +0 -129
- agenta/sdk/tracing/tracing_context.py +0 -27
- {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/WHEEL +0 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/entry_points.txt +0 -0
agenta/sdk/decorators/tracing.py
CHANGED
|
@@ -1,111 +1,187 @@
|
|
|
1
|
-
# Stdlib Imports
|
|
2
1
|
import inspect
|
|
3
2
|
import traceback
|
|
4
3
|
from functools import wraps
|
|
5
|
-
from
|
|
4
|
+
from itertools import chain
|
|
5
|
+
from typing import Callable, Optional, Any, Dict, List
|
|
6
6
|
|
|
7
|
-
# Own Imports
|
|
8
7
|
import agenta as ag
|
|
9
|
-
from agenta.sdk.decorators.base import BaseDecorator
|
|
10
|
-
from agenta.sdk.tracing.logger import llm_logger as logging
|
|
11
|
-
from agenta.sdk.utils.debug import debug, DEBUG, SHIFT
|
|
12
8
|
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
15
11
|
|
|
12
|
+
from agenta.sdk.context.tracing import tracing_context
|
|
13
|
+
from agenta.sdk.tracing.conventions import parse_span_kind
|
|
16
14
|
|
|
17
|
-
class instrument(BaseDecorator):
|
|
18
|
-
"""Decorator class for monitoring llm apps functions.
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Example:
|
|
24
|
-
```python
|
|
25
|
-
import agenta as ag
|
|
26
|
-
|
|
27
|
-
prompt_config = {"system_prompt": ..., "temperature": 0.5, "max_tokens": ...}
|
|
28
|
-
|
|
29
|
-
@ag.instrument(spankind="llm")
|
|
30
|
-
async def litellm_openai_call(prompt:str) -> str:
|
|
31
|
-
return "do something"
|
|
32
|
-
|
|
33
|
-
@ag.instrument(config=prompt_config) # spankind for parent span defaults to workflow
|
|
34
|
-
async def generate(prompt: str):
|
|
35
|
-
return ...
|
|
36
|
-
```
|
|
37
|
-
"""
|
|
16
|
+
class instrument:
|
|
17
|
+
DEFAULT_KEY = "__default__"
|
|
38
18
|
|
|
39
19
|
def __init__(
|
|
40
20
|
self,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
ignore_inputs:
|
|
44
|
-
ignore_outputs:
|
|
21
|
+
kind: str = "task",
|
|
22
|
+
config: Optional[Dict[str, Any]] = None,
|
|
23
|
+
ignore_inputs: Optional[bool] = None,
|
|
24
|
+
ignore_outputs: Optional[bool] = None,
|
|
25
|
+
max_depth: Optional[int] = 2,
|
|
26
|
+
# DEPRECATED
|
|
27
|
+
spankind: Optional[str] = "TASK",
|
|
45
28
|
) -> None:
|
|
29
|
+
self.kind = spankind if spankind is not None else kind
|
|
46
30
|
self.config = config
|
|
47
|
-
self.spankind = spankind
|
|
48
31
|
self.ignore_inputs = ignore_inputs
|
|
49
32
|
self.ignore_outputs = ignore_outputs
|
|
33
|
+
self.max_depth = max_depth
|
|
50
34
|
|
|
51
35
|
def __call__(self, func: Callable[..., Any]):
|
|
52
36
|
is_coroutine_function = inspect.iscoroutinefunction(func)
|
|
53
37
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
38
|
+
def parse(*args, **kwargs) -> Dict[str, Any]:
|
|
39
|
+
inputs = {
|
|
40
|
+
key: value
|
|
41
|
+
for key, value in chain(
|
|
42
|
+
zip(inspect.getfullargspec(func).args, args),
|
|
43
|
+
kwargs.items(),
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return inputs
|
|
58
48
|
|
|
59
|
-
|
|
49
|
+
def redact(
|
|
50
|
+
io: Dict[str, Any], ignore: List[str] | bool = False
|
|
51
|
+
) -> Dict[str, Any]:
|
|
52
|
+
"""
|
|
53
|
+
Redact user-defined sensitive information from inputs and outputs as defined by the ignore list or boolean flag.
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
Example:
|
|
56
|
+
- ignore = ["password"] -> {"username": "admin", "password": "********"} -> {"username": "admin"}
|
|
57
|
+
- ignore = True -> {"username": "admin", "password": "********"} -> {}
|
|
58
|
+
- ignore = False -> {"username": "admin", "password": "********"} -> {"username": "admin", "password": "********"}
|
|
59
|
+
"""
|
|
60
|
+
io = {
|
|
61
|
+
key: value
|
|
62
|
+
for key, value in io.items()
|
|
65
63
|
if key
|
|
66
64
|
not in (
|
|
67
|
-
|
|
68
|
-
if isinstance(
|
|
69
|
-
else []
|
|
70
|
-
if blacklist is False
|
|
65
|
+
ignore
|
|
66
|
+
if isinstance(ignore, list)
|
|
71
67
|
else io.keys()
|
|
68
|
+
if ignore is True
|
|
69
|
+
else []
|
|
72
70
|
)
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
TRACE_DEFAULT_KEY = "__default__"
|
|
73
|
+
return io
|
|
77
74
|
|
|
78
|
-
|
|
75
|
+
def patch(result: Any) -> Dict[str, Any]:
|
|
76
|
+
"""
|
|
77
|
+
Patch the result to ensure that it is a dictionary, with a default key when necessary.
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
79
|
+
Example:
|
|
80
|
+
- result = "Hello, World!" -> {"__default__": "Hello, World!"}
|
|
81
|
+
- result = {"message": "Hello, World!", "cost": 0.0, "usage": {}} -> {"__default__": "Hello, World!"}
|
|
82
|
+
- result = {"message": "Hello, World!"} -> {"message": "Hello, World!"}
|
|
83
|
+
"""
|
|
84
|
+
outputs = (
|
|
85
|
+
{instrument.DEFAULT_KEY: result}
|
|
86
|
+
if not isinstance(result, dict)
|
|
87
|
+
else (
|
|
88
|
+
{instrument.DEFAULT_KEY: result["message"]}
|
|
89
|
+
if all(key in result for key in ["message", "cost", "usage"])
|
|
90
|
+
else result
|
|
91
|
+
)
|
|
92
|
+
)
|
|
94
93
|
|
|
95
94
|
return outputs
|
|
96
95
|
|
|
97
96
|
@wraps(func)
|
|
98
97
|
async def async_wrapper(*args, **kwargs):
|
|
99
98
|
async def wrapped_func(*args, **kwargs):
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
):
|
|
99
|
+
if not ag.tracing.get_current_span().is_recording():
|
|
100
|
+
self.kind = "workflow"
|
|
101
|
+
|
|
102
|
+
kind = parse_span_kind(self.kind)
|
|
103
|
+
|
|
104
|
+
with ag.tracer.start_as_current_span(func.__name__, kind=kind):
|
|
105
|
+
span = ag.tracing.get_current_span()
|
|
106
|
+
|
|
107
|
+
with suppress():
|
|
108
|
+
span.set_attributes(
|
|
109
|
+
attributes={"node": self.kind},
|
|
110
|
+
namespace="type",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if span.parent is None:
|
|
114
|
+
rctx = tracing_context.get()
|
|
115
|
+
|
|
116
|
+
span.set_attributes(
|
|
117
|
+
attributes={"configuration": rctx.get("config", {})},
|
|
118
|
+
namespace="meta",
|
|
119
|
+
)
|
|
120
|
+
span.set_attributes(
|
|
121
|
+
attributes={"environment": rctx.get("environment", {})},
|
|
122
|
+
namespace="meta",
|
|
123
|
+
)
|
|
124
|
+
span.set_attributes(
|
|
125
|
+
attributes={"version": rctx.get("version", {})},
|
|
126
|
+
namespace="meta",
|
|
127
|
+
)
|
|
128
|
+
span.set_attributes(
|
|
129
|
+
attributes={"variant": rctx.get("variant", {})},
|
|
130
|
+
namespace="meta",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
_inputs = redact(parse(*args, **kwargs), self.ignore_inputs)
|
|
134
|
+
span.set_attributes(
|
|
135
|
+
attributes={"inputs": _inputs},
|
|
136
|
+
namespace="data",
|
|
137
|
+
max_depth=self.max_depth,
|
|
138
|
+
)
|
|
139
|
+
|
|
106
140
|
result = await func(*args, **kwargs)
|
|
107
141
|
|
|
108
|
-
|
|
142
|
+
with suppress():
|
|
143
|
+
cost = None
|
|
144
|
+
usage = {}
|
|
145
|
+
|
|
146
|
+
if isinstance(result, dict):
|
|
147
|
+
cost = result.get("cost", None)
|
|
148
|
+
usage = result.get("usage", {})
|
|
149
|
+
|
|
150
|
+
span.set_attributes(
|
|
151
|
+
attributes={"total": cost},
|
|
152
|
+
namespace="metrics.unit.costs",
|
|
153
|
+
)
|
|
154
|
+
span.set_attributes(
|
|
155
|
+
attributes=(
|
|
156
|
+
{
|
|
157
|
+
"prompt": usage.get("prompt_tokens", None),
|
|
158
|
+
"completion": usage.get("completion_tokens", None),
|
|
159
|
+
"total": usage.get("total_tokens", None),
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
namespace="metrics.unit.tokens",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
_outputs = redact(patch(result), self.ignore_outputs)
|
|
166
|
+
span.set_attributes(
|
|
167
|
+
attributes={"outputs": _outputs},
|
|
168
|
+
namespace="data",
|
|
169
|
+
max_depth=self.max_depth,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
span.set_status("OK")
|
|
173
|
+
|
|
174
|
+
with suppress():
|
|
175
|
+
if hasattr(span, "parent") and span.parent is None:
|
|
176
|
+
tracing_context.set(
|
|
177
|
+
tracing_context.get()
|
|
178
|
+
| {
|
|
179
|
+
"root": {
|
|
180
|
+
"trace_id": span.get_span_context().trace_id,
|
|
181
|
+
"span_id": span.get_span_context().span_id,
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
)
|
|
109
185
|
|
|
110
186
|
return result
|
|
111
187
|
|
|
@@ -114,15 +190,91 @@ class instrument(BaseDecorator):
|
|
|
114
190
|
@wraps(func)
|
|
115
191
|
def sync_wrapper(*args, **kwargs):
|
|
116
192
|
def wrapped_func(*args, **kwargs):
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
):
|
|
193
|
+
if not ag.tracing.get_current_span().is_recording():
|
|
194
|
+
self.kind = "workflow"
|
|
195
|
+
|
|
196
|
+
kind = parse_span_kind(self.kind)
|
|
197
|
+
|
|
198
|
+
with ag.tracer.start_as_current_span(func.__name__, kind=kind):
|
|
199
|
+
span = ag.tracing.get_current_span()
|
|
200
|
+
|
|
201
|
+
with suppress():
|
|
202
|
+
span.set_attributes(
|
|
203
|
+
attributes={"node": self.kind},
|
|
204
|
+
namespace="type",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if span.parent is None:
|
|
208
|
+
rctx = tracing_context.get()
|
|
209
|
+
|
|
210
|
+
span.set_attributes(
|
|
211
|
+
attributes={"configuration": rctx.get("config", {})},
|
|
212
|
+
namespace="meta",
|
|
213
|
+
)
|
|
214
|
+
span.set_attributes(
|
|
215
|
+
attributes={"environment": rctx.get("environment", {})},
|
|
216
|
+
namespace="meta",
|
|
217
|
+
)
|
|
218
|
+
span.set_attributes(
|
|
219
|
+
attributes={"version": rctx.get("version", {})},
|
|
220
|
+
namespace="meta",
|
|
221
|
+
)
|
|
222
|
+
span.set_attributes(
|
|
223
|
+
attributes={"variant": rctx.get("variant", {})},
|
|
224
|
+
namespace="meta",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
_inputs = redact(parse(*args, **kwargs), self.ignore_inputs)
|
|
228
|
+
span.set_attributes(
|
|
229
|
+
attributes={"inputs": _inputs},
|
|
230
|
+
namespace="data",
|
|
231
|
+
max_depth=self.max_depth,
|
|
232
|
+
)
|
|
233
|
+
|
|
123
234
|
result = func(*args, **kwargs)
|
|
124
235
|
|
|
125
|
-
|
|
236
|
+
with suppress():
|
|
237
|
+
cost = None
|
|
238
|
+
usage = {}
|
|
239
|
+
if isinstance(result, dict):
|
|
240
|
+
cost = result.get("cost", None)
|
|
241
|
+
usage = result.get("usage", {})
|
|
242
|
+
|
|
243
|
+
span.set_attributes(
|
|
244
|
+
attributes={"total": cost},
|
|
245
|
+
namespace="metrics.unit.costs",
|
|
246
|
+
)
|
|
247
|
+
span.set_attributes(
|
|
248
|
+
attributes=(
|
|
249
|
+
{
|
|
250
|
+
"prompt": usage.get("prompt_tokens", None),
|
|
251
|
+
"completion": usage.get("completion_tokens", None),
|
|
252
|
+
"total": usage.get("total_tokens", None),
|
|
253
|
+
}
|
|
254
|
+
),
|
|
255
|
+
namespace="metrics.unit.tokens",
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
_outputs = redact(patch(result), self.ignore_outputs)
|
|
259
|
+
span.set_attributes(
|
|
260
|
+
attributes={"outputs": _outputs},
|
|
261
|
+
namespace="data",
|
|
262
|
+
max_depth=self.max_depth,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
span.set_status("OK")
|
|
266
|
+
|
|
267
|
+
with suppress():
|
|
268
|
+
if hasattr(span, "parent") and span.parent is None:
|
|
269
|
+
tracing_context.set(
|
|
270
|
+
tracing_context.get()
|
|
271
|
+
| {
|
|
272
|
+
"root": {
|
|
273
|
+
"trace_id": span.get_span_context().trace_id,
|
|
274
|
+
"span_id": span.get_span_context().span_id,
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
)
|
|
126
278
|
|
|
127
279
|
return result
|
|
128
280
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .litellm import litellm_handler
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import agenta as ag
|
|
2
|
+
|
|
3
|
+
from opentelemetry.trace import SpanKind
|
|
4
|
+
|
|
5
|
+
from agenta.sdk.tracing.spans import CustomSpan
|
|
6
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
7
|
+
from agenta.sdk.utils.logging import log
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def litellm_handler():
|
|
11
|
+
try:
|
|
12
|
+
from litellm.utils import ModelResponse
|
|
13
|
+
from litellm.integrations.custom_logger import (
|
|
14
|
+
CustomLogger as LitellmCustomLogger,
|
|
15
|
+
)
|
|
16
|
+
except ImportError as exc:
|
|
17
|
+
raise ImportError(
|
|
18
|
+
"The litellm SDK is not installed. Please install it using `pip install litellm`."
|
|
19
|
+
) from exc
|
|
20
|
+
except Exception as exc:
|
|
21
|
+
raise Exception(
|
|
22
|
+
"Unexpected error occurred when importing litellm: {}".format(exc)
|
|
23
|
+
) from exc
|
|
24
|
+
|
|
25
|
+
class LitellmHandler(LitellmCustomLogger):
|
|
26
|
+
"""This handler is responsible for instrumenting certain events when using litellm to call LLMs.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
LitellmCustomLogger (object): custom logger that allows us to override the events to capture.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
self.span = None
|
|
34
|
+
|
|
35
|
+
def log_pre_api_call(
|
|
36
|
+
self,
|
|
37
|
+
model,
|
|
38
|
+
messages,
|
|
39
|
+
kwargs,
|
|
40
|
+
):
|
|
41
|
+
type = (
|
|
42
|
+
"chat"
|
|
43
|
+
if kwargs.get("call_type") in ["completion", "acompletion"]
|
|
44
|
+
else "embedding"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
kind = SpanKind.CLIENT
|
|
48
|
+
|
|
49
|
+
self.span = CustomSpan(
|
|
50
|
+
ag.tracer.start_span(name=f"litellm_{kind.name.lower()}", kind=kind)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.span.set_attributes(
|
|
54
|
+
attributes={"node": type},
|
|
55
|
+
namespace="type",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if not self.span:
|
|
59
|
+
log.error("LiteLLM callback error: span not found.")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
log.info(f"log_pre_api_call({hex(self.span.context.span_id)[2:]})")
|
|
63
|
+
|
|
64
|
+
self.span.set_attributes(
|
|
65
|
+
attributes={"inputs": {"messages": kwargs["messages"]}},
|
|
66
|
+
namespace="data",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
self.span.set_attributes(
|
|
70
|
+
attributes={
|
|
71
|
+
"configuration": {
|
|
72
|
+
"model": kwargs.get("model"),
|
|
73
|
+
**kwargs.get("optional_params"),
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
namespace="meta",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def log_stream_event(
|
|
80
|
+
self,
|
|
81
|
+
kwargs,
|
|
82
|
+
response_obj,
|
|
83
|
+
start_time,
|
|
84
|
+
end_time,
|
|
85
|
+
):
|
|
86
|
+
if not self.span:
|
|
87
|
+
log.error("LiteLLM callback error: span not found.")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
# log.info(f"log_stream({hex(self.span.context.span_id)[2:]})")
|
|
91
|
+
|
|
92
|
+
self.span.set_attributes(
|
|
93
|
+
attributes={
|
|
94
|
+
"output": {"__default__": kwargs.get("complete_streaming_response")}
|
|
95
|
+
},
|
|
96
|
+
namespace="data",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
self.span.set_attributes(
|
|
100
|
+
attributes={"total": kwargs.get("response_cost")},
|
|
101
|
+
namespace="metrics.unit.costs",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self.span.set_attributes(
|
|
105
|
+
attributes=(
|
|
106
|
+
{
|
|
107
|
+
"prompt": response_obj.usage.prompt_tokens,
|
|
108
|
+
"completion": response_obj.usage.completion_tokens,
|
|
109
|
+
"total": response_obj.usage.total_tokens,
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
namespace="metrics.unit.tokens",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
self.span.set_status(status="OK")
|
|
116
|
+
|
|
117
|
+
self.span.end()
|
|
118
|
+
|
|
119
|
+
def log_success_event(
|
|
120
|
+
self,
|
|
121
|
+
kwargs,
|
|
122
|
+
response_obj,
|
|
123
|
+
start_time,
|
|
124
|
+
end_time,
|
|
125
|
+
):
|
|
126
|
+
if not self.span:
|
|
127
|
+
log.error("LiteLLM callback error: span not found.")
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
# log.info(f"log_success({hex(self.span.context.span_id)[2:]})")
|
|
131
|
+
|
|
132
|
+
self.span.set_attributes(
|
|
133
|
+
attributes={
|
|
134
|
+
"output": {"__default__": response_obj.choices[0].message.content}
|
|
135
|
+
},
|
|
136
|
+
namespace="data",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.span.set_attributes(
|
|
140
|
+
attributes={"total": kwargs.get("response_cost")},
|
|
141
|
+
namespace="metrics.unit.costs",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
self.span.set_attributes(
|
|
145
|
+
attributes=(
|
|
146
|
+
{
|
|
147
|
+
"prompt": response_obj.usage.prompt_tokens,
|
|
148
|
+
"completion": response_obj.usage.completion_tokens,
|
|
149
|
+
"total": response_obj.usage.total_tokens,
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
namespace="metrics.unit.tokens",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
self.span.set_status(status="OK")
|
|
156
|
+
|
|
157
|
+
self.span.end()
|
|
158
|
+
|
|
159
|
+
def log_failure_event(
|
|
160
|
+
self,
|
|
161
|
+
kwargs,
|
|
162
|
+
response_obj,
|
|
163
|
+
start_time,
|
|
164
|
+
end_time,
|
|
165
|
+
):
|
|
166
|
+
if not self.span:
|
|
167
|
+
log.error("LiteLLM callback error: span not found.")
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
# log.info(f"log_failure({hex(self.span.context.span_id)[2:]})")
|
|
171
|
+
|
|
172
|
+
self.span.record_exception(kwargs["exception"])
|
|
173
|
+
|
|
174
|
+
self.span.set_status(status="ERROR")
|
|
175
|
+
|
|
176
|
+
self.span.end()
|
|
177
|
+
|
|
178
|
+
async def async_log_stream_event(
|
|
179
|
+
self,
|
|
180
|
+
kwargs,
|
|
181
|
+
response_obj,
|
|
182
|
+
start_time,
|
|
183
|
+
end_time,
|
|
184
|
+
):
|
|
185
|
+
if not self.span:
|
|
186
|
+
log.error("LiteLLM callback error: span not found.")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
# log.info(f"async_log_stream({hex(self.span.context.span_id)[2:]})")
|
|
190
|
+
|
|
191
|
+
self.span.set_attributes(
|
|
192
|
+
attributes={
|
|
193
|
+
"output": {"__default__": kwargs.get("complete_streaming_response")}
|
|
194
|
+
},
|
|
195
|
+
namespace="data",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
self.span.set_attributes(
|
|
199
|
+
attributes={"total": kwargs.get("response_cost")},
|
|
200
|
+
namespace="metrics.unit.costs",
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
self.span.set_attributes(
|
|
204
|
+
attributes=(
|
|
205
|
+
{
|
|
206
|
+
"prompt": response_obj.usage.prompt_tokens,
|
|
207
|
+
"completion": response_obj.usage.completion_tokens,
|
|
208
|
+
"total": response_obj.usage.total_tokens,
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
namespace="metrics.unit.tokens",
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
self.span.set_status(status="OK")
|
|
215
|
+
|
|
216
|
+
self.span.end()
|
|
217
|
+
|
|
218
|
+
async def async_log_success_event(
|
|
219
|
+
self,
|
|
220
|
+
kwargs,
|
|
221
|
+
response_obj,
|
|
222
|
+
start_time,
|
|
223
|
+
end_time,
|
|
224
|
+
):
|
|
225
|
+
if not self.span:
|
|
226
|
+
log.error("LiteLLM callback error: span not found.")
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
log.info(f"async_log_success({hex(self.span.context.span_id)[2:]})")
|
|
230
|
+
|
|
231
|
+
self.span.set_attributes(
|
|
232
|
+
attributes={
|
|
233
|
+
"output": {"__default__": kwargs.get("complete_streaming_response")}
|
|
234
|
+
},
|
|
235
|
+
namespace="data",
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
self.span.set_attributes(
|
|
239
|
+
attributes={"total": kwargs.get("response_cost")},
|
|
240
|
+
namespace="metrics.unit.costs",
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
self.span.set_attributes(
|
|
244
|
+
attributes=(
|
|
245
|
+
{
|
|
246
|
+
"prompt": response_obj.usage.prompt_tokens,
|
|
247
|
+
"completion": response_obj.usage.completion_tokens,
|
|
248
|
+
"total": response_obj.usage.total_tokens,
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
namespace="metrics.unit.tokens",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
self.span.set_status(status="OK")
|
|
255
|
+
|
|
256
|
+
self.span.end()
|
|
257
|
+
|
|
258
|
+
async def async_log_failure_event(
|
|
259
|
+
self,
|
|
260
|
+
kwargs,
|
|
261
|
+
response_obj,
|
|
262
|
+
start_time,
|
|
263
|
+
end_time,
|
|
264
|
+
):
|
|
265
|
+
if not self.span:
|
|
266
|
+
log.error("LiteLLM callback error: span not found.")
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
# log.info(f"async_log_failure({hex(self.span.context.span_id)[2:]})")
|
|
270
|
+
|
|
271
|
+
self.span.record_exception(kwargs["exception"])
|
|
272
|
+
|
|
273
|
+
self.span.set_status(status="ERROR")
|
|
274
|
+
|
|
275
|
+
self.span.end()
|
|
276
|
+
|
|
277
|
+
return LitellmHandler()
|
agenta/sdk/router.py
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
|
-
from .context import get_contexts
|
|
3
2
|
|
|
4
3
|
router = APIRouter()
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
@router.get("/contexts/")
|
|
8
|
-
def get_all_contexts():
|
|
9
|
-
contexts = get_contexts()
|
|
10
|
-
return {"contexts": contexts}
|
|
11
|
-
|
|
12
|
-
|
|
13
6
|
@router.get("/health")
|
|
14
7
|
def health():
|
|
15
8
|
return {"status": "ok"}
|
agenta/sdk/tracing/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .tracing import Tracing, get_tracer
|