agenta 0.25.3a1__py3-none-any.whl → 0.25.4__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 (42) hide show
  1. agenta/__init__.py +7 -6
  2. agenta/client/backend/client.py +14 -22
  3. agenta/client/backend/core/http_client.py +15 -23
  4. agenta/client/backend/core/pydantic_utilities.py +2 -2
  5. agenta/sdk/__init__.py +6 -27
  6. agenta/sdk/agenta_init.py +26 -73
  7. agenta/sdk/config_manager.py +2 -2
  8. agenta/sdk/context.py +41 -0
  9. agenta/sdk/decorators/base.py +10 -0
  10. agenta/sdk/decorators/{routing.py → llm_entrypoint.py} +125 -136
  11. agenta/sdk/decorators/tracing.py +81 -243
  12. agenta/sdk/router.py +7 -0
  13. agenta/sdk/tracing/__init__.py +0 -1
  14. agenta/sdk/tracing/callbacks.py +187 -0
  15. agenta/sdk/tracing/llm_tracing.py +617 -0
  16. agenta/sdk/{utils/logging.py → tracing/logger.py} +5 -3
  17. agenta/sdk/tracing/tasks_manager.py +129 -0
  18. agenta/sdk/tracing/tracing_context.py +27 -0
  19. agenta/sdk/types.py +12 -0
  20. agenta/sdk/utils/debug.py +5 -5
  21. agenta/sdk/utils/globals.py +5 -3
  22. agenta/sdk/utils/{costs.py → helper/openai_cost.py} +0 -3
  23. {agenta-0.25.3a1.dist-info → agenta-0.25.4.dist-info}/METADATA +2 -4
  24. {agenta-0.25.3a1.dist-info → agenta-0.25.4.dist-info}/RECORD +26 -36
  25. {agenta-0.25.3a1.dist-info → agenta-0.25.4.dist-info}/WHEEL +1 -1
  26. agenta/sdk/context/__init__.py +0 -0
  27. agenta/sdk/context/routing.py +0 -25
  28. agenta/sdk/context/tracing.py +0 -3
  29. agenta/sdk/decorators/__init__.py +0 -0
  30. agenta/sdk/litellm/__init__.py +0 -1
  31. agenta/sdk/litellm/litellm.py +0 -275
  32. agenta/sdk/tracing/attributes.py +0 -181
  33. agenta/sdk/tracing/context.py +0 -21
  34. agenta/sdk/tracing/conventions.py +0 -43
  35. agenta/sdk/tracing/exporters.py +0 -53
  36. agenta/sdk/tracing/inline.py +0 -1230
  37. agenta/sdk/tracing/processors.py +0 -65
  38. agenta/sdk/tracing/spans.py +0 -124
  39. agenta/sdk/tracing/tracing.py +0 -171
  40. agenta/sdk/utils/exceptions.py +0 -18
  41. agenta/sdk/utils/singleton.py +0 -13
  42. {agenta-0.25.3a1.dist-info → agenta-0.25.4.dist-info}/entry_points.txt +0 -0
@@ -1,275 +0,0 @@
1
- import agenta as ag
2
-
3
- from agenta.sdk.tracing.spans import CustomSpan
4
- from agenta.sdk.utils.exceptions import suppress
5
- from agenta.sdk.utils.logging import log
6
-
7
-
8
- def litellm_handler():
9
- try:
10
- from litellm.utils import ModelResponse
11
- from litellm.integrations.custom_logger import (
12
- CustomLogger as LitellmCustomLogger,
13
- )
14
- except ImportError as exc:
15
- raise ImportError(
16
- "The litellm SDK is not installed. Please install it using `pip install litellm`."
17
- ) from exc
18
- except Exception as exc:
19
- raise Exception(
20
- "Unexpected error occurred when importing litellm: {}".format(exc)
21
- ) from exc
22
-
23
- class LitellmHandler(LitellmCustomLogger):
24
- """This handler is responsible for instrumenting certain events when using litellm to call LLMs.
25
-
26
- Args:
27
- LitellmCustomLogger (object): custom logger that allows us to override the events to capture.
28
- """
29
-
30
- def __init__(self):
31
- self.span = None
32
-
33
- def log_pre_api_call(
34
- self,
35
- model,
36
- messages,
37
- kwargs,
38
- ):
39
- type = (
40
- "chat"
41
- if kwargs.get("call_type") in ["completion", "acompletion"]
42
- else "embedding"
43
- )
44
-
45
- kind = "CLIENT"
46
-
47
- self.span = CustomSpan(
48
- ag.tracer.start_span(name=f"litellm_{kind.lower()}", kind=kind)
49
- )
50
-
51
- self.span.set_attributes(
52
- attributes={"node": type},
53
- namespace="type",
54
- )
55
-
56
- if not self.span:
57
- log.error("LiteLLM callback error: span not found.")
58
- return
59
-
60
- log.info(f"log_pre_api_call({hex(self.span.context.span_id)[2:]})")
61
-
62
- self.span.set_attributes(
63
- attributes={"inputs": {"messages": kwargs["messages"]}},
64
- namespace="data",
65
- )
66
-
67
- self.span.set_attributes(
68
- attributes={
69
- "configuration": {
70
- "model": kwargs.get("model"),
71
- **kwargs.get("optional_params"),
72
- }
73
- },
74
- namespace="meta",
75
- )
76
-
77
- def log_stream_event(
78
- self,
79
- kwargs,
80
- response_obj,
81
- start_time,
82
- end_time,
83
- ):
84
- if not self.span:
85
- log.error("LiteLLM callback error: span not found.")
86
- return
87
-
88
- # log.info(f"log_stream({hex(self.span.context.span_id)[2:]})")
89
-
90
- self.span.set_attributes(
91
- attributes={
92
- "output": {"__default__": kwargs.get("complete_streaming_response")}
93
- },
94
- namespace="data",
95
- )
96
-
97
- self.span.set_attributes(
98
- attributes={"total": kwargs.get("response_cost")},
99
- namespace="metrics.unit.costs",
100
- )
101
-
102
- self.span.set_attributes(
103
- attributes=(
104
- {
105
- "prompt": response_obj.usage.prompt_tokens,
106
- "completion": response_obj.usage.completion_tokens,
107
- "total": response_obj.usage.total_tokens,
108
- }
109
- ),
110
- namespace="metrics.unit.tokens",
111
- )
112
-
113
- self.span.set_status(status="OK")
114
-
115
- self.span.end()
116
-
117
- def log_success_event(
118
- self,
119
- kwargs,
120
- response_obj,
121
- start_time,
122
- end_time,
123
- ):
124
- if not self.span:
125
- log.error("LiteLLM callback error: span not found.")
126
- return
127
-
128
- # log.info(f"log_success({hex(self.span.context.span_id)[2:]})")
129
-
130
- self.span.set_attributes(
131
- attributes={
132
- "output": {"__default__": response_obj.choices[0].message.content}
133
- },
134
- namespace="data",
135
- )
136
-
137
- self.span.set_attributes(
138
- attributes={"total": kwargs.get("response_cost")},
139
- namespace="metrics.unit.costs",
140
- )
141
-
142
- self.span.set_attributes(
143
- attributes=(
144
- {
145
- "prompt": response_obj.usage.prompt_tokens,
146
- "completion": response_obj.usage.completion_tokens,
147
- "total": response_obj.usage.total_tokens,
148
- }
149
- ),
150
- namespace="metrics.unit.tokens",
151
- )
152
-
153
- self.span.set_status(status="OK")
154
-
155
- self.span.end()
156
-
157
- def log_failure_event(
158
- self,
159
- kwargs,
160
- response_obj,
161
- start_time,
162
- end_time,
163
- ):
164
- if not self.span:
165
- log.error("LiteLLM callback error: span not found.")
166
- return
167
-
168
- # log.info(f"log_failure({hex(self.span.context.span_id)[2:]})")
169
-
170
- self.span.record_exception(kwargs["exception"])
171
-
172
- self.span.set_status(status="ERROR")
173
-
174
- self.span.end()
175
-
176
- async def async_log_stream_event(
177
- self,
178
- kwargs,
179
- response_obj,
180
- start_time,
181
- end_time,
182
- ):
183
- if not self.span:
184
- log.error("LiteLLM callback error: span not found.")
185
- return
186
-
187
- # log.info(f"async_log_stream({hex(self.span.context.span_id)[2:]})")
188
-
189
- self.span.set_attributes(
190
- attributes={
191
- "output": {"__default__": kwargs.get("complete_streaming_response")}
192
- },
193
- namespace="data",
194
- )
195
-
196
- self.span.set_attributes(
197
- attributes={"total": kwargs.get("response_cost")},
198
- namespace="metrics.unit.costs",
199
- )
200
-
201
- self.span.set_attributes(
202
- attributes=(
203
- {
204
- "prompt": response_obj.usage.prompt_tokens,
205
- "completion": response_obj.usage.completion_tokens,
206
- "total": response_obj.usage.total_tokens,
207
- }
208
- ),
209
- namespace="metrics.unit.tokens",
210
- )
211
-
212
- self.span.set_status(status="OK")
213
-
214
- self.span.end()
215
-
216
- async def async_log_success_event(
217
- self,
218
- kwargs,
219
- response_obj,
220
- start_time,
221
- end_time,
222
- ):
223
- if not self.span:
224
- log.error("LiteLLM callback error: span not found.")
225
- return
226
-
227
- log.info(f"async_log_success({hex(self.span.context.span_id)[2:]})")
228
-
229
- self.span.set_attributes(
230
- attributes={
231
- "output": {"__default__": kwargs.get("complete_streaming_response")}
232
- },
233
- namespace="data",
234
- )
235
-
236
- self.span.set_attributes(
237
- attributes={"total": kwargs.get("response_cost")},
238
- namespace="metrics.unit.costs",
239
- )
240
-
241
- self.span.set_attributes(
242
- attributes=(
243
- {
244
- "prompt": response_obj.usage.prompt_tokens,
245
- "completion": response_obj.usage.completion_tokens,
246
- "total": response_obj.usage.total_tokens,
247
- }
248
- ),
249
- namespace="metrics.unit.tokens",
250
- )
251
-
252
- self.span.set_status(status="OK")
253
-
254
- self.span.end()
255
-
256
- async def async_log_failure_event(
257
- self,
258
- kwargs,
259
- response_obj,
260
- start_time,
261
- end_time,
262
- ):
263
- if not self.span:
264
- log.error("LiteLLM callback error: span not found.")
265
- return
266
-
267
- # log.info(f"async_log_failure({hex(self.span.context.span_id)[2:]})")
268
-
269
- self.span.record_exception(kwargs["exception"])
270
-
271
- self.span.set_status(status="ERROR")
272
-
273
- self.span.end()
274
-
275
- return LitellmHandler()
@@ -1,181 +0,0 @@
1
- from json import loads, dumps
2
- from typing import Optional, Union, Sequence, Any, Dict
3
-
4
- Primitive = Union[str, int, float, bool, bytes]
5
- PrimitivesSequence = Sequence[Primitive]
6
- Attribute = Union[Primitive, PrimitivesSequence]
7
-
8
-
9
- def _marshal(
10
- unmarshalled: Dict[str, Any],
11
- *,
12
- parent_key: Optional[str] = "",
13
- depth: Optional[int] = 0,
14
- max_depth: Optional[int] = None,
15
- ) -> Dict[str, Any]:
16
- """
17
- Marshals a dictionary of unmarshalled attributes into a flat dictionary
18
-
19
- Example:
20
- unmarshalled = {
21
- "ag": {
22
- "type": "tree",
23
- "node": {
24
- "name": "root",
25
- "children": [
26
- {
27
- "name": "child1",
28
- },
29
- {
30
- "name": "child2",
31
- }
32
- ]
33
- }
34
- }
35
- }
36
- marshalled = {
37
- "ag.type": "tree",
38
- "ag.node.name": "root",
39
- "ag.node.children.0.name": "child1",
40
- "ag.node.children.1.name": "child2"
41
- }
42
- """
43
- marshalled = {}
44
-
45
- # If max_depth is set and we've reached it,
46
- # just return the unmarshalled attributes
47
- if max_depth is not None and depth >= max_depth:
48
- marshalled[parent_key] = unmarshalled
49
- # MISSING ENCODING TO JSON IF NOT PRIMITIVE
50
-
51
- return marshalled
52
-
53
- # Otherwise,
54
- # iterate over the unmarshalled attributes and marshall them
55
- for key, value in unmarshalled.items():
56
- child_key = f"{parent_key}.{key}" if parent_key else key
57
-
58
- if isinstance(value, dict):
59
- dict_key = child_key
60
-
61
- marshalled.update(
62
- _marshal(
63
- value,
64
- parent_key=dict_key,
65
- depth=depth + 1,
66
- max_depth=max_depth,
67
- )
68
- )
69
- elif isinstance(value, list):
70
- if max_depth is not None and depth + 1 >= max_depth:
71
- marshalled[child_key] = value
72
- # MISSING ENCODING TO JSON IF NOT PRIMITIVE
73
- else:
74
- for i, item in enumerate(value):
75
- list_key = f"{child_key}.{i}"
76
-
77
- if isinstance(item, (dict, list)):
78
- marshalled.update(
79
- _marshal(
80
- item,
81
- parent_key=list_key,
82
- depth=depth + 1,
83
- max_depth=max_depth,
84
- )
85
- )
86
- else:
87
- marshalled[list_key] = item
88
- # MISSING ENCODING TO JSON IF NOT PRIMITIVE
89
- else:
90
- marshalled[child_key] = value
91
- # MISSING ENCODING TO JSON IF NOT PRIMITIVE
92
-
93
- return marshalled
94
-
95
-
96
- def _encode_key(namespace: Optional[str] = None, key: str = "") -> str:
97
- if namespace is None:
98
- return key
99
-
100
- return f"ag.{namespace}.{key}"
101
-
102
-
103
- def _encode_value(value: Any) -> Optional[Attribute]:
104
- if value is None:
105
- return None
106
-
107
- if isinstance(value, (str, int, float, bool, bytes)):
108
- return value
109
-
110
- if isinstance(value, dict) or isinstance(value, list):
111
- encoded = dumps(value)
112
- value = "@ag.type=json:" + encoded
113
- return value
114
-
115
- return repr(value)
116
-
117
-
118
- def serialize(
119
- *,
120
- namespace: str,
121
- attributes: Dict[str, Any],
122
- max_depth: Optional[int] = None,
123
- ) -> Dict[str, str]:
124
- if not isinstance(attributes, dict):
125
- return {}
126
-
127
- _attributes = {
128
- k: v
129
- for k, v in {
130
- _encode_key(namespace, key): _encode_value(value)
131
- for key, value in _marshal(attributes, max_depth=max_depth).items()
132
- }.items()
133
- if v is not None
134
- }
135
-
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
- """
@@ -1,21 +0,0 @@
1
- from contextvars import ContextVar
2
- from contextlib import contextmanager
3
- from traceback import format_exc
4
-
5
- from agenta.sdk.utils.logging import log
6
-
7
- tracing_context = ContextVar("tracing_context", default={})
8
-
9
-
10
- @contextmanager
11
- def tracing_context_manager():
12
- _tracing_context = {"health": {"status": "ok"}}
13
-
14
- token = tracing_context.set(_tracing_context)
15
- try:
16
- yield
17
- except Exception as e:
18
- log.error(f"Error with tracing context: {_tracing_context}")
19
- log.error(f"Exception: {format_exc()}")
20
- finally:
21
- tracing_context.reset(token)
@@ -1,43 +0,0 @@
1
- from typing import Literal
2
-
3
- from opentelemetry.trace import SpanKind
4
-
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
- ]
23
-
24
-
25
- def parse_span_kind(type: str) -> SpanKind:
26
- kind = SpanKind.INTERNAL
27
- if type in [
28
- "agent",
29
- "chain",
30
- "workflow",
31
- ]:
32
- kind = SpanKind.SERVER
33
- elif type in [
34
- "tool",
35
- "embedding",
36
- "query",
37
- "completion",
38
- "chat",
39
- "rerank",
40
- ]:
41
- kind = SpanKind.CLIENT
42
-
43
- return kind
@@ -1,53 +0,0 @@
1
- from typing import Sequence, Dict, List
2
-
3
- from opentelemetry.sdk.trace.export import (
4
- ConsoleSpanExporter,
5
- SpanExporter,
6
- SpanExportResult,
7
- ReadableSpan,
8
- )
9
- from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
10
- OTLPSpanExporter,
11
- )
12
-
13
- from agenta.sdk.utils.exceptions import suppress
14
-
15
-
16
- class InlineTraceExporter(SpanExporter):
17
- def __init__(self, registry: Dict[str, List[ReadableSpan]]):
18
- self._shutdown = False
19
- self._registry = registry
20
-
21
- def export(
22
- self,
23
- spans: Sequence[ReadableSpan],
24
- ) -> SpanExportResult:
25
- if self._shutdown:
26
- return
27
-
28
- with suppress():
29
- for span in spans:
30
- trace_id = span.get_span_context().trace_id
31
-
32
- if trace_id not in self._registry:
33
- self._registry[trace_id] = []
34
-
35
- self._registry[trace_id].append(span)
36
-
37
- def shutdown(self) -> None:
38
- self._shutdown = True
39
-
40
- def force_flush(self, timeout_millis: int = 30000) -> bool:
41
- return True
42
-
43
- def fetch(self, trace_id: int) -> List[ReadableSpan]:
44
- trace = self._registry.get(trace_id, [])
45
-
46
- del self._registry[trace_id]
47
-
48
- return trace
49
-
50
-
51
- ConsoleExporter = ConsoleSpanExporter
52
- InlineExporter = InlineTraceExporter
53
- OTLPExporter = OTLPSpanExporter