agenta 0.25.4a2__py3-none-any.whl → 0.25.4a4__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 +7 -6
- agenta/client/backend/client.py +14 -22
- agenta/client/backend/core/http_client.py +15 -23
- agenta/client/backend/core/pydantic_utilities.py +0 -2
- agenta/sdk/__init__.py +6 -27
- agenta/sdk/agenta_init.py +26 -73
- agenta/sdk/config_manager.py +2 -2
- agenta/sdk/context.py +41 -0
- agenta/sdk/decorators/base.py +10 -0
- agenta/sdk/decorators/{routing.py → llm_entrypoint.py} +124 -137
- agenta/sdk/decorators/tracing.py +79 -247
- agenta/sdk/router.py +7 -0
- agenta/sdk/tracing/__init__.py +0 -1
- agenta/sdk/tracing/callbacks.py +187 -0
- agenta/sdk/tracing/llm_tracing.py +617 -0
- agenta/sdk/{utils/logging.py → tracing/logger.py} +5 -3
- agenta/sdk/tracing/tasks_manager.py +129 -0
- agenta/sdk/tracing/tracing_context.py +27 -0
- agenta/sdk/types.py +12 -0
- agenta/sdk/utils/debug.py +5 -5
- agenta/sdk/utils/globals.py +5 -3
- agenta/sdk/utils/{costs.py → helper/openai_cost.py} +0 -3
- {agenta-0.25.4a2.dist-info → agenta-0.25.4a4.dist-info}/METADATA +1 -5
- {agenta-0.25.4a2.dist-info → agenta-0.25.4a4.dist-info}/RECORD +26 -36
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/routing.py +0 -25
- agenta/sdk/context/tracing.py +0 -3
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/litellm/__init__.py +0 -1
- agenta/sdk/litellm/litellm.py +0 -277
- agenta/sdk/tracing/attributes.py +0 -181
- agenta/sdk/tracing/context.py +0 -21
- agenta/sdk/tracing/conventions.py +0 -43
- agenta/sdk/tracing/exporters.py +0 -53
- agenta/sdk/tracing/inline.py +0 -1307
- agenta/sdk/tracing/processors.py +0 -65
- agenta/sdk/tracing/spans.py +0 -124
- agenta/sdk/tracing/tracing.py +0 -174
- agenta/sdk/utils/exceptions.py +0 -19
- agenta/sdk/utils/singleton.py +0 -13
- {agenta-0.25.4a2.dist-info → agenta-0.25.4a4.dist-info}/WHEEL +0 -0
- {agenta-0.25.4a2.dist-info → agenta-0.25.4a4.dist-info}/entry_points.txt +0 -0
agenta/sdk/decorators/tracing.py
CHANGED
|
@@ -1,196 +1,111 @@
|
|
|
1
|
+
# Stdlib Imports
|
|
1
2
|
import inspect
|
|
2
3
|
import traceback
|
|
3
4
|
from functools import wraps
|
|
4
|
-
from
|
|
5
|
-
from typing import Callable, Optional, Any, Dict, List
|
|
5
|
+
from typing import Any, Callable, Optional, List, Union
|
|
6
6
|
|
|
7
|
+
# Own Imports
|
|
7
8
|
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
|
|
8
12
|
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
logging.setLevel("DEBUG")
|
|
11
15
|
|
|
12
|
-
from agenta.sdk.context.tracing import tracing_context
|
|
13
|
-
from agenta.sdk.tracing.conventions import parse_span_kind
|
|
14
16
|
|
|
17
|
+
class instrument(BaseDecorator):
|
|
18
|
+
"""Decorator class for monitoring llm apps functions.
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
Args:
|
|
21
|
+
BaseDecorator (object): base decorator class
|
|
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
|
+
"""
|
|
18
38
|
|
|
19
39
|
def __init__(
|
|
20
40
|
self,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ignore_inputs:
|
|
24
|
-
ignore_outputs:
|
|
25
|
-
max_depth: Optional[int] = 2,
|
|
26
|
-
# DEPRECATED
|
|
27
|
-
spankind: Optional[str] = "TASK",
|
|
41
|
+
config: Optional[dict] = None,
|
|
42
|
+
spankind: str = "workflow",
|
|
43
|
+
ignore_inputs: Union[List[str], bool] = False,
|
|
44
|
+
ignore_outputs: Union[List[str], bool] = False,
|
|
28
45
|
) -> None:
|
|
29
|
-
self.kind = spankind if spankind is not None else kind
|
|
30
46
|
self.config = config
|
|
47
|
+
self.spankind = spankind
|
|
31
48
|
self.ignore_inputs = ignore_inputs
|
|
32
49
|
self.ignore_outputs = ignore_outputs
|
|
33
|
-
self.max_depth = max_depth
|
|
34
50
|
|
|
35
51
|
def __call__(self, func: Callable[..., Any]):
|
|
36
52
|
is_coroutine_function = inspect.iscoroutinefunction(func)
|
|
37
53
|
|
|
38
|
-
def
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
zip(inspect.getfullargspec(func).args, args),
|
|
43
|
-
kwargs.items(),
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return inputs
|
|
54
|
+
def get_inputs(*args, **kwargs):
|
|
55
|
+
func_args = inspect.getfullargspec(func).args
|
|
56
|
+
input_dict = {name: value for name, value in zip(func_args, args)}
|
|
57
|
+
input_dict.update(kwargs)
|
|
48
58
|
|
|
49
|
-
|
|
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.
|
|
59
|
+
return input_dict
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"""
|
|
60
|
-
io = {
|
|
61
|
-
key: value
|
|
62
|
-
for key, value in io.items()
|
|
61
|
+
def redact(io, blacklist):
|
|
62
|
+
return {
|
|
63
|
+
key: io[key]
|
|
64
|
+
for key in io.keys()
|
|
63
65
|
if key
|
|
64
66
|
not in (
|
|
65
|
-
|
|
66
|
-
if isinstance(
|
|
67
|
-
else io.keys()
|
|
68
|
-
if ignore is True
|
|
67
|
+
blacklist
|
|
68
|
+
if isinstance(blacklist, list)
|
|
69
69
|
else []
|
|
70
|
+
if blacklist is False
|
|
71
|
+
else io.keys()
|
|
70
72
|
)
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
def patch(result):
|
|
76
|
+
TRACE_DEFAULT_KEY = "__default__"
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
"""
|
|
77
|
-
Patch the result to ensure that it is a dictionary, with a default key when necessary.
|
|
78
|
+
outputs = result
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
# PATCH : if result is not a dict, make it a dict
|
|
81
|
+
if not isinstance(result, dict):
|
|
82
|
+
outputs = {TRACE_DEFAULT_KEY: result}
|
|
83
|
+
else:
|
|
84
|
+
# PATCH : if result is a legacy dict, clean it up
|
|
85
|
+
if (
|
|
86
|
+
"message" in result.keys()
|
|
87
|
+
and "cost" in result.keys()
|
|
88
|
+
and "usage" in result.keys()
|
|
89
|
+
):
|
|
90
|
+
outputs = {TRACE_DEFAULT_KEY: result["message"]}
|
|
91
|
+
|
|
92
|
+
ag.tracing.store_cost(result["cost"])
|
|
93
|
+
ag.tracing.store_usage(result["usage"])
|
|
93
94
|
|
|
94
95
|
return outputs
|
|
95
96
|
|
|
96
97
|
@wraps(func)
|
|
97
98
|
async def async_wrapper(*args, **kwargs):
|
|
98
99
|
async def wrapped_func(*args, **kwargs):
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
140
|
-
try:
|
|
141
|
-
result = await func(*args, **kwargs)
|
|
142
|
-
except Exception as e:
|
|
143
|
-
traceback.print_exc()
|
|
144
|
-
|
|
145
|
-
span.record_exception(e)
|
|
146
|
-
|
|
147
|
-
span.set_status("ERROR")
|
|
100
|
+
with ag.tracing.Context(
|
|
101
|
+
name=func.__name__,
|
|
102
|
+
input=redact(get_inputs(*args, **kwargs), self.ignore_inputs),
|
|
103
|
+
spankind=self.spankind,
|
|
104
|
+
config=self.config,
|
|
105
|
+
):
|
|
106
|
+
result = await func(*args, **kwargs)
|
|
148
107
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
with suppress():
|
|
152
|
-
cost = None
|
|
153
|
-
usage = {}
|
|
154
|
-
|
|
155
|
-
if isinstance(result, dict):
|
|
156
|
-
cost = result.get("cost", None)
|
|
157
|
-
usage = result.get("usage", {})
|
|
158
|
-
|
|
159
|
-
span.set_attributes(
|
|
160
|
-
attributes={"total": cost},
|
|
161
|
-
namespace="metrics.unit.costs",
|
|
162
|
-
)
|
|
163
|
-
span.set_attributes(
|
|
164
|
-
attributes=(
|
|
165
|
-
{
|
|
166
|
-
"prompt": usage.get("prompt_tokens", None),
|
|
167
|
-
"completion": usage.get("completion_tokens", None),
|
|
168
|
-
"total": usage.get("total_tokens", None),
|
|
169
|
-
}
|
|
170
|
-
),
|
|
171
|
-
namespace="metrics.unit.tokens",
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
_outputs = redact(patch(result), self.ignore_outputs)
|
|
175
|
-
span.set_attributes(
|
|
176
|
-
attributes={"outputs": _outputs},
|
|
177
|
-
namespace="data",
|
|
178
|
-
max_depth=self.max_depth,
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
span.set_status("OK")
|
|
182
|
-
|
|
183
|
-
with suppress():
|
|
184
|
-
if hasattr(span, "parent") and span.parent is None:
|
|
185
|
-
tracing_context.set(
|
|
186
|
-
tracing_context.get()
|
|
187
|
-
| {
|
|
188
|
-
"root": {
|
|
189
|
-
"trace_id": span.get_span_context().trace_id,
|
|
190
|
-
"span_id": span.get_span_context().span_id,
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
)
|
|
108
|
+
ag.tracing.store_outputs(redact(patch(result), self.ignore_outputs))
|
|
194
109
|
|
|
195
110
|
return result
|
|
196
111
|
|
|
@@ -199,98 +114,15 @@ class instrument:
|
|
|
199
114
|
@wraps(func)
|
|
200
115
|
def sync_wrapper(*args, **kwargs):
|
|
201
116
|
def wrapped_func(*args, **kwargs):
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
span.set_attributes(
|
|
212
|
-
attributes={"node": self.kind},
|
|
213
|
-
namespace="type",
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
if span.parent is None:
|
|
217
|
-
rctx = tracing_context.get()
|
|
218
|
-
|
|
219
|
-
span.set_attributes(
|
|
220
|
-
attributes={"configuration": rctx.get("config", {})},
|
|
221
|
-
namespace="meta",
|
|
222
|
-
)
|
|
223
|
-
span.set_attributes(
|
|
224
|
-
attributes={"environment": rctx.get("environment", {})},
|
|
225
|
-
namespace="meta",
|
|
226
|
-
)
|
|
227
|
-
span.set_attributes(
|
|
228
|
-
attributes={"version": rctx.get("version", {})},
|
|
229
|
-
namespace="meta",
|
|
230
|
-
)
|
|
231
|
-
span.set_attributes(
|
|
232
|
-
attributes={"variant": rctx.get("variant", {})},
|
|
233
|
-
namespace="meta",
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
_inputs = redact(parse(*args, **kwargs), self.ignore_inputs)
|
|
237
|
-
span.set_attributes(
|
|
238
|
-
attributes={"inputs": _inputs},
|
|
239
|
-
namespace="data",
|
|
240
|
-
max_depth=self.max_depth,
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
try:
|
|
244
|
-
result = func(*args, **kwargs)
|
|
245
|
-
except Exception as e:
|
|
246
|
-
span.record_exception(e)
|
|
247
|
-
|
|
248
|
-
span.set_status("ERROR")
|
|
249
|
-
|
|
250
|
-
raise e
|
|
251
|
-
|
|
252
|
-
with suppress():
|
|
253
|
-
cost = None
|
|
254
|
-
usage = {}
|
|
255
|
-
if isinstance(result, dict):
|
|
256
|
-
cost = result.get("cost", None)
|
|
257
|
-
usage = result.get("usage", {})
|
|
258
|
-
|
|
259
|
-
span.set_attributes(
|
|
260
|
-
attributes={"total": cost},
|
|
261
|
-
namespace="metrics.unit.costs",
|
|
262
|
-
)
|
|
263
|
-
span.set_attributes(
|
|
264
|
-
attributes=(
|
|
265
|
-
{
|
|
266
|
-
"prompt": usage.get("prompt_tokens", None),
|
|
267
|
-
"completion": usage.get("completion_tokens", None),
|
|
268
|
-
"total": usage.get("total_tokens", None),
|
|
269
|
-
}
|
|
270
|
-
),
|
|
271
|
-
namespace="metrics.unit.tokens",
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
_outputs = redact(patch(result), self.ignore_outputs)
|
|
275
|
-
span.set_attributes(
|
|
276
|
-
attributes={"outputs": _outputs},
|
|
277
|
-
namespace="data",
|
|
278
|
-
max_depth=self.max_depth,
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
span.set_status("OK")
|
|
282
|
-
|
|
283
|
-
with suppress():
|
|
284
|
-
if hasattr(span, "parent") and span.parent is None:
|
|
285
|
-
tracing_context.set(
|
|
286
|
-
tracing_context.get()
|
|
287
|
-
| {
|
|
288
|
-
"root": {
|
|
289
|
-
"trace_id": span.get_span_context().trace_id,
|
|
290
|
-
"span_id": span.get_span_context().span_id,
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
)
|
|
117
|
+
with ag.tracing.Context(
|
|
118
|
+
name=func.__name__,
|
|
119
|
+
input=redact(get_inputs(*args, **kwargs), self.ignore_inputs),
|
|
120
|
+
spankind=self.spankind,
|
|
121
|
+
config=self.config,
|
|
122
|
+
):
|
|
123
|
+
result = func(*args, **kwargs)
|
|
124
|
+
|
|
125
|
+
ag.tracing.store_outputs(redact(patch(result), self.ignore_outputs))
|
|
294
126
|
|
|
295
127
|
return result
|
|
296
128
|
|
agenta/sdk/router.py
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
|
+
from .context import get_contexts
|
|
2
3
|
|
|
3
4
|
router = APIRouter()
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
@router.get("/contexts/")
|
|
8
|
+
def get_all_contexts():
|
|
9
|
+
contexts = get_contexts()
|
|
10
|
+
return {"contexts": contexts}
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
@router.get("/health")
|
|
7
14
|
def health():
|
|
8
15
|
return {"status": "ok"}
|
agenta/sdk/tracing/__init__.py
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .tracing import Tracing, get_tracer
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import agenta as ag
|
|
2
|
+
|
|
3
|
+
from agenta.sdk.tracing.tracing_context import tracing_context, TracingContext
|
|
4
|
+
from agenta.sdk.tracing.logger import llm_logger as logging
|
|
5
|
+
|
|
6
|
+
from agenta.sdk.utils.debug import debug
|
|
7
|
+
|
|
8
|
+
TRACE_DEFAULT_KEY = "__default__"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def litellm_handler():
|
|
12
|
+
try:
|
|
13
|
+
from litellm.utils import ModelResponse
|
|
14
|
+
from litellm.integrations.custom_logger import (
|
|
15
|
+
CustomLogger as LitellmCustomLogger,
|
|
16
|
+
)
|
|
17
|
+
except ImportError as exc:
|
|
18
|
+
raise ImportError(
|
|
19
|
+
"The litellm SDK is not installed. Please install it using `pip install litellm`."
|
|
20
|
+
) from exc
|
|
21
|
+
except Exception as exc:
|
|
22
|
+
raise Exception(
|
|
23
|
+
"Unexpected error occurred when importing litellm: {}".format(exc)
|
|
24
|
+
) from exc
|
|
25
|
+
|
|
26
|
+
class LitellmHandler(LitellmCustomLogger):
|
|
27
|
+
"""This handler is responsible for instrumenting certain events when using litellm to call LLMs.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
LitellmCustomLogger (object): custom logger that allows us to override the events to capture.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.span = None
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def _trace(self):
|
|
38
|
+
return ag.tracing
|
|
39
|
+
|
|
40
|
+
@debug()
|
|
41
|
+
def log_pre_api_call(self, model, messages, kwargs):
|
|
42
|
+
call_type = kwargs.get("call_type")
|
|
43
|
+
span_kind = (
|
|
44
|
+
"llm" if call_type in ["completion", "acompletion"] else "embedding"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
self.span = ag.tracing.open_span(
|
|
48
|
+
name=f"{span_kind}_call",
|
|
49
|
+
input={"messages": kwargs["messages"]},
|
|
50
|
+
spankind=span_kind,
|
|
51
|
+
active=False,
|
|
52
|
+
)
|
|
53
|
+
logging.info(f"log_pre_api_call({self.span.id})")
|
|
54
|
+
ag.tracing.set_attributes(
|
|
55
|
+
{
|
|
56
|
+
"model_config": {
|
|
57
|
+
"model": kwargs.get("model"),
|
|
58
|
+
**kwargs.get(
|
|
59
|
+
"optional_params"
|
|
60
|
+
), # model-specific params passed in
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@debug()
|
|
66
|
+
def log_stream_event(self, kwargs, response_obj, start_time, end_time):
|
|
67
|
+
logging.info(f"log_stream_event({self.span.id})")
|
|
68
|
+
ag.tracing.set_status(status="OK", span_id=self.span.id)
|
|
69
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
70
|
+
ag.tracing.store_usage(
|
|
71
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
72
|
+
span_id=self.span.id,
|
|
73
|
+
)
|
|
74
|
+
ag.tracing.store_outputs(
|
|
75
|
+
# the complete streamed response (only set if `completion(..stream=True)`
|
|
76
|
+
outputs={TRACE_DEFAULT_KEY: kwargs.get("complete_streaming_response")},
|
|
77
|
+
span_id=self.span.id,
|
|
78
|
+
)
|
|
79
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
80
|
+
|
|
81
|
+
@debug()
|
|
82
|
+
def log_success_event(self, kwargs, response_obj, start_time, end_time):
|
|
83
|
+
logging.info(f"log_success_event({self.span.id})")
|
|
84
|
+
ag.tracing.set_status(status="OK", span_id=self.span.id)
|
|
85
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
86
|
+
ag.tracing.store_usage(
|
|
87
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
88
|
+
span_id=self.span.id,
|
|
89
|
+
)
|
|
90
|
+
ag.tracing.store_outputs(
|
|
91
|
+
outputs={TRACE_DEFAULT_KEY: response_obj.choices[0].message.content},
|
|
92
|
+
span_id=self.span.id,
|
|
93
|
+
)
|
|
94
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
95
|
+
|
|
96
|
+
@debug()
|
|
97
|
+
def log_failure_event(self, kwargs, response_obj, start_time, end_time):
|
|
98
|
+
logging.info("log_failure_event()", self.span)
|
|
99
|
+
ag.tracing.set_status(status="ERROR", span_id=self.span.id)
|
|
100
|
+
ag.tracing.set_attributes(
|
|
101
|
+
{
|
|
102
|
+
"traceback_exception": repr(
|
|
103
|
+
kwargs["traceback_exception"]
|
|
104
|
+
), # the traceback generated via `traceback.format_exc()`
|
|
105
|
+
"call_end_time": kwargs[
|
|
106
|
+
"end_time"
|
|
107
|
+
], # datetime object of when call was completed
|
|
108
|
+
},
|
|
109
|
+
span_id=self.span.id,
|
|
110
|
+
)
|
|
111
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
112
|
+
ag.tracing.store_usage(
|
|
113
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
114
|
+
span_id=self.span.id,
|
|
115
|
+
)
|
|
116
|
+
ag.tracing.store_outputs(
|
|
117
|
+
# the Exception raised
|
|
118
|
+
outputs={TRACE_DEFAULT_KEY: repr(kwargs["exception"])},
|
|
119
|
+
span_id=self.span.id,
|
|
120
|
+
)
|
|
121
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
122
|
+
|
|
123
|
+
@debug()
|
|
124
|
+
async def async_log_stream_event(
|
|
125
|
+
self, kwargs, response_obj, start_time, end_time
|
|
126
|
+
):
|
|
127
|
+
logging.info(f"async_log_stream_event({self.span.id})")
|
|
128
|
+
ag.tracing.set_status(status="OK", span_id=self.span.id)
|
|
129
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
130
|
+
ag.tracing.store_usage(
|
|
131
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
132
|
+
span_id=self.span.id,
|
|
133
|
+
)
|
|
134
|
+
ag.tracing.store_outputs(
|
|
135
|
+
# the complete streamed response (only set if `completion(..stream=True)`)
|
|
136
|
+
outputs={TRACE_DEFAULT_KEY: kwargs.get("complete_streaming_response")},
|
|
137
|
+
span_id=self.span.id,
|
|
138
|
+
)
|
|
139
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
140
|
+
|
|
141
|
+
@debug()
|
|
142
|
+
async def async_log_success_event(
|
|
143
|
+
self, kwargs, response_obj, start_time, end_time
|
|
144
|
+
):
|
|
145
|
+
logging.info(f"async_log_success_event({self.span.id})")
|
|
146
|
+
ag.tracing.set_status(status="OK", span_id=self.span.id)
|
|
147
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
148
|
+
ag.tracing.store_usage(
|
|
149
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
150
|
+
span_id=self.span.id,
|
|
151
|
+
)
|
|
152
|
+
ag.tracing.store_outputs(
|
|
153
|
+
outputs={TRACE_DEFAULT_KEY: response_obj.choices[0].message.content},
|
|
154
|
+
span_id=self.span.id,
|
|
155
|
+
)
|
|
156
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
157
|
+
|
|
158
|
+
@debug()
|
|
159
|
+
async def async_log_failure_event(
|
|
160
|
+
self, kwargs, response_obj, start_time, end_time
|
|
161
|
+
):
|
|
162
|
+
logging.info(f"async_log_failure_event({self.span.id})")
|
|
163
|
+
ag.tracing.set_status(status="ERROR", span_id=self.span.id)
|
|
164
|
+
ag.tracing.set_attributes(
|
|
165
|
+
{
|
|
166
|
+
"traceback_exception": kwargs[
|
|
167
|
+
"traceback_exception"
|
|
168
|
+
], # the traceback generated via `traceback.format_exc()`
|
|
169
|
+
"call_end_time": kwargs[
|
|
170
|
+
"end_time"
|
|
171
|
+
], # datetime object of when call was completed
|
|
172
|
+
},
|
|
173
|
+
span_id=self.span.id,
|
|
174
|
+
)
|
|
175
|
+
ag.tracing.store_cost(kwargs.get("response_cost"), span_id=self.span.id)
|
|
176
|
+
ag.tracing.store_usage(
|
|
177
|
+
response_obj.usage.dict() if hasattr(response_obj, "usage") else None,
|
|
178
|
+
span_id=self.span.id,
|
|
179
|
+
)
|
|
180
|
+
ag.tracing.store_outputs(
|
|
181
|
+
# the Exception raised
|
|
182
|
+
outputs={TRACE_DEFAULT_KEY: repr(kwargs["exception"])},
|
|
183
|
+
span_id=self.span.id,
|
|
184
|
+
)
|
|
185
|
+
ag.tracing.close_span(span_id=self.span.id)
|
|
186
|
+
|
|
187
|
+
return LitellmHandler()
|