agenta 0.26.0a0__py3-none-any.whl → 0.27.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 +29 -10
- agenta/cli/helper.py +5 -1
- agenta/client/backend/__init__.py +14 -0
- agenta/client/backend/apps/client.py +28 -20
- agenta/client/backend/client.py +47 -16
- agenta/client/backend/containers/client.py +5 -1
- agenta/client/backend/core/__init__.py +2 -1
- agenta/client/backend/core/client_wrapper.py +6 -6
- agenta/client/backend/core/file.py +33 -11
- agenta/client/backend/core/http_client.py +45 -31
- agenta/client/backend/core/pydantic_utilities.py +144 -29
- agenta/client/backend/core/request_options.py +3 -0
- agenta/client/backend/core/serialization.py +139 -42
- agenta/client/backend/evaluations/client.py +7 -2
- agenta/client/backend/evaluators/client.py +349 -1
- agenta/client/backend/observability/client.py +11 -2
- agenta/client/backend/testsets/client.py +10 -10
- agenta/client/backend/types/__init__.py +14 -0
- agenta/client/backend/types/app.py +1 -0
- agenta/client/backend/types/app_variant_response.py +3 -1
- agenta/client/backend/types/config_dto.py +32 -0
- agenta/client/backend/types/config_response_model.py +32 -0
- agenta/client/backend/types/create_span.py +3 -2
- agenta/client/backend/types/environment_output.py +1 -0
- agenta/client/backend/types/environment_output_extended.py +1 -0
- agenta/client/backend/types/evaluation.py +1 -2
- agenta/client/backend/types/evaluator.py +2 -0
- agenta/client/backend/types/evaluator_config.py +1 -0
- agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
- agenta/client/backend/types/evaluator_output_interface.py +21 -0
- agenta/client/backend/types/human_evaluation.py +1 -2
- agenta/client/backend/types/lifecycle_dto.py +24 -0
- agenta/client/backend/types/llm_tokens.py +2 -2
- agenta/client/backend/types/reference_dto.py +23 -0
- agenta/client/backend/types/reference_request_model.py +23 -0
- agenta/client/backend/types/span.py +1 -0
- agenta/client/backend/types/span_detail.py +7 -1
- agenta/client/backend/types/test_set_output_response.py +5 -2
- agenta/client/backend/types/trace_detail.py +7 -1
- agenta/client/backend/types/with_pagination.py +4 -2
- agenta/client/backend/variants/client.py +1565 -272
- agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
- agenta/sdk/__init__.py +44 -7
- agenta/sdk/agenta_init.py +85 -33
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/routing.py +26 -0
- agenta/sdk/context/tracing.py +3 -0
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +216 -191
- agenta/sdk/decorators/tracing.py +218 -99
- agenta/sdk/litellm/__init__.py +1 -0
- agenta/sdk/litellm/litellm.py +288 -0
- agenta/sdk/managers/__init__.py +6 -0
- agenta/sdk/managers/config.py +318 -0
- agenta/sdk/managers/deployment.py +45 -0
- agenta/sdk/managers/shared.py +639 -0
- agenta/sdk/managers/variant.py +182 -0
- agenta/sdk/router.py +0 -7
- agenta/sdk/tracing/__init__.py +1 -0
- agenta/sdk/tracing/attributes.py +141 -0
- agenta/sdk/tracing/context.py +24 -0
- agenta/sdk/tracing/conventions.py +49 -0
- agenta/sdk/tracing/exporters.py +65 -0
- agenta/sdk/tracing/inline.py +1252 -0
- agenta/sdk/tracing/processors.py +117 -0
- agenta/sdk/tracing/spans.py +136 -0
- agenta/sdk/tracing/tracing.py +233 -0
- agenta/sdk/types.py +49 -2
- agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
- agenta/sdk/utils/debug.py +5 -5
- agenta/sdk/utils/exceptions.py +52 -0
- agenta/sdk/utils/globals.py +3 -5
- agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
- agenta/sdk/utils/singleton.py +13 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/METADATA +5 -1
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/RECORD +78 -57
- agenta/sdk/config_manager.py +0 -205
- agenta/sdk/context.py +0 -41
- agenta/sdk/decorators/base.py +0 -10
- agenta/sdk/tracing/callbacks.py +0 -187
- agenta/sdk/tracing/llm_tracing.py +0 -617
- agenta/sdk/tracing/tasks_manager.py +0 -129
- agenta/sdk/tracing/tracing_context.py +0 -27
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/WHEEL +0 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import asyncio
|
|
11
|
-
import traceback
|
|
12
|
-
import functools
|
|
1
|
+
from typing import Type, Any, Callable, Dict, Optional, Tuple, List
|
|
2
|
+
from annotated_types import Ge, Le, Gt, Lt
|
|
3
|
+
from pydantic import BaseModel, HttpUrl, ValidationError
|
|
4
|
+
from json import dumps
|
|
5
|
+
from inspect import signature, iscoroutinefunction, Signature, Parameter, _empty
|
|
6
|
+
from argparse import ArgumentParser
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from asyncio import sleep, get_event_loop
|
|
9
|
+
from traceback import format_exc, format_exception
|
|
13
10
|
from pathlib import Path
|
|
14
11
|
from tempfile import NamedTemporaryFile
|
|
15
|
-
from
|
|
16
|
-
from importlib.metadata import version
|
|
12
|
+
from os import environ
|
|
17
13
|
|
|
18
14
|
from fastapi.middleware.cors import CORSMiddleware
|
|
19
15
|
from fastapi import Body, FastAPI, UploadFile, HTTPException
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
from agenta.sdk.context import
|
|
17
|
+
from agenta.sdk.context.routing import routing_context_manager, routing_context
|
|
18
|
+
from agenta.sdk.context.tracing import tracing_context
|
|
23
19
|
from agenta.sdk.router import router as router
|
|
24
|
-
from agenta.sdk.
|
|
25
|
-
from agenta.sdk.
|
|
26
|
-
from agenta.sdk.decorators.base import BaseDecorator
|
|
20
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
21
|
+
from agenta.sdk.utils.logging import log
|
|
27
22
|
from agenta.sdk.types import (
|
|
28
|
-
Context,
|
|
29
23
|
DictInput,
|
|
30
24
|
FloatParam,
|
|
31
25
|
InFile,
|
|
@@ -39,16 +33,8 @@ from agenta.sdk.types import (
|
|
|
39
33
|
BaseResponse,
|
|
40
34
|
BinaryParam,
|
|
41
35
|
)
|
|
42
|
-
import pydantic
|
|
43
|
-
|
|
44
|
-
from pydantic import BaseModel
|
|
45
|
-
from typing import Type
|
|
46
|
-
from annotated_types import Ge, Le, Gt, Lt
|
|
47
|
-
|
|
48
|
-
from pydantic import BaseModel, HttpUrl
|
|
49
|
-
import contextvars
|
|
50
|
-
from contextlib import contextmanager
|
|
51
36
|
|
|
37
|
+
import agenta as ag
|
|
52
38
|
|
|
53
39
|
app = FastAPI()
|
|
54
40
|
|
|
@@ -67,36 +53,14 @@ app.add_middleware(
|
|
|
67
53
|
app.include_router(router, prefix="")
|
|
68
54
|
|
|
69
55
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
route_context = contextvars.ContextVar("route_context", default={})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@contextmanager
|
|
76
|
-
def route_context_manager(
|
|
77
|
-
config: Optional[Dict[str, Any]] = None,
|
|
78
|
-
environment: Optional[str] = None,
|
|
79
|
-
version: Optional[str] = None,
|
|
80
|
-
variant: Optional[str] = None,
|
|
81
|
-
):
|
|
82
|
-
context = {
|
|
83
|
-
"config": config,
|
|
84
|
-
"environment": environment,
|
|
85
|
-
"version": version,
|
|
86
|
-
"variant": variant,
|
|
87
|
-
}
|
|
88
|
-
token = route_context.set(context)
|
|
89
|
-
try:
|
|
90
|
-
yield
|
|
91
|
-
finally:
|
|
92
|
-
route_context.reset(token)
|
|
56
|
+
log.setLevel("DEBUG")
|
|
93
57
|
|
|
94
58
|
|
|
95
59
|
class PathValidator(BaseModel):
|
|
96
60
|
url: HttpUrl
|
|
97
61
|
|
|
98
62
|
|
|
99
|
-
class route
|
|
63
|
+
class route:
|
|
100
64
|
# This decorator is used to expose specific stages of a workflow (embedding, retrieval, summarization, etc.)
|
|
101
65
|
# as independent endpoints. It is designed for backward compatibility with existing code that uses
|
|
102
66
|
# the @entrypoint decorator, which has certain limitations. By using @route(), we can create new
|
|
@@ -118,7 +82,7 @@ class route(BaseDecorator):
|
|
|
118
82
|
return f
|
|
119
83
|
|
|
120
84
|
|
|
121
|
-
class entrypoint
|
|
85
|
+
class entrypoint:
|
|
122
86
|
"""
|
|
123
87
|
Decorator class to wrap a function for HTTP POST, terminal exposure and enable tracing.
|
|
124
88
|
|
|
@@ -152,19 +116,20 @@ class entrypoint(BaseDecorator):
|
|
|
152
116
|
routes = list()
|
|
153
117
|
|
|
154
118
|
def __init__(
|
|
155
|
-
self,
|
|
119
|
+
self,
|
|
120
|
+
func: Callable[..., Any],
|
|
121
|
+
route_path="",
|
|
122
|
+
config_schema: Optional[BaseModel] = None,
|
|
156
123
|
):
|
|
157
|
-
logging.info(f"Using Agenta Python SDK version {version('agenta')}")
|
|
158
|
-
|
|
159
124
|
DEFAULT_PATH = "generate"
|
|
160
125
|
PLAYGROUND_PATH = "/playground"
|
|
161
126
|
RUN_PATH = "/run"
|
|
162
|
-
func_signature =
|
|
127
|
+
func_signature = signature(func)
|
|
163
128
|
try:
|
|
164
129
|
config = (
|
|
165
130
|
config_schema() if config_schema else None
|
|
166
131
|
) # we initialize the config object to be able to use it
|
|
167
|
-
except
|
|
132
|
+
except ValidationError as e:
|
|
168
133
|
raise ValueError(
|
|
169
134
|
f"Error initializing config_schema. Please ensure all required fields have default values: {str(e)}"
|
|
170
135
|
) from e
|
|
@@ -176,20 +141,19 @@ class entrypoint(BaseDecorator):
|
|
|
176
141
|
config_params = config.dict() if config else ag.config.all()
|
|
177
142
|
ingestible_files = self.extract_ingestible_files(func_signature)
|
|
178
143
|
|
|
144
|
+
self.route_path = route_path
|
|
145
|
+
|
|
179
146
|
### --- Playground --- #
|
|
180
|
-
@
|
|
181
|
-
@functools.wraps(func)
|
|
147
|
+
@wraps(func)
|
|
182
148
|
async def wrapper(*args, **kwargs) -> Any:
|
|
183
149
|
func_params, api_config_params = self.split_kwargs(kwargs, config_params)
|
|
184
150
|
self.ingest_files(func_params, ingestible_files)
|
|
185
151
|
if not config_schema:
|
|
186
152
|
ag.config.set(**api_config_params)
|
|
187
153
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)
|
|
192
|
-
with route_context_manager(config=api_config_params):
|
|
154
|
+
with routing_context_manager(
|
|
155
|
+
config=api_config_params,
|
|
156
|
+
):
|
|
193
157
|
entrypoint_result = await self.execute_function(
|
|
194
158
|
func,
|
|
195
159
|
True, # inline trace: True
|
|
@@ -241,12 +205,13 @@ class entrypoint(BaseDecorator):
|
|
|
241
205
|
)
|
|
242
206
|
### ---------------------------- #
|
|
243
207
|
|
|
244
|
-
### --- Deployed
|
|
245
|
-
@
|
|
246
|
-
@functools.wraps(func)
|
|
208
|
+
### --- Deployed --- #
|
|
209
|
+
@wraps(func)
|
|
247
210
|
async def wrapper_deployed(*args, **kwargs) -> Any:
|
|
248
211
|
func_params = {
|
|
249
|
-
k: v
|
|
212
|
+
k: v
|
|
213
|
+
for k, v in kwargs.items()
|
|
214
|
+
if k not in ["config", "environment", "app"]
|
|
250
215
|
}
|
|
251
216
|
if not config_schema:
|
|
252
217
|
if "environment" in kwargs and kwargs["environment"] is not None:
|
|
@@ -256,12 +221,19 @@ class entrypoint(BaseDecorator):
|
|
|
256
221
|
else:
|
|
257
222
|
ag.config.pull(config_name="default")
|
|
258
223
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
224
|
+
app_id = environ.get("AGENTA_APP_ID")
|
|
225
|
+
|
|
226
|
+
with routing_context_manager(
|
|
227
|
+
application={
|
|
228
|
+
"id": app_id,
|
|
229
|
+
"slug": kwargs["app"],
|
|
230
|
+
},
|
|
231
|
+
variant={
|
|
232
|
+
"slug": kwargs.get("config"),
|
|
233
|
+
},
|
|
234
|
+
environment={
|
|
235
|
+
"slug": kwargs.get("environment"),
|
|
236
|
+
},
|
|
265
237
|
):
|
|
266
238
|
entrypoint_result = await self.execute_function(
|
|
267
239
|
func,
|
|
@@ -284,7 +256,7 @@ class entrypoint(BaseDecorator):
|
|
|
284
256
|
|
|
285
257
|
route_deployed = f"{RUN_PATH}{route_path}"
|
|
286
258
|
app.post(route_deployed, response_model=BaseResponse)(wrapper_deployed)
|
|
287
|
-
###
|
|
259
|
+
### ---------------- #
|
|
288
260
|
|
|
289
261
|
### --- Update OpenAPI --- #
|
|
290
262
|
app.openapi_schema = None # Forces FastAPI to re-generate the schema
|
|
@@ -315,8 +287,8 @@ class entrypoint(BaseDecorator):
|
|
|
315
287
|
|
|
316
288
|
def extract_ingestible_files(
|
|
317
289
|
self,
|
|
318
|
-
func_signature:
|
|
319
|
-
) -> Dict[str,
|
|
290
|
+
func_signature: Signature,
|
|
291
|
+
) -> Dict[str, Parameter]:
|
|
320
292
|
"""Extract parameters annotated as InFile from function signature."""
|
|
321
293
|
|
|
322
294
|
return {
|
|
@@ -343,7 +315,7 @@ class entrypoint(BaseDecorator):
|
|
|
343
315
|
def ingest_files(
|
|
344
316
|
self,
|
|
345
317
|
func_params: Dict[str, Any],
|
|
346
|
-
ingestible_files: Dict[str,
|
|
318
|
+
ingestible_files: Dict[str, Parameter],
|
|
347
319
|
) -> None:
|
|
348
320
|
"""Ingest files specified in function parameters."""
|
|
349
321
|
|
|
@@ -352,96 +324,134 @@ class entrypoint(BaseDecorator):
|
|
|
352
324
|
func_params[name] = self.ingest_file(func_params[name])
|
|
353
325
|
|
|
354
326
|
async def execute_function(
|
|
355
|
-
self,
|
|
327
|
+
self,
|
|
328
|
+
func: Callable[..., Any],
|
|
329
|
+
inline_trace,
|
|
330
|
+
*args,
|
|
331
|
+
**func_params,
|
|
356
332
|
):
|
|
357
|
-
|
|
333
|
+
log.info(f"---------------------------")
|
|
334
|
+
log.info(f"Agenta SDK - running route: {repr(self.route_path or '/')}")
|
|
335
|
+
log.info(f"---------------------------")
|
|
336
|
+
|
|
337
|
+
tracing_context.set(routing_context.get())
|
|
358
338
|
|
|
359
339
|
try:
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
logging.info(f"Using Agenta Python SDK version {version('agenta')}")
|
|
340
|
+
result = (
|
|
341
|
+
await func(*args, **func_params["params"])
|
|
342
|
+
if iscoroutinefunction(func)
|
|
343
|
+
else func(*args, **func_params["params"])
|
|
344
|
+
)
|
|
366
345
|
|
|
367
|
-
|
|
368
|
-
TIMEOUT = 1
|
|
369
|
-
TIMESTEP = 0.1
|
|
370
|
-
NOFSTEPS = TIMEOUT / TIMESTEP
|
|
346
|
+
return await self.handle_success(result, inline_trace)
|
|
371
347
|
|
|
372
|
-
|
|
373
|
-
|
|
348
|
+
except Exception as error:
|
|
349
|
+
self.handle_failure(error)
|
|
374
350
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
351
|
+
async def handle_success(self, result: Any, inline_trace: bool):
|
|
352
|
+
data = None
|
|
353
|
+
trace = dict()
|
|
378
354
|
|
|
379
|
-
|
|
355
|
+
with suppress():
|
|
356
|
+
data = self.patch_result(result)
|
|
380
357
|
|
|
381
|
-
if
|
|
382
|
-
|
|
383
|
-
else:
|
|
384
|
-
result = func(*args, **func_params["params"])
|
|
358
|
+
if inline_trace:
|
|
359
|
+
trace = await self.fetch_inline_trace(inline_trace)
|
|
385
360
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
361
|
+
log.info(f"----------------------------------")
|
|
362
|
+
log.info(f"Agenta SDK - exiting with success: 200")
|
|
363
|
+
log.info(f"----------------------------------")
|
|
389
364
|
|
|
390
|
-
|
|
391
|
-
await asyncio.sleep(TIMESTEP)
|
|
392
|
-
remaining_steps -= 1
|
|
365
|
+
return BaseResponse(data=data, trace=trace)
|
|
393
366
|
|
|
394
|
-
|
|
367
|
+
def handle_failure(self, error: Exception):
|
|
368
|
+
log.error("--------------------------------------------------")
|
|
369
|
+
log.error("Agenta SDK - handling application exception below:")
|
|
370
|
+
log.error("--------------------------------------------------")
|
|
371
|
+
log.error(format_exc().strip("\n"))
|
|
372
|
+
log.error("--------------------------------------------------")
|
|
395
373
|
|
|
396
|
-
|
|
397
|
-
|
|
374
|
+
status_code = error.status_code if hasattr(error, "status_code") else 500
|
|
375
|
+
message = str(error)
|
|
376
|
+
stacktrace = format_exception(error, value=error, tb=error.__traceback__) # type: ignore
|
|
377
|
+
detail = {"message": message, "stacktrace": stacktrace}
|
|
398
378
|
|
|
399
|
-
|
|
400
|
-
|
|
379
|
+
log.error(f"----------------------------------")
|
|
380
|
+
log.error(f"Agenta SDK - exiting with failure: {status_code}")
|
|
381
|
+
log.error(f"----------------------------------")
|
|
401
382
|
|
|
402
|
-
|
|
403
|
-
save_context(result)
|
|
383
|
+
raise HTTPException(status_code=status_code, detail=detail)
|
|
404
384
|
|
|
405
|
-
|
|
385
|
+
def patch_result(self, result: Any):
|
|
386
|
+
"""
|
|
387
|
+
Patch the result to only include the message if the result is a FuncResponse-style dictionary with message, cost, and usage keys.
|
|
406
388
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
389
|
+
Example:
|
|
390
|
+
```python
|
|
391
|
+
result = {
|
|
392
|
+
"message": "Hello, world!",
|
|
393
|
+
"cost": 0.5,
|
|
394
|
+
"usage": {
|
|
395
|
+
"prompt_tokens": 10,
|
|
396
|
+
"completion_tokens": 20,
|
|
397
|
+
"total_tokens": 30
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
result = patch_result(result)
|
|
401
|
+
print(result)
|
|
402
|
+
# Output: "Hello, world!"
|
|
403
|
+
```
|
|
404
|
+
"""
|
|
405
|
+
data = (
|
|
406
|
+
result["message"]
|
|
407
|
+
if isinstance(result, dict)
|
|
408
|
+
and all(key in result for key in ["message", "cost", "usage"])
|
|
409
|
+
else result
|
|
410
|
+
)
|
|
418
411
|
|
|
419
|
-
|
|
412
|
+
if data is None:
|
|
413
|
+
data = (
|
|
414
|
+
"Function executed successfully, but did return None. \n Are you sure you did not forget to return a value?",
|
|
415
|
+
)
|
|
420
416
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
"Function executed successfully, but did return None. \n Are you sure you did not forget to return a value?",
|
|
424
|
-
)
|
|
417
|
+
if not isinstance(result, dict):
|
|
418
|
+
data = str(data)
|
|
425
419
|
|
|
426
|
-
|
|
420
|
+
return data
|
|
427
421
|
|
|
428
|
-
|
|
422
|
+
async def fetch_inline_trace(self, inline_trace):
|
|
423
|
+
WAIT_FOR_SPANS = True
|
|
424
|
+
TIMEOUT = 1
|
|
425
|
+
TIMESTEP = 0.1
|
|
426
|
+
FINALSTEP = 0.001
|
|
427
|
+
NOFSTEPS = TIMEOUT / TIMESTEP
|
|
429
428
|
|
|
430
|
-
|
|
429
|
+
trace = None
|
|
431
430
|
|
|
432
|
-
|
|
433
|
-
self.handle_exception(e)
|
|
431
|
+
root_context: Dict[str, Any] = tracing_context.get().get("root")
|
|
434
432
|
|
|
435
|
-
|
|
436
|
-
status_code = e.status_code if hasattr(e, "status_code") else 500
|
|
437
|
-
message = str(e)
|
|
438
|
-
stacktrace = traceback.format_exception(e, value=e, tb=e.__traceback__) # type: ignore
|
|
439
|
-
detail = {"message": message, "stacktrace": stacktrace}
|
|
433
|
+
trace_id = root_context.get("trace_id") if root_context else None
|
|
440
434
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
435
|
+
if trace_id is not None:
|
|
436
|
+
if inline_trace:
|
|
437
|
+
if WAIT_FOR_SPANS:
|
|
438
|
+
remaining_steps = NOFSTEPS
|
|
439
|
+
|
|
440
|
+
while (
|
|
441
|
+
not ag.tracing.is_inline_trace_ready(trace_id)
|
|
442
|
+
and remaining_steps > 0
|
|
443
|
+
):
|
|
444
|
+
await sleep(TIMESTEP)
|
|
445
|
+
|
|
446
|
+
remaining_steps -= 1
|
|
447
|
+
|
|
448
|
+
await sleep(FINALSTEP)
|
|
449
|
+
|
|
450
|
+
trace = ag.tracing.get_inline_trace(trace_id)
|
|
451
|
+
else:
|
|
452
|
+
trace = {"trace_id": trace_id}
|
|
453
|
+
|
|
454
|
+
return trace
|
|
445
455
|
|
|
446
456
|
def update_wrapper_signature(
|
|
447
457
|
self, wrapper: Callable[..., Any], updated_params: List
|
|
@@ -451,25 +461,25 @@ class entrypoint(BaseDecorator):
|
|
|
451
461
|
|
|
452
462
|
Args:
|
|
453
463
|
wrapper (callable): A callable object, such as a function or a method, that requires a signature update.
|
|
454
|
-
updated_params (List[
|
|
464
|
+
updated_params (List[Parameter]): A list of `Parameter` objects representing the updated parameters
|
|
455
465
|
for the wrapper function.
|
|
456
466
|
"""
|
|
457
467
|
|
|
458
|
-
wrapper_signature =
|
|
468
|
+
wrapper_signature = signature(wrapper)
|
|
459
469
|
wrapper_signature = wrapper_signature.replace(parameters=updated_params)
|
|
460
470
|
wrapper.__signature__ = wrapper_signature # type: ignore
|
|
461
471
|
|
|
462
472
|
def update_function_signature(
|
|
463
473
|
self,
|
|
464
474
|
wrapper: Callable[..., Any],
|
|
465
|
-
func_signature:
|
|
475
|
+
func_signature: Signature,
|
|
466
476
|
config_class: Type[BaseModel], # TODO: change to our type
|
|
467
477
|
config_dict: Dict[str, Any],
|
|
468
|
-
ingestible_files: Dict[str,
|
|
478
|
+
ingestible_files: Dict[str, Parameter],
|
|
469
479
|
) -> None:
|
|
470
480
|
"""Update the function signature to include new parameters."""
|
|
471
481
|
|
|
472
|
-
updated_params: List[
|
|
482
|
+
updated_params: List[Parameter] = []
|
|
473
483
|
if config_class:
|
|
474
484
|
self.add_config_params_to_parser(updated_params, config_class)
|
|
475
485
|
else:
|
|
@@ -480,21 +490,21 @@ class entrypoint(BaseDecorator):
|
|
|
480
490
|
def update_deployed_function_signature(
|
|
481
491
|
self,
|
|
482
492
|
wrapper: Callable[..., Any],
|
|
483
|
-
func_signature:
|
|
484
|
-
ingestible_files: Dict[str,
|
|
493
|
+
func_signature: Signature,
|
|
494
|
+
ingestible_files: Dict[str, Parameter],
|
|
485
495
|
) -> None:
|
|
486
496
|
"""Update the function signature to include new parameters."""
|
|
487
497
|
|
|
488
|
-
updated_params: List[
|
|
498
|
+
updated_params: List[Parameter] = []
|
|
489
499
|
self.add_func_params_to_parser(updated_params, func_signature, ingestible_files)
|
|
490
500
|
for param in [
|
|
491
501
|
"config",
|
|
492
502
|
"environment",
|
|
493
503
|
]: # we add the config and environment parameters
|
|
494
504
|
updated_params.append(
|
|
495
|
-
|
|
505
|
+
Parameter(
|
|
496
506
|
name=param,
|
|
497
|
-
kind=
|
|
507
|
+
kind=Parameter.KEYWORD_ONLY,
|
|
498
508
|
default=Body(None),
|
|
499
509
|
annotation=str,
|
|
500
510
|
)
|
|
@@ -508,9 +518,9 @@ class entrypoint(BaseDecorator):
|
|
|
508
518
|
for name, field in config_class.__fields__.items():
|
|
509
519
|
assert field.default is not None, f"Field {name} has no default value"
|
|
510
520
|
updated_params.append(
|
|
511
|
-
|
|
521
|
+
Parameter(
|
|
512
522
|
name=name,
|
|
513
|
-
kind=
|
|
523
|
+
kind=Parameter.KEYWORD_ONLY,
|
|
514
524
|
annotation=field.annotation.__name__,
|
|
515
525
|
default=Body(field.default),
|
|
516
526
|
)
|
|
@@ -525,9 +535,9 @@ class entrypoint(BaseDecorator):
|
|
|
525
535
|
len(param.__class__.__bases__) == 1
|
|
526
536
|
), f"Inherited standard type of {param.__class__} needs to be one."
|
|
527
537
|
updated_params.append(
|
|
528
|
-
|
|
538
|
+
Parameter(
|
|
529
539
|
name=name,
|
|
530
|
-
kind=
|
|
540
|
+
kind=Parameter.KEYWORD_ONLY,
|
|
531
541
|
default=Body(param),
|
|
532
542
|
annotation=param.__class__.__bases__[
|
|
533
543
|
0
|
|
@@ -540,23 +550,23 @@ class entrypoint(BaseDecorator):
|
|
|
540
550
|
def add_func_params_to_parser(
|
|
541
551
|
self,
|
|
542
552
|
updated_params: list,
|
|
543
|
-
func_signature:
|
|
544
|
-
ingestible_files: Dict[str,
|
|
553
|
+
func_signature: Signature,
|
|
554
|
+
ingestible_files: Dict[str, Parameter],
|
|
545
555
|
) -> None:
|
|
546
556
|
"""Add function parameters to function signature."""
|
|
547
557
|
for name, param in func_signature.parameters.items():
|
|
548
558
|
if name in ingestible_files:
|
|
549
559
|
updated_params.append(
|
|
550
|
-
|
|
560
|
+
Parameter(name, param.kind, annotation=UploadFile)
|
|
551
561
|
)
|
|
552
562
|
else:
|
|
553
563
|
assert (
|
|
554
564
|
len(param.default.__class__.__bases__) == 1
|
|
555
565
|
), f"Inherited standard type of {param.default.__class__} needs to be one."
|
|
556
566
|
updated_params.append(
|
|
557
|
-
|
|
567
|
+
Parameter(
|
|
558
568
|
name,
|
|
559
|
-
|
|
569
|
+
Parameter.KEYWORD_ONLY,
|
|
560
570
|
default=Body(..., embed=True),
|
|
561
571
|
annotation=param.default.__class__.__bases__[
|
|
562
572
|
0
|
|
@@ -585,7 +595,7 @@ class entrypoint(BaseDecorator):
|
|
|
585
595
|
def handle_terminal_run(
|
|
586
596
|
self,
|
|
587
597
|
func: Callable,
|
|
588
|
-
func_params: Dict[str,
|
|
598
|
+
func_params: Dict[str, Parameter],
|
|
589
599
|
config_params: Dict[str, Any],
|
|
590
600
|
ingestible_files: Dict,
|
|
591
601
|
):
|
|
@@ -599,7 +609,7 @@ class entrypoint(BaseDecorator):
|
|
|
599
609
|
"""
|
|
600
610
|
|
|
601
611
|
# For required parameters, we add them as arguments
|
|
602
|
-
parser =
|
|
612
|
+
parser = ArgumentParser()
|
|
603
613
|
for name, param in func_params.items():
|
|
604
614
|
if name in ingestible_files:
|
|
605
615
|
parser.add_argument(name, type=str)
|
|
@@ -644,28 +654,46 @@ class entrypoint(BaseDecorator):
|
|
|
644
654
|
}
|
|
645
655
|
)
|
|
646
656
|
|
|
647
|
-
|
|
648
|
-
ag.tracing.update_baggage({"config": args_config_params, "environment": "bash"})
|
|
657
|
+
loop = get_event_loop()
|
|
649
658
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
659
|
+
with routing_context_manager(
|
|
660
|
+
config=args_config_params,
|
|
661
|
+
environment="terminal",
|
|
662
|
+
):
|
|
663
|
+
result = loop.run_until_complete(
|
|
664
|
+
self.execute_function(
|
|
665
|
+
func,
|
|
666
|
+
True, # inline trace: True
|
|
667
|
+
**{"params": args_func_params, "config_params": args_config_params},
|
|
668
|
+
)
|
|
657
669
|
)
|
|
658
|
-
)
|
|
659
670
|
|
|
660
|
-
|
|
671
|
+
SHOW_DETAILS = True
|
|
672
|
+
SHOW_DATA = False
|
|
673
|
+
SHOW_TRACE = False
|
|
674
|
+
|
|
675
|
+
if result.trace:
|
|
676
|
+
log.info("\n========= Result =========\n")
|
|
677
|
+
|
|
678
|
+
log.info(f"trace_id: {result.trace['trace_id']}")
|
|
679
|
+
if SHOW_DETAILS:
|
|
680
|
+
log.info(f"latency: {result.trace.get('latency')}")
|
|
681
|
+
log.info(f"cost: {result.trace.get('cost')}")
|
|
682
|
+
log.info(f"usage: {list(result.trace.get('usage', {}).values())}")
|
|
661
683
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
684
|
+
if SHOW_DATA:
|
|
685
|
+
log.info(" ")
|
|
686
|
+
log.info(f"data:")
|
|
687
|
+
log.info(dumps(result.data, indent=2))
|
|
666
688
|
|
|
667
|
-
|
|
668
|
-
|
|
689
|
+
if SHOW_TRACE:
|
|
690
|
+
log.info(" ")
|
|
691
|
+
log.info(f"trace:")
|
|
692
|
+
log.info(f"----------------")
|
|
693
|
+
log.info(dumps(result.trace.get("spans", []), indent=2))
|
|
694
|
+
log.info(f"----------------")
|
|
695
|
+
|
|
696
|
+
log.info("\n==========================\n")
|
|
669
697
|
|
|
670
698
|
def override_config_in_schema(
|
|
671
699
|
self,
|
|
@@ -872,10 +900,7 @@ class entrypoint(BaseDecorator):
|
|
|
872
900
|
subschema["maximum"] = param_val.maxval # type: ignore
|
|
873
901
|
subschema["default"] = param_val
|
|
874
902
|
|
|
875
|
-
elif (
|
|
876
|
-
isinstance(param_val, inspect.Parameter)
|
|
877
|
-
and param_val.annotation is DictInput
|
|
878
|
-
):
|
|
903
|
+
elif isinstance(param_val, Parameter) and param_val.annotation is DictInput:
|
|
879
904
|
subschema = find_in_schema(
|
|
880
905
|
param_val.annotation.__schema_type_properties__(),
|
|
881
906
|
schema_to_override,
|
|
@@ -894,7 +919,7 @@ class entrypoint(BaseDecorator):
|
|
|
894
919
|
subschema["default"] = param_val
|
|
895
920
|
|
|
896
921
|
elif (
|
|
897
|
-
isinstance(param_val,
|
|
922
|
+
isinstance(param_val, Parameter)
|
|
898
923
|
and param_val.annotation is MessagesInput
|
|
899
924
|
):
|
|
900
925
|
subschema = find_in_schema(
|
|
@@ -906,7 +931,7 @@ class entrypoint(BaseDecorator):
|
|
|
906
931
|
subschema["default"] = param_val.default
|
|
907
932
|
|
|
908
933
|
elif (
|
|
909
|
-
isinstance(param_val,
|
|
934
|
+
isinstance(param_val, Parameter)
|
|
910
935
|
and param_val.annotation is FileInputURL
|
|
911
936
|
):
|
|
912
937
|
subschema = find_in_schema(
|
|
@@ -930,6 +955,6 @@ class entrypoint(BaseDecorator):
|
|
|
930
955
|
"title": str(param_name).capitalize(),
|
|
931
956
|
"type": get_type_from_param(param_val),
|
|
932
957
|
}
|
|
933
|
-
if param_val.default !=
|
|
958
|
+
if param_val.default != _empty:
|
|
934
959
|
subschema["default"] = param_val.default # type: ignore
|
|
935
960
|
schema_to_override[param_name] = subschema
|