agenta 0.12.3__py3-none-any.whl → 0.32.0a1__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 +64 -7
- agenta/cli/helper.py +7 -3
- agenta/cli/main.py +15 -50
- agenta/cli/variant_commands.py +50 -29
- agenta/client/Readme.md +72 -64
- agenta/client/api.py +2 -2
- agenta/client/backend/__init__.py +193 -22
- agenta/client/backend/access_control/__init__.py +1 -0
- agenta/client/backend/access_control/client.py +167 -0
- agenta/client/backend/apps/__init__.py +1 -0
- agenta/client/backend/apps/client.py +1691 -0
- agenta/client/backend/bases/__init__.py +1 -0
- agenta/client/backend/bases/client.py +190 -0
- agenta/client/backend/client.py +2508 -5712
- agenta/client/backend/configs/__init__.py +1 -0
- agenta/client/backend/configs/client.py +604 -0
- agenta/client/backend/containers/__init__.py +5 -0
- agenta/client/backend/containers/client.py +648 -0
- agenta/client/backend/containers/types/__init__.py +5 -0
- agenta/client/backend/{types → containers/types}/container_templates_response.py +1 -2
- agenta/client/backend/core/__init__.py +30 -0
- agenta/client/backend/core/client_wrapper.py +42 -9
- agenta/client/backend/core/file.py +70 -0
- agenta/client/backend/core/http_client.py +575 -0
- agenta/client/backend/core/jsonable_encoder.py +33 -39
- agenta/client/backend/core/pydantic_utilities.py +325 -0
- agenta/client/backend/core/query_encoder.py +60 -0
- agenta/client/backend/core/remove_none_from_dict.py +2 -2
- agenta/client/backend/core/request_options.py +35 -0
- agenta/client/backend/core/serialization.py +276 -0
- agenta/client/backend/environments/__init__.py +1 -0
- agenta/client/backend/environments/client.py +196 -0
- agenta/client/backend/evaluations/__init__.py +1 -0
- agenta/client/backend/evaluations/client.py +1469 -0
- agenta/client/backend/evaluators/__init__.py +1 -0
- agenta/client/backend/evaluators/client.py +1283 -0
- agenta/client/backend/observability/__init__.py +1 -0
- agenta/client/backend/observability/client.py +1286 -0
- agenta/client/backend/observability_v_1/__init__.py +5 -0
- agenta/client/backend/observability_v_1/client.py +763 -0
- agenta/client/backend/observability_v_1/types/__init__.py +7 -0
- agenta/client/backend/observability_v_1/types/format.py +5 -0
- agenta/client/backend/observability_v_1/types/query_analytics_response.py +7 -0
- agenta/client/backend/observability_v_1/types/query_traces_response.py +11 -0
- agenta/client/backend/scopes/__init__.py +1 -0
- agenta/client/backend/scopes/client.py +114 -0
- agenta/client/backend/testsets/__init__.py +1 -0
- agenta/client/backend/testsets/client.py +1284 -0
- agenta/client/backend/types/__init__.py +154 -26
- agenta/client/backend/types/agenta_node_dto.py +48 -0
- agenta/client/backend/types/agenta_node_dto_nodes_value.py +6 -0
- agenta/client/backend/types/agenta_nodes_response.py +30 -0
- agenta/client/backend/types/agenta_root_dto.py +30 -0
- agenta/client/backend/types/agenta_roots_response.py +30 -0
- agenta/client/backend/types/agenta_tree_dto.py +30 -0
- agenta/client/backend/types/agenta_trees_response.py +30 -0
- agenta/client/backend/types/aggregated_result.py +16 -31
- agenta/client/backend/types/aggregated_result_evaluator_config.py +8 -0
- agenta/client/backend/types/analytics_response.py +24 -0
- agenta/client/backend/types/app.py +17 -30
- agenta/client/backend/types/app_variant_response.py +36 -0
- agenta/client/backend/types/app_variant_revision.py +17 -32
- agenta/client/backend/types/base_output.py +13 -28
- agenta/client/backend/types/body_import_testset.py +15 -31
- agenta/client/backend/types/bucket_dto.py +26 -0
- agenta/client/backend/types/collect_status_response.py +22 -0
- agenta/client/backend/types/config_db.py +16 -31
- agenta/client/backend/types/config_dto.py +32 -0
- agenta/client/backend/types/config_response_model.py +32 -0
- agenta/client/backend/types/correct_answer.py +22 -0
- agenta/client/backend/types/create_app_output.py +13 -28
- agenta/client/backend/types/create_span.py +45 -0
- agenta/client/backend/types/create_trace_response.py +22 -0
- agenta/client/backend/types/docker_env_vars.py +13 -28
- agenta/client/backend/types/environment_output.py +22 -34
- agenta/client/backend/types/environment_output_extended.py +31 -0
- agenta/client/backend/types/environment_revision.py +26 -0
- agenta/client/backend/types/error.py +22 -0
- agenta/client/backend/types/evaluation.py +22 -33
- agenta/client/backend/types/evaluation_scenario.py +18 -33
- agenta/client/backend/types/evaluation_scenario_input.py +16 -31
- agenta/client/backend/types/evaluation_scenario_output.py +17 -30
- agenta/client/backend/types/evaluation_scenario_result.py +14 -29
- agenta/client/backend/types/evaluation_scenario_score_update.py +21 -0
- agenta/client/backend/types/evaluation_status_enum.py +11 -29
- agenta/client/backend/types/evaluation_type.py +3 -21
- agenta/client/backend/types/evaluator.py +20 -31
- agenta/client/backend/types/evaluator_config.py +21 -33
- 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/exception_dto.py +26 -0
- agenta/client/backend/types/get_config_response.py +23 -0
- agenta/client/backend/types/header_dto.py +22 -0
- agenta/client/backend/types/http_validation_error.py +14 -29
- agenta/client/backend/types/human_evaluation.py +18 -34
- agenta/client/backend/types/human_evaluation_scenario.py +22 -38
- agenta/client/backend/types/human_evaluation_scenario_input.py +13 -28
- agenta/client/backend/types/human_evaluation_scenario_output.py +13 -28
- agenta/client/backend/types/human_evaluation_scenario_update.py +30 -0
- agenta/client/backend/types/human_evaluation_update.py +22 -0
- agenta/client/backend/types/image.py +18 -32
- agenta/client/backend/types/invite_request.py +16 -30
- agenta/client/backend/types/legacy_analytics_response.py +29 -0
- agenta/client/backend/types/legacy_data_point.py +27 -0
- agenta/client/backend/types/lifecycle_dto.py +24 -0
- agenta/client/backend/types/link_dto.py +24 -0
- agenta/client/backend/types/list_api_keys_response.py +24 -0
- agenta/client/backend/types/llm_run_rate_limit.py +13 -28
- agenta/client/backend/types/llm_tokens.py +23 -0
- agenta/client/backend/types/metrics_dto.py +24 -0
- agenta/client/backend/types/new_human_evaluation.py +27 -0
- agenta/client/backend/types/new_testset.py +16 -31
- agenta/client/backend/types/node_dto.py +24 -0
- agenta/client/backend/types/node_type.py +19 -0
- agenta/client/backend/types/o_tel_context_dto.py +22 -0
- agenta/client/backend/types/o_tel_event_dto.py +23 -0
- agenta/client/backend/types/o_tel_extra_dto.py +26 -0
- agenta/client/backend/types/o_tel_link_dto.py +23 -0
- agenta/client/backend/types/o_tel_span_dto.py +37 -0
- agenta/client/backend/types/o_tel_span_kind.py +15 -0
- agenta/client/backend/types/o_tel_spans_response.py +24 -0
- agenta/client/backend/types/o_tel_status_code.py +8 -0
- agenta/client/backend/types/organization.py +22 -35
- agenta/client/backend/types/organization_output.py +13 -28
- agenta/client/backend/types/outputs.py +5 -0
- agenta/client/backend/types/parent_dto.py +21 -0
- agenta/client/backend/types/permission.py +41 -0
- agenta/client/backend/types/projects_response.py +28 -0
- agenta/client/backend/types/provider_key_dto.py +23 -0
- agenta/client/backend/types/provider_kind.py +21 -0
- agenta/client/backend/types/reference_dto.py +23 -0
- agenta/client/backend/types/reference_request_model.py +23 -0
- agenta/client/backend/types/result.py +18 -31
- agenta/client/backend/types/root_dto.py +21 -0
- agenta/client/backend/types/{human_evaluation_scenario_score.py → score.py} +1 -1
- agenta/client/backend/types/secret_dto.py +24 -0
- agenta/client/backend/types/{human_evaluation_scenario_update_score.py → secret_kind.py} +1 -1
- agenta/client/backend/types/secret_response_dto.py +27 -0
- agenta/client/backend/types/simple_evaluation_output.py +13 -28
- agenta/client/backend/types/span.py +39 -49
- agenta/client/backend/types/span_detail.py +44 -0
- agenta/client/backend/types/span_dto.py +54 -0
- agenta/client/backend/types/span_dto_nodes_value.py +9 -0
- agenta/client/backend/types/span_status_code.py +5 -0
- agenta/client/backend/types/span_variant.py +23 -0
- agenta/client/backend/types/status_code.py +5 -0
- agenta/client/backend/types/status_dto.py +23 -0
- agenta/client/backend/types/template.py +14 -29
- agenta/client/backend/types/template_image_info.py +21 -35
- agenta/client/backend/types/test_set_output_response.py +20 -33
- agenta/client/backend/types/test_set_simple_response.py +13 -28
- agenta/client/backend/types/time_dto.py +23 -0
- agenta/client/backend/types/trace_detail.py +44 -0
- agenta/client/backend/types/tree_dto.py +23 -0
- agenta/client/backend/types/tree_type.py +5 -0
- agenta/client/backend/types/update_app_output.py +22 -0
- agenta/client/backend/types/uri.py +13 -28
- agenta/client/backend/types/validation_error.py +13 -28
- agenta/client/backend/types/variant_action.py +14 -29
- agenta/client/backend/types/variant_action_enum.py +1 -19
- agenta/client/backend/types/with_pagination.py +26 -0
- agenta/client/backend/types/workspace_member_response.py +23 -0
- agenta/client/backend/types/workspace_permission.py +25 -0
- agenta/client/backend/types/workspace_response.py +29 -0
- agenta/client/backend/types/workspace_role.py +15 -0
- agenta/client/backend/types/workspace_role_response.py +23 -0
- agenta/client/backend/variants/__init__.py +5 -0
- agenta/client/backend/variants/client.py +2814 -0
- agenta/client/backend/variants/types/__init__.py +7 -0
- agenta/client/backend/variants/types/add_variant_from_base_and_config_response.py +8 -0
- agenta/client/backend/vault/__init__.py +1 -0
- agenta/client/backend/vault/client.py +685 -0
- agenta/client/client.py +1 -1
- agenta/config.py +0 -2
- agenta/config.toml +0 -1
- agenta/docker/docker-assets/Dockerfile.cloud.template +2 -1
- agenta/docker/docker-assets/Dockerfile.template +2 -1
- agenta/docker/docker_utils.py +11 -12
- agenta/sdk/__init__.py +58 -7
- agenta/sdk/agenta_init.py +182 -164
- agenta/sdk/assets.py +95 -0
- agenta/sdk/client.py +56 -0
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/exporting.py +25 -0
- agenta/sdk/context/routing.py +27 -0
- agenta/sdk/context/tracing.py +28 -0
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/decorators/routing.py +576 -0
- agenta/sdk/decorators/tracing.py +296 -0
- agenta/sdk/litellm/__init__.py +1 -0
- agenta/sdk/litellm/litellm.py +314 -0
- agenta/sdk/litellm/mockllm.py +27 -0
- agenta/sdk/litellm/mocks/__init__.py +26 -0
- agenta/sdk/managers/__init__.py +6 -0
- agenta/sdk/managers/config.py +208 -0
- agenta/sdk/managers/deployment.py +45 -0
- agenta/sdk/managers/secrets.py +38 -0
- agenta/sdk/managers/shared.py +639 -0
- agenta/sdk/managers/variant.py +182 -0
- agenta/sdk/managers/vault.py +16 -0
- agenta/sdk/middleware/__init__.py +0 -0
- agenta/sdk/middleware/auth.py +180 -0
- agenta/sdk/middleware/cache.py +47 -0
- agenta/sdk/middleware/config.py +255 -0
- agenta/sdk/middleware/cors.py +29 -0
- agenta/sdk/middleware/inline.py +38 -0
- agenta/sdk/middleware/mock.py +33 -0
- agenta/sdk/middleware/otel.py +40 -0
- agenta/sdk/middleware/vault.py +145 -0
- agenta/sdk/router.py +0 -7
- agenta/sdk/tracing/__init__.py +1 -0
- agenta/sdk/tracing/attributes.py +141 -0
- agenta/sdk/tracing/conventions.py +49 -0
- agenta/sdk/tracing/exporters.py +103 -0
- agenta/sdk/tracing/inline.py +1146 -0
- agenta/sdk/tracing/processors.py +121 -0
- agenta/sdk/tracing/spans.py +136 -0
- agenta/sdk/tracing/tracing.py +237 -0
- agenta/sdk/types.py +478 -74
- agenta/sdk/utils/__init__.py +0 -0
- agenta/sdk/utils/constants.py +1 -0
- agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
- agenta/sdk/utils/exceptions.py +59 -0
- agenta/sdk/utils/globals.py +6 -10
- agenta/sdk/utils/helpers.py +8 -0
- agenta/sdk/utils/logging.py +21 -0
- agenta/sdk/utils/singleton.py +13 -0
- agenta/sdk/utils/timing.py +58 -0
- {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/METADATA +98 -151
- agenta-0.32.0a1.dist-info/RECORD +263 -0
- {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/WHEEL +1 -1
- agenta/client/backend/types/add_variant_from_base_and_config_response.py +0 -7
- agenta/client/backend/types/app_variant_output.py +0 -47
- agenta/client/backend/types/app_variant_output_extended.py +0 -50
- agenta/client/backend/types/delete_evaluation.py +0 -36
- agenta/client/backend/types/evaluation_webhook.py +0 -36
- agenta/client/backend/types/feedback.py +0 -40
- agenta/client/backend/types/get_config_reponse.py +0 -39
- agenta/client/backend/types/list_api_keys_output.py +0 -39
- agenta/client/backend/types/trace.py +0 -48
- agenta/sdk/agenta_decorator.py +0 -443
- agenta/sdk/context.py +0 -41
- agenta-0.12.3.dist-info/RECORD +0 -114
- {agenta-0.12.3.dist-info → agenta-0.32.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
4
|
+
from fastapi import Request, FastAPI
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
8
|
+
|
|
9
|
+
from agenta.sdk.utils.constants import TRUTHY
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InlineMiddleware(BaseHTTPMiddleware):
|
|
13
|
+
def __init__(self, app: FastAPI):
|
|
14
|
+
super().__init__(app)
|
|
15
|
+
|
|
16
|
+
async def dispatch(
|
|
17
|
+
self,
|
|
18
|
+
request: Request,
|
|
19
|
+
call_next: Callable,
|
|
20
|
+
):
|
|
21
|
+
request.state.inline = False
|
|
22
|
+
|
|
23
|
+
with suppress():
|
|
24
|
+
baggage = request.state.otel.get("baggage") if request.state.otel else {}
|
|
25
|
+
|
|
26
|
+
inline = (
|
|
27
|
+
str(
|
|
28
|
+
# CLEANEST
|
|
29
|
+
baggage.get("inline")
|
|
30
|
+
# ALTERNATIVE
|
|
31
|
+
or request.query_params.get("inline")
|
|
32
|
+
)
|
|
33
|
+
in TRUTHY
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
request.state.inline = inline
|
|
37
|
+
|
|
38
|
+
return await call_next(request)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
4
|
+
from fastapi import Request, FastAPI
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MockMiddleware(BaseHTTPMiddleware):
|
|
11
|
+
def __init__(self, app: FastAPI):
|
|
12
|
+
super().__init__(app)
|
|
13
|
+
|
|
14
|
+
async def dispatch(
|
|
15
|
+
self,
|
|
16
|
+
request: Request,
|
|
17
|
+
call_next: Callable,
|
|
18
|
+
):
|
|
19
|
+
request.state.mock = None
|
|
20
|
+
|
|
21
|
+
with suppress():
|
|
22
|
+
baggage = request.state.otel.get("baggage") if request.state.otel else {}
|
|
23
|
+
|
|
24
|
+
mock = (
|
|
25
|
+
# CLEANEST
|
|
26
|
+
baggage.get("mock")
|
|
27
|
+
# ALTERNATIVE
|
|
28
|
+
or request.query_params.get("mock")
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
request.state.mock = mock
|
|
32
|
+
|
|
33
|
+
return await call_next(request)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
4
|
+
from fastapi import Request, FastAPI
|
|
5
|
+
|
|
6
|
+
from opentelemetry.baggage.propagation import W3CBaggagePropagator
|
|
7
|
+
|
|
8
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OTelMiddleware(BaseHTTPMiddleware):
|
|
12
|
+
def __init__(self, app: FastAPI):
|
|
13
|
+
super().__init__(app)
|
|
14
|
+
|
|
15
|
+
async def dispatch(self, request: Request, call_next: Callable):
|
|
16
|
+
request.state.otel = {}
|
|
17
|
+
|
|
18
|
+
with suppress():
|
|
19
|
+
baggage = await self._get_baggage(request)
|
|
20
|
+
|
|
21
|
+
request.state.otel = {"baggage": baggage}
|
|
22
|
+
|
|
23
|
+
return await call_next(request)
|
|
24
|
+
|
|
25
|
+
async def _get_baggage(
|
|
26
|
+
self,
|
|
27
|
+
request,
|
|
28
|
+
):
|
|
29
|
+
_baggage = {"baggage": request.headers.get("Baggage", "")}
|
|
30
|
+
|
|
31
|
+
context = W3CBaggagePropagator().extract(_baggage)
|
|
32
|
+
|
|
33
|
+
baggage = {}
|
|
34
|
+
|
|
35
|
+
if context:
|
|
36
|
+
for partial in context.values():
|
|
37
|
+
for key, value in partial.items():
|
|
38
|
+
baggage[key] = value
|
|
39
|
+
|
|
40
|
+
return baggage
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from json import dumps
|
|
3
|
+
from typing import Callable, Dict, Optional, List, Any, get_args
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
from fastapi import FastAPI, Request
|
|
7
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
8
|
+
|
|
9
|
+
from agenta.sdk.utils.constants import TRUTHY
|
|
10
|
+
from agenta.client.backend.types.provider_kind import ProviderKind
|
|
11
|
+
from agenta.sdk.utils.exceptions import suppress, display_exception
|
|
12
|
+
from agenta.client.backend.types.secret_dto import SecretDto as SecretDTO
|
|
13
|
+
from agenta.client.backend.types.provider_key_dto import (
|
|
14
|
+
ProviderKeyDto as ProviderKeyDTO,
|
|
15
|
+
)
|
|
16
|
+
from agenta.sdk.middleware.cache import TTLLRUCache, CACHE_CAPACITY, CACHE_TTL
|
|
17
|
+
|
|
18
|
+
import agenta as ag
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_PROVIDER_KINDS = []
|
|
22
|
+
|
|
23
|
+
for arg in ProviderKind.__args__: # type: ignore
|
|
24
|
+
if hasattr(arg, "__args__"):
|
|
25
|
+
_PROVIDER_KINDS.extend(arg.__args__)
|
|
26
|
+
|
|
27
|
+
_CACHE_ENABLED = getenv("AGENTA_MIDDLEWARE_CACHE_ENABLED", "true").lower() in TRUTHY
|
|
28
|
+
|
|
29
|
+
_cache = TTLLRUCache(capacity=CACHE_CAPACITY, ttl=CACHE_TTL)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class VaultMiddleware(BaseHTTPMiddleware):
|
|
33
|
+
def __init__(self, app: FastAPI):
|
|
34
|
+
super().__init__(app)
|
|
35
|
+
|
|
36
|
+
self.host = ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.host
|
|
37
|
+
|
|
38
|
+
def _transform_secrets_response_to_secret_dto(
|
|
39
|
+
self, secrets_list: List[Dict[str, Any]]
|
|
40
|
+
) -> List[Dict[str, Any]]:
|
|
41
|
+
secrets_dto_dict = [
|
|
42
|
+
{
|
|
43
|
+
"kind": secret.get("secret", {}).get("kind"),
|
|
44
|
+
"data": secret.get("secret", {}).get("data", {}),
|
|
45
|
+
}
|
|
46
|
+
for secret in secrets_list
|
|
47
|
+
]
|
|
48
|
+
return secrets_dto_dict
|
|
49
|
+
|
|
50
|
+
async def dispatch(
|
|
51
|
+
self,
|
|
52
|
+
request: Request,
|
|
53
|
+
call_next: Callable,
|
|
54
|
+
):
|
|
55
|
+
request.state.vault = {}
|
|
56
|
+
|
|
57
|
+
with suppress():
|
|
58
|
+
secrets = await self._get_secrets(request)
|
|
59
|
+
|
|
60
|
+
request.state.vault = {"secrets": secrets}
|
|
61
|
+
|
|
62
|
+
return await call_next(request)
|
|
63
|
+
|
|
64
|
+
async def _get_secrets(self, request: Request) -> Optional[Dict]:
|
|
65
|
+
credentials = request.state.auth.get("credentials")
|
|
66
|
+
|
|
67
|
+
headers = None
|
|
68
|
+
if credentials:
|
|
69
|
+
headers = {"Authorization": credentials}
|
|
70
|
+
|
|
71
|
+
_hash = dumps(
|
|
72
|
+
{
|
|
73
|
+
"headers": headers,
|
|
74
|
+
},
|
|
75
|
+
sort_keys=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if _CACHE_ENABLED:
|
|
79
|
+
secrets_cache = _cache.get(_hash)
|
|
80
|
+
|
|
81
|
+
if secrets_cache:
|
|
82
|
+
secrets = secrets_cache.get("secrets")
|
|
83
|
+
|
|
84
|
+
return secrets
|
|
85
|
+
|
|
86
|
+
local_secrets: List[SecretDTO] = []
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
for provider_kind in _PROVIDER_KINDS:
|
|
90
|
+
provider = provider_kind
|
|
91
|
+
key_name = f"{provider.upper()}_API_KEY"
|
|
92
|
+
key = getenv(key_name)
|
|
93
|
+
|
|
94
|
+
if not key:
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
secret = SecretDTO(
|
|
98
|
+
# kind=... # defaults to 'provider_kind'
|
|
99
|
+
data=ProviderKeyDTO(
|
|
100
|
+
provider=provider,
|
|
101
|
+
key=key,
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
local_secrets.append(secret.model_dump())
|
|
106
|
+
except: # pylint: disable=bare-except
|
|
107
|
+
display_exception("Vault: Local Secrets Exception")
|
|
108
|
+
|
|
109
|
+
vault_secrets: List[SecretDTO] = []
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
async with httpx.AsyncClient() as client:
|
|
113
|
+
response = await client.get(
|
|
114
|
+
f"{self.host}/api/vault/v1/secrets",
|
|
115
|
+
headers=headers,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if response.status_code != 200:
|
|
119
|
+
vault_secrets = []
|
|
120
|
+
|
|
121
|
+
else:
|
|
122
|
+
secrets = response.json()
|
|
123
|
+
vault_secrets = self._transform_secrets_response_to_secret_dto(
|
|
124
|
+
secrets
|
|
125
|
+
)
|
|
126
|
+
except: # pylint: disable=bare-except
|
|
127
|
+
display_exception("Vault: Vault Secrets Exception")
|
|
128
|
+
|
|
129
|
+
merged_secrets = {}
|
|
130
|
+
|
|
131
|
+
if local_secrets:
|
|
132
|
+
for secret in local_secrets:
|
|
133
|
+
provider = secret["data"]["provider"]
|
|
134
|
+
merged_secrets[provider] = secret
|
|
135
|
+
|
|
136
|
+
if vault_secrets:
|
|
137
|
+
for secret in vault_secrets:
|
|
138
|
+
provider = secret["data"]["provider"]
|
|
139
|
+
merged_secrets[provider] = secret
|
|
140
|
+
|
|
141
|
+
secrets = list(merged_secrets.values())
|
|
142
|
+
|
|
143
|
+
_cache.put(_hash, {"secrets": secrets})
|
|
144
|
+
|
|
145
|
+
return secrets
|
agenta/sdk/router.py
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
|
-
from .context import get_contexts
|
|
3
2
|
|
|
4
3
|
router = APIRouter()
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
@router.get("/contexts/")
|
|
8
|
-
def get_all_contexts():
|
|
9
|
-
contexts = get_contexts()
|
|
10
|
-
return {"contexts": contexts}
|
|
11
|
-
|
|
12
|
-
|
|
13
6
|
@router.get("/health")
|
|
14
7
|
def health():
|
|
15
8
|
return {"status": "ok"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .tracing import Tracing, get_tracer
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from json import loads, dumps
|
|
2
|
+
from typing import Optional, Union, Sequence, Any, Dict
|
|
3
|
+
|
|
4
|
+
Primitive = Union[str, int, float, bool, bytes]
|
|
5
|
+
PrimitivesSequence = Sequence[Primitive]
|
|
6
|
+
Attribute = Union[Primitive, PrimitivesSequence]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _marshal(
|
|
10
|
+
unmarshalled: Dict[str, Any],
|
|
11
|
+
*,
|
|
12
|
+
parent_key: Optional[str] = "",
|
|
13
|
+
depth: Optional[int] = 0,
|
|
14
|
+
max_depth: Optional[int] = None,
|
|
15
|
+
) -> Dict[str, Any]:
|
|
16
|
+
"""
|
|
17
|
+
Marshals a dictionary of unmarshalled attributes into a flat dictionary
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
unmarshalled = {
|
|
21
|
+
"ag": {
|
|
22
|
+
"type": "tree",
|
|
23
|
+
"node": {
|
|
24
|
+
"name": "root",
|
|
25
|
+
"children": [
|
|
26
|
+
{
|
|
27
|
+
"name": "child1",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "child2",
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
marshalled = {
|
|
37
|
+
"ag.type": "tree",
|
|
38
|
+
"ag.node.name": "root",
|
|
39
|
+
"ag.node.children.0.name": "child1",
|
|
40
|
+
"ag.node.children.1.name": "child2"
|
|
41
|
+
}
|
|
42
|
+
"""
|
|
43
|
+
marshalled = {}
|
|
44
|
+
|
|
45
|
+
# If max_depth is set and we've reached it,
|
|
46
|
+
# just return the unmarshalled attributes
|
|
47
|
+
if max_depth is not None and depth >= max_depth:
|
|
48
|
+
marshalled[parent_key] = unmarshalled
|
|
49
|
+
# MISSING ENCODING TO JSON IF NOT PRIMITIVE
|
|
50
|
+
|
|
51
|
+
return marshalled
|
|
52
|
+
|
|
53
|
+
# Otherwise,
|
|
54
|
+
# iterate over the unmarshalled attributes and marshall them
|
|
55
|
+
for key, value in unmarshalled.items():
|
|
56
|
+
child_key = f"{parent_key}.{key}" if parent_key else key
|
|
57
|
+
|
|
58
|
+
if isinstance(value, dict):
|
|
59
|
+
dict_key = child_key
|
|
60
|
+
|
|
61
|
+
marshalled.update(
|
|
62
|
+
_marshal(
|
|
63
|
+
value,
|
|
64
|
+
parent_key=dict_key,
|
|
65
|
+
depth=depth + 1,
|
|
66
|
+
max_depth=max_depth,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
elif isinstance(value, list):
|
|
70
|
+
if max_depth is not None and depth + 1 >= max_depth:
|
|
71
|
+
marshalled[child_key] = value
|
|
72
|
+
# MISSING ENCODING TO JSON IF NOT PRIMITIVE
|
|
73
|
+
else:
|
|
74
|
+
for i, item in enumerate(value):
|
|
75
|
+
list_key = f"{child_key}.{i}"
|
|
76
|
+
|
|
77
|
+
if isinstance(item, (dict, list)):
|
|
78
|
+
marshalled.update(
|
|
79
|
+
_marshal(
|
|
80
|
+
item,
|
|
81
|
+
parent_key=list_key,
|
|
82
|
+
depth=depth + 1,
|
|
83
|
+
max_depth=max_depth,
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
marshalled[list_key] = item
|
|
88
|
+
# MISSING ENCODING TO JSON IF NOT PRIMITIVE
|
|
89
|
+
else:
|
|
90
|
+
marshalled[child_key] = value
|
|
91
|
+
# MISSING ENCODING TO JSON IF NOT PRIMITIVE
|
|
92
|
+
|
|
93
|
+
return marshalled
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _encode_key(
|
|
97
|
+
namespace: Optional[str] = None,
|
|
98
|
+
key: str = "",
|
|
99
|
+
) -> str:
|
|
100
|
+
if namespace is None:
|
|
101
|
+
return key
|
|
102
|
+
|
|
103
|
+
return f"ag.{namespace}.{key}"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _encode_value(
|
|
107
|
+
value: Any,
|
|
108
|
+
) -> Optional[Attribute]:
|
|
109
|
+
if value is None:
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
if isinstance(value, (str, int, float, bool, bytes)):
|
|
113
|
+
return value
|
|
114
|
+
|
|
115
|
+
if isinstance(value, dict) or isinstance(value, list):
|
|
116
|
+
encoded = dumps(value)
|
|
117
|
+
value = "@ag.type=json:" + encoded
|
|
118
|
+
return value
|
|
119
|
+
|
|
120
|
+
return repr(value)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def serialize(
|
|
124
|
+
*,
|
|
125
|
+
namespace: str,
|
|
126
|
+
attributes: Dict[str, Any],
|
|
127
|
+
max_depth: Optional[int] = None,
|
|
128
|
+
) -> Dict[str, str]:
|
|
129
|
+
if not isinstance(attributes, dict):
|
|
130
|
+
return {}
|
|
131
|
+
|
|
132
|
+
_attributes = {
|
|
133
|
+
k: v
|
|
134
|
+
for k, v in {
|
|
135
|
+
_encode_key(namespace, key): _encode_value(value)
|
|
136
|
+
for key, value in _marshal(attributes, max_depth=max_depth).items()
|
|
137
|
+
}.items()
|
|
138
|
+
if v is not None
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return _attributes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from re import fullmatch
|
|
3
|
+
|
|
4
|
+
from opentelemetry.trace import SpanKind
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Reference(str, Enum):
|
|
8
|
+
#
|
|
9
|
+
VARIANT_ID = "variant.id"
|
|
10
|
+
VARIANT_SLUG = "variant.slug"
|
|
11
|
+
VARIANT_VERSION = "variant.version"
|
|
12
|
+
#
|
|
13
|
+
ENVIRONMENT_ID = "environment.id"
|
|
14
|
+
ENVIRONMENT_SLUG = "environment.slug"
|
|
15
|
+
ENVIRONMENT_VERSION = "environment.version"
|
|
16
|
+
#
|
|
17
|
+
APPLICATION_ID = "application.id"
|
|
18
|
+
APPLICATION_SLUG = "application.slug"
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_PATTERN = r"[A-Za-z0-9._-]+"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_valid_attribute_key(
|
|
26
|
+
string: str,
|
|
27
|
+
):
|
|
28
|
+
return bool(fullmatch(_PATTERN, string))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def parse_span_kind(type: str) -> SpanKind:
|
|
32
|
+
kind = SpanKind.INTERNAL
|
|
33
|
+
if type in [
|
|
34
|
+
"agent",
|
|
35
|
+
"chain",
|
|
36
|
+
"workflow",
|
|
37
|
+
]:
|
|
38
|
+
kind = SpanKind.SERVER
|
|
39
|
+
elif type in [
|
|
40
|
+
"tool",
|
|
41
|
+
"embedding",
|
|
42
|
+
"query",
|
|
43
|
+
"completion",
|
|
44
|
+
"chat",
|
|
45
|
+
"rerank",
|
|
46
|
+
]:
|
|
47
|
+
kind = SpanKind.CLIENT
|
|
48
|
+
|
|
49
|
+
return kind
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from typing import Sequence, Dict, List
|
|
2
|
+
|
|
3
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
4
|
+
from opentelemetry.sdk.trace.export import (
|
|
5
|
+
ConsoleSpanExporter,
|
|
6
|
+
SpanExporter,
|
|
7
|
+
SpanExportResult,
|
|
8
|
+
ReadableSpan,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
12
|
+
from agenta.sdk.context.exporting import (
|
|
13
|
+
exporting_context_manager,
|
|
14
|
+
exporting_context,
|
|
15
|
+
ExportingContext,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InlineTraceExporter(SpanExporter):
|
|
20
|
+
def __init__(self, registry: Dict[str, List[ReadableSpan]]):
|
|
21
|
+
self._shutdown = False
|
|
22
|
+
self._registry = registry
|
|
23
|
+
|
|
24
|
+
def export(
|
|
25
|
+
self,
|
|
26
|
+
spans: Sequence[ReadableSpan],
|
|
27
|
+
) -> SpanExportResult:
|
|
28
|
+
if self._shutdown:
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
with suppress():
|
|
32
|
+
for span in spans:
|
|
33
|
+
trace_id = span.get_span_context().trace_id
|
|
34
|
+
|
|
35
|
+
if trace_id not in self._registry:
|
|
36
|
+
self._registry[trace_id] = []
|
|
37
|
+
|
|
38
|
+
self._registry[trace_id].append(span)
|
|
39
|
+
|
|
40
|
+
def shutdown(self) -> None:
|
|
41
|
+
self._shutdown = True
|
|
42
|
+
|
|
43
|
+
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
def is_ready(
|
|
47
|
+
self,
|
|
48
|
+
trace_id: int,
|
|
49
|
+
) -> bool:
|
|
50
|
+
is_ready = trace_id in self._registry
|
|
51
|
+
|
|
52
|
+
return is_ready
|
|
53
|
+
|
|
54
|
+
def fetch(
|
|
55
|
+
self,
|
|
56
|
+
trace_id: int,
|
|
57
|
+
) -> List[ReadableSpan]:
|
|
58
|
+
trace = self._registry.get(trace_id, [])
|
|
59
|
+
|
|
60
|
+
if trace_id in self._registry:
|
|
61
|
+
del self._registry[trace_id]
|
|
62
|
+
|
|
63
|
+
return trace
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class OTLPExporter(OTLPSpanExporter):
|
|
67
|
+
_MAX_RETRY_TIMEOUT = 2
|
|
68
|
+
|
|
69
|
+
def __init__(self, *args, credentials: Dict[int, str] = None, **kwargs):
|
|
70
|
+
super().__init__(*args, **kwargs)
|
|
71
|
+
|
|
72
|
+
self.credentials = credentials
|
|
73
|
+
|
|
74
|
+
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
75
|
+
credentials = None
|
|
76
|
+
|
|
77
|
+
if self.credentials:
|
|
78
|
+
trace_ids = set(span.get_span_context().trace_id for span in spans)
|
|
79
|
+
|
|
80
|
+
if len(trace_ids) == 1:
|
|
81
|
+
trace_id = trace_ids.pop()
|
|
82
|
+
|
|
83
|
+
if trace_id in self.credentials:
|
|
84
|
+
credentials = self.credentials.pop(trace_id)
|
|
85
|
+
|
|
86
|
+
with exporting_context_manager(
|
|
87
|
+
context=ExportingContext(
|
|
88
|
+
credentials=credentials,
|
|
89
|
+
)
|
|
90
|
+
):
|
|
91
|
+
return super().export(spans)
|
|
92
|
+
|
|
93
|
+
def _export(self, serialized_data: bytes):
|
|
94
|
+
credentials = exporting_context.get().credentials
|
|
95
|
+
|
|
96
|
+
if credentials:
|
|
97
|
+
self._session.headers.update({"Authorization": credentials})
|
|
98
|
+
|
|
99
|
+
return super()._export(serialized_data)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
ConsoleExporter = ConsoleSpanExporter
|
|
103
|
+
InlineExporter = InlineTraceExporter
|