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
|
@@ -0,0 +1,181 @@
|
|
|
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
|
+
"""
|
|
@@ -0,0 +1,21 @@
|
|
|
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)
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|