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.

Files changed (41) hide show
  1. agenta/__init__.py +6 -7
  2. agenta/client/backend/client.py +22 -14
  3. agenta/client/backend/core/http_client.py +23 -15
  4. agenta/sdk/__init__.py +27 -6
  5. agenta/sdk/agenta_init.py +73 -26
  6. agenta/sdk/config_manager.py +2 -2
  7. agenta/sdk/context/__init__.py +0 -0
  8. agenta/sdk/context/routing.py +25 -0
  9. agenta/sdk/context/tracing.py +3 -0
  10. agenta/sdk/decorators/__init__.py +0 -0
  11. agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +137 -124
  12. agenta/sdk/decorators/tracing.py +228 -76
  13. agenta/sdk/litellm/__init__.py +1 -0
  14. agenta/sdk/litellm/litellm.py +277 -0
  15. agenta/sdk/router.py +0 -7
  16. agenta/sdk/tracing/__init__.py +1 -0
  17. agenta/sdk/tracing/attributes.py +181 -0
  18. agenta/sdk/tracing/context.py +21 -0
  19. agenta/sdk/tracing/conventions.py +43 -0
  20. agenta/sdk/tracing/exporters.py +53 -0
  21. agenta/sdk/tracing/inline.py +1306 -0
  22. agenta/sdk/tracing/processors.py +65 -0
  23. agenta/sdk/tracing/spans.py +124 -0
  24. agenta/sdk/tracing/tracing.py +174 -0
  25. agenta/sdk/types.py +0 -12
  26. agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
  27. agenta/sdk/utils/debug.py +5 -5
  28. agenta/sdk/utils/exceptions.py +19 -0
  29. agenta/sdk/utils/globals.py +3 -5
  30. agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
  31. agenta/sdk/utils/singleton.py +13 -0
  32. {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/METADATA +5 -1
  33. {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/RECORD +35 -25
  34. agenta/sdk/context.py +0 -41
  35. agenta/sdk/decorators/base.py +0 -10
  36. agenta/sdk/tracing/callbacks.py +0 -187
  37. agenta/sdk/tracing/llm_tracing.py +0 -617
  38. agenta/sdk/tracing/tasks_manager.py +0 -129
  39. agenta/sdk/tracing/tracing_context.py +0 -27
  40. {agenta-0.26.0a0.dist-info → agenta-0.27.0a0.dist-info}/WHEEL +0 -0
  41. {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