agenta 0.72.4__py3-none-any.whl → 0.75.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.
- agenta/__init__.py +9 -3
- agenta/sdk/__init__.py +2 -4
- agenta/sdk/agenta_init.py +22 -75
- agenta/sdk/context/serving.py +2 -0
- agenta/sdk/contexts/routing.py +2 -0
- agenta/sdk/contexts/running.py +3 -2
- agenta/sdk/decorators/running.py +8 -4
- agenta/sdk/decorators/serving.py +82 -41
- agenta/sdk/engines/tracing/inline.py +8 -1
- agenta/sdk/evaluations/preview/evaluate.py +36 -8
- agenta/sdk/evaluations/runs.py +2 -1
- agenta/sdk/litellm/mockllm.py +2 -2
- agenta/sdk/managers/config.py +3 -1
- agenta/sdk/managers/secrets.py +25 -8
- agenta/sdk/managers/testsets.py +143 -227
- agenta/sdk/middleware/vault.py +33 -18
- agenta/sdk/middlewares/running/vault.py +33 -17
- agenta/sdk/router.py +30 -5
- agenta/sdk/tracing/inline.py +8 -1
- agenta/sdk/types.py +13 -19
- agenta/sdk/utils/client.py +10 -9
- agenta/sdk/utils/lazy.py +253 -0
- agenta/sdk/workflows/builtin.py +2 -0
- agenta/sdk/workflows/configurations.py +1 -0
- agenta/sdk/workflows/handlers.py +236 -81
- agenta/sdk/workflows/interfaces.py +47 -0
- agenta/sdk/workflows/runners/base.py +6 -2
- agenta/sdk/workflows/runners/daytona.py +250 -131
- agenta/sdk/workflows/runners/local.py +22 -56
- agenta/sdk/workflows/runners/registry.py +1 -1
- agenta/sdk/workflows/sandbox.py +17 -5
- agenta/sdk/workflows/templates.py +81 -0
- agenta/sdk/workflows/utils.py +6 -0
- {agenta-0.72.4.dist-info → agenta-0.75.0.dist-info}/METADATA +4 -8
- {agenta-0.72.4.dist-info → agenta-0.75.0.dist-info}/RECORD +36 -36
- agenta/config.py +0 -25
- agenta/config.toml +0 -4
- {agenta-0.72.4.dist-info → agenta-0.75.0.dist-info}/WHEEL +0 -0
agenta/sdk/middleware/vault.py
CHANGED
|
@@ -82,13 +82,17 @@ class VaultMiddleware(BaseHTTPMiddleware):
|
|
|
82
82
|
request.state.vault = {}
|
|
83
83
|
|
|
84
84
|
with suppress():
|
|
85
|
-
secrets = await self._get_secrets(request)
|
|
85
|
+
secrets, vault_secrets, local_secrets = await self._get_secrets(request)
|
|
86
86
|
|
|
87
|
-
request.state.vault = {
|
|
87
|
+
request.state.vault = {
|
|
88
|
+
"secrets": secrets,
|
|
89
|
+
"vault_secrets": vault_secrets,
|
|
90
|
+
"local_secrets": local_secrets,
|
|
91
|
+
}
|
|
88
92
|
|
|
89
93
|
return await call_next(request)
|
|
90
94
|
|
|
91
|
-
async def _get_secrets(self, request: Request) ->
|
|
95
|
+
async def _get_secrets(self, request: Request) -> tuple[list, list, list]:
|
|
92
96
|
credentials = request.state.auth.get("credentials")
|
|
93
97
|
|
|
94
98
|
headers = None
|
|
@@ -107,8 +111,13 @@ class VaultMiddleware(BaseHTTPMiddleware):
|
|
|
107
111
|
|
|
108
112
|
if secrets_cache:
|
|
109
113
|
secrets = secrets_cache.get("secrets")
|
|
114
|
+
vault_secrets = secrets_cache.get("vault_secrets")
|
|
115
|
+
local_secrets = secrets_cache.get("local_secrets")
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
if vault_secrets is None or local_secrets is None:
|
|
118
|
+
return secrets, [], []
|
|
119
|
+
|
|
120
|
+
return secrets, vault_secrets, local_secrets
|
|
112
121
|
|
|
113
122
|
local_secrets: List[Dict[str, Any]] = []
|
|
114
123
|
allow_secrets = True
|
|
@@ -137,7 +146,7 @@ class VaultMiddleware(BaseHTTPMiddleware):
|
|
|
137
146
|
except DenyException as e: # pylint: disable=bare-except
|
|
138
147
|
log.warning(f"Agenta [secrets] {e.status_code}: {e.content}")
|
|
139
148
|
allow_secrets = False
|
|
140
|
-
except: # pylint: disable=bare-except
|
|
149
|
+
except Exception: # pylint: disable=bare-except
|
|
141
150
|
display_exception("Vault: Local Secrets Exception")
|
|
142
151
|
|
|
143
152
|
vault_secrets: List[Dict[str, Any]] = []
|
|
@@ -154,33 +163,39 @@ class VaultMiddleware(BaseHTTPMiddleware):
|
|
|
154
163
|
|
|
155
164
|
else:
|
|
156
165
|
vault_secrets = response.json()
|
|
157
|
-
except: # pylint: disable=bare-except
|
|
166
|
+
except Exception: # pylint: disable=bare-except
|
|
158
167
|
display_exception("Vault: Vault Secrets Exception")
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
custom_secrets = []
|
|
169
|
+
local_standard = {}
|
|
170
|
+
vault_standard = {}
|
|
171
|
+
vault_custom = []
|
|
164
172
|
|
|
165
173
|
if local_secrets:
|
|
166
174
|
for secret in local_secrets:
|
|
167
|
-
|
|
175
|
+
local_standard[secret["data"]["kind"]] = secret # type: ignore
|
|
168
176
|
|
|
169
177
|
if vault_secrets:
|
|
170
178
|
for secret in vault_secrets:
|
|
171
179
|
if secret["kind"] == "provider_key": # type: ignore
|
|
172
|
-
|
|
180
|
+
vault_standard[secret["data"]["kind"]] = secret # type: ignore
|
|
173
181
|
elif secret["kind"] == "custom_provider": # type: ignore
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
standard_secrets = list(standard_secrets.values())
|
|
182
|
+
vault_custom.append(secret)
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
combined_standard = {**local_standard, **vault_standard}
|
|
185
|
+
combined_vault = list(vault_standard.values()) + vault_custom
|
|
186
|
+
secrets = list(combined_standard.values()) + vault_custom
|
|
179
187
|
|
|
180
188
|
if not allow_secrets:
|
|
181
|
-
_cache.put(
|
|
189
|
+
_cache.put(
|
|
190
|
+
_hash,
|
|
191
|
+
{
|
|
192
|
+
"secrets": secrets,
|
|
193
|
+
"vault_secrets": combined_vault,
|
|
194
|
+
"local_secrets": local_secrets,
|
|
195
|
+
},
|
|
196
|
+
)
|
|
182
197
|
|
|
183
|
-
return secrets
|
|
198
|
+
return secrets, combined_vault, local_secrets
|
|
184
199
|
|
|
185
200
|
async def _allow_local_secrets(self, credentials):
|
|
186
201
|
try:
|
|
@@ -36,7 +36,7 @@ _CACHE_ENABLED = (
|
|
|
36
36
|
_cache = TTLLRUCache()
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
async def get_secrets(api_url, credentials) -> list:
|
|
39
|
+
async def get_secrets(api_url, credentials) -> tuple[list, list, list]:
|
|
40
40
|
headers = None
|
|
41
41
|
if credentials:
|
|
42
42
|
headers = {"Authorization": credentials}
|
|
@@ -53,8 +53,13 @@ async def get_secrets(api_url, credentials) -> list:
|
|
|
53
53
|
|
|
54
54
|
if secrets_cache:
|
|
55
55
|
secrets = secrets_cache.get("secrets")
|
|
56
|
+
vault_secrets = secrets_cache.get("vault_secrets")
|
|
57
|
+
local_secrets = secrets_cache.get("local_secrets")
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
if vault_secrets is None or local_secrets is None:
|
|
60
|
+
return secrets, [], []
|
|
61
|
+
|
|
62
|
+
return secrets, vault_secrets, local_secrets
|
|
58
63
|
|
|
59
64
|
local_secrets: List[Dict[str, Any]] = []
|
|
60
65
|
|
|
@@ -76,7 +81,7 @@ async def get_secrets(api_url, credentials) -> list:
|
|
|
76
81
|
)
|
|
77
82
|
|
|
78
83
|
local_secrets.append(secret.model_dump())
|
|
79
|
-
except: # pylint: disable=bare-except
|
|
84
|
+
except Exception: # pylint: disable=bare-except
|
|
80
85
|
display_exception("Vault: Local Secrets Exception")
|
|
81
86
|
|
|
82
87
|
vault_secrets: List[Dict[str, Any]] = []
|
|
@@ -93,32 +98,38 @@ async def get_secrets(api_url, credentials) -> list:
|
|
|
93
98
|
|
|
94
99
|
else:
|
|
95
100
|
vault_secrets = response.json()
|
|
96
|
-
except: # pylint: disable=bare-except
|
|
101
|
+
except Exception: # pylint: disable=bare-except
|
|
97
102
|
display_exception("Vault: Vault Secrets Exception")
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
custom_secrets = []
|
|
104
|
+
local_standard = {}
|
|
105
|
+
vault_standard = {}
|
|
106
|
+
vault_custom = []
|
|
103
107
|
|
|
104
108
|
if local_secrets:
|
|
105
109
|
for secret in local_secrets:
|
|
106
|
-
|
|
110
|
+
local_standard[secret["data"]["kind"]] = secret # type: ignore
|
|
107
111
|
|
|
108
112
|
if vault_secrets:
|
|
109
113
|
for secret in vault_secrets:
|
|
110
114
|
if secret["kind"] == "provider_key": # type: ignore
|
|
111
|
-
|
|
115
|
+
vault_standard[secret["data"]["kind"]] = secret # type: ignore
|
|
112
116
|
elif secret["kind"] == "custom_provider": # type: ignore
|
|
113
|
-
|
|
117
|
+
vault_custom.append(secret)
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
combined_standard = {**local_standard, **vault_standard}
|
|
120
|
+
combined_vault = list(vault_standard.values()) + vault_custom
|
|
121
|
+
secrets = list(combined_standard.values()) + vault_custom
|
|
116
122
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
_cache.put(
|
|
124
|
+
_hash,
|
|
125
|
+
{
|
|
126
|
+
"secrets": secrets,
|
|
127
|
+
"vault_secrets": combined_vault,
|
|
128
|
+
"local_secrets": local_secrets,
|
|
129
|
+
},
|
|
130
|
+
)
|
|
120
131
|
|
|
121
|
-
return secrets
|
|
132
|
+
return secrets, combined_vault, local_secrets
|
|
122
133
|
|
|
123
134
|
|
|
124
135
|
class VaultMiddleware:
|
|
@@ -133,8 +144,13 @@ class VaultMiddleware:
|
|
|
133
144
|
ctx = RunningContext.get()
|
|
134
145
|
credentials = ctx.credentials
|
|
135
146
|
|
|
136
|
-
secrets = await get_secrets(
|
|
147
|
+
secrets, vault_secrets, local_secrets = await get_secrets(
|
|
148
|
+
api_url,
|
|
149
|
+
credentials,
|
|
150
|
+
)
|
|
137
151
|
|
|
138
152
|
ctx.secrets = secrets
|
|
153
|
+
ctx.vault_secrets = vault_secrets
|
|
154
|
+
ctx.local_secrets = local_secrets
|
|
139
155
|
|
|
140
156
|
return await call_next(request)
|
agenta/sdk/router.py
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from fastapi import APIRouter
|
|
4
5
|
|
|
6
|
+
from agenta.sdk.utils.lazy import _load_fastapi
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
_router: Optional["APIRouter"] = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _LazyRouter:
|
|
12
|
+
def __getattr__(self, name):
|
|
13
|
+
return getattr(get_router(), name)
|
|
14
|
+
|
|
15
|
+
def __call__(self, *args, **kwargs):
|
|
16
|
+
return get_router()(*args, **kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_router() -> "APIRouter":
|
|
20
|
+
global _router # pylint: disable=global-statement
|
|
21
|
+
|
|
22
|
+
if _router is None:
|
|
23
|
+
fastapi = _load_fastapi()
|
|
24
|
+
_router = fastapi.APIRouter()
|
|
25
|
+
|
|
26
|
+
@_router.get("/health")
|
|
27
|
+
def health():
|
|
28
|
+
return {"status": "ok"}
|
|
29
|
+
|
|
30
|
+
return _router
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
router = _LazyRouter()
|
agenta/sdk/tracing/inline.py
CHANGED
|
@@ -949,9 +949,10 @@ def parse_to_agenta_span_dto(
|
|
|
949
949
|
########################################
|
|
950
950
|
|
|
951
951
|
|
|
952
|
-
from litellm import cost_calculator
|
|
953
952
|
from opentelemetry.sdk.trace import ReadableSpan
|
|
954
953
|
|
|
954
|
+
from agenta.sdk.utils.lazy import _load_litellm
|
|
955
|
+
|
|
955
956
|
from agenta.sdk.types import AgentaNodeDto, AgentaNodesResponse
|
|
956
957
|
|
|
957
958
|
|
|
@@ -1112,6 +1113,12 @@ TYPES_WITH_COSTS = [
|
|
|
1112
1113
|
|
|
1113
1114
|
|
|
1114
1115
|
def calculate_costs(span_idx: Dict[str, SpanDTO]):
|
|
1116
|
+
litellm = _load_litellm()
|
|
1117
|
+
if not litellm:
|
|
1118
|
+
return
|
|
1119
|
+
|
|
1120
|
+
cost_calculator = litellm.cost_calculator
|
|
1121
|
+
|
|
1115
1122
|
for span in span_idx.values():
|
|
1116
1123
|
if (
|
|
1117
1124
|
span.node.type
|
agenta/sdk/types.py
CHANGED
|
@@ -496,17 +496,11 @@ class TemplateFormatError(PromptTemplateError):
|
|
|
496
496
|
super().__init__(message)
|
|
497
497
|
|
|
498
498
|
|
|
499
|
-
import json
|
|
500
499
|
import re
|
|
501
500
|
from typing import Any, Dict, Iterable, Tuple, Optional
|
|
502
501
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
import jsonpath # ✅ use module API
|
|
506
|
-
from jsonpath import JSONPointer # pointer class is fine to use
|
|
507
|
-
except Exception:
|
|
508
|
-
jsonpath = None
|
|
509
|
-
JSONPointer = None
|
|
502
|
+
from agenta.sdk.utils.lazy import _load_jinja2, _load_jsonpath
|
|
503
|
+
|
|
510
504
|
|
|
511
505
|
# ========= Scheme detection =========
|
|
512
506
|
|
|
@@ -549,7 +543,8 @@ def resolve_dot_notation(expr: str, data: dict) -> object:
|
|
|
549
543
|
|
|
550
544
|
|
|
551
545
|
def resolve_json_path(expr: str, data: dict) -> object:
|
|
552
|
-
|
|
546
|
+
json_path, _ = _load_jsonpath()
|
|
547
|
+
if json_path is None:
|
|
553
548
|
raise ImportError("python-jsonpath is required for json-path ($...)")
|
|
554
549
|
|
|
555
550
|
if not (expr == "$" or expr.startswith("$.") or expr.startswith("$[")):
|
|
@@ -559,15 +554,16 @@ def resolve_json_path(expr: str, data: dict) -> object:
|
|
|
559
554
|
)
|
|
560
555
|
|
|
561
556
|
# Use package-level APIf
|
|
562
|
-
results =
|
|
557
|
+
results = json_path.findall(expr, data) # always returns a list
|
|
563
558
|
return results[0] if len(results) == 1 else results
|
|
564
559
|
|
|
565
560
|
|
|
566
561
|
def resolve_json_pointer(expr: str, data: Dict[str, Any]) -> Any:
|
|
567
562
|
"""Resolve a JSON Pointer; returns a single value."""
|
|
568
|
-
|
|
563
|
+
_, json_pointer = _load_jsonpath()
|
|
564
|
+
if json_pointer is None:
|
|
569
565
|
raise ImportError("python-jsonpath is required for json-pointer (/...)")
|
|
570
|
-
return
|
|
566
|
+
return json_pointer(expr).resolve(data)
|
|
571
567
|
|
|
572
568
|
|
|
573
569
|
def resolve_any(expr: str, data: Dict[str, Any]) -> Any:
|
|
@@ -635,12 +631,10 @@ def compute_truly_unreplaced(original: set, rendered: str) -> set:
|
|
|
635
631
|
|
|
636
632
|
def missing_lib_hints(unreplaced: set) -> Optional[str]:
|
|
637
633
|
"""Suggest installing python-jsonpath if placeholders indicate json-path or json-pointer usage."""
|
|
638
|
-
if any(expr.startswith("$") or expr.startswith("/") for expr in unreplaced)
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
"Install python-jsonpath to enable json-path ($...) and json-pointer (/...)"
|
|
643
|
-
)
|
|
634
|
+
if any(expr.startswith("$") or expr.startswith("/") for expr in unreplaced):
|
|
635
|
+
json_path, json_pointer = _load_jsonpath()
|
|
636
|
+
if json_path is None or json_pointer is None:
|
|
637
|
+
return "Install python-jsonpath to enable json-path ($...) and json-pointer (/...)"
|
|
644
638
|
return None
|
|
645
639
|
|
|
646
640
|
|
|
@@ -692,7 +686,7 @@ class PromptTemplate(BaseModel):
|
|
|
692
686
|
return content.format(**kwargs)
|
|
693
687
|
|
|
694
688
|
elif self.template_format == "jinja2":
|
|
695
|
-
|
|
689
|
+
Template, TemplateError = _load_jinja2()
|
|
696
690
|
|
|
697
691
|
try:
|
|
698
692
|
return Template(content).render(**kwargs)
|
agenta/sdk/utils/client.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import httpx
|
|
2
2
|
|
|
3
3
|
BASE_TIMEOUT = 10
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ log = get_module_logger(__name__)
|
|
|
11
11
|
|
|
12
12
|
def authed_api():
|
|
13
13
|
"""
|
|
14
|
-
Preconfigured
|
|
14
|
+
Preconfigured httpx client for authenticated endpoints (supports all methods).
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
api_url = ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.api_url
|
|
@@ -27,12 +27,13 @@ def authed_api():
|
|
|
27
27
|
headers = kwargs.pop("headers", {})
|
|
28
28
|
headers.setdefault("Authorization", f"ApiKey {api_key}")
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
with httpx.Client() as client:
|
|
31
|
+
return client.request(
|
|
32
|
+
method=method,
|
|
33
|
+
url=url,
|
|
34
|
+
headers=headers,
|
|
35
|
+
timeout=BASE_TIMEOUT,
|
|
36
|
+
**kwargs,
|
|
37
|
+
)
|
|
37
38
|
|
|
38
39
|
return _request
|
agenta/sdk/utils/lazy.py
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
from typing import Any, Callable, Optional, Protocol, Tuple, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from daytona import (
|
|
5
|
+
CreateSandboxFromSnapshotParams,
|
|
6
|
+
Daytona,
|
|
7
|
+
DaytonaConfig,
|
|
8
|
+
Sandbox,
|
|
9
|
+
)
|
|
10
|
+
from fastapi import APIRouter, Body, FastAPI, HTTPException, Request
|
|
11
|
+
from jinja2 import Template, TemplateError
|
|
12
|
+
from openai import AsyncOpenAI, OpenAIError
|
|
13
|
+
from starlette.responses import Response as StarletteResponse, StreamingResponse
|
|
14
|
+
from jsonpath import JSONPointer
|
|
15
|
+
import jsonpath as jsonpath_module
|
|
16
|
+
import yaml as yaml_module
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _JsonpathModule(Protocol):
|
|
20
|
+
findall: Callable[..., Any]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _LitellmModule(Protocol):
|
|
24
|
+
cost_calculator: Any
|
|
25
|
+
acompletion: Callable[..., Any]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _FastAPIModule(Protocol):
|
|
29
|
+
FastAPI: type["FastAPI"]
|
|
30
|
+
APIRouter: type["APIRouter"]
|
|
31
|
+
Request: type["Request"]
|
|
32
|
+
HTTPException: type["HTTPException"]
|
|
33
|
+
Body: Any
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _YamlModule(Protocol):
|
|
37
|
+
def safe_load(self, *args: Any, **kwargs: Any) -> Any: ...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
_litellm_module: Optional[_LitellmModule] = None
|
|
41
|
+
_litellm_checked = False
|
|
42
|
+
|
|
43
|
+
_jsonpath_module: Optional[_JsonpathModule] = None
|
|
44
|
+
_jsonpath_pointer: Optional[type["JSONPointer"]] = None
|
|
45
|
+
_jsonpath_checked = False
|
|
46
|
+
|
|
47
|
+
_openai_cached: Optional[Tuple[type["AsyncOpenAI"], type["OpenAIError"]]] = None
|
|
48
|
+
_openai_checked = False
|
|
49
|
+
|
|
50
|
+
_yaml_module: Optional[_YamlModule] = None
|
|
51
|
+
_yaml_checked = False
|
|
52
|
+
|
|
53
|
+
_jinja_cached: Optional[Tuple[type["Template"], type["TemplateError"]]] = None
|
|
54
|
+
_jinja_checked = False
|
|
55
|
+
|
|
56
|
+
_fastapi_module: Optional[_FastAPIModule] = None
|
|
57
|
+
_fastapi_checked = False
|
|
58
|
+
|
|
59
|
+
_starlette_responses_cached: Optional[
|
|
60
|
+
Tuple[type["StarletteResponse"], type["StreamingResponse"]]
|
|
61
|
+
] = None
|
|
62
|
+
_starlette_responses_checked = False
|
|
63
|
+
|
|
64
|
+
_daytona_cached: Optional[
|
|
65
|
+
Tuple[
|
|
66
|
+
type["Daytona"],
|
|
67
|
+
type["DaytonaConfig"],
|
|
68
|
+
type["Sandbox"],
|
|
69
|
+
type["CreateSandboxFromSnapshotParams"],
|
|
70
|
+
]
|
|
71
|
+
] = None
|
|
72
|
+
_daytona_checked = False
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _load_litellm(
|
|
76
|
+
injected: Optional[_LitellmModule] = None,
|
|
77
|
+
) -> Optional[_LitellmModule]:
|
|
78
|
+
global _litellm_module, _litellm_checked # pylint: disable=global-statement
|
|
79
|
+
|
|
80
|
+
if _litellm_checked:
|
|
81
|
+
return _litellm_module
|
|
82
|
+
|
|
83
|
+
if injected is not None:
|
|
84
|
+
_litellm_checked = True
|
|
85
|
+
_litellm_module = injected
|
|
86
|
+
return _litellm_module
|
|
87
|
+
|
|
88
|
+
_litellm_checked = True
|
|
89
|
+
try:
|
|
90
|
+
import litellm as _litellm
|
|
91
|
+
except Exception:
|
|
92
|
+
_litellm_module = None
|
|
93
|
+
else:
|
|
94
|
+
_litellm_module = _litellm
|
|
95
|
+
|
|
96
|
+
return _litellm_module
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _load_jsonpath() -> Tuple[Optional[_JsonpathModule], Optional[type["JSONPointer"]]]:
|
|
100
|
+
global _jsonpath_module, _jsonpath_pointer, _jsonpath_checked # pylint: disable=global-statement
|
|
101
|
+
|
|
102
|
+
if _jsonpath_checked:
|
|
103
|
+
return _jsonpath_module, _jsonpath_pointer
|
|
104
|
+
|
|
105
|
+
_jsonpath_checked = True
|
|
106
|
+
try:
|
|
107
|
+
import jsonpath as _jsonpath
|
|
108
|
+
from jsonpath import JSONPointer as _JSONPointer
|
|
109
|
+
except Exception:
|
|
110
|
+
_jsonpath_module = None
|
|
111
|
+
_jsonpath_pointer = None
|
|
112
|
+
else:
|
|
113
|
+
_jsonpath_module = _jsonpath
|
|
114
|
+
_jsonpath_pointer = _JSONPointer
|
|
115
|
+
|
|
116
|
+
return _jsonpath_module, _jsonpath_pointer
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _load_openai() -> Tuple[type["AsyncOpenAI"], type["OpenAIError"]]:
|
|
120
|
+
global _openai_cached, _openai_checked # pylint: disable=global-statement
|
|
121
|
+
|
|
122
|
+
if _openai_checked:
|
|
123
|
+
if _openai_cached is None:
|
|
124
|
+
raise ImportError(
|
|
125
|
+
"openai is required for semantic similarity evaluation. "
|
|
126
|
+
"Install it with `pip install openai`."
|
|
127
|
+
)
|
|
128
|
+
return _openai_cached
|
|
129
|
+
|
|
130
|
+
_openai_checked = True
|
|
131
|
+
try:
|
|
132
|
+
from openai import AsyncOpenAI, OpenAIError
|
|
133
|
+
except Exception as exc:
|
|
134
|
+
_openai_cached = None
|
|
135
|
+
raise ImportError(
|
|
136
|
+
"openai is required for semantic similarity evaluation. "
|
|
137
|
+
"Install it with `pip install openai`."
|
|
138
|
+
) from exc
|
|
139
|
+
|
|
140
|
+
_openai_cached = (AsyncOpenAI, OpenAIError)
|
|
141
|
+
return _openai_cached
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _load_yaml() -> _YamlModule:
|
|
145
|
+
global _yaml_module, _yaml_checked # pylint: disable=global-statement
|
|
146
|
+
|
|
147
|
+
if _yaml_checked:
|
|
148
|
+
if _yaml_module is None:
|
|
149
|
+
raise ImportError("pyyaml is required to load YAML configs.")
|
|
150
|
+
return _yaml_module
|
|
151
|
+
|
|
152
|
+
_yaml_checked = True
|
|
153
|
+
try:
|
|
154
|
+
import yaml as _yaml
|
|
155
|
+
except Exception as exc:
|
|
156
|
+
_yaml_module = None
|
|
157
|
+
raise ImportError("pyyaml is required to load YAML configs.") from exc
|
|
158
|
+
|
|
159
|
+
_yaml_module = _yaml
|
|
160
|
+
return _yaml_module
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _load_jinja2() -> Tuple[type["Template"], type["TemplateError"]]:
|
|
164
|
+
global _jinja_cached, _jinja_checked # pylint: disable=global-statement
|
|
165
|
+
|
|
166
|
+
if _jinja_checked:
|
|
167
|
+
if _jinja_cached is None:
|
|
168
|
+
raise ImportError("jinja2 is required for jinja2 template rendering.")
|
|
169
|
+
return _jinja_cached
|
|
170
|
+
|
|
171
|
+
_jinja_checked = True
|
|
172
|
+
try:
|
|
173
|
+
from jinja2 import Template, TemplateError
|
|
174
|
+
except Exception as exc:
|
|
175
|
+
_jinja_cached = None
|
|
176
|
+
raise ImportError("jinja2 is required for jinja2 template rendering.") from exc
|
|
177
|
+
|
|
178
|
+
_jinja_cached = (Template, TemplateError)
|
|
179
|
+
return _jinja_cached
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _load_fastapi() -> _FastAPIModule:
|
|
183
|
+
global _fastapi_module, _fastapi_checked # pylint: disable=global-statement
|
|
184
|
+
|
|
185
|
+
if _fastapi_checked:
|
|
186
|
+
if _fastapi_module is None:
|
|
187
|
+
raise ImportError("fastapi is required for serving routes.")
|
|
188
|
+
return _fastapi_module
|
|
189
|
+
|
|
190
|
+
_fastapi_checked = True
|
|
191
|
+
try:
|
|
192
|
+
import fastapi as _fastapi
|
|
193
|
+
except Exception as exc:
|
|
194
|
+
_fastapi_module = None
|
|
195
|
+
raise ImportError("fastapi is required for serving routes.") from exc
|
|
196
|
+
|
|
197
|
+
_fastapi_module = _fastapi
|
|
198
|
+
return _fastapi_module
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _load_starlette_responses() -> Tuple[
|
|
202
|
+
type["StarletteResponse"], type["StreamingResponse"]
|
|
203
|
+
]:
|
|
204
|
+
global _starlette_responses_cached, _starlette_responses_checked # pylint: disable=global-statement
|
|
205
|
+
|
|
206
|
+
if _starlette_responses_checked:
|
|
207
|
+
if _starlette_responses_cached is None:
|
|
208
|
+
raise ImportError("starlette is required for response handling.")
|
|
209
|
+
return _starlette_responses_cached
|
|
210
|
+
|
|
211
|
+
_starlette_responses_checked = True
|
|
212
|
+
try:
|
|
213
|
+
from starlette.responses import Response as StarletteResponse, StreamingResponse
|
|
214
|
+
except Exception as exc:
|
|
215
|
+
_starlette_responses_cached = None
|
|
216
|
+
raise ImportError("starlette is required for response handling.") from exc
|
|
217
|
+
|
|
218
|
+
_starlette_responses_cached = (StarletteResponse, StreamingResponse)
|
|
219
|
+
return _starlette_responses_cached
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _load_daytona() -> Tuple[
|
|
223
|
+
type["Daytona"],
|
|
224
|
+
type["DaytonaConfig"],
|
|
225
|
+
type["Sandbox"],
|
|
226
|
+
type["CreateSandboxFromSnapshotParams"],
|
|
227
|
+
]:
|
|
228
|
+
global _daytona_cached, _daytona_checked # pylint: disable=global-statement
|
|
229
|
+
|
|
230
|
+
if _daytona_checked:
|
|
231
|
+
if _daytona_cached is None:
|
|
232
|
+
raise ImportError("daytona is required for Daytona sandbox execution.")
|
|
233
|
+
return _daytona_cached
|
|
234
|
+
|
|
235
|
+
_daytona_checked = True
|
|
236
|
+
try:
|
|
237
|
+
from daytona import (
|
|
238
|
+
Daytona,
|
|
239
|
+
DaytonaConfig,
|
|
240
|
+
Sandbox,
|
|
241
|
+
CreateSandboxFromSnapshotParams,
|
|
242
|
+
)
|
|
243
|
+
except Exception as exc:
|
|
244
|
+
_daytona_cached = None
|
|
245
|
+
raise ImportError("daytona is required for Daytona sandbox execution.") from exc
|
|
246
|
+
|
|
247
|
+
_daytona_cached = (
|
|
248
|
+
Daytona,
|
|
249
|
+
DaytonaConfig,
|
|
250
|
+
Sandbox,
|
|
251
|
+
CreateSandboxFromSnapshotParams,
|
|
252
|
+
)
|
|
253
|
+
return _daytona_cached
|
agenta/sdk/workflows/builtin.py
CHANGED
|
@@ -166,11 +166,13 @@ def auto_custom_code_run(
|
|
|
166
166
|
#
|
|
167
167
|
correct_answer_key: Optional[str] = "correct_answer",
|
|
168
168
|
threshold: Optional[float] = 0.5,
|
|
169
|
+
runtime: Optional[str] = "python",
|
|
169
170
|
) -> Workflow:
|
|
170
171
|
parameters = dict(
|
|
171
172
|
code=code,
|
|
172
173
|
correct_answer_key=correct_answer_key,
|
|
173
174
|
threshold=threshold,
|
|
175
|
+
runtime=runtime,
|
|
174
176
|
)
|
|
175
177
|
|
|
176
178
|
return evaluator(
|
|
@@ -5,6 +5,7 @@ echo_v0_configuration = WorkflowServiceConfiguration()
|
|
|
5
5
|
auto_exact_match_v0_configuration = WorkflowServiceConfiguration()
|
|
6
6
|
auto_regex_test_v0_configuration = WorkflowServiceConfiguration()
|
|
7
7
|
field_match_test_v0_configuration = WorkflowServiceConfiguration()
|
|
8
|
+
json_multi_field_match_v0_configuration = WorkflowServiceConfiguration()
|
|
8
9
|
auto_webhook_test_v0_configuration = WorkflowServiceConfiguration()
|
|
9
10
|
auto_custom_code_run_v0_configuration = WorkflowServiceConfiguration()
|
|
10
11
|
auto_ai_critique_v0_configuration = WorkflowServiceConfiguration()
|