agenta 0.15.0__py3-none-any.whl → 0.15.0a0__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.

@@ -1,4 +1,4 @@
1
- agenta/__init__.py,sha256=O7kq034_S58b2yzrtR_m3Qd-0t7FAh9q7Z7_HsoD-9Y,796
1
+ agenta/__init__.py,sha256=rCZ-mUOGnyKQpfWQFzXIEFX7KBlGC3qFMighdIVJgDc,610
2
2
  agenta/cli/evaluation_commands.py,sha256=fs6492tprPId9p8eGO02Xy-NCBm2RZNJLZWcUxugwd8,474
3
3
  agenta/cli/helper.py,sha256=vRxHyeNaltzNIGrfU2vO0H28_rXDzx9QqIZ_S-W6zL4,6212
4
4
  agenta/cli/main.py,sha256=Wz0ODhoeKK3Qg_CFUhu6D909szk05tc8ZVBB6H1-w7k,9763
@@ -10,7 +10,7 @@ agenta/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  agenta/client/api.py,sha256=0u1vd7V2ctFEtY6KeGGiOeoDv6vyeit32u6c6BVyc4w,2434
11
11
  agenta/client/api_models.py,sha256=zebfE2-0-SW1SvzyarzmSJMXqyiCLKrX2sHpzoX-RnU,623
12
12
  agenta/client/backend/__init__.py,sha256=tkSqI-dciccMpM2diWMe7pF0SjsGXPV_kR-029xNN9w,3853
13
- agenta/client/backend/client.py,sha256=LDuJbFQ9wnhBDeldrlJfOt2TsvO102fy1iKbQG4n_fE,73738
13
+ agenta/client/backend/client.py,sha256=UvNYKUplPdK1AkFfRsOdyEI7hoTqNCtD_pKlkgtUGGo,73690
14
14
  agenta/client/backend/core/__init__.py,sha256=QJS3CJ2TYP2E1Tge0CS6Z7r8LTNzJHQVX1hD3558eP0,519
15
15
  agenta/client/backend/core/api_error.py,sha256=TtMtCdxXjd7Tasc9c8ooFg124nPrb2MXG-tKOXV4u9I,440
16
16
  agenta/client/backend/core/client_wrapper.py,sha256=kQEqxdm31r7V9x--mMliWOdMujD3dtPZyYBNzxgNdrs,972
@@ -54,7 +54,7 @@ agenta/client/backend/types/base_output.py,sha256=ynXhDBQKrkR6Lnkx-yv6Q8xW4wXmzX
54
54
  agenta/client/backend/types/body_import_testset.py,sha256=7dVF3mv3VO0Co8F0qxLAgu4jabqDPjebK4mYvcd_TuA,1061
55
55
  agenta/client/backend/types/config_db.py,sha256=P0cSYvVOn0ZxpYMIdvhWpQVjRuBS5APe6qlc69AXaF4,1028
56
56
  agenta/client/backend/types/create_app_output.py,sha256=pgnTnfZx35Q-8wZ1yTZBQ0ydYacGzFC9kyLug_UvymM,986
57
- agenta/client/backend/types/create_span.py,sha256=Ldb2zclVtVyBRKxM2Ap3YjE-FP3jbaOya96_ZsYw1cg,1794
57
+ agenta/client/backend/types/create_span.py,sha256=_3G4WUnmgXtTCkIJFpce-9PDh6KDDZ2YkvXVOE8GSx8,1793
58
58
  agenta/client/backend/types/create_trace_response.py,sha256=FO-Ii9JEn2AQ1nmZYmjnKRbACsNxRvY_-xn7Ys7Yo8A,1012
59
59
  agenta/client/backend/types/docker_env_vars.py,sha256=altCvA1k-zdAkKNYLwaCnmV48HZg9cwe2cHu_BGImac,986
60
60
  agenta/client/backend/types/environment_output.py,sha256=dl0GKodeqB7kWK5mH6Y4iBppkpwRzSTmtkXH1II4L6w,1257
@@ -119,27 +119,26 @@ agenta/client/client.py,sha256=DWOGS9A8u4wu28s9jGOR4eRhf7vo4zT7GyDvrIGu59Y,19648
119
119
  agenta/client/exceptions.py,sha256=cxLjjKvZKlUgBxt4Vn9J_SsezJPPNHvrZxnoq-D6zmw,94
120
120
  agenta/config.py,sha256=Id-Ie1yf9QRP1YPhRYaYSOruRe6RBrsCXkG9rAa-ZtA,732
121
121
  agenta/config.toml,sha256=ptE0P49bwsu3Luyn7OLFmk2buPhj5D-MA-O_ErOGoLg,223
122
- agenta/docker/docker-assets/Dockerfile.cloud.template,sha256=Mn9g7bTQSnPXcCLZo-iVirV3cveCQHC_F7IECQufmME,389
122
+ agenta/docker/docker-assets/Dockerfile.cloud.template,sha256=uJuXKvtkMY6f4KaOh3XE5pmuJR7mfZEXJk_8hj2uatc,386
123
123
  agenta/docker/docker-assets/Dockerfile.template,sha256=aVA_okx0xXalcTvdQGhSfzSjNpQZVoLJCGYA39-2Nwk,280
124
124
  agenta/docker/docker-assets/README.md,sha256=XHxwh2ks_ozrtAU7SLbL3J14SB2holG6buoTxwmMiZM,102
125
125
  agenta/docker/docker-assets/entrypoint.sh,sha256=29XK8VQjQsx4hN2j-4JDy-6kQb5y4LCqZEa7PD4eqCQ,74
126
126
  agenta/docker/docker-assets/lambda_function.py,sha256=h4UZSSfqwpfsCgERv6frqwm_4JrYu9rLz3I-LxCfeEg,83
127
127
  agenta/docker/docker-assets/main.py,sha256=7MI-21n81U7N7A0GxebNi0cmGWtJKcR2sPB6FcH2QfA,251
128
128
  agenta/docker/docker_utils.py,sha256=5uHMCzXkCvIsDdEiwbnnn97KkzsFbBvyMwogCsv_Z5U,3509
129
- agenta/sdk/__init__.py,sha256=oHgl-qoEyi3d2VI_Kv-rIMSx9zgs6b5MP62PLq5GqYI,762
130
- agenta/sdk/agenta_init.py,sha256=j7qwyDtXfLozWpnayJHPz2aQOzHSGvHo9V6s0FXeUe8,9937
129
+ agenta/sdk/__init__.py,sha256=jmeLRuXrew02ZruODZYIu4kpw0S8vV6JhMPQWFGtj30,648
130
+ agenta/sdk/agenta_decorator.py,sha256=_WaU-KkqnGTQobobX0LU2QszS9RdR8oOgIFksd40wh0,20210
131
+ agenta/sdk/agenta_init.py,sha256=wDfStpe8_3ZXRLtikarwDKI_VpA1YW4eIz_3fXq39is,9044
131
132
  agenta/sdk/client.py,sha256=trKyBOYFZRk0v5Eptxvh87yPf50Y9CqY6Qgv4Fy-VH4,2142
132
133
  agenta/sdk/context.py,sha256=q-PxL05-I84puunUAs9LGsffEXcYhDxhQxjuOz2vK90,901
133
- agenta/sdk/decorators/base.py,sha256=9aNdX5h8a2mFweuhdO-BQPwXGKY9ONPIdLRhSGAGMfY,217
134
- agenta/sdk/decorators/llm_entrypoint.py,sha256=QjkpKEgsKzO83MNOb37MupwCX5hrm7_1-qbtbpqVMYM,19400
135
- agenta/sdk/decorators/tracing.py,sha256=bC-YlPQUrHBEqvhLJxr63N0qlo1jvrbt7ro2AMGXXZw,3160
136
134
  agenta/sdk/router.py,sha256=0sbajvn5C7t18anH6yNo7-oYxldHnYfwcbmQnIXBePw,269
137
135
  agenta/sdk/tracing/context_manager.py,sha256=HskDaiORoOhjeN375gm05wYnieQzh5UnoIsnSAHkAyc,252
138
- agenta/sdk/tracing/llm_tracing.py,sha256=PmMYQ5N8atYut85Rk2hZ1jmvSF80Duuy6Clf7URcTCA,8193
139
- agenta/sdk/tracing/logger.py,sha256=GfH7V-jBHcn7h5dbdrnkDMe_ml3wkXFBeoQiqR4KVRc,474
140
- agenta/sdk/tracing/tasks_manager.py,sha256=ROrWIaqS2J2HHiJtRWiHKlLY8CCsqToP5VeXu7mamck,3748
141
- agenta/sdk/types.py,sha256=pjVThuJ9iGbWnwmDmKJnG8S6Q_wHe1fRtMS6jknYSJM,5881
142
- agenta/sdk/utils/globals.py,sha256=JmhJcCOSbwvjQ6GDyUc2_SYR27DZk7YcrRH80ktHHOM,435
136
+ agenta/sdk/tracing/decorators.py,sha256=ujtU8gf3GDoHYuLTfEYK_2eIYZ-1oX5dpv02Mf4l_II,1191
137
+ agenta/sdk/tracing/llm_tracing.py,sha256=UiotJ56EFA3VPt7LREkcK2w51D9-0T1QNvBy4zNWEdY,7348
138
+ agenta/sdk/tracing/logger.py,sha256=4zG9c51p8xPdKA5SL8MOgBfkpCnBSuV6JfWiXO0A7oc,473
139
+ agenta/sdk/tracing/tasks_manager.py,sha256=XVGBEOwmHa6KcCC0PApk0_bZ0Ilk2ESuduNObB1rw2s,3792
140
+ agenta/sdk/types.py,sha256=_rE1lPBlhwwwzPeSaPJYVaZSOg6l4alGBL8aufI8LJM,5711
141
+ agenta/sdk/utils/globals.py,sha256=lpgflY8xovZJtHfJf41dbNCZGwx07YNkG9ldruv6xoI,360
143
142
  agenta/sdk/utils/helper/openai_cost.py,sha256=1VkgvucDnNZm1pTfcVLz9icWunntp1d7zwMmnviy3Uw,5877
144
143
  agenta/sdk/utils/preinit.py,sha256=YlJL7RLfel0R7DFp-jK7OV-z4ZIQJM0oupYlk7g8b5o,1278
145
144
  agenta/templates/compose_email/README.md,sha256=ss7vZPpI1Hg0VmYtFliwq_r5LnqbCy_S5OQDXg8UoIA,308
@@ -157,7 +156,7 @@ agenta/templates/simple_prompt/app.py,sha256=kODgF6lhzsaJPdgL5b21bUki6jkvqjWZzWR
157
156
  agenta/templates/simple_prompt/env.example,sha256=g9AE5bYcGPpxawXMJ96gh8oenEPCHTabsiOnfQo3c5k,70
158
157
  agenta/templates/simple_prompt/requirements.txt,sha256=ywRglRy7pPkw8bljmMEJJ4aOOQKrt9FGKULZ-DGkoBU,23
159
158
  agenta/templates/simple_prompt/template.toml,sha256=DQBtRrF4GU8LBEXOZ-GGuINXMQDKGTEG5y37tnvIUIE,60
160
- agenta-0.15.0.dist-info/METADATA,sha256=fw71SzzTzKG1bcyoCV78EtObsmPtFUsUmFcAZQ6HtA4,26463
161
- agenta-0.15.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
162
- agenta-0.15.0.dist-info/entry_points.txt,sha256=PDiu8_8AsL7ibU9v4iNoOKR1S7F2rdxjlEprjM9QOgo,46
163
- agenta-0.15.0.dist-info/RECORD,,
159
+ agenta-0.15.0a0.dist-info/METADATA,sha256=g_MOVUim-ykewN3u3F7zkFtRebo7gxuYnZsEwGO21XM,26480
160
+ agenta-0.15.0a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
161
+ agenta-0.15.0a0.dist-info/entry_points.txt,sha256=PDiu8_8AsL7ibU9v4iNoOKR1S7F2rdxjlEprjM9QOgo,46
162
+ agenta-0.15.0a0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- # Stdlib Imports
2
- from typing import Any, Callable
3
-
4
-
5
- class BaseDecorator:
6
- def __init__(self):
7
- pass
8
-
9
- def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
10
- raise NotImplementedError
@@ -1,499 +0,0 @@
1
- """The code for the Agenta SDK"""
2
-
3
- import os
4
- import sys
5
- import time
6
- import inspect
7
- import argparse
8
- import asyncio
9
- import traceback
10
- import functools
11
- from pathlib import Path
12
- from tempfile import NamedTemporaryFile
13
- from typing import Any, Callable, Dict, Optional, Tuple, List
14
-
15
- from fastapi.middleware.cors import CORSMiddleware
16
- from fastapi import Body, FastAPI, UploadFile, HTTPException
17
-
18
- import agenta
19
- from agenta.sdk.context import save_context
20
- from agenta.sdk.router import router as router
21
- from agenta.sdk.tracing.llm_tracing import Tracing
22
- from agenta.sdk.decorators.base import BaseDecorator
23
- from agenta.sdk.types import (
24
- Context,
25
- DictInput,
26
- FloatParam,
27
- InFile,
28
- IntParam,
29
- MultipleChoiceParam,
30
- GroupedMultipleChoiceParam,
31
- TextParam,
32
- MessagesInput,
33
- FileInputURL,
34
- FuncResponse,
35
- BinaryParam,
36
- )
37
-
38
- app = FastAPI()
39
-
40
- origins = [
41
- "*",
42
- ]
43
-
44
- app.add_middleware(
45
- CORSMiddleware,
46
- allow_origins=origins,
47
- allow_credentials=True,
48
- allow_methods=["*"],
49
- allow_headers=["*"],
50
- )
51
-
52
- app.include_router(router, prefix="")
53
-
54
-
55
- class entrypoint(BaseDecorator):
56
- """Decorator class to wrap a function for HTTP POST, terminal exposure and enable tracing.
57
-
58
-
59
- Example:
60
- ```python
61
- import agenta as ag
62
-
63
- @ag.entrypoint
64
- async def chain_of_prompts_llm(prompt: str):
65
- return ...
66
- ```
67
- """
68
-
69
- def __init__(self, func: Callable[..., Any]):
70
- endpoint_name = "generate"
71
- func_signature = inspect.signature(func)
72
- config_params = agenta.config.all()
73
- ingestible_files = self.extract_ingestible_files(func_signature)
74
-
75
- @functools.wraps(func)
76
- async def wrapper(*args, **kwargs) -> Any:
77
- func_params, api_config_params = self.split_kwargs(kwargs, config_params)
78
- self.ingest_files(func_params, ingestible_files)
79
- agenta.config.set(**api_config_params)
80
-
81
- # Set the configuration and environment of the LLM app parent span at run-time
82
- agenta.tracing.set_span_attribute(
83
- {"config": config_params, "environment": "playground"}
84
- )
85
-
86
- llm_result = await self.execute_function(
87
- func, *args, params=func_params, config_params=config_params
88
- )
89
- return llm_result
90
-
91
- @functools.wraps(func)
92
- async def wrapper_deployed(*args, **kwargs) -> Any:
93
- func_params = {
94
- k: v for k, v in kwargs.items() if k not in ["config", "environment"]
95
- }
96
-
97
- if "environment" in kwargs and kwargs["environment"] is not None:
98
- agenta.config.pull(environment_name=kwargs["environment"])
99
- elif "config" in kwargs and kwargs["config"] is not None:
100
- agenta.config.pull(config_name=kwargs["config"])
101
- else:
102
- agenta.config.pull(config_name="default")
103
-
104
- # Set the configuration and environment of the LLM app parent span at run-time
105
- agenta.tracing.set_span_attribute(
106
- {"config": config_params, "environment": kwargs["environment"]}
107
- )
108
-
109
- llm_result = await self.execute_function(
110
- func, *args, params=func_params, config_params=config_params
111
- )
112
- return llm_result
113
-
114
- self.update_function_signature(
115
- wrapper, func_signature, config_params, ingestible_files
116
- )
117
- route = f"/{endpoint_name}"
118
- app.post(route, response_model=FuncResponse)(wrapper)
119
-
120
- self.update_deployed_function_signature(
121
- wrapper_deployed,
122
- func_signature,
123
- ingestible_files,
124
- )
125
- route_deployed = f"/{endpoint_name}_deployed"
126
- app.post(route_deployed, response_model=FuncResponse)(wrapper_deployed)
127
- self.override_schema(
128
- openapi_schema=app.openapi(),
129
- func_name=func.__name__,
130
- endpoint=endpoint_name,
131
- params={**config_params, **func_signature.parameters},
132
- )
133
-
134
- if self.is_main_script(func):
135
- self.handle_terminal_run(
136
- func,
137
- func_signature.parameters, # type: ignore
138
- config_params,
139
- ingestible_files,
140
- )
141
-
142
- def extract_ingestible_files(
143
- self,
144
- func_signature: inspect.Signature,
145
- ) -> Dict[str, inspect.Parameter]:
146
- """Extract parameters annotated as InFile from function signature."""
147
-
148
- return {
149
- name: param
150
- for name, param in func_signature.parameters.items()
151
- if param.annotation is InFile
152
- }
153
-
154
- def split_kwargs(
155
- self, kwargs: Dict[str, Any], config_params: Dict[str, Any]
156
- ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
157
- """Split keyword arguments into function parameters and API configuration parameters."""
158
-
159
- func_params = {k: v for k, v in kwargs.items() if k not in config_params}
160
- api_config_params = {k: v for k, v in kwargs.items() if k in config_params}
161
- return func_params, api_config_params
162
-
163
- def ingest_file(self, upfile: UploadFile):
164
- temp_file = NamedTemporaryFile(delete=False)
165
- temp_file.write(upfile.file.read())
166
- temp_file.close()
167
- return InFile(file_name=upfile.filename, file_path=temp_file.name)
168
-
169
- def ingest_files(
170
- self,
171
- func_params: Dict[str, Any],
172
- ingestible_files: Dict[str, inspect.Parameter],
173
- ) -> None:
174
- """Ingest files specified in function parameters."""
175
-
176
- for name in ingestible_files:
177
- if name in func_params and func_params[name] is not None:
178
- func_params[name] = self.ingest_file(func_params[name])
179
-
180
- async def execute_function(self, func: Callable[..., Any], *args, **func_params):
181
- """Execute the function and handle any exceptions."""
182
-
183
- try:
184
- """Note: The following block is for backward compatibility.
185
- It allows functions to work seamlessly whether they are synchronous or asynchronous.
186
- For synchronous functions, it calls them directly, while for asynchronous functions,
187
- it awaits their execution.
188
- """
189
- is_coroutine_function = inspect.iscoroutinefunction(func)
190
- start_time = time.perf_counter()
191
- if is_coroutine_function:
192
- result = await func(*args, **func_params["params"])
193
- else:
194
- result = func(*args, **func_params["params"])
195
-
196
- end_time = time.perf_counter()
197
- latency = end_time - start_time
198
-
199
- if isinstance(result, Context):
200
- save_context(result)
201
- if isinstance(result, Dict):
202
- return FuncResponse(**result, latency=round(latency, 4))
203
- if isinstance(result, str):
204
- return FuncResponse(message=result, latency=round(latency, 4)) # type: ignore
205
- if isinstance(result, int) or isinstance(result, float):
206
- return FuncResponse(message=str(result), latency=round(latency, 4))
207
- if result is None:
208
- return FuncResponse(
209
- message="Function executed successfully, but did return None. \n Are you sure you did not forget to return a value?",
210
- latency=round(latency, 4),
211
- )
212
- except Exception as e:
213
- self.handle_exception(e)
214
- return FuncResponse(message="Unexpected error occurred when calling the @entrypoing decorated function", latency=0) # type: ignore
215
-
216
- def handle_exception(self, e: Exception):
217
- """Handle exceptions."""
218
-
219
- status_code: int = e.status_code if hasattr(e, "status_code") else 500
220
- traceback_str = traceback.format_exception(e, value=e, tb=e.__traceback__) # type: ignore
221
- raise HTTPException(
222
- status_code=status_code,
223
- detail={"error": str(e), "traceback": "".join(traceback_str)},
224
- )
225
-
226
- def update_wrapper_signature(
227
- self, wrapper: Callable[..., Any], updated_params: List
228
- ):
229
- """
230
- Updates the signature of a wrapper function with a new list of parameters.
231
-
232
- Args:
233
- wrapper (callable): A callable object, such as a function or a method, that requires a signature update.
234
- updated_params (List[inspect.Parameter]): A list of `inspect.Parameter` objects representing the updated parameters
235
- for the wrapper function.
236
- """
237
-
238
- wrapper_signature = inspect.signature(wrapper)
239
- wrapper_signature = wrapper_signature.replace(parameters=updated_params)
240
- wrapper.__signature__ = wrapper_signature
241
-
242
- def update_function_signature(
243
- self,
244
- wrapper: Callable[..., Any],
245
- func_signature: inspect.Signature,
246
- config_params: Dict[str, Any],
247
- ingestible_files: Dict[str, inspect.Parameter],
248
- ) -> None:
249
- """Update the function signature to include new parameters."""
250
-
251
- updated_params = []
252
- self.add_config_params_to_parser(updated_params, config_params)
253
- self.add_func_params_to_parser(updated_params, func_signature, ingestible_files)
254
- self.update_wrapper_signature(wrapper, updated_params)
255
-
256
- def update_deployed_function_signature(
257
- self,
258
- wrapper: Callable[..., Any],
259
- func_signature: inspect.Signature,
260
- ingestible_files: Dict[str, inspect.Parameter],
261
- ) -> None:
262
- """Update the function signature to include new parameters."""
263
- updated_params = []
264
- self.add_func_params_to_parser(updated_params, func_signature, ingestible_files)
265
- for param in [
266
- "config",
267
- "environment",
268
- ]: # we add the config and environment parameters
269
- updated_params.append(
270
- inspect.Parameter(
271
- param,
272
- inspect.Parameter.KEYWORD_ONLY,
273
- default=Body(None),
274
- annotation=str,
275
- )
276
- )
277
- self.update_wrapper_signature(wrapper, updated_params)
278
-
279
- def add_config_params_to_parser(
280
- self, updated_params: list, config_params: Dict[str, Any]
281
- ) -> None:
282
- """Add configuration parameters to function signature."""
283
- for name, param in config_params.items():
284
- updated_params.append(
285
- inspect.Parameter(
286
- name,
287
- inspect.Parameter.KEYWORD_ONLY,
288
- default=Body(param),
289
- annotation=Optional[type(param)],
290
- )
291
- )
292
-
293
- def add_func_params_to_parser(
294
- self,
295
- updated_params: list,
296
- func_signature: inspect.Signature,
297
- ingestible_files: Dict[str, inspect.Parameter],
298
- ) -> None:
299
- """Add function parameters to function signature."""
300
- for name, param in func_signature.parameters.items():
301
- if name in ingestible_files:
302
- updated_params.append(
303
- inspect.Parameter(name, param.kind, annotation=UploadFile)
304
- )
305
- else:
306
- updated_params.append(
307
- inspect.Parameter(
308
- name,
309
- inspect.Parameter.KEYWORD_ONLY,
310
- default=Body(..., embed=True),
311
- annotation=param.annotation,
312
- )
313
- )
314
-
315
- def is_main_script(self, func: Callable) -> bool:
316
- """
317
- Check if the script containing the function is the main script being run.
318
-
319
- Args:
320
- func (Callable): The function object to check.
321
-
322
- Returns:
323
- bool: True if the script containing the function is the main script, False otherwise.
324
-
325
- Example:
326
- if is_main_script(my_function):
327
- print("This is the main script.")
328
- """
329
- return func.__module__ == "__main__"
330
-
331
- def handle_terminal_run(
332
- self,
333
- func: Callable,
334
- func_params: Dict[str, inspect.Parameter],
335
- config_params: Dict[str, Any],
336
- ingestible_files: Dict,
337
- ):
338
- """
339
- Parses command line arguments and sets configuration when script is run from the terminal.
340
-
341
- Args:
342
- func_params (dict): A dictionary containing the function parameters and their annotations.
343
- config_params (dict): A dictionary containing the configuration parameters.
344
- ingestible_files (dict): A dictionary containing the files that should be ingested.
345
- """
346
-
347
- # For required parameters, we add them as arguments
348
- parser = argparse.ArgumentParser()
349
- for name, param in func_params.items():
350
- if name in ingestible_files:
351
- parser.add_argument(name, type=str)
352
- else:
353
- parser.add_argument(name, type=param.annotation)
354
-
355
- for name, param in config_params.items():
356
- if type(param) is MultipleChoiceParam:
357
- parser.add_argument(
358
- f"--{name}",
359
- type=str,
360
- default=param.default,
361
- choices=param.choices,
362
- )
363
- else:
364
- parser.add_argument(
365
- f"--{name}",
366
- type=type(param),
367
- default=param,
368
- )
369
-
370
- args = parser.parse_args()
371
-
372
- # split the arg list into the arg in the app_param and
373
- # the args from the sig.parameter
374
- args_config_params = {k: v for k, v in vars(args).items() if k in config_params}
375
- args_func_params = {
376
- k: v for k, v in vars(args).items() if k not in config_params
377
- }
378
- for name in ingestible_files:
379
- args_func_params[name] = InFile(
380
- file_name=Path(args_func_params[name]).stem,
381
- file_path=args_func_params[name],
382
- )
383
-
384
- agenta.config.set(**args_config_params)
385
-
386
- # Set the configuration and environment of the LLM app parent span at run-time
387
- agenta.tracing.set_span_attribute(
388
- {"config": agenta.config.all(), "environment": "bash"}
389
- )
390
-
391
- loop = asyncio.get_event_loop()
392
- result = loop.run_until_complete(
393
- self.execute_function(
394
- func,
395
- **{"params": args_func_params, "config_params": args_config_params},
396
- )
397
- )
398
- print(
399
- f"\n========== Result ==========\n\nMessage: {result.message}\nCost: {result.cost}\nToken Usage: {result.usage}"
400
- )
401
-
402
- def override_schema(
403
- self, openapi_schema: dict, func_name: str, endpoint: str, params: dict
404
- ):
405
- """
406
- Overrides the default openai schema generated by fastapi with additional information about:
407
- - The choices available for each MultipleChoiceParam instance
408
- - The min and max values for each FloatParam instance
409
- - The min and max values for each IntParam instance
410
- - The default value for DictInput instance
411
- - The default value for MessagesParam instance
412
- - The default value for FileInputURL instance
413
- - The default value for BinaryParam instance
414
- - ... [PLEASE ADD AT EACH CHANGE]
415
-
416
- Args:
417
- openapi_schema (dict): The openapi schema generated by fastapi
418
- func_name (str): The name of the function to override
419
- endpoint (str): The name of the endpoint to override
420
- params (dict(param_name, param_val)): The dictionary of the parameters for the function
421
- """
422
-
423
- def find_in_schema(schema: dict, param_name: str, xparam: str):
424
- """Finds a parameter in the schema based on its name and x-parameter value"""
425
- for _, value in schema.items():
426
- value_title_lower = str(value.get("title")).lower()
427
- value_title = (
428
- "_".join(value_title_lower.split())
429
- if len(value_title_lower.split()) >= 2
430
- else value_title_lower
431
- )
432
-
433
- if (
434
- isinstance(value, dict)
435
- and value.get("x-parameter") == xparam
436
- and value_title == param_name
437
- ):
438
- return value
439
-
440
- schema_to_override = openapi_schema["components"]["schemas"][
441
- f"Body_{func_name}_{endpoint}_post"
442
- ]["properties"]
443
- for param_name, param_val in params.items():
444
- if isinstance(param_val, GroupedMultipleChoiceParam):
445
- subschema = find_in_schema(
446
- schema_to_override, param_name, "grouped_choice"
447
- )
448
- assert (
449
- subschema
450
- ), f"GroupedMultipleChoiceParam '{param_name}' is in the parameters but could not be found in the openapi.json"
451
- subschema["choices"] = param_val.choices
452
- subschema["default"] = param_val.default
453
- if isinstance(param_val, MultipleChoiceParam):
454
- subschema = find_in_schema(schema_to_override, param_name, "choice")
455
- default = str(param_val)
456
- param_choices = param_val.choices
457
- choices = (
458
- [default] + param_choices
459
- if param_val not in param_choices
460
- else param_choices
461
- )
462
- subschema["enum"] = choices
463
- subschema["default"] = (
464
- default if default in param_choices else choices[0]
465
- )
466
- if isinstance(param_val, FloatParam):
467
- subschema = find_in_schema(schema_to_override, param_name, "float")
468
- subschema["minimum"] = param_val.minval
469
- subschema["maximum"] = param_val.maxval
470
- subschema["default"] = param_val
471
- if isinstance(param_val, IntParam):
472
- subschema = find_in_schema(schema_to_override, param_name, "int")
473
- subschema["minimum"] = param_val.minval
474
- subschema["maximum"] = param_val.maxval
475
- subschema["default"] = param_val
476
- if (
477
- isinstance(param_val, inspect.Parameter)
478
- and param_val.annotation is DictInput
479
- ):
480
- subschema = find_in_schema(schema_to_override, param_name, "dict")
481
- subschema["default"] = param_val.default["default_keys"]
482
- if isinstance(param_val, TextParam):
483
- subschema = find_in_schema(schema_to_override, param_name, "text")
484
- subschema["default"] = param_val
485
- if (
486
- isinstance(param_val, inspect.Parameter)
487
- and param_val.annotation is MessagesInput
488
- ):
489
- subschema = find_in_schema(schema_to_override, param_name, "messages")
490
- subschema["default"] = param_val.default
491
- if (
492
- isinstance(param_val, inspect.Parameter)
493
- and param_val.annotation is FileInputURL
494
- ):
495
- subschema = find_in_schema(schema_to_override, param_name, "file_url")
496
- subschema["default"] = "https://example.com"
497
- if isinstance(param_val, BinaryParam):
498
- subschema = find_in_schema(schema_to_override, param_name, "bool")
499
- subschema["default"] = param_val.default
@@ -1,98 +0,0 @@
1
- # Stdlib Imports
2
- import inspect
3
- from functools import wraps
4
- from typing import Any, Callable, Optional
5
-
6
- # Own Imports
7
- import agenta as ag
8
- from agenta.sdk.decorators.base import BaseDecorator
9
-
10
-
11
- class instrument(BaseDecorator):
12
- """Decorator class for monitoring llm apps functions.
13
-
14
- Args:
15
- BaseDecorator (object): base decorator class
16
-
17
- Example:
18
- ```python
19
- import agenta as ag
20
-
21
- prompt_config = {"system_prompt": ..., "temperature": 0.5, "max_tokens": ...}
22
-
23
- @ag.instrument(spankind="llm")
24
- async def litellm_openai_call(prompt:str) -> str:
25
- return "do something"
26
-
27
- @ag.instrument(config=prompt_config) # spankind for parent span defaults to workflow
28
- async def generate(prompt: str):
29
- return ...
30
- ```
31
- """
32
-
33
- def __init__(
34
- self, config: Optional[dict] = None, spankind: str = "workflow"
35
- ) -> None:
36
- self.config = config
37
- self.spankind = spankind
38
- self.tracing = ag.tracing
39
-
40
- def __call__(self, func: Callable[..., Any]):
41
- is_coroutine_function = inspect.iscoroutinefunction(func)
42
-
43
- @wraps(func)
44
- async def async_wrapper(*args, **kwargs):
45
- result = None
46
- func_args = inspect.getfullargspec(func).args
47
- input_dict = {name: value for name, value in zip(func_args, args)}
48
- input_dict.update(kwargs)
49
-
50
- span = self.tracing.start_span(
51
- name=func.__name__,
52
- input=input_dict,
53
- spankind=self.spankind,
54
- config=self.config,
55
- )
56
-
57
- try:
58
- result = await func(*args, **kwargs)
59
- self.tracing.update_span_status(span=span, value="OK")
60
- except Exception as e:
61
- result = str(e)
62
- self.tracing.update_span_status(span=span, value="ERROR")
63
- finally:
64
- self.tracing.end_span(
65
- outputs=(
66
- {"message": result} if not isinstance(result, dict) else result
67
- )
68
- )
69
- return result
70
-
71
- @wraps(func)
72
- def sync_wrapper(*args, **kwargs):
73
- result = None
74
- func_args = inspect.getfullargspec(func).args
75
- input_dict = {name: value for name, value in zip(func_args, args)}
76
- input_dict.update(kwargs)
77
-
78
- span = self.tracing.start_span(
79
- name=func.__name__,
80
- input=input_dict,
81
- spankind=self.spankind,
82
- config=self.config,
83
- )
84
-
85
- try:
86
- result = func(*args, **kwargs)
87
- self.tracing.update_span_status(span=span, value="OK")
88
- except Exception as e:
89
- result = str(e)
90
- self.tracing.update_span_status(span=span, value="ERROR")
91
- finally:
92
- self.tracing.end_span(
93
- outputs=(
94
- {"message": result} if not isinstance(result, dict) else result
95
- )
96
- )
97
-
98
- return async_wrapper if is_coroutine_function else sync_wrapper