agenta 0.12.6__py3-none-any.whl → 0.13.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 (89) hide show
  1. agenta/__init__.py +4 -1
  2. agenta/cli/helper.py +1 -1
  3. agenta/cli/main.py +1 -1
  4. agenta/cli/variant_commands.py +7 -5
  5. agenta/client/api.py +1 -1
  6. agenta/client/backend/__init__.py +78 -18
  7. agenta/client/backend/client.py +1031 -5526
  8. agenta/client/backend/resources/__init__.py +31 -0
  9. agenta/client/backend/resources/apps/__init__.py +1 -0
  10. agenta/client/backend/resources/apps/client.py +977 -0
  11. agenta/client/backend/resources/bases/__init__.py +1 -0
  12. agenta/client/backend/resources/bases/client.py +127 -0
  13. agenta/client/backend/resources/configs/__init__.py +1 -0
  14. agenta/client/backend/resources/configs/client.py +377 -0
  15. agenta/client/backend/resources/containers/__init__.py +5 -0
  16. agenta/client/backend/resources/containers/client.py +383 -0
  17. agenta/client/backend/resources/containers/types/__init__.py +5 -0
  18. agenta/client/backend/{types → resources/containers/types}/container_templates_response.py +1 -1
  19. agenta/client/backend/resources/environments/__init__.py +1 -0
  20. agenta/client/backend/resources/environments/client.py +131 -0
  21. agenta/client/backend/resources/evaluations/__init__.py +1 -0
  22. agenta/client/backend/resources/evaluations/client.py +1008 -0
  23. agenta/client/backend/resources/evaluators/__init__.py +1 -0
  24. agenta/client/backend/resources/evaluators/client.py +594 -0
  25. agenta/client/backend/resources/observability/__init__.py +1 -0
  26. agenta/client/backend/resources/observability/client.py +1184 -0
  27. agenta/client/backend/resources/testsets/__init__.py +1 -0
  28. agenta/client/backend/resources/testsets/client.py +689 -0
  29. agenta/client/backend/resources/variants/__init__.py +5 -0
  30. agenta/client/backend/resources/variants/client.py +796 -0
  31. agenta/client/backend/resources/variants/types/__init__.py +7 -0
  32. agenta/client/backend/resources/variants/types/add_variant_from_base_and_config_response.py +7 -0
  33. agenta/client/backend/types/__init__.py +54 -22
  34. agenta/client/backend/types/aggregated_result.py +2 -2
  35. agenta/client/backend/types/aggregated_result_evaluator_config.py +9 -0
  36. agenta/client/backend/types/{app_variant_output.py → app_variant_response.py} +4 -2
  37. agenta/client/backend/types/{trace.py → create_span.py} +20 -10
  38. agenta/client/backend/types/create_trace_response.py +37 -0
  39. agenta/client/backend/types/environment_output.py +3 -1
  40. agenta/client/backend/types/environment_output_extended.py +45 -0
  41. agenta/client/backend/types/environment_revision.py +41 -0
  42. agenta/client/backend/types/error.py +37 -0
  43. agenta/client/backend/types/evaluation.py +6 -3
  44. agenta/client/backend/types/evaluation_scenario_output.py +4 -2
  45. agenta/client/backend/types/{delete_evaluation.py → evaluation_scenario_score_update.py} +2 -2
  46. agenta/client/backend/types/evaluation_status_enum.py +4 -0
  47. agenta/client/backend/types/evaluator.py +1 -0
  48. agenta/client/backend/types/{get_config_reponse.py → get_config_response.py} +1 -2
  49. agenta/client/backend/types/human_evaluation_scenario.py +2 -2
  50. agenta/client/backend/types/{app_variant_output_extended.py → human_evaluation_scenario_update.py} +11 -16
  51. agenta/client/backend/types/human_evaluation_update.py +37 -0
  52. agenta/client/backend/types/image.py +1 -0
  53. agenta/client/backend/types/invite_request.py +1 -0
  54. agenta/client/backend/types/{list_api_keys_output.py → list_api_keys_response.py} +1 -1
  55. agenta/client/backend/types/llm_tokens.py +38 -0
  56. agenta/client/backend/types/new_human_evaluation.py +42 -0
  57. agenta/client/backend/types/organization.py +1 -0
  58. agenta/client/backend/types/permission.py +141 -0
  59. agenta/client/backend/types/result.py +2 -0
  60. agenta/client/backend/types/{human_evaluation_scenario_score.py → score.py} +1 -1
  61. agenta/client/backend/types/span.py +18 -16
  62. agenta/client/backend/types/span_detail.py +52 -0
  63. agenta/client/backend/types/span_kind.py +49 -0
  64. agenta/client/backend/types/span_status_code.py +29 -0
  65. agenta/client/backend/types/span_variant.py +38 -0
  66. agenta/client/backend/types/trace_detail.py +52 -0
  67. agenta/client/backend/types/with_pagination.py +40 -0
  68. agenta/client/backend/types/workspace_member_response.py +38 -0
  69. agenta/client/backend/types/workspace_permission.py +40 -0
  70. agenta/client/backend/types/workspace_response.py +44 -0
  71. agenta/client/backend/types/workspace_role.py +41 -0
  72. agenta/client/backend/types/workspace_role_response.py +38 -0
  73. agenta/docker/docker_utils.py +1 -5
  74. agenta/sdk/__init__.py +4 -1
  75. agenta/sdk/agenta_decorator.py +76 -18
  76. agenta/sdk/agenta_init.py +53 -21
  77. agenta/sdk/tracing/context_manager.py +13 -0
  78. agenta/sdk/tracing/decorators.py +41 -0
  79. agenta/sdk/tracing/llm_tracing.py +220 -0
  80. agenta/sdk/tracing/logger.py +19 -0
  81. agenta/sdk/tracing/tasks_manager.py +130 -0
  82. agenta/sdk/types.py +38 -0
  83. {agenta-0.12.6.dist-info → agenta-0.13.0.dist-info}/METADATA +47 -96
  84. agenta-0.13.0.dist-info/RECORD +161 -0
  85. agenta/client/backend/types/add_variant_from_base_and_config_response.py +0 -7
  86. agenta/client/backend/types/human_evaluation_scenario_update_score.py +0 -5
  87. agenta-0.12.6.dist-info/RECORD +0 -114
  88. {agenta-0.12.6.dist-info → agenta-0.13.0.dist-info}/WHEEL +0 -0
  89. {agenta-0.12.6.dist-info → agenta-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,44 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import datetime as dt
4
+ import typing
5
+
6
+ from ..core.datetime_utils import serialize_datetime
7
+ from .workspace_member_response import WorkspaceMemberResponse
8
+
9
+ try:
10
+ import pydantic.v1 as pydantic # type: ignore
11
+ except ImportError:
12
+ import pydantic # type: ignore
13
+
14
+
15
+ class WorkspaceResponse(pydantic.BaseModel):
16
+ created_at: typing.Optional[dt.datetime]
17
+ updated_at: typing.Optional[dt.datetime]
18
+ id: str
19
+ name: str
20
+ description: typing.Optional[str]
21
+ type: typing.Optional[str]
22
+ organization: str
23
+ members: typing.Optional[typing.List[WorkspaceMemberResponse]]
24
+
25
+ def json(self, **kwargs: typing.Any) -> str:
26
+ kwargs_with_defaults: typing.Any = {
27
+ "by_alias": True,
28
+ "exclude_unset": True,
29
+ **kwargs,
30
+ }
31
+ return super().json(**kwargs_with_defaults)
32
+
33
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
34
+ kwargs_with_defaults: typing.Any = {
35
+ "by_alias": True,
36
+ "exclude_unset": True,
37
+ **kwargs,
38
+ }
39
+ return super().dict(**kwargs_with_defaults)
40
+
41
+ class Config:
42
+ frozen = True
43
+ smart_union = True
44
+ json_encoders = {dt.datetime: serialize_datetime}
@@ -0,0 +1,41 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import enum
4
+ import typing
5
+
6
+ T_Result = typing.TypeVar("T_Result")
7
+
8
+
9
+ class WorkspaceRole(str, enum.Enum):
10
+ """
11
+ An enumeration.
12
+ """
13
+
14
+ OWNER = "owner"
15
+ VIEWER = "viewer"
16
+ EDITOR = "editor"
17
+ EVALUATOR = "evaluator"
18
+ WORKSPACE_ADMIN = "workspace_admin"
19
+ DEPLOYMENT_MANAGER = "deployment_manager"
20
+
21
+ def visit(
22
+ self,
23
+ owner: typing.Callable[[], T_Result],
24
+ viewer: typing.Callable[[], T_Result],
25
+ editor: typing.Callable[[], T_Result],
26
+ evaluator: typing.Callable[[], T_Result],
27
+ workspace_admin: typing.Callable[[], T_Result],
28
+ deployment_manager: typing.Callable[[], T_Result],
29
+ ) -> T_Result:
30
+ if self is WorkspaceRole.OWNER:
31
+ return owner()
32
+ if self is WorkspaceRole.VIEWER:
33
+ return viewer()
34
+ if self is WorkspaceRole.EDITOR:
35
+ return editor()
36
+ if self is WorkspaceRole.EVALUATOR:
37
+ return evaluator()
38
+ if self is WorkspaceRole.WORKSPACE_ADMIN:
39
+ return workspace_admin()
40
+ if self is WorkspaceRole.DEPLOYMENT_MANAGER:
41
+ return deployment_manager()
@@ -0,0 +1,38 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import datetime as dt
4
+ import typing
5
+
6
+ from ..core.datetime_utils import serialize_datetime
7
+ from .workspace_role import WorkspaceRole
8
+
9
+ try:
10
+ import pydantic.v1 as pydantic # type: ignore
11
+ except ImportError:
12
+ import pydantic # type: ignore
13
+
14
+
15
+ class WorkspaceRoleResponse(pydantic.BaseModel):
16
+ role_name: WorkspaceRole
17
+ role_description: typing.Optional[str]
18
+
19
+ def json(self, **kwargs: typing.Any) -> str:
20
+ kwargs_with_defaults: typing.Any = {
21
+ "by_alias": True,
22
+ "exclude_unset": True,
23
+ **kwargs,
24
+ }
25
+ return super().json(**kwargs_with_defaults)
26
+
27
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
28
+ kwargs_with_defaults: typing.Any = {
29
+ "by_alias": True,
30
+ "exclude_unset": True,
31
+ **kwargs,
32
+ }
33
+ return super().dict(**kwargs_with_defaults)
34
+
35
+ class Config:
36
+ frozen = True
37
+ smart_union = True
38
+ json_encoders = {dt.datetime: serialize_datetime}
@@ -3,11 +3,7 @@ import shutil
3
3
  import tarfile
4
4
  import tempfile
5
5
  from pathlib import Path
6
- from tempfile import TemporaryDirectory
7
6
 
8
- import docker
9
- from agenta.config import settings
10
- from docker.models.images import Image
11
7
 
12
8
  logger = logging.getLogger(__name__)
13
9
  logger.setLevel(logging.DEBUG)
@@ -15,7 +11,7 @@ logger.setLevel(logging.DEBUG)
15
11
  DEBUG = False
16
12
 
17
13
 
18
- def create_dockerfile(out_folder: Path):
14
+ def create_dockerfile(out_folder: Path) -> Path:
19
15
  """Creates a dockerfile based on the template in the out_folder.
20
16
 
21
17
  Arguments:
agenta/sdk/__init__.py CHANGED
@@ -9,12 +9,15 @@ from .types import (
9
9
  InFile,
10
10
  IntParam,
11
11
  MultipleChoiceParam,
12
+ GroupedMultipleChoiceParam,
12
13
  TextParam,
13
14
  MessagesInput,
14
15
  FileInputURL,
15
16
  BinaryParam,
16
17
  )
17
- from .agenta_init import Config, init
18
+ from .tracing.decorators import span
19
+ from .agenta_init import Config, init, llm_tracing
18
20
  from .utils.helper.openai_cost import calculate_token_usage
19
21
 
22
+
20
23
  config = PreInitObject("agenta.config", Config)
@@ -5,15 +5,15 @@ import sys
5
5
  import time
6
6
  import inspect
7
7
  import argparse
8
+ import asyncio
8
9
  import traceback
9
10
  import functools
10
11
  from pathlib import Path
11
12
  from tempfile import NamedTemporaryFile
12
- from typing import Any, Callable, Dict, Optional, Tuple, List, Union
13
+ from typing import Any, Callable, Dict, Optional, Tuple, List
13
14
 
14
- from fastapi import Body, FastAPI, UploadFile
15
- from fastapi.responses import JSONResponse
16
15
  from fastapi.middleware.cors import CORSMiddleware
16
+ from fastapi import Body, FastAPI, UploadFile, HTTPException
17
17
 
18
18
  import agenta
19
19
  from .context import save_context
@@ -25,6 +25,7 @@ from .types import (
25
25
  InFile,
26
26
  IntParam,
27
27
  MultipleChoiceParam,
28
+ GroupedMultipleChoiceParam,
28
29
  TextParam,
29
30
  MessagesInput,
30
31
  FileInputURL,
@@ -72,12 +73,34 @@ def entrypoint(func: Callable[..., Any]) -> Callable[..., Any]:
72
73
  config_params = agenta.config.all()
73
74
  ingestible_files = extract_ingestible_files(func_signature)
74
75
 
76
+ # Initialize tracing
77
+ tracing = agenta.llm_tracing()
78
+
75
79
  @functools.wraps(func)
76
80
  async def wrapper(*args, **kwargs) -> Any:
77
81
  func_params, api_config_params = split_kwargs(kwargs, config_params)
82
+
83
+ # Start tracing
84
+ tracing.start_parent_span(
85
+ name=func.__name__,
86
+ inputs=func_params,
87
+ config=config_params,
88
+ environment="playground", # type: ignore #NOTE: wrapper is only called in playground
89
+ )
90
+
91
+ # Ingest files, prepare configurations and run llm app
78
92
  ingest_files(func_params, ingestible_files)
79
93
  agenta.config.set(**api_config_params)
80
- return await execute_function(func, *args, **func_params)
94
+ llm_result = await execute_function(
95
+ func, *args, params=func_params, config_params=config_params
96
+ )
97
+
98
+ # End trace recording
99
+ tracing.end_recording(
100
+ outputs=llm_result.dict(),
101
+ span=tracing.active_trace,
102
+ )
103
+ return llm_result
81
104
 
82
105
  @functools.wraps(func)
83
106
  async def wrapper_deployed(*args, **kwargs) -> Any:
@@ -90,7 +113,27 @@ def entrypoint(func: Callable[..., Any]) -> Callable[..., Any]:
90
113
  agenta.config.pull(config_name=kwargs["config"])
91
114
  else:
92
115
  agenta.config.pull(config_name="default")
93
- return await execute_function(func, *args, **func_params)
116
+
117
+ config = agenta.config.all()
118
+
119
+ # Start tracing
120
+ tracing.start_parent_span(
121
+ name=func.__name__,
122
+ inputs=func_params,
123
+ config=config,
124
+ environment=kwargs["environment"], # type: ignore #NOTE: wrapper is only called in playground
125
+ )
126
+
127
+ llm_result = await execute_function(
128
+ func, *args, params=func_params, config_params=config_params
129
+ )
130
+
131
+ # End trace recording
132
+ tracing.end_recording(
133
+ outputs=llm_result.dict(),
134
+ span=tracing.active_trace,
135
+ )
136
+ return llm_result
94
137
 
95
138
  update_function_signature(wrapper, func_signature, config_params, ingestible_files)
96
139
  route = f"/{endpoint_name}"
@@ -152,9 +195,7 @@ def ingest_files(
152
195
  func_params[name] = ingest_file(func_params[name])
153
196
 
154
197
 
155
- async def execute_function(
156
- func: Callable[..., Any], *args, **func_params
157
- ) -> Union[Dict[str, Any], JSONResponse]:
198
+ async def execute_function(func: Callable[..., Any], *args, **func_params):
158
199
  """Execute the function and handle any exceptions."""
159
200
 
160
201
  try:
@@ -166,30 +207,32 @@ async def execute_function(
166
207
  is_coroutine_function = inspect.iscoroutinefunction(func)
167
208
  start_time = time.perf_counter()
168
209
  if is_coroutine_function:
169
- result = await func(*args, **func_params)
210
+ result = await func(*args, **func_params["params"])
170
211
  else:
171
- result = func(*args, **func_params)
212
+ result = func(*args, **func_params["params"])
213
+
172
214
  end_time = time.perf_counter()
173
215
  latency = end_time - start_time
174
216
 
175
217
  if isinstance(result, Context):
176
218
  save_context(result)
177
219
  if isinstance(result, Dict):
178
- return FuncResponse(**result, latency=round(latency, 4)).dict()
220
+ return FuncResponse(**result, latency=round(latency, 4))
179
221
  if isinstance(result, str):
180
- return FuncResponse(message=result, latency=round(latency, 4)).dict()
222
+ return FuncResponse(message=result, latency=round(latency, 4)) # type: ignore
181
223
  except Exception as e:
182
- return handle_exception(e)
224
+ handle_exception(e)
225
+ return FuncResponse(message="Unexpected error occurred", latency=0) # type: ignore
183
226
 
184
227
 
185
- def handle_exception(e: Exception) -> JSONResponse:
186
- """Handle exceptions and return a JSONResponse."""
228
+ def handle_exception(e: Exception):
229
+ """Handle exceptions."""
187
230
 
188
231
  status_code: int = e.status_code if hasattr(e, "status_code") else 500
189
- traceback_str = traceback.format_exception(e, value=e, tb=e.__traceback__)
190
- return JSONResponse(
232
+ traceback_str = traceback.format_exception(e, value=e, tb=e.__traceback__) # type: ignore
233
+ raise HTTPException(
191
234
  status_code=status_code,
192
- content={"error": str(e), "traceback": "".join(traceback_str)},
235
+ detail={"error": str(e), "traceback": "".join(traceback_str)},
193
236
  )
194
237
 
195
238
 
@@ -355,6 +398,14 @@ def handle_terminal_run(
355
398
  )
356
399
  agenta.config.set(**args_config_params)
357
400
 
401
+ loop = asyncio.get_event_loop()
402
+ result = loop.run_until_complete(
403
+ execute_function(
404
+ func, **{"params": args_func_params, "config_params": args_config_params}
405
+ )
406
+ )
407
+ print(result)
408
+
358
409
 
359
410
  def override_schema(openapi_schema: dict, func_name: str, endpoint: str, params: dict):
360
411
  """
@@ -396,6 +447,13 @@ def override_schema(openapi_schema: dict, func_name: str, endpoint: str, params:
396
447
  f"Body_{func_name}_{endpoint}_post"
397
448
  ]["properties"]
398
449
  for param_name, param_val in params.items():
450
+ if isinstance(param_val, GroupedMultipleChoiceParam):
451
+ subschema = find_in_schema(schema_to_override, param_name, "grouped_choice")
452
+ assert (
453
+ subschema
454
+ ), f"GroupedMultipleChoiceParam '{param_name}' is in the parameters but could not be found in the openapi.json"
455
+ subschema["choices"] = param_val.choices
456
+ subschema["default"] = param_val.default
399
457
  if isinstance(param_val, MultipleChoiceParam):
400
458
  subschema = find_in_schema(schema_to_override, param_name, "choice")
401
459
  default = str(param_val)
agenta/sdk/agenta_init.py CHANGED
@@ -1,11 +1,14 @@
1
- from agenta.client.exceptions import APIRequestError
2
- from agenta.client.backend.client import AgentaApi
3
1
  import os
4
2
  import logging
5
3
  from typing import Any, Optional
6
4
 
7
5
  from .utils.globals import set_global
8
6
 
7
+ from agenta.client.backend.client import AgentaApi
8
+ from agenta.sdk.tracing.llm_tracing import Tracing
9
+ from agenta.client.exceptions import APIRequestError
10
+
11
+
9
12
  logger = logging.getLogger(__name__)
10
13
  logger.setLevel(logging.DEBUG)
11
14
 
@@ -40,6 +43,7 @@ class AgentaSingleton:
40
43
  base_name: Optional[str] = None,
41
44
  api_key: Optional[str] = None,
42
45
  base_id: Optional[str] = None,
46
+ app_id: Optional[str] = None,
43
47
  host: Optional[str] = None,
44
48
  **kwargs: Any,
45
49
  ) -> None:
@@ -75,30 +79,44 @@ class AgentaSingleton:
75
79
  )
76
80
  else:
77
81
  try:
78
- apps = client.list_apps(app_name=app_name)
79
- if len(apps) == 0:
80
- raise APIRequestError(f"App with name {app_name} not found")
81
-
82
- app_id = apps[0].app_id
83
- if not app_id:
84
- raise APIRequestError(
85
- f"App with name {app_name} does not exist on the server."
86
- )
87
-
88
- bases = client.list_bases(app_id=app_id, base_name=base_name)
89
- if len(bases) == 0:
90
- raise APIRequestError(f"No base was found for the app {app_id}")
91
-
92
- base_id = bases[0].base_id
82
+ app_id = self.get_app(app_name)
83
+ base_id = self.get_app_base(app_id, base_name)
93
84
  except Exception as ex:
94
85
  raise APIRequestError(
95
86
  f"Failed to get base id and/or app_id from the server with error: {ex}"
96
87
  )
88
+
97
89
  self.base_id = base_id
98
90
  self.host = host
91
+ self.app_id = os.environ.get("AGENTA_APP_ID") if app_id is None else app_id
92
+ self.variant_id = os.environ.get("AGENTA_VARIANT_ID")
93
+ self.variant_name = os.environ.get("AGENTA_VARIANT_NAME")
99
94
  self.api_key = api_key
100
95
  self.config = Config(base_id=base_id, host=host)
101
96
 
97
+ def get_app(self, app_name: str) -> str:
98
+ apps = client.apps.list_apps(app_name=app_name)
99
+ if len(apps) == 0:
100
+ raise APIRequestError(f"App with name {app_name} not found")
101
+
102
+ app_id = apps[0].app_id
103
+ return app_id
104
+
105
+ def get_app_base(self, app_id: str, base_name: str) -> str:
106
+ bases = client.bases.list_bases(app_id=app_id, base_name=base_name)
107
+ if len(bases) == 0:
108
+ raise APIRequestError(f"No base was found for the app {app_id}")
109
+ return bases[0].base_id
110
+
111
+ def get_current_config(self):
112
+ """
113
+ Retrieves the current active configuration
114
+ """
115
+
116
+ if self._config_data is None:
117
+ raise RuntimeError("AgentaSingleton has not been initialized")
118
+ return self._config_data
119
+
102
120
 
103
121
  class Config:
104
122
  def __init__(self, base_id, host):
@@ -139,7 +157,7 @@ class Config:
139
157
  if not self.persist:
140
158
  return
141
159
  try:
142
- client.save_config(
160
+ client.configs.save_config(
143
161
  base_id=self.base_id,
144
162
  config_name=config_name,
145
163
  parameters=kwargs,
@@ -161,12 +179,12 @@ class Config:
161
179
  if self.persist:
162
180
  try:
163
181
  if environment_name:
164
- config = client.get_config(
182
+ config = client.configs.get_config(
165
183
  base_id=self.base_id, environment_name=environment_name
166
184
  )
167
185
 
168
186
  else:
169
- config = client.get_config(
187
+ config = client.configs.get_config(
170
188
  base_id=self.base_id,
171
189
  config_name=config_name,
172
190
  )
@@ -176,7 +194,7 @@ class Config:
176
194
  + str(ex)
177
195
  )
178
196
  try:
179
- self.set(**config.parameters)
197
+ self.set(**{"current_version": config.current_version, **config.parameters})
180
198
  except Exception as ex:
181
199
  logger.warning("Failed to set the configuration with error: " + str(ex))
182
200
 
@@ -210,3 +228,17 @@ def init(app_name=None, base_name=None, **kwargs):
210
228
  singleton = AgentaSingleton()
211
229
  singleton.init(app_name=app_name, base_name=base_name, **kwargs)
212
230
  set_global(setup=singleton.setup, config=singleton.config)
231
+
232
+
233
+ def llm_tracing(max_workers: Optional[int] = None) -> Tracing:
234
+ """Function to start llm tracing."""
235
+
236
+ singleton = AgentaSingleton()
237
+ return Tracing(
238
+ base_url=singleton.host,
239
+ app_id=singleton.app_id, # type: ignore
240
+ variant_id=singleton.variant_id, # type: ignore
241
+ variant_name=singleton.variant_name,
242
+ api_key=singleton.api_key,
243
+ max_workers=max_workers,
244
+ )
@@ -0,0 +1,13 @@
1
+ # Own Imports
2
+ from agenta.sdk.tracing.llm_tracing import Tracing
3
+
4
+
5
+ class TracingContextManager:
6
+ def __init__(self, tracing: Tracing):
7
+ ...
8
+
9
+ def __enter__(self):
10
+ ...
11
+
12
+ def __exit__(self, exc_type, exc_val, exc_tb):
13
+ ...
@@ -0,0 +1,41 @@
1
+ # Stdlib Imports
2
+ import inspect
3
+ from functools import wraps
4
+
5
+ # Own Imports
6
+ import agenta as ag
7
+
8
+
9
+ def span(type: str):
10
+ """Decorator to automatically start and end spans."""
11
+
12
+ tracing = ag.llm_tracing()
13
+
14
+ def decorator(func):
15
+ @wraps(func)
16
+ async def wrapper(*args, **kwargs):
17
+ result = None
18
+ span = tracing.start_span(
19
+ name=func.__name__,
20
+ input=kwargs,
21
+ spankind=type,
22
+ )
23
+ try:
24
+ is_coroutine_function = inspect.iscoroutinefunction(func)
25
+ if is_coroutine_function:
26
+ result = await func(*args, **kwargs)
27
+ else:
28
+ result = func(*args, **kwargs)
29
+ tracing.update_span_status(span=span, value="OK")
30
+ except Exception as e:
31
+ result = str(e)
32
+ tracing.update_span_status(span=span, value="ERROR")
33
+ finally:
34
+ if not isinstance(result, dict):
35
+ result = {"message": result}
36
+ tracing.end_span(outputs=result, span=span)
37
+ return result
38
+
39
+ return wrapper
40
+
41
+ return decorator