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.
- agenta/__init__.py +4 -1
- agenta/cli/helper.py +1 -1
- agenta/cli/main.py +1 -1
- agenta/cli/variant_commands.py +7 -5
- agenta/client/api.py +1 -1
- agenta/client/backend/__init__.py +78 -18
- agenta/client/backend/client.py +1031 -5526
- agenta/client/backend/resources/__init__.py +31 -0
- agenta/client/backend/resources/apps/__init__.py +1 -0
- agenta/client/backend/resources/apps/client.py +977 -0
- agenta/client/backend/resources/bases/__init__.py +1 -0
- agenta/client/backend/resources/bases/client.py +127 -0
- agenta/client/backend/resources/configs/__init__.py +1 -0
- agenta/client/backend/resources/configs/client.py +377 -0
- agenta/client/backend/resources/containers/__init__.py +5 -0
- agenta/client/backend/resources/containers/client.py +383 -0
- agenta/client/backend/resources/containers/types/__init__.py +5 -0
- agenta/client/backend/{types → resources/containers/types}/container_templates_response.py +1 -1
- agenta/client/backend/resources/environments/__init__.py +1 -0
- agenta/client/backend/resources/environments/client.py +131 -0
- agenta/client/backend/resources/evaluations/__init__.py +1 -0
- agenta/client/backend/resources/evaluations/client.py +1008 -0
- agenta/client/backend/resources/evaluators/__init__.py +1 -0
- agenta/client/backend/resources/evaluators/client.py +594 -0
- agenta/client/backend/resources/observability/__init__.py +1 -0
- agenta/client/backend/resources/observability/client.py +1184 -0
- agenta/client/backend/resources/testsets/__init__.py +1 -0
- agenta/client/backend/resources/testsets/client.py +689 -0
- agenta/client/backend/resources/variants/__init__.py +5 -0
- agenta/client/backend/resources/variants/client.py +796 -0
- agenta/client/backend/resources/variants/types/__init__.py +7 -0
- agenta/client/backend/resources/variants/types/add_variant_from_base_and_config_response.py +7 -0
- agenta/client/backend/types/__init__.py +54 -22
- agenta/client/backend/types/aggregated_result.py +2 -2
- agenta/client/backend/types/aggregated_result_evaluator_config.py +9 -0
- agenta/client/backend/types/{app_variant_output.py → app_variant_response.py} +4 -2
- agenta/client/backend/types/{trace.py → create_span.py} +20 -10
- agenta/client/backend/types/create_trace_response.py +37 -0
- agenta/client/backend/types/environment_output.py +3 -1
- agenta/client/backend/types/environment_output_extended.py +45 -0
- agenta/client/backend/types/environment_revision.py +41 -0
- agenta/client/backend/types/error.py +37 -0
- agenta/client/backend/types/evaluation.py +6 -3
- agenta/client/backend/types/evaluation_scenario_output.py +4 -2
- agenta/client/backend/types/{delete_evaluation.py → evaluation_scenario_score_update.py} +2 -2
- agenta/client/backend/types/evaluation_status_enum.py +4 -0
- agenta/client/backend/types/evaluator.py +1 -0
- agenta/client/backend/types/{get_config_reponse.py → get_config_response.py} +1 -2
- agenta/client/backend/types/human_evaluation_scenario.py +2 -2
- agenta/client/backend/types/{app_variant_output_extended.py → human_evaluation_scenario_update.py} +11 -16
- agenta/client/backend/types/human_evaluation_update.py +37 -0
- agenta/client/backend/types/image.py +1 -0
- agenta/client/backend/types/invite_request.py +1 -0
- agenta/client/backend/types/{list_api_keys_output.py → list_api_keys_response.py} +1 -1
- agenta/client/backend/types/llm_tokens.py +38 -0
- agenta/client/backend/types/new_human_evaluation.py +42 -0
- agenta/client/backend/types/organization.py +1 -0
- agenta/client/backend/types/permission.py +141 -0
- agenta/client/backend/types/result.py +2 -0
- agenta/client/backend/types/{human_evaluation_scenario_score.py → score.py} +1 -1
- agenta/client/backend/types/span.py +18 -16
- agenta/client/backend/types/span_detail.py +52 -0
- agenta/client/backend/types/span_kind.py +49 -0
- agenta/client/backend/types/span_status_code.py +29 -0
- agenta/client/backend/types/span_variant.py +38 -0
- agenta/client/backend/types/trace_detail.py +52 -0
- agenta/client/backend/types/with_pagination.py +40 -0
- agenta/client/backend/types/workspace_member_response.py +38 -0
- agenta/client/backend/types/workspace_permission.py +40 -0
- agenta/client/backend/types/workspace_response.py +44 -0
- agenta/client/backend/types/workspace_role.py +41 -0
- agenta/client/backend/types/workspace_role_response.py +38 -0
- agenta/docker/docker_utils.py +1 -5
- agenta/sdk/__init__.py +4 -1
- agenta/sdk/agenta_decorator.py +76 -18
- agenta/sdk/agenta_init.py +53 -21
- agenta/sdk/tracing/context_manager.py +13 -0
- agenta/sdk/tracing/decorators.py +41 -0
- agenta/sdk/tracing/llm_tracing.py +220 -0
- agenta/sdk/tracing/logger.py +19 -0
- agenta/sdk/tracing/tasks_manager.py +130 -0
- agenta/sdk/types.py +38 -0
- {agenta-0.12.6.dist-info → agenta-0.13.0.dist-info}/METADATA +47 -96
- agenta-0.13.0.dist-info/RECORD +161 -0
- agenta/client/backend/types/add_variant_from_base_and_config_response.py +0 -7
- agenta/client/backend/types/human_evaluation_scenario_update_score.py +0 -5
- agenta-0.12.6.dist-info/RECORD +0 -114
- {agenta-0.12.6.dist-info → agenta-0.13.0.dist-info}/WHEEL +0 -0
- {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}
|
agenta/docker/docker_utils.py
CHANGED
|
@@ -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 .
|
|
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)
|
agenta/sdk/agenta_decorator.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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))
|
|
220
|
+
return FuncResponse(**result, latency=round(latency, 4))
|
|
179
221
|
if isinstance(result, str):
|
|
180
|
-
return FuncResponse(message=result, latency=round(latency, 4))
|
|
222
|
+
return FuncResponse(message=result, latency=round(latency, 4)) # type: ignore
|
|
181
223
|
except Exception as e:
|
|
182
|
-
|
|
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)
|
|
186
|
-
"""Handle exceptions
|
|
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
|
-
|
|
232
|
+
traceback_str = traceback.format_exception(e, value=e, tb=e.__traceback__) # type: ignore
|
|
233
|
+
raise HTTPException(
|
|
191
234
|
status_code=status_code,
|
|
192
|
-
|
|
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
|
-
|
|
79
|
-
|
|
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,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
|