agenta 0.27.0a8__py3-none-any.whl → 0.27.0a12__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 (62) hide show
  1. agenta/__init__.py +21 -3
  2. agenta/client/backend/__init__.py +14 -0
  3. agenta/client/backend/apps/client.py +28 -20
  4. agenta/client/backend/client.py +25 -2
  5. agenta/client/backend/containers/client.py +5 -1
  6. agenta/client/backend/core/__init__.py +2 -1
  7. agenta/client/backend/core/client_wrapper.py +6 -6
  8. agenta/client/backend/core/file.py +33 -11
  9. agenta/client/backend/core/http_client.py +24 -18
  10. agenta/client/backend/core/pydantic_utilities.py +144 -29
  11. agenta/client/backend/core/request_options.py +3 -0
  12. agenta/client/backend/core/serialization.py +139 -42
  13. agenta/client/backend/evaluations/client.py +7 -2
  14. agenta/client/backend/evaluators/client.py +349 -1
  15. agenta/client/backend/observability/client.py +11 -2
  16. agenta/client/backend/testsets/client.py +10 -10
  17. agenta/client/backend/types/__init__.py +14 -0
  18. agenta/client/backend/types/app.py +1 -0
  19. agenta/client/backend/types/app_variant_response.py +3 -1
  20. agenta/client/backend/types/config_dto.py +32 -0
  21. agenta/client/backend/types/config_response_model.py +32 -0
  22. agenta/client/backend/types/create_span.py +3 -2
  23. agenta/client/backend/types/environment_output.py +1 -0
  24. agenta/client/backend/types/environment_output_extended.py +1 -0
  25. agenta/client/backend/types/evaluation.py +1 -2
  26. agenta/client/backend/types/evaluator.py +2 -0
  27. agenta/client/backend/types/evaluator_config.py +1 -0
  28. agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
  29. agenta/client/backend/types/evaluator_output_interface.py +21 -0
  30. agenta/client/backend/types/human_evaluation.py +1 -2
  31. agenta/client/backend/types/lifecycle_dto.py +24 -0
  32. agenta/client/backend/types/llm_tokens.py +2 -2
  33. agenta/client/backend/types/reference_dto.py +23 -0
  34. agenta/client/backend/types/reference_request_model.py +23 -0
  35. agenta/client/backend/types/span.py +1 -0
  36. agenta/client/backend/types/span_detail.py +7 -1
  37. agenta/client/backend/types/test_set_output_response.py +5 -2
  38. agenta/client/backend/types/trace_detail.py +7 -1
  39. agenta/client/backend/types/with_pagination.py +4 -2
  40. agenta/client/backend/variants/client.py +1565 -272
  41. agenta/sdk/__init__.py +19 -5
  42. agenta/sdk/agenta_init.py +21 -7
  43. agenta/sdk/context/routing.py +6 -5
  44. agenta/sdk/decorators/routing.py +16 -5
  45. agenta/sdk/decorators/tracing.py +16 -9
  46. agenta/sdk/litellm/litellm.py +47 -36
  47. agenta/sdk/managers/__init__.py +6 -0
  48. agenta/sdk/managers/config.py +318 -0
  49. agenta/sdk/managers/deployment.py +45 -0
  50. agenta/sdk/managers/shared.py +639 -0
  51. agenta/sdk/managers/variant.py +182 -0
  52. agenta/sdk/tracing/exporters.py +10 -1
  53. agenta/sdk/tracing/inline.py +45 -0
  54. agenta/sdk/tracing/processors.py +34 -7
  55. agenta/sdk/tracing/tracing.py +0 -10
  56. agenta/sdk/types.py +47 -2
  57. agenta/sdk/utils/exceptions.py +31 -1
  58. {agenta-0.27.0a8.dist-info → agenta-0.27.0a12.dist-info}/METADATA +1 -1
  59. {agenta-0.27.0a8.dist-info → agenta-0.27.0a12.dist-info}/RECORD +61 -50
  60. agenta/sdk/config_manager.py +0 -205
  61. {agenta-0.27.0a8.dist-info → agenta-0.27.0a12.dist-info}/WHEEL +0 -0
  62. {agenta-0.27.0a8.dist-info → agenta-0.27.0a12.dist-info}/entry_points.txt +0 -0
agenta/sdk/__init__.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from typing import Optional
2
2
 
3
3
  from .utils.preinit import PreInitObject # always the first import!
4
+
5
+ import agenta.client.backend.types as client_types # pylint: disable=wrong-import-order
6
+
4
7
  from .types import (
5
8
  DictInput,
6
9
  MultipleChoice,
@@ -21,12 +24,19 @@ from .tracing.conventions import Reference
21
24
  from .decorators.routing import entrypoint, app, route
22
25
  from .agenta_init import Config, AgentaSingleton, init as _init
23
26
  from .utils.costs import calculate_token_usage
24
- from .config_manager import ConfigManager
27
+ from .managers.config import ConfigManager
28
+ from .managers.variant import VariantManager
29
+ from .managers.deployment import DeploymentManager
25
30
 
26
31
  config = PreInitObject("agenta.config", Config)
27
32
  DEFAULT_AGENTA_SINGLETON_INSTANCE = AgentaSingleton()
28
- tracing = DEFAULT_AGENTA_SINGLETON_INSTANCE.tracing # type: ignore
29
33
 
34
+ types = client_types
35
+
36
+ api = None
37
+ async_api = None
38
+
39
+ tracing = DEFAULT_AGENTA_SINGLETON_INSTANCE.tracing # type: ignore
30
40
  tracer = get_tracer(tracing)
31
41
 
32
42
 
@@ -36,14 +46,18 @@ def init(
36
46
  api_key: Optional[str] = None,
37
47
  config_fname: Optional[str] = None,
38
48
  ):
39
- global tracing
40
- global tracer
49
+ global api, async_api, tracing, tracer
41
50
 
42
51
  _init(
43
52
  host=host,
44
- app_id=app_id,
45
53
  api_key=api_key,
46
54
  config_fname=config_fname,
55
+ # DEPRECATING
56
+ app_id=app_id,
47
57
  )
48
58
 
59
+ api = DEFAULT_AGENTA_SINGLETON_INSTANCE.api # type: ignore
60
+ async_api = DEFAULT_AGENTA_SINGLETON_INSTANCE.async_api # type: ignore
61
+
62
+ tracing = DEFAULT_AGENTA_SINGLETON_INSTANCE.tracing # type: ignore
49
63
  tracer = get_tracer(tracing)
agenta/sdk/agenta_init.py CHANGED
@@ -6,7 +6,7 @@ from importlib.metadata import version
6
6
 
7
7
  from agenta.sdk.utils.logging import log
8
8
  from agenta.sdk.utils.globals import set_global
9
- from agenta.client.backend.client import AgentaApi
9
+ from agenta.client.backend.client import AgentaApi, AsyncAgentaApi
10
10
  from agenta.sdk.tracing import Tracing
11
11
  from agenta.client.exceptions import APIRequestError
12
12
 
@@ -22,6 +22,9 @@ class AgentaSingleton:
22
22
  config = None
23
23
  tracing = None
24
24
 
25
+ api = None
26
+ async_api = None
27
+
25
28
  def __new__(cls):
26
29
  if not cls._instance:
27
30
  cls._instance = super(AgentaSingleton, cls).__new__(cls)
@@ -33,14 +36,11 @@ class AgentaSingleton:
33
36
  host: Optional[str] = None,
34
37
  api_key: Optional[str] = None,
35
38
  config_fname: Optional[str] = None,
36
- #
39
+ # DEPRECATING
37
40
  app_id: Optional[str] = None,
38
41
  ) -> None:
39
- log.info(f"---------------------------")
40
- log.info(f"Agenta SDK - using version: {version('agenta')}")
41
- log.info(f"---------------------------")
42
-
43
- """Main function to initialize the singleton.
42
+ """
43
+ Main function to initialize the singleton.
44
44
 
45
45
  Initializes the singleton with the given `app_id`, `host`, and `api_key`. The order of precedence for these variables is:
46
46
  1. Explicit argument provided in the function call.
@@ -62,6 +62,10 @@ class AgentaSingleton:
62
62
  ValueError: If `app_id` is not specified either as an argument, in the config file, or in the environment variables.
63
63
  """
64
64
 
65
+ log.info("---------------------------")
66
+ log.info("Agenta SDK - using version: %s", version("agenta"))
67
+ log.info("---------------------------")
68
+
65
69
  config = {}
66
70
  if config_fname:
67
71
  config = toml.load(config_fname)
@@ -97,6 +101,16 @@ class AgentaSingleton:
97
101
  app_id=self.app_id,
98
102
  )
99
103
 
104
+ self.api = AgentaApi(
105
+ base_url=self.host + "/api",
106
+ api_key=api_key if api_key else "",
107
+ )
108
+
109
+ self.async_api = AsyncAgentaApi(
110
+ base_url=self.host + "/api",
111
+ api_key=api_key if api_key else "",
112
+ )
113
+
100
114
  self.base_id = os.environ.get("AGENTA_BASE_ID")
101
115
 
102
116
  self.config = Config(
@@ -7,16 +7,17 @@ routing_context = ContextVar("routing_context", default={})
7
7
 
8
8
  @contextmanager
9
9
  def routing_context_manager(
10
+ *,
10
11
  config: Optional[Dict[str, Any]] = None,
11
- environment: Optional[str] = None,
12
- version: Optional[str] = None,
13
- variant: Optional[str] = None,
12
+ application: Optional[Dict[str, Any]] = None,
13
+ variant: Optional[Dict[str, Any]] = None,
14
+ environment: Optional[Dict[str, Any]] = None,
14
15
  ):
15
16
  context = {
16
17
  "config": config,
17
- "environment": environment,
18
- "version": version,
18
+ "application": application,
19
19
  "variant": variant,
20
+ "environment": environment,
20
21
  }
21
22
  token = routing_context.set(context)
22
23
  try:
@@ -9,6 +9,7 @@ from asyncio import sleep, get_event_loop
9
9
  from traceback import format_exc, format_exception
10
10
  from pathlib import Path
11
11
  from tempfile import NamedTemporaryFile
12
+ from os import environ
12
13
 
13
14
  from fastapi.middleware.cors import CORSMiddleware
14
15
  from fastapi import Body, FastAPI, UploadFile, HTTPException
@@ -152,7 +153,6 @@ class entrypoint:
152
153
 
153
154
  with routing_context_manager(
154
155
  config=api_config_params,
155
- environment="playground",
156
156
  ):
157
157
  entrypoint_result = await self.execute_function(
158
158
  func,
@@ -209,7 +209,9 @@ class entrypoint:
209
209
  @wraps(func)
210
210
  async def wrapper_deployed(*args, **kwargs) -> Any:
211
211
  func_params = {
212
- k: v for k, v in kwargs.items() if k not in ["config", "environment"]
212
+ k: v
213
+ for k, v in kwargs.items()
214
+ if k not in ["config", "environment", "app"]
213
215
  }
214
216
  if not config_schema:
215
217
  if "environment" in kwargs and kwargs["environment"] is not None:
@@ -219,10 +221,19 @@ class entrypoint:
219
221
  else:
220
222
  ag.config.pull(config_name="default")
221
223
 
224
+ app_id = environ.get("AGENTA_APP_ID")
225
+
222
226
  with routing_context_manager(
223
- config=config_params,
224
- variant=kwargs["config"],
225
- environment=kwargs["environment"],
227
+ application={
228
+ "id": app_id,
229
+ "slug": kwargs["app"],
230
+ },
231
+ variant={
232
+ "slug": kwargs.get("config"),
233
+ },
234
+ environment={
235
+ "slug": kwargs.get("environment"),
236
+ },
226
237
  ):
227
238
  entrypoint_result = await self.execute_function(
228
239
  func,
@@ -10,12 +10,12 @@ from agenta.sdk.tracing.conventions import parse_span_kind
10
10
  import agenta as ag
11
11
 
12
12
 
13
- class instrument:
13
+ class instrument: # pylint: disable=invalid-name
14
14
  DEFAULT_KEY = "__default__"
15
15
 
16
16
  def __init__(
17
17
  self,
18
- type: str = "task",
18
+ type: str = "task", # pylint: disable=redefined-builtin
19
19
  config: Optional[Dict[str, Any]] = None,
20
20
  ignore_inputs: Optional[bool] = None,
21
21
  ignore_outputs: Optional[bool] = None,
@@ -196,12 +196,16 @@ class instrument:
196
196
  ignore: Union[List[str], bool] = False,
197
197
  ) -> Dict[str, Any]:
198
198
  """
199
- Redact user-defined sensitive information from inputs and outputs as defined by the ignore list or boolean flag.
199
+ Redact user-defined sensitive information
200
+ from inputs and outputs as defined by the ignore list or boolean flag.
200
201
 
201
202
  Example:
202
- - ignore = ["password"] -> {"username": "admin", "password": "********"} -> {"username": "admin"}
203
- - ignore = True -> {"username": "admin", "password": "********"} -> {}
204
- - ignore = False -> {"username": "admin", "password": "********"} -> {"username": "admin", "password": "********"}
203
+ - ignore = ["password"] -> {"username": "admin", "password": "********"}
204
+ -> {"username": "admin"}
205
+ - ignore = True -> {"username": "admin", "password": "********"}
206
+ -> {}
207
+ - ignore = False -> {"username": "admin", "password": "********"}
208
+ -> {"username": "admin", "password": "********"}
205
209
  """
206
210
  io = {
207
211
  key: value
@@ -226,9 +230,12 @@ class instrument:
226
230
  Patch the result to ensure that it is a dictionary, with a default key when necessary.
227
231
 
228
232
  Example:
229
- - result = "Hello, World!" -> {"__default__": "Hello, World!"}
230
- - result = {"message": "Hello, World!", "cost": 0.0, "usage": {}} -> {"__default__": "Hello, World!"}
231
- - result = {"message": "Hello, World!"} -> {"message": "Hello, World!"}
233
+ - result = "Hello, World!"
234
+ -> {"__default__": "Hello, World!"}
235
+ - result = {"message": "Hello, World!", "cost": 0.0, "usage": {}}
236
+ -> {"__default__": "Hello, World!"}
237
+ - result = {"message": "Hello, World!"}
238
+ -> {"message": "Hello, World!"}
232
239
  """
233
240
  outputs = (
234
241
  {instrument.DEFAULT_KEY: result}
@@ -1,16 +1,15 @@
1
- import agenta as ag
2
-
3
1
  from opentelemetry.trace import SpanKind
4
2
 
3
+ import agenta as ag
4
+
5
5
  from agenta.sdk.tracing.spans import CustomSpan
6
- from agenta.sdk.utils.exceptions import suppress
6
+ from agenta.sdk.utils.exceptions import suppress # TODO: use it !
7
7
  from agenta.sdk.utils.logging import log
8
8
 
9
9
 
10
10
  def litellm_handler():
11
11
  try:
12
- from litellm.utils import ModelResponse
13
- from litellm.integrations.custom_logger import (
12
+ from litellm.integrations.custom_logger import ( # pylint: disable=import-outside-toplevel
14
13
  CustomLogger as LitellmCustomLogger,
15
14
  )
16
15
  except ImportError as exc:
@@ -18,18 +17,23 @@ def litellm_handler():
18
17
  "The litellm SDK is not installed. Please install it using `pip install litellm`."
19
18
  ) from exc
20
19
  except Exception as exc:
21
- raise Exception(
22
- "Unexpected error occurred when importing litellm: {}".format(exc)
20
+ raise Exception( # pylint: disable=broad-exception-raised
21
+ f"Unexpected error occurred when importing litellm: {exc}"
23
22
  ) from exc
24
23
 
25
24
  class LitellmHandler(LitellmCustomLogger):
26
- """This handler is responsible for instrumenting certain events when using litellm to call LLMs.
25
+ """
26
+ This handler is responsible for instrumenting certain events,
27
+ when using litellm to call LLMs.
27
28
 
28
29
  Args:
29
- LitellmCustomLogger (object): custom logger that allows us to override the events to capture.
30
+ LitellmCustomLogger (object): custom logger that allows us
31
+ to override the events to capture.
30
32
  """
31
33
 
32
34
  def __init__(self):
35
+ super().__init__()
36
+
33
37
  self.span = None
34
38
 
35
39
  def log_pre_api_call(
@@ -38,7 +42,7 @@ def litellm_handler():
38
42
  messages,
39
43
  kwargs,
40
44
  ):
41
- type = (
45
+ type = ( # pylint: disable=redefined-builtin
42
46
  "chat"
43
47
  if kwargs.get("call_type") in ["completion", "acompletion"]
44
48
  else "embedding"
@@ -59,10 +63,8 @@ def litellm_handler():
59
63
  log.error("LiteLLM callback error: span not found.")
60
64
  return
61
65
 
62
- log.info(f"log_pre_api_call({hex(self.span.context.span_id)[2:]})")
63
-
64
66
  self.span.set_attributes(
65
- attributes={"inputs": {"messages": kwargs["messages"]}},
67
+ attributes={"inputs": {"prompt": kwargs["messages"]}},
66
68
  namespace="data",
67
69
  )
68
70
 
@@ -87,12 +89,14 @@ def litellm_handler():
87
89
  log.error("LiteLLM callback error: span not found.")
88
90
  return
89
91
 
90
- # log.info(f"log_stream({hex(self.span.context.span_id)[2:]})")
92
+ result = kwargs.get("complete_streaming_response")
93
+
94
+ outputs = (
95
+ {"__default__": result} if not isinstance(result, dict) else result
96
+ )
91
97
 
92
98
  self.span.set_attributes(
93
- attributes={
94
- "output": {"__default__": kwargs.get("complete_streaming_response")}
95
- },
99
+ attributes={"outputs": outputs},
96
100
  namespace="data",
97
101
  )
98
102
 
@@ -127,14 +131,20 @@ def litellm_handler():
127
131
  log.error("LiteLLM callback error: span not found.")
128
132
  return
129
133
 
130
- # log.info(f"log_success({hex(self.span.context.span_id)[2:]})")
134
+ try:
135
+ result = []
136
+ for choice in response_obj.choices:
137
+ message = choice.message.__dict__
138
+ result.append(message)
131
139
 
132
- self.span.set_attributes(
133
- attributes={
134
- "output": {"__default__": response_obj.choices[0].message.content}
135
- },
136
- namespace="data",
137
- )
140
+ outputs = {"completion": result}
141
+ self.span.set_attributes(
142
+ attributes={"outputs": outputs},
143
+ namespace="data",
144
+ )
145
+
146
+ except Exception as e:
147
+ pass
138
148
 
139
149
  self.span.set_attributes(
140
150
  attributes={"total": kwargs.get("response_cost")},
@@ -167,8 +177,6 @@ def litellm_handler():
167
177
  log.error("LiteLLM callback error: span not found.")
168
178
  return
169
179
 
170
- # log.info(f"log_failure({hex(self.span.context.span_id)[2:]})")
171
-
172
180
  self.span.record_exception(kwargs["exception"])
173
181
 
174
182
  self.span.set_status(status="ERROR")
@@ -186,12 +194,14 @@ def litellm_handler():
186
194
  log.error("LiteLLM callback error: span not found.")
187
195
  return
188
196
 
189
- # log.info(f"async_log_stream({hex(self.span.context.span_id)[2:]})")
197
+ result = kwargs.get("complete_streaming_response")
198
+
199
+ outputs = (
200
+ {"__default__": result} if not isinstance(result, dict) else result
201
+ )
190
202
 
191
203
  self.span.set_attributes(
192
- attributes={
193
- "output": {"__default__": kwargs.get("complete_streaming_response")}
194
- },
204
+ attributes={"outputs": outputs},
195
205
  namespace="data",
196
206
  )
197
207
 
@@ -226,12 +236,15 @@ def litellm_handler():
226
236
  log.error("LiteLLM callback error: span not found.")
227
237
  return
228
238
 
229
- log.info(f"async_log_success({hex(self.span.context.span_id)[2:]})")
239
+ # result = kwargs.get("complete_streaming_response")
240
+ result = response_obj.choices[0].message.content
241
+
242
+ outputs = (
243
+ {"__default__": result} if not isinstance(result, dict) else result
244
+ )
230
245
 
231
246
  self.span.set_attributes(
232
- attributes={
233
- "output": {"__default__": kwargs.get("complete_streaming_response")}
234
- },
247
+ attributes={"outputs": outputs},
235
248
  namespace="data",
236
249
  )
237
250
 
@@ -266,8 +279,6 @@ def litellm_handler():
266
279
  log.error("LiteLLM callback error: span not found.")
267
280
  return
268
281
 
269
- # log.info(f"async_log_failure({hex(self.span.context.span_id)[2:]})")
270
-
271
282
  self.span.record_exception(kwargs["exception"])
272
283
 
273
284
  self.span.set_status(status="ERROR")
@@ -0,0 +1,6 @@
1
+ from agenta.sdk.managers.config import ConfigManager
2
+ from agenta.sdk.managers.variant import VariantManager
3
+ from agenta.sdk.managers.deployment import DeploymentManager
4
+
5
+
6
+ __all__ = ["ConfigManager", "VariantManager", "DeploymentManager"]