agenta 0.25.4__py3-none-any.whl → 0.25.4a1__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 +6 -7
  2. agenta/client/backend/client.py +22 -14
  3. agenta/client/backend/core/http_client.py +23 -15
  4. agenta/client/backend/core/pydantic_utilities.py +2 -2
  5. agenta/sdk/__init__.py +27 -6
  6. agenta/sdk/agenta_init.py +73 -26
  7. agenta/sdk/config_manager.py +2 -2
  8. agenta/sdk/context/__init__.py +0 -0
  9. agenta/sdk/context/routing.py +25 -0
  10. agenta/sdk/context/tracing.py +3 -0
  11. agenta/sdk/decorators/__init__.py +0 -0
  12. agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +138 -124
  13. agenta/sdk/decorators/tracing.py +247 -79
  14. agenta/sdk/litellm/__init__.py +1 -0
  15. agenta/sdk/litellm/litellm.py +275 -0
  16. agenta/sdk/router.py +0 -7
  17. agenta/sdk/tracing/__init__.py +1 -0
  18. agenta/sdk/tracing/attributes.py +181 -0
  19. agenta/sdk/tracing/context.py +21 -0
  20. agenta/sdk/tracing/conventions.py +43 -0
  21. agenta/sdk/tracing/exporters.py +53 -0
  22. agenta/sdk/tracing/inline.py +1269 -0
  23. agenta/sdk/tracing/processors.py +65 -0
  24. agenta/sdk/tracing/spans.py +124 -0
  25. agenta/sdk/tracing/tracing.py +174 -0
  26. agenta/sdk/types.py +0 -12
  27. agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
  28. agenta/sdk/utils/debug.py +5 -5
  29. agenta/sdk/utils/exceptions.py +19 -0
  30. agenta/sdk/utils/globals.py +3 -5
  31. agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
  32. agenta/sdk/utils/singleton.py +13 -0
  33. {agenta-0.25.4.dist-info → agenta-0.25.4a1.dist-info}/METADATA +4 -2
  34. {agenta-0.25.4.dist-info → agenta-0.25.4a1.dist-info}/RECORD +36 -26
  35. {agenta-0.25.4.dist-info → agenta-0.25.4a1.dist-info}/WHEEL +1 -1
  36. agenta/sdk/context.py +0 -41
  37. agenta/sdk/decorators/base.py +0 -10
  38. agenta/sdk/tracing/callbacks.py +0 -187
  39. agenta/sdk/tracing/llm_tracing.py +0 -617
  40. agenta/sdk/tracing/tasks_manager.py +0 -129
  41. agenta/sdk/tracing/tracing_context.py +0 -27
  42. {agenta-0.25.4.dist-info → agenta-0.25.4a1.dist-info}/entry_points.txt +0 -0
agenta/__init__.py CHANGED
@@ -1,7 +1,5 @@
1
1
  from .sdk.utils.preinit import PreInitObject
2
- from .sdk.context import get_contexts, save_context
3
2
  from .sdk.types import (
4
- Context,
5
3
  DictInput,
6
4
  MultipleChoice,
7
5
  FloatParam,
@@ -15,16 +13,17 @@ from .sdk.types import (
15
13
  BinaryParam,
16
14
  )
17
15
 
18
- from .sdk.tracing.logger import llm_logger as logging
19
- from .sdk.tracing.llm_tracing import Tracing
16
+ from .sdk.utils.logging import log as logging
17
+ from .sdk.tracing import Tracing
20
18
  from .sdk.decorators.tracing import instrument
21
- from .sdk.decorators.llm_entrypoint import entrypoint, app, route
19
+ from .sdk.decorators.routing import entrypoint, app, route
22
20
  from .sdk.agenta_init import Config, AgentaSingleton, init
23
- from .sdk.utils.helper.openai_cost import calculate_token_usage
21
+ from .sdk.utils.costs import calculate_token_usage
24
22
  from .sdk.client import Agenta
25
- from .sdk.tracing import callbacks
23
+ from .sdk.litellm import litellm as callbacks
26
24
  from .sdk.config_manager import ConfigManager
27
25
  from .sdk import assets as assets
26
+ from .sdk import tracer
28
27
 
29
28
  config = PreInitObject("agenta.config", Config)
30
29
  DEFAULT_AGENTA_SINGLETON_INSTANCE = AgentaSingleton()
@@ -88,13 +88,17 @@ class AgentaApi:
88
88
  self._client_wrapper = SyncClientWrapper(
89
89
  base_url=base_url,
90
90
  api_key=api_key,
91
- httpx_client=httpx_client
92
- if httpx_client is not None
93
- else httpx.Client(
94
- timeout=_defaulted_timeout, follow_redirects=follow_redirects
95
- )
96
- if follow_redirects is not None
97
- else httpx.Client(timeout=_defaulted_timeout),
91
+ httpx_client=(
92
+ httpx_client
93
+ if httpx_client is not None
94
+ else (
95
+ httpx.Client(
96
+ timeout=_defaulted_timeout, follow_redirects=follow_redirects
97
+ )
98
+ if follow_redirects is not None
99
+ else httpx.Client(timeout=_defaulted_timeout)
100
+ )
101
+ ),
98
102
  timeout=_defaulted_timeout,
99
103
  )
100
104
  self.observability = ObservabilityClient(client_wrapper=self._client_wrapper)
@@ -1603,13 +1607,17 @@ class AsyncAgentaApi:
1603
1607
  self._client_wrapper = AsyncClientWrapper(
1604
1608
  base_url=base_url,
1605
1609
  api_key=api_key,
1606
- httpx_client=httpx_client
1607
- if httpx_client is not None
1608
- else httpx.AsyncClient(
1609
- timeout=_defaulted_timeout, follow_redirects=follow_redirects
1610
- )
1611
- if follow_redirects is not None
1612
- else httpx.AsyncClient(timeout=_defaulted_timeout),
1610
+ httpx_client=(
1611
+ httpx_client
1612
+ if httpx_client is not None
1613
+ else (
1614
+ httpx.AsyncClient(
1615
+ timeout=_defaulted_timeout, follow_redirects=follow_redirects
1616
+ )
1617
+ if follow_redirects is not None
1618
+ else httpx.AsyncClient(timeout=_defaulted_timeout)
1619
+ )
1620
+ ),
1613
1621
  timeout=_defaulted_timeout,
1614
1622
  )
1615
1623
  self.observability = AsyncObservabilityClient(
@@ -148,9 +148,9 @@ def get_request_body(
148
148
  json_body = maybe_filter_request_body(json, request_options, omit)
149
149
 
150
150
  # If you have an empty JSON body, you should just send None
151
- return (
152
- json_body if json_body != {} else None
153
- ), data_body if data_body != {} else None
151
+ return (json_body if json_body != {} else None), (
152
+ data_body if data_body != {} else None
153
+ )
154
154
 
155
155
 
156
156
  class HttpClient:
@@ -246,9 +246,11 @@ class HttpClient:
246
246
  json=json_body,
247
247
  data=data_body,
248
248
  content=content,
249
- files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
250
- if files is not None
251
- else None,
249
+ files=(
250
+ convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
251
+ if files is not None
252
+ else None
253
+ ),
252
254
  timeout=timeout,
253
255
  )
254
256
 
@@ -345,9 +347,11 @@ class HttpClient:
345
347
  json=json_body,
346
348
  data=data_body,
347
349
  content=content,
348
- files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
349
- if files is not None
350
- else None,
350
+ files=(
351
+ convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
352
+ if files is not None
353
+ else None
354
+ ),
351
355
  timeout=timeout,
352
356
  ) as stream:
353
357
  yield stream
@@ -447,9 +451,11 @@ class AsyncHttpClient:
447
451
  json=json_body,
448
452
  data=data_body,
449
453
  content=content,
450
- files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
451
- if files is not None
452
- else None,
454
+ files=(
455
+ convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
456
+ if files is not None
457
+ else None
458
+ ),
453
459
  timeout=timeout,
454
460
  )
455
461
 
@@ -545,9 +551,11 @@ class AsyncHttpClient:
545
551
  json=json_body,
546
552
  data=data_body,
547
553
  content=content,
548
- files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
549
- if files is not None
550
- else None,
554
+ files=(
555
+ convert_file_dict_to_httpx_tuples(remove_none_from_dict(files))
556
+ if files is not None
557
+ else None
558
+ ),
551
559
  timeout=timeout,
552
560
  ) as stream:
553
561
  yield stream
@@ -77,8 +77,8 @@ def to_jsonable_with_fallback(
77
77
  class UniversalBaseModel(pydantic.BaseModel):
78
78
  class Config:
79
79
  populate_by_name = True
80
- smart_union = True
81
- allow_population_by_field_name = True
80
+ # smart_union = True
81
+ # allow_population_by_field_name = True
82
82
  json_encoders = {dt.datetime: serialize_datetime}
83
83
 
84
84
  def json(self, **kwargs: typing.Any) -> str:
agenta/sdk/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
+ from typing import Optional
2
+
1
3
  from .utils.preinit import PreInitObject # always the first import!
2
- from .context import get_contexts, save_context
3
4
  from .types import (
4
- Context,
5
5
  DictInput,
6
6
  MultipleChoice,
7
7
  FloatParam,
@@ -15,13 +15,34 @@ from .types import (
15
15
  BinaryParam,
16
16
  )
17
17
 
18
- from .tracing.llm_tracing import Tracing
18
+ from .tracing import Tracing, get_tracer
19
19
  from .decorators.tracing import instrument
20
- from .decorators.llm_entrypoint import entrypoint, app, route
21
- from .agenta_init import Config, AgentaSingleton, init
22
- from .utils.helper.openai_cost import calculate_token_usage
20
+ from .decorators.routing import entrypoint, app, route
21
+ from .agenta_init import Config, AgentaSingleton, init as _init
22
+ from .utils.costs import calculate_token_usage
23
23
  from .config_manager import ConfigManager
24
24
 
25
25
  config = PreInitObject("agenta.config", Config)
26
26
  DEFAULT_AGENTA_SINGLETON_INSTANCE = AgentaSingleton()
27
27
  tracing = DEFAULT_AGENTA_SINGLETON_INSTANCE.tracing # type: ignore
28
+
29
+ tracer = get_tracer(tracing)
30
+
31
+
32
+ def init(
33
+ host: Optional[str] = None,
34
+ app_id: Optional[str] = None,
35
+ api_key: Optional[str] = None,
36
+ config_fname: Optional[str] = None,
37
+ ):
38
+ global tracing
39
+ global tracer
40
+
41
+ _init(
42
+ host=host,
43
+ app_id=app_id,
44
+ api_key=api_key,
45
+ config_fname=config_fname,
46
+ )
47
+
48
+ tracer = get_tracer(tracing)
agenta/sdk/agenta_init.py CHANGED
@@ -2,10 +2,12 @@ import os
2
2
  import logging
3
3
  import toml
4
4
  from typing import Optional
5
+ from importlib.metadata import version
5
6
 
7
+ from agenta.sdk.utils.logging import log
6
8
  from agenta.sdk.utils.globals import set_global
7
9
  from agenta.client.backend.client import AgentaApi
8
- from agenta.sdk.tracing.llm_tracing import Tracing
10
+ from agenta.sdk.tracing import Tracing
9
11
  from agenta.client.exceptions import APIRequestError
10
12
 
11
13
 
@@ -17,9 +19,8 @@ class AgentaSingleton:
17
19
  """Singleton class to save all the "global variables" for the sdk."""
18
20
 
19
21
  _instance = None
20
- setup = None
21
22
  config = None
22
- tracing: Optional[Tracing] = None
23
+ tracing = None
23
24
 
24
25
  def __new__(cls):
25
26
  if not cls._instance:
@@ -28,11 +29,18 @@ class AgentaSingleton:
28
29
 
29
30
  def init(
30
31
  self,
31
- app_id: Optional[str] = None,
32
+ *,
32
33
  host: Optional[str] = None,
34
+ project_id: Optional[str] = None,
33
35
  api_key: Optional[str] = None,
34
36
  config_fname: Optional[str] = None,
37
+ #
38
+ app_id: Optional[str] = None,
35
39
  ) -> None:
40
+ log.info(f"\n--------------------------------")
41
+ log.info(f"Using Agenta Python SDK version: {version('agenta')}")
42
+ log.info(f"--------------------------------\n")
43
+
36
44
  """Main function to initialize the singleton.
37
45
 
38
46
  Initializes the singleton with the given `app_id`, `host`, and `api_key`. The order of precedence for these variables is:
@@ -54,20 +62,20 @@ class AgentaSingleton:
54
62
  Raises:
55
63
  ValueError: If `app_id` is not specified either as an argument, in the config file, or in the environment variables.
56
64
  """
65
+
57
66
  config = {}
58
67
  if config_fname:
59
68
  config = toml.load(config_fname)
60
69
 
61
- self.app_id = app_id or config.get("app_id") or os.environ.get("AGENTA_APP_ID")
62
70
  self.host = (
63
71
  host
72
+ or os.environ.get("AGENTA_HOST")
64
73
  or config.get("backend_host")
65
- or os.environ.get("AGENTA_HOST", "https://cloud.agenta.ai")
66
- )
67
- self.api_key = (
68
- api_key or config.get("api_key") or os.environ.get("AGENTA_API_KEY")
74
+ or config.get("host")
75
+ or "https://cloud.agenta.ai"
69
76
  )
70
77
 
78
+ self.app_id = app_id or config.get("app_id") or os.environ.get("AGENTA_APP_ID")
71
79
  if not self.app_id:
72
80
  raise ValueError(
73
81
  "App ID must be specified. You can provide it in one of the following ways:\n"
@@ -75,26 +83,60 @@ class AgentaSingleton:
75
83
  "2. In the configuration file specified by config_fname.\n"
76
84
  "3. As an environment variable 'AGENTA_APP_ID'."
77
85
  )
86
+
87
+ self.project_id = (
88
+ project_id
89
+ or config.get("project_id")
90
+ or os.environ.get("AGENTA_PROJECT_ID")
91
+ )
92
+
93
+ self.api_key = (
94
+ api_key or config.get("api_key") or os.environ.get("AGENTA_API_KEY")
95
+ )
96
+
97
+ self.tracing = Tracing(
98
+ url=f"{self.host}/api/observability/v1/traces", # type: ignore
99
+ )
100
+
101
+ self.tracing.configure(
102
+ project_id=self.project_id,
103
+ api_key=self.api_key,
104
+ # DEPRECATED
105
+ app_id=self.app_id,
106
+ )
107
+
78
108
  self.base_id = os.environ.get("AGENTA_BASE_ID")
79
- if self.base_id is None:
80
- print(
81
- "Warning: Your configuration will not be saved permanently since base_id is not provided."
82
- )
83
109
 
84
- self.config = Config(base_id=self.base_id, host=self.host, api_key=self.api_key) # type: ignore
110
+ self.config = Config(
111
+ host=self.host,
112
+ base_id=self.base_id,
113
+ api_key=self.api_key,
114
+ )
85
115
 
86
116
 
87
117
  class Config:
88
- def __init__(self, base_id: str, host: str, api_key: Optional[str] = ""):
89
- self.base_id = base_id
118
+ def __init__(
119
+ self,
120
+ host: str,
121
+ base_id: Optional[str] = None,
122
+ api_key: Optional[str] = "",
123
+ ):
90
124
  self.host = host
91
125
 
126
+ self.base_id = base_id
127
+
128
+ if self.base_id is None:
129
+ print(
130
+ "Warning: Your configuration will not be saved permanently since base_id is not provided.\n"
131
+ )
132
+
92
133
  if base_id is None or host is None:
93
134
  self.persist = False
94
135
  else:
95
136
  self.persist = True
96
137
  self.client = AgentaApi(
97
- base_url=self.host + "/api", api_key=api_key if api_key else ""
138
+ base_url=self.host + "/api",
139
+ api_key=api_key if api_key else "",
98
140
  )
99
141
 
100
142
  def register_default(self, overwrite=False, **kwargs):
@@ -208,11 +250,12 @@ class Config:
208
250
 
209
251
 
210
252
  def init(
211
- app_id: Optional[str] = None,
212
253
  host: Optional[str] = None,
254
+ project_id: Optional[str] = None,
213
255
  api_key: Optional[str] = None,
214
256
  config_fname: Optional[str] = None,
215
- max_workers: Optional[int] = None,
257
+ # DEPRECATED
258
+ app_id: Optional[str] = None,
216
259
  ):
217
260
  """Main function to initialize the agenta sdk.
218
261
 
@@ -238,12 +281,16 @@ def init(
238
281
 
239
282
  singleton = AgentaSingleton()
240
283
 
241
- singleton.init(app_id=app_id, host=host, api_key=api_key, config_fname=config_fname)
284
+ singleton.init(
285
+ host=host,
286
+ project_id=project_id,
287
+ api_key=api_key,
288
+ config_fname=config_fname,
289
+ # DEPRECATED
290
+ app_id=app_id,
291
+ )
242
292
 
243
- tracing = Tracing(
244
- host=singleton.host, # type: ignore
245
- app_id=singleton.app_id, # type: ignore
246
- api_key=singleton.api_key,
247
- max_workers=max_workers,
293
+ set_global(
294
+ config=singleton.config,
295
+ tracing=singleton.tracing,
248
296
  )
249
- set_global(setup=singleton.setup, config=singleton.config, tracing=tracing)
@@ -7,7 +7,7 @@ import yaml
7
7
  from pydantic import BaseModel, ValidationError
8
8
 
9
9
  from agenta.client.backend.client import AgentaApi
10
- from agenta.sdk.decorators.llm_entrypoint import route_context
10
+ from agenta.sdk.context.routing import routing_context
11
11
 
12
12
  from . import AgentaSingleton
13
13
 
@@ -47,7 +47,7 @@ class ConfigManager:
47
47
  3. 'variant'
48
48
  Only one of these should be provided.
49
49
  """
50
- context = route_context.get()
50
+ context = routing_context.get()
51
51
  if ("config" in context and context["config"]) and (
52
52
  ("environment" in context and context["environment"])
53
53
  or ("variant" in context and context["variant"])
File without changes
@@ -0,0 +1,25 @@
1
+ from contextlib import contextmanager
2
+ from contextvars import ContextVar
3
+ from typing import Any, Dict, Optional
4
+
5
+ routing_context = ContextVar("routing_context", default={})
6
+
7
+
8
+ @contextmanager
9
+ def routing_context_manager(
10
+ config: Optional[Dict[str, Any]] = None,
11
+ environment: Optional[str] = None,
12
+ version: Optional[str] = None,
13
+ variant: Optional[str] = None,
14
+ ):
15
+ context = {
16
+ "config": config,
17
+ "environment": environment,
18
+ "version": version,
19
+ "variant": variant,
20
+ }
21
+ token = routing_context.set(context)
22
+ try:
23
+ yield
24
+ finally:
25
+ routing_context.reset(token)
@@ -0,0 +1,3 @@
1
+ from contextvars import ContextVar
2
+
3
+ tracing_context = ContextVar("tracing_context", default={})
File without changes