agenta 0.26.0a0__py3-none-any.whl → 0.27.0__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 (85) hide show
  1. agenta/__init__.py +29 -10
  2. agenta/cli/helper.py +5 -1
  3. agenta/client/backend/__init__.py +14 -0
  4. agenta/client/backend/apps/client.py +28 -20
  5. agenta/client/backend/client.py +47 -16
  6. agenta/client/backend/containers/client.py +5 -1
  7. agenta/client/backend/core/__init__.py +2 -1
  8. agenta/client/backend/core/client_wrapper.py +6 -6
  9. agenta/client/backend/core/file.py +33 -11
  10. agenta/client/backend/core/http_client.py +45 -31
  11. agenta/client/backend/core/pydantic_utilities.py +144 -29
  12. agenta/client/backend/core/request_options.py +3 -0
  13. agenta/client/backend/core/serialization.py +139 -42
  14. agenta/client/backend/evaluations/client.py +7 -2
  15. agenta/client/backend/evaluators/client.py +349 -1
  16. agenta/client/backend/observability/client.py +11 -2
  17. agenta/client/backend/testsets/client.py +10 -10
  18. agenta/client/backend/types/__init__.py +14 -0
  19. agenta/client/backend/types/app.py +1 -0
  20. agenta/client/backend/types/app_variant_response.py +3 -1
  21. agenta/client/backend/types/config_dto.py +32 -0
  22. agenta/client/backend/types/config_response_model.py +32 -0
  23. agenta/client/backend/types/create_span.py +3 -2
  24. agenta/client/backend/types/environment_output.py +1 -0
  25. agenta/client/backend/types/environment_output_extended.py +1 -0
  26. agenta/client/backend/types/evaluation.py +1 -2
  27. agenta/client/backend/types/evaluator.py +2 -0
  28. agenta/client/backend/types/evaluator_config.py +1 -0
  29. agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
  30. agenta/client/backend/types/evaluator_output_interface.py +21 -0
  31. agenta/client/backend/types/human_evaluation.py +1 -2
  32. agenta/client/backend/types/lifecycle_dto.py +24 -0
  33. agenta/client/backend/types/llm_tokens.py +2 -2
  34. agenta/client/backend/types/reference_dto.py +23 -0
  35. agenta/client/backend/types/reference_request_model.py +23 -0
  36. agenta/client/backend/types/span.py +1 -0
  37. agenta/client/backend/types/span_detail.py +7 -1
  38. agenta/client/backend/types/test_set_output_response.py +5 -2
  39. agenta/client/backend/types/trace_detail.py +7 -1
  40. agenta/client/backend/types/with_pagination.py +4 -2
  41. agenta/client/backend/variants/client.py +1565 -272
  42. agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
  43. agenta/sdk/__init__.py +44 -7
  44. agenta/sdk/agenta_init.py +85 -33
  45. agenta/sdk/context/__init__.py +0 -0
  46. agenta/sdk/context/routing.py +26 -0
  47. agenta/sdk/context/tracing.py +3 -0
  48. agenta/sdk/decorators/__init__.py +0 -0
  49. agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +216 -191
  50. agenta/sdk/decorators/tracing.py +218 -99
  51. agenta/sdk/litellm/__init__.py +1 -0
  52. agenta/sdk/litellm/litellm.py +288 -0
  53. agenta/sdk/managers/__init__.py +6 -0
  54. agenta/sdk/managers/config.py +318 -0
  55. agenta/sdk/managers/deployment.py +45 -0
  56. agenta/sdk/managers/shared.py +639 -0
  57. agenta/sdk/managers/variant.py +182 -0
  58. agenta/sdk/router.py +0 -7
  59. agenta/sdk/tracing/__init__.py +1 -0
  60. agenta/sdk/tracing/attributes.py +141 -0
  61. agenta/sdk/tracing/context.py +24 -0
  62. agenta/sdk/tracing/conventions.py +49 -0
  63. agenta/sdk/tracing/exporters.py +65 -0
  64. agenta/sdk/tracing/inline.py +1252 -0
  65. agenta/sdk/tracing/processors.py +117 -0
  66. agenta/sdk/tracing/spans.py +136 -0
  67. agenta/sdk/tracing/tracing.py +233 -0
  68. agenta/sdk/types.py +49 -2
  69. agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
  70. agenta/sdk/utils/debug.py +5 -5
  71. agenta/sdk/utils/exceptions.py +52 -0
  72. agenta/sdk/utils/globals.py +3 -5
  73. agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
  74. agenta/sdk/utils/singleton.py +13 -0
  75. {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/METADATA +5 -1
  76. {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/RECORD +78 -57
  77. agenta/sdk/config_manager.py +0 -205
  78. agenta/sdk/context.py +0 -41
  79. agenta/sdk/decorators/base.py +0 -10
  80. agenta/sdk/tracing/callbacks.py +0 -187
  81. agenta/sdk/tracing/llm_tracing.py +0 -617
  82. agenta/sdk/tracing/tasks_manager.py +0 -129
  83. agenta/sdk/tracing/tracing_context.py +0 -27
  84. {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/WHEEL +0 -0
  85. {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,182 @@
1
+ from typing import Optional
2
+
3
+ from agenta.sdk.managers.shared import SharedManager
4
+
5
+
6
+ class VariantManager(SharedManager):
7
+ @classmethod
8
+ def create(
9
+ cls,
10
+ *,
11
+ parameters: dict,
12
+ variant_slug: str,
13
+ #
14
+ app_id: Optional[str] = None,
15
+ app_slug: Optional[str] = None,
16
+ ):
17
+ variant = SharedManager.add(
18
+ app_id=app_id,
19
+ app_slug=app_slug,
20
+ variant_slug=variant_slug,
21
+ )
22
+
23
+ if variant:
24
+ variant = SharedManager.commit(
25
+ parameters=parameters,
26
+ app_id=app_id,
27
+ app_slug=app_slug,
28
+ variant_slug=variant_slug,
29
+ )
30
+
31
+ return variant
32
+
33
+ @classmethod
34
+ async def acreate(
35
+ cls,
36
+ *,
37
+ parameters: dict,
38
+ variant_slug: str,
39
+ #
40
+ app_id: Optional[str] = None,
41
+ app_slug: Optional[str] = None,
42
+ ):
43
+ variant = await SharedManager.aadd(
44
+ app_id=app_id,
45
+ app_slug=app_slug,
46
+ variant_slug=variant_slug,
47
+ )
48
+ if variant:
49
+ variant = await SharedManager.acommit(
50
+ parameters=parameters,
51
+ app_id=app_id,
52
+ app_slug=app_slug,
53
+ variant_slug=variant_slug,
54
+ )
55
+
56
+ return variant
57
+
58
+ @classmethod
59
+ def commit(
60
+ cls,
61
+ *,
62
+ parameters: dict,
63
+ variant_slug: str,
64
+ #
65
+ app_id: Optional[str] = None,
66
+ app_slug: Optional[str] = None,
67
+ ):
68
+ variant = SharedManager.commit(
69
+ parameters=parameters,
70
+ app_id=app_id,
71
+ app_slug=app_slug,
72
+ variant_slug=variant_slug,
73
+ )
74
+ return variant
75
+
76
+ @classmethod
77
+ async def acommit(
78
+ cls,
79
+ *,
80
+ parameters: dict,
81
+ variant_slug: str,
82
+ #
83
+ app_id: Optional[str] = None,
84
+ app_slug: Optional[str] = None,
85
+ ):
86
+ variant = await SharedManager.acommit(
87
+ parameters=parameters,
88
+ app_id=app_id,
89
+ app_slug=app_slug,
90
+ variant_slug=variant_slug,
91
+ )
92
+ return variant
93
+
94
+ @classmethod
95
+ def delete(
96
+ cls,
97
+ *,
98
+ variant_slug: str,
99
+ #
100
+ app_id: Optional[str] = None,
101
+ app_slug: Optional[str] = None,
102
+ ):
103
+ message = SharedManager.delete(
104
+ app_id=app_id,
105
+ app_slug=app_slug,
106
+ variant_slug=variant_slug,
107
+ )
108
+ return message
109
+
110
+ @classmethod
111
+ async def adelete(
112
+ cls,
113
+ *,
114
+ variant_slug: str,
115
+ #
116
+ app_id: Optional[str] = None,
117
+ app_slug: Optional[str] = None,
118
+ ):
119
+ message = await SharedManager.adelete(
120
+ app_id=app_id,
121
+ app_slug=app_slug,
122
+ variant_slug=variant_slug,
123
+ )
124
+ return message
125
+
126
+ @classmethod
127
+ def list(
128
+ cls,
129
+ *,
130
+ app_id: Optional[str] = None,
131
+ app_slug: Optional[str] = None,
132
+ ):
133
+ variants = SharedManager.list(
134
+ app_id=app_id,
135
+ app_slug=app_slug,
136
+ )
137
+ return variants
138
+
139
+ @classmethod
140
+ async def alist(
141
+ cls,
142
+ *,
143
+ app_id: Optional[str] = None,
144
+ app_slug: Optional[str] = None,
145
+ ):
146
+ variants = await SharedManager.alist(
147
+ app_id=app_id,
148
+ app_slug=app_slug,
149
+ )
150
+ return variants
151
+
152
+ @classmethod
153
+ def history(
154
+ cls,
155
+ *,
156
+ variant_slug: str,
157
+ #
158
+ app_id: Optional[str] = None,
159
+ app_slug: Optional[str] = None,
160
+ ):
161
+ variants = SharedManager.history(
162
+ app_id=app_id,
163
+ app_slug=app_slug,
164
+ variant_slug=variant_slug,
165
+ )
166
+ return variants
167
+
168
+ @classmethod
169
+ async def ahistory(
170
+ cls,
171
+ *,
172
+ variant_slug: str,
173
+ #
174
+ app_id: Optional[str] = None,
175
+ app_slug: Optional[str] = None,
176
+ ):
177
+ variants = await SharedManager.ahistory(
178
+ app_id=app_id,
179
+ app_slug=app_slug,
180
+ variant_slug=variant_slug,
181
+ )
182
+ return variants
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"}
@@ -0,0 +1 @@
1
+ from .tracing import Tracing, get_tracer
@@ -0,0 +1,141 @@
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(
97
+ namespace: Optional[str] = None,
98
+ key: str = "",
99
+ ) -> str:
100
+ if namespace is None:
101
+ return key
102
+
103
+ return f"ag.{namespace}.{key}"
104
+
105
+
106
+ def _encode_value(
107
+ value: Any,
108
+ ) -> Optional[Attribute]:
109
+ if value is None:
110
+ return None
111
+
112
+ if isinstance(value, (str, int, float, bool, bytes)):
113
+ return value
114
+
115
+ if isinstance(value, dict) or isinstance(value, list):
116
+ encoded = dumps(value)
117
+ value = "@ag.type=json:" + encoded
118
+ return value
119
+
120
+ return repr(value)
121
+
122
+
123
+ def serialize(
124
+ *,
125
+ namespace: str,
126
+ attributes: Dict[str, Any],
127
+ max_depth: Optional[int] = None,
128
+ ) -> Dict[str, str]:
129
+ if not isinstance(attributes, dict):
130
+ return {}
131
+
132
+ _attributes = {
133
+ k: v
134
+ for k, v in {
135
+ _encode_key(namespace, key): _encode_value(value)
136
+ for key, value in _marshal(attributes, max_depth=max_depth).items()
137
+ }.items()
138
+ if v is not None
139
+ }
140
+
141
+ return _attributes
@@ -0,0 +1,24 @@
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("----------------------------------------------")
19
+ log.error("Agenta SDK - handling tracing exception below:")
20
+ log.error("----------------------------------------------")
21
+ log.error(format_exc().strip("\n"))
22
+ log.error("----------------------------------------------")
23
+ finally:
24
+ tracing_context.reset(token)
@@ -0,0 +1,49 @@
1
+ from enum import Enum
2
+ from re import fullmatch
3
+
4
+ from opentelemetry.trace import SpanKind
5
+
6
+
7
+ class Reference(str, Enum):
8
+ #
9
+ VARIANT_ID = "variant.id"
10
+ VARIANT_SLUG = "variant.slug"
11
+ VARIANT_VERSION = "variant.version"
12
+ #
13
+ ENVIRONMENT_ID = "environment.id"
14
+ ENVIRONMENT_SLUG = "environment.slug"
15
+ ENVIRONMENT_VERSION = "environment.version"
16
+ #
17
+ APPLICATION_ID = "application.id"
18
+ APPLICATION_SLUG = "application.slug"
19
+ #
20
+
21
+
22
+ _PATTERN = r"[A-Za-z0-9._-]+"
23
+
24
+
25
+ def is_valid_attribute_key(
26
+ string: str,
27
+ ):
28
+ return bool(fullmatch(_PATTERN, string))
29
+
30
+
31
+ def parse_span_kind(type: str) -> SpanKind:
32
+ kind = SpanKind.INTERNAL
33
+ if type in [
34
+ "agent",
35
+ "chain",
36
+ "workflow",
37
+ ]:
38
+ kind = SpanKind.SERVER
39
+ elif type in [
40
+ "tool",
41
+ "embedding",
42
+ "query",
43
+ "completion",
44
+ "chat",
45
+ "rerank",
46
+ ]:
47
+ kind = SpanKind.CLIENT
48
+
49
+ return kind
@@ -0,0 +1,65 @@
1
+ from typing import Sequence, Dict, List
2
+
3
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
4
+ from opentelemetry.sdk.trace.export import (
5
+ ConsoleSpanExporter,
6
+ SpanExporter,
7
+ SpanExportResult,
8
+ ReadableSpan,
9
+ )
10
+
11
+ from agenta.sdk.utils.exceptions import suppress
12
+
13
+
14
+ class InlineTraceExporter(SpanExporter):
15
+ def __init__(self, registry: Dict[str, List[ReadableSpan]]):
16
+ self._shutdown = False
17
+ self._registry = registry
18
+
19
+ def export(
20
+ self,
21
+ spans: Sequence[ReadableSpan],
22
+ ) -> SpanExportResult:
23
+ if self._shutdown:
24
+ return
25
+
26
+ with suppress():
27
+ for span in spans:
28
+ trace_id = span.get_span_context().trace_id
29
+
30
+ if trace_id not in self._registry:
31
+ self._registry[trace_id] = []
32
+
33
+ self._registry[trace_id].append(span)
34
+
35
+ def shutdown(self) -> None:
36
+ self._shutdown = True
37
+
38
+ def force_flush(self, timeout_millis: int = 30000) -> bool:
39
+ return True
40
+
41
+ def is_ready(
42
+ self,
43
+ trace_id: int,
44
+ ) -> bool:
45
+ is_ready = trace_id in self._registry
46
+
47
+ return is_ready
48
+
49
+ def fetch(
50
+ self,
51
+ trace_id: int,
52
+ ) -> List[ReadableSpan]:
53
+ trace = self._registry.get(trace_id, [])
54
+
55
+ if trace_id in self._registry:
56
+ del self._registry[trace_id]
57
+
58
+ return trace
59
+
60
+
61
+ OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
62
+
63
+ ConsoleExporter = ConsoleSpanExporter
64
+ InlineExporter = InlineTraceExporter
65
+ OTLPExporter = OTLPSpanExporter