agenta 0.52.6__py3-none-any.whl → 0.63.2__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 +12 -3
- agenta/client/__init__.py +4 -4
- agenta/client/backend/__init__.py +4 -4
- agenta/client/backend/api_keys/client.py +2 -2
- agenta/client/backend/billing/client.py +2 -2
- agenta/client/backend/billing/raw_client.py +2 -2
- agenta/client/backend/client.py +56 -48
- agenta/client/backend/core/client_wrapper.py +2 -2
- agenta/client/backend/core/file.py +3 -1
- agenta/client/backend/core/http_client.py +3 -3
- agenta/client/backend/core/pydantic_utilities.py +13 -3
- agenta/client/backend/human_evaluations/client.py +2 -2
- agenta/client/backend/human_evaluations/raw_client.py +2 -2
- agenta/client/backend/organization/client.py +46 -34
- agenta/client/backend/organization/raw_client.py +32 -26
- agenta/client/backend/raw_client.py +26 -26
- agenta/client/backend/testsets/client.py +18 -18
- agenta/client/backend/testsets/raw_client.py +30 -30
- agenta/client/backend/types/__init__.py +4 -4
- agenta/client/backend/types/account_request.py +3 -1
- agenta/client/backend/types/account_response.py +3 -1
- agenta/client/backend/types/agenta_node_dto.py +3 -1
- agenta/client/backend/types/agenta_nodes_response.py +3 -1
- agenta/client/backend/types/agenta_root_dto.py +3 -1
- agenta/client/backend/types/agenta_roots_response.py +3 -1
- agenta/client/backend/types/agenta_tree_dto.py +3 -1
- agenta/client/backend/types/agenta_trees_response.py +3 -1
- agenta/client/backend/types/aggregated_result.py +3 -1
- agenta/client/backend/types/analytics_response.py +3 -1
- agenta/client/backend/types/annotation.py +6 -4
- agenta/client/backend/types/annotation_create.py +3 -1
- agenta/client/backend/types/annotation_edit.py +3 -1
- agenta/client/backend/types/annotation_link.py +3 -1
- agenta/client/backend/types/annotation_link_response.py +3 -1
- agenta/client/backend/types/annotation_query.py +3 -1
- agenta/client/backend/types/annotation_query_request.py +3 -1
- agenta/client/backend/types/annotation_reference.py +3 -1
- agenta/client/backend/types/annotation_references.py +3 -1
- agenta/client/backend/types/annotation_response.py +3 -1
- agenta/client/backend/types/annotations_response.py +3 -1
- agenta/client/backend/types/app.py +3 -1
- agenta/client/backend/types/app_variant_response.py +3 -1
- agenta/client/backend/types/app_variant_revision.py +3 -1
- agenta/client/backend/types/artifact.py +6 -4
- agenta/client/backend/types/base_output.py +3 -1
- agenta/client/backend/types/body_fetch_workflow_revision.py +3 -1
- agenta/client/backend/types/body_import_testset.py +3 -1
- agenta/client/backend/types/bucket_dto.py +3 -1
- agenta/client/backend/types/collect_status_response.py +3 -1
- agenta/client/backend/types/config_db.py +3 -1
- agenta/client/backend/types/config_dto.py +3 -1
- agenta/client/backend/types/config_response_model.py +3 -1
- agenta/client/backend/types/correct_answer.py +3 -1
- agenta/client/backend/types/create_app_output.py +3 -1
- agenta/client/backend/types/custom_model_settings_dto.py +3 -1
- agenta/client/backend/types/custom_provider_dto.py +3 -1
- agenta/client/backend/types/custom_provider_kind.py +1 -1
- agenta/client/backend/types/custom_provider_settings_dto.py +3 -1
- agenta/client/backend/types/delete_evaluation.py +3 -1
- agenta/client/backend/types/environment_output.py +3 -1
- agenta/client/backend/types/environment_output_extended.py +3 -1
- agenta/client/backend/types/environment_revision.py +3 -1
- agenta/client/backend/types/error.py +3 -1
- agenta/client/backend/types/evaluation.py +3 -1
- agenta/client/backend/types/evaluation_scenario.py +3 -1
- agenta/client/backend/types/evaluation_scenario_input.py +3 -1
- agenta/client/backend/types/evaluation_scenario_output.py +3 -1
- agenta/client/backend/types/evaluation_scenario_result.py +3 -1
- agenta/client/backend/types/evaluator.py +6 -4
- agenta/client/backend/types/evaluator_config.py +6 -4
- agenta/client/backend/types/evaluator_flags.py +3 -1
- agenta/client/backend/types/evaluator_mapping_output_interface.py +3 -1
- agenta/client/backend/types/evaluator_output_interface.py +3 -1
- agenta/client/backend/types/evaluator_query.py +3 -1
- agenta/client/backend/types/evaluator_query_request.py +3 -1
- agenta/client/backend/types/evaluator_request.py +3 -1
- agenta/client/backend/types/evaluator_response.py +3 -1
- agenta/client/backend/types/evaluators_response.py +3 -1
- agenta/client/backend/types/exception_dto.py +3 -1
- agenta/client/backend/types/extended_o_tel_tracing_response.py +3 -1
- agenta/client/backend/types/get_config_response.py +3 -1
- agenta/client/backend/types/header.py +3 -1
- agenta/client/backend/types/http_validation_error.py +3 -1
- agenta/client/backend/types/human_evaluation.py +3 -1
- agenta/client/backend/types/human_evaluation_scenario.py +3 -1
- agenta/client/backend/types/human_evaluation_scenario_input.py +3 -1
- agenta/client/backend/types/human_evaluation_scenario_output.py +3 -1
- agenta/client/backend/types/invite_request.py +3 -1
- agenta/client/backend/types/legacy_analytics_response.py +3 -1
- agenta/client/backend/types/legacy_data_point.py +3 -1
- agenta/client/backend/types/legacy_evaluator.py +3 -1
- agenta/client/backend/types/legacy_scope_request.py +3 -1
- agenta/client/backend/types/legacy_scopes_response.py +3 -1
- agenta/client/backend/types/legacy_subscription_request.py +3 -1
- agenta/client/backend/types/legacy_user_request.py +3 -1
- agenta/client/backend/types/legacy_user_response.py +3 -1
- agenta/client/backend/types/lifecycle_dto.py +3 -1
- agenta/client/backend/types/link_dto.py +3 -1
- agenta/client/backend/types/list_api_keys_response.py +3 -1
- agenta/client/backend/types/llm_run_rate_limit.py +3 -1
- agenta/client/backend/types/meta_request.py +3 -1
- agenta/client/backend/types/metrics_dto.py +3 -1
- agenta/client/backend/types/new_testset.py +3 -1
- agenta/client/backend/types/node_dto.py +3 -1
- agenta/client/backend/types/o_tel_context_dto.py +3 -1
- agenta/client/backend/types/o_tel_event.py +6 -4
- agenta/client/backend/types/o_tel_event_dto.py +3 -1
- agenta/client/backend/types/o_tel_extra_dto.py +3 -1
- agenta/client/backend/types/o_tel_flat_span.py +6 -4
- agenta/client/backend/types/o_tel_link.py +6 -4
- agenta/client/backend/types/o_tel_link_dto.py +3 -1
- agenta/client/backend/types/o_tel_links_response.py +3 -1
- agenta/client/backend/types/o_tel_span.py +1 -1
- agenta/client/backend/types/o_tel_span_dto.py +3 -1
- agenta/client/backend/types/o_tel_spans_tree.py +3 -1
- agenta/client/backend/types/o_tel_tracing_data_response.py +3 -1
- agenta/client/backend/types/o_tel_tracing_request.py +3 -1
- agenta/client/backend/types/o_tel_tracing_response.py +3 -1
- agenta/client/backend/types/organization.py +3 -1
- agenta/client/backend/types/organization_details.py +3 -1
- agenta/client/backend/types/organization_membership_request.py +3 -1
- agenta/client/backend/types/organization_output.py +3 -1
- agenta/client/backend/types/organization_request.py +3 -1
- agenta/client/backend/types/parent_dto.py +3 -1
- agenta/client/backend/types/project_membership_request.py +3 -1
- agenta/client/backend/types/project_request.py +3 -1
- agenta/client/backend/types/project_scope.py +3 -1
- agenta/client/backend/types/projects_response.py +3 -1
- agenta/client/backend/types/reference.py +6 -4
- agenta/client/backend/types/reference_dto.py +3 -1
- agenta/client/backend/types/reference_request_model.py +3 -1
- agenta/client/backend/types/result.py +3 -1
- agenta/client/backend/types/root_dto.py +3 -1
- agenta/client/backend/types/scopes_response_model.py +3 -1
- agenta/client/backend/types/secret_dto.py +3 -1
- agenta/client/backend/types/secret_response_dto.py +3 -1
- agenta/client/backend/types/simple_evaluation_output.py +3 -1
- agenta/client/backend/types/span_dto.py +6 -4
- agenta/client/backend/types/standard_provider_dto.py +3 -1
- agenta/client/backend/types/standard_provider_settings_dto.py +3 -1
- agenta/client/backend/types/status_dto.py +3 -1
- agenta/client/backend/types/tags_request.py +3 -1
- agenta/client/backend/types/testcase_response.py +6 -4
- agenta/client/backend/types/testset.py +6 -4
- agenta/client/backend/types/{test_set_output_response.py → testset_output_response.py} +4 -2
- agenta/client/backend/types/testset_request.py +3 -1
- agenta/client/backend/types/testset_response.py +3 -1
- agenta/client/backend/types/{test_set_simple_response.py → testset_simple_response.py} +4 -2
- agenta/client/backend/types/testsets_response.py +3 -1
- agenta/client/backend/types/time_dto.py +3 -1
- agenta/client/backend/types/tree_dto.py +3 -1
- agenta/client/backend/types/update_app_output.py +3 -1
- agenta/client/backend/types/user_request.py +3 -1
- agenta/client/backend/types/validation_error.py +3 -1
- agenta/client/backend/types/workflow_artifact.py +6 -4
- agenta/client/backend/types/workflow_data.py +3 -1
- agenta/client/backend/types/workflow_flags.py +3 -1
- agenta/client/backend/types/workflow_request.py +3 -1
- agenta/client/backend/types/workflow_response.py +3 -1
- agenta/client/backend/types/workflow_revision.py +6 -4
- agenta/client/backend/types/workflow_revision_request.py +3 -1
- agenta/client/backend/types/workflow_revision_response.py +3 -1
- agenta/client/backend/types/workflow_revisions_response.py +3 -1
- agenta/client/backend/types/workflow_variant.py +6 -4
- agenta/client/backend/types/workflow_variant_request.py +3 -1
- agenta/client/backend/types/workflow_variant_response.py +3 -1
- agenta/client/backend/types/workflow_variants_response.py +3 -1
- agenta/client/backend/types/workflows_response.py +3 -1
- agenta/client/backend/types/workspace.py +3 -1
- agenta/client/backend/types/workspace_member_response.py +3 -1
- agenta/client/backend/types/workspace_membership_request.py +3 -1
- agenta/client/backend/types/workspace_permission.py +3 -1
- agenta/client/backend/types/workspace_request.py +3 -1
- agenta/client/backend/types/workspace_response.py +3 -1
- agenta/client/backend/vault/raw_client.py +4 -4
- agenta/client/backend/workspace/client.py +2 -2
- agenta/client/client.py +102 -88
- agenta/sdk/__init__.py +52 -3
- agenta/sdk/agenta_init.py +43 -16
- agenta/sdk/assets.py +23 -15
- agenta/sdk/context/serving.py +20 -8
- agenta/sdk/context/tracing.py +40 -22
- agenta/sdk/contexts/__init__.py +0 -0
- agenta/sdk/contexts/routing.py +38 -0
- agenta/sdk/contexts/running.py +57 -0
- agenta/sdk/contexts/tracing.py +86 -0
- agenta/sdk/decorators/__init__.py +1 -0
- agenta/sdk/decorators/routing.py +284 -0
- agenta/sdk/decorators/running.py +692 -98
- agenta/sdk/decorators/serving.py +20 -21
- agenta/sdk/decorators/tracing.py +176 -131
- agenta/sdk/engines/__init__.py +0 -0
- agenta/sdk/engines/running/__init__.py +0 -0
- agenta/sdk/engines/running/utils.py +17 -0
- agenta/sdk/engines/tracing/__init__.py +1 -0
- agenta/sdk/engines/tracing/attributes.py +185 -0
- agenta/sdk/engines/tracing/conventions.py +49 -0
- agenta/sdk/engines/tracing/exporters.py +130 -0
- agenta/sdk/engines/tracing/inline.py +1154 -0
- agenta/sdk/engines/tracing/processors.py +190 -0
- agenta/sdk/engines/tracing/propagation.py +102 -0
- agenta/sdk/engines/tracing/spans.py +136 -0
- agenta/sdk/engines/tracing/tracing.py +324 -0
- agenta/sdk/evaluations/__init__.py +2 -0
- agenta/sdk/evaluations/metrics.py +37 -0
- agenta/sdk/evaluations/preview/__init__.py +0 -0
- agenta/sdk/evaluations/preview/evaluate.py +765 -0
- agenta/sdk/evaluations/preview/utils.py +861 -0
- agenta/sdk/evaluations/results.py +66 -0
- agenta/sdk/evaluations/runs.py +153 -0
- agenta/sdk/evaluations/scenarios.py +48 -0
- agenta/sdk/litellm/litellm.py +12 -0
- agenta/sdk/litellm/mockllm.py +6 -8
- agenta/sdk/litellm/mocks/__init__.py +5 -5
- agenta/sdk/managers/applications.py +304 -0
- agenta/sdk/managers/config.py +2 -2
- agenta/sdk/managers/evaluations.py +0 -0
- agenta/sdk/managers/evaluators.py +303 -0
- agenta/sdk/managers/secrets.py +161 -24
- agenta/sdk/managers/shared.py +3 -1
- agenta/sdk/managers/testsets.py +441 -0
- agenta/sdk/managers/vault.py +3 -3
- agenta/sdk/middleware/auth.py +0 -176
- agenta/sdk/middleware/config.py +27 -9
- agenta/sdk/middleware/vault.py +204 -9
- agenta/sdk/middlewares/__init__.py +0 -0
- agenta/sdk/middlewares/routing/__init__.py +0 -0
- agenta/sdk/middlewares/routing/auth.py +263 -0
- agenta/sdk/middlewares/routing/cors.py +30 -0
- agenta/sdk/middlewares/routing/otel.py +29 -0
- agenta/sdk/middlewares/running/__init__.py +0 -0
- agenta/sdk/middlewares/running/normalizer.py +321 -0
- agenta/sdk/middlewares/running/resolver.py +161 -0
- agenta/sdk/middlewares/running/vault.py +140 -0
- agenta/sdk/models/__init__.py +0 -0
- agenta/sdk/models/blobs.py +33 -0
- agenta/sdk/models/evaluations.py +119 -0
- agenta/sdk/models/git.py +126 -0
- agenta/sdk/models/shared.py +167 -0
- agenta/sdk/models/testsets.py +163 -0
- agenta/sdk/models/tracing.py +202 -0
- agenta/sdk/models/workflows.py +753 -0
- agenta/sdk/tracing/attributes.py +4 -4
- agenta/sdk/tracing/exporters.py +67 -17
- agenta/sdk/tracing/inline.py +37 -45
- agenta/sdk/tracing/processors.py +97 -0
- agenta/sdk/tracing/propagation.py +3 -1
- agenta/sdk/tracing/spans.py +4 -0
- agenta/sdk/tracing/tracing.py +13 -15
- agenta/sdk/types.py +222 -22
- agenta/sdk/utils/cache.py +1 -1
- agenta/sdk/utils/client.py +38 -0
- agenta/sdk/utils/helpers.py +13 -12
- agenta/sdk/utils/logging.py +18 -78
- agenta/sdk/utils/references.py +23 -0
- agenta/sdk/workflows/builtin.py +600 -0
- agenta/sdk/workflows/configurations.py +22 -0
- agenta/sdk/workflows/errors.py +292 -0
- agenta/sdk/workflows/handlers.py +1791 -0
- agenta/sdk/workflows/interfaces.py +948 -0
- agenta/sdk/workflows/sandbox.py +118 -0
- agenta/sdk/workflows/utils.py +303 -6
- {agenta-0.52.6.dist-info → agenta-0.63.2.dist-info}/METADATA +37 -33
- agenta-0.63.2.dist-info/RECORD +421 -0
- {agenta-0.52.6.dist-info → agenta-0.63.2.dist-info}/WHEEL +1 -1
- agenta/sdk/middleware/adapt.py +0 -253
- agenta/sdk/middleware/base.py +0 -40
- agenta/sdk/middleware/flags.py +0 -40
- agenta/sdk/workflows/types.py +0 -472
- agenta-0.52.6.dist-info/RECORD +0 -371
- /agenta/sdk/{workflows → engines/running}/registry.py +0 -0
agenta/sdk/decorators/serving.py
CHANGED
|
@@ -28,13 +28,12 @@ from agenta.sdk.middleware.otel import OTelMiddleware
|
|
|
28
28
|
from agenta.sdk.middleware.auth import AuthHTTPMiddleware
|
|
29
29
|
from agenta.sdk.middleware.cors import CORSMiddleware
|
|
30
30
|
|
|
31
|
-
from agenta.sdk.
|
|
32
|
-
|
|
31
|
+
from agenta.sdk.contexts.routing import (
|
|
32
|
+
routing_context_manager,
|
|
33
33
|
RoutingContext,
|
|
34
34
|
)
|
|
35
|
-
from agenta.sdk.
|
|
35
|
+
from agenta.sdk.contexts.tracing import (
|
|
36
36
|
tracing_context_manager,
|
|
37
|
-
tracing_context,
|
|
38
37
|
TracingContext,
|
|
39
38
|
)
|
|
40
39
|
from agenta.sdk.router import router
|
|
@@ -338,7 +337,7 @@ class entrypoint:
|
|
|
338
337
|
inline = state.inline
|
|
339
338
|
mock = state.mock
|
|
340
339
|
|
|
341
|
-
with
|
|
340
|
+
with routing_context_manager(
|
|
342
341
|
context=RoutingContext(
|
|
343
342
|
parameters=parameters,
|
|
344
343
|
secrets=secrets,
|
|
@@ -394,15 +393,15 @@ class entrypoint:
|
|
|
394
393
|
|
|
395
394
|
try:
|
|
396
395
|
if isinstance(result, StarletteResponse):
|
|
397
|
-
result.headers.setdefault("
|
|
396
|
+
result.headers.setdefault("x-ag-version", "3.0")
|
|
398
397
|
if content_type:
|
|
399
|
-
result.headers.setdefault("
|
|
398
|
+
result.headers.setdefault("x-ag-content-type", content_type)
|
|
400
399
|
if tree_id:
|
|
401
|
-
result.headers.setdefault("
|
|
400
|
+
result.headers.setdefault("x-ag-tree-id", tree_id)
|
|
402
401
|
if trace_id:
|
|
403
|
-
result.headers.setdefault("
|
|
402
|
+
result.headers.setdefault("x-ag-trace-id", trace_id)
|
|
404
403
|
if span_id:
|
|
405
|
-
result.headers.setdefault("
|
|
404
|
+
result.headers.setdefault("x-ag-span-id", span_id)
|
|
406
405
|
|
|
407
406
|
return result
|
|
408
407
|
except:
|
|
@@ -530,7 +529,7 @@ class entrypoint:
|
|
|
530
529
|
async def fetch_inline_trace_id(
|
|
531
530
|
self,
|
|
532
531
|
):
|
|
533
|
-
context =
|
|
532
|
+
context = TracingContext.get()
|
|
534
533
|
|
|
535
534
|
link = context.link
|
|
536
535
|
|
|
@@ -549,7 +548,7 @@ class entrypoint:
|
|
|
549
548
|
TIMESTEP = 0.1
|
|
550
549
|
NOFSTEPS = TIMEOUT / TIMESTEP
|
|
551
550
|
|
|
552
|
-
context =
|
|
551
|
+
context = TracingContext.get()
|
|
553
552
|
|
|
554
553
|
link = context.link
|
|
555
554
|
|
|
@@ -657,9 +656,9 @@ class entrypoint:
|
|
|
657
656
|
def add_func_params_to_parser(self, updated_params: list) -> None:
|
|
658
657
|
"""Add function parameters to function signature."""
|
|
659
658
|
for name, param in signature(self.func).parameters.items():
|
|
660
|
-
assert (
|
|
661
|
-
|
|
662
|
-
)
|
|
659
|
+
assert len(param.default.__class__.__bases__) == 1, (
|
|
660
|
+
f"Inherited standard type of {param.default.__class__} needs to be one."
|
|
661
|
+
)
|
|
663
662
|
updated_params.append(
|
|
664
663
|
Parameter(
|
|
665
664
|
name,
|
|
@@ -719,9 +718,9 @@ class entrypoint:
|
|
|
719
718
|
-1
|
|
720
719
|
] # Extract schema name
|
|
721
720
|
if schema_name in schema_name_map:
|
|
722
|
-
content["schema"][
|
|
723
|
-
"
|
|
724
|
-
|
|
721
|
+
content["schema"]["$ref"] = (
|
|
722
|
+
f"#/components/schemas/{schema_name_map[schema_name]}"
|
|
723
|
+
)
|
|
725
724
|
|
|
726
725
|
if "responses" in method:
|
|
727
726
|
for status_code, response in method["responses"].items():
|
|
@@ -735,9 +734,9 @@ class entrypoint:
|
|
|
735
734
|
-1
|
|
736
735
|
] # Extract schema name
|
|
737
736
|
if schema_name in schema_name_map:
|
|
738
|
-
content["schema"][
|
|
739
|
-
"
|
|
740
|
-
|
|
737
|
+
content["schema"]["$ref"] = (
|
|
738
|
+
f"#/components/schemas/{schema_name_map[schema_name]}"
|
|
739
|
+
)
|
|
741
740
|
|
|
742
741
|
# ✅ Update OpenAPI schema with fixed schemas
|
|
743
742
|
openapi_schema["components"]["schemas"] = updated_schemas
|
agenta/sdk/decorators/tracing.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
# /agenta/sdk/decorators/tracing.py
|
|
2
|
+
|
|
1
3
|
from typing import Callable, Optional, Any, Dict, List, Union
|
|
2
4
|
|
|
3
5
|
from opentelemetry import context as otel_context
|
|
4
6
|
from opentelemetry.context import attach, detach
|
|
5
|
-
from opentelemetry import trace
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
from functools import wraps
|
|
@@ -14,21 +15,37 @@ from inspect import (
|
|
|
14
15
|
isasyncgenfunction,
|
|
15
16
|
)
|
|
16
17
|
|
|
18
|
+
from pydantic import BaseModel
|
|
19
|
+
|
|
17
20
|
from opentelemetry import baggage
|
|
18
21
|
from opentelemetry.context import attach, detach, get_current
|
|
19
22
|
from opentelemetry.baggage import set_baggage, get_all
|
|
20
23
|
|
|
21
24
|
from agenta.sdk.utils.logging import get_module_logger
|
|
22
25
|
from agenta.sdk.utils.exceptions import suppress
|
|
23
|
-
from agenta.sdk.
|
|
24
|
-
|
|
26
|
+
from agenta.sdk.contexts.tracing import (
|
|
27
|
+
TracingContext,
|
|
28
|
+
tracing_context_manager,
|
|
29
|
+
)
|
|
25
30
|
from agenta.sdk.tracing.conventions import parse_span_kind
|
|
26
31
|
|
|
27
32
|
import agenta as ag
|
|
28
33
|
|
|
34
|
+
|
|
29
35
|
log = get_module_logger(__name__)
|
|
30
36
|
|
|
31
37
|
|
|
38
|
+
def _has_instrument(handler: Callable[..., Any]) -> bool:
|
|
39
|
+
return bool(getattr(handler, "__has_instrument__", False))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def auto_instrument(handler: Callable[..., Any]) -> Callable[..., Any]:
|
|
43
|
+
if _has_instrument(handler):
|
|
44
|
+
return handler
|
|
45
|
+
|
|
46
|
+
return instrument()(handler)
|
|
47
|
+
|
|
48
|
+
|
|
32
49
|
class instrument: # pylint: disable=invalid-name
|
|
33
50
|
DEFAULT_KEY = "__default__"
|
|
34
51
|
|
|
@@ -41,7 +58,8 @@ class instrument: # pylint: disable=invalid-name
|
|
|
41
58
|
redact: Optional[Callable[..., Any]] = None,
|
|
42
59
|
redact_on_error: Optional[bool] = True,
|
|
43
60
|
max_depth: Optional[int] = 2,
|
|
44
|
-
aggregate: Optional[
|
|
61
|
+
aggregate: Optional[Union[bool, Callable]] = None, # stream to batch
|
|
62
|
+
annotate: Optional[bool] = None, # annotation vs invocation
|
|
45
63
|
# DEPRECATING
|
|
46
64
|
kind: str = "task",
|
|
47
65
|
spankind: Optional[str] = "TASK",
|
|
@@ -55,142 +73,183 @@ class instrument: # pylint: disable=invalid-name
|
|
|
55
73
|
self.redact_on_error = redact_on_error
|
|
56
74
|
self.max_depth = max_depth
|
|
57
75
|
self.aggregate = aggregate
|
|
76
|
+
self.annotate = annotate
|
|
58
77
|
|
|
59
|
-
def __call__(self,
|
|
60
|
-
is_coroutine_function = iscoroutinefunction(
|
|
61
|
-
is_sync_generator = isgeneratorfunction(
|
|
62
|
-
is_async_generator = isasyncgenfunction(
|
|
78
|
+
def __call__(self, handler: Callable[..., Any]):
|
|
79
|
+
is_coroutine_function = iscoroutinefunction(handler)
|
|
80
|
+
is_sync_generator = isgeneratorfunction(handler)
|
|
81
|
+
is_async_generator = isasyncgenfunction(handler)
|
|
63
82
|
|
|
64
83
|
# ---- ASYNC GENERATOR ----
|
|
65
84
|
if is_async_generator:
|
|
66
85
|
|
|
67
|
-
@wraps(
|
|
86
|
+
@wraps(handler)
|
|
68
87
|
def astream_wrapper(*args, **kwargs):
|
|
69
|
-
|
|
88
|
+
with tracing_context_manager(context=TracingContext.get()):
|
|
89
|
+
# debug_otel_context("[BEFORE STREAM] [BEFORE SETUP]")
|
|
70
90
|
|
|
71
|
-
|
|
91
|
+
captured_ctx = otel_context.get_current()
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
self._parse_type_and_kind()
|
|
74
94
|
|
|
75
|
-
|
|
95
|
+
self._attach_baggage()
|
|
76
96
|
|
|
77
|
-
|
|
97
|
+
ctx = self._get_traceparent()
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
# debug_otel_context("[BEFORE STREAM] [AFTER SETUP]")
|
|
80
100
|
|
|
81
|
-
|
|
82
|
-
|
|
101
|
+
async def wrapped_generator():
|
|
102
|
+
# debug_otel_context("[WITHIN STREAM] [BEFORE ATTACH]")
|
|
83
103
|
|
|
84
|
-
|
|
104
|
+
otel_token = otel_context.attach(captured_ctx)
|
|
85
105
|
|
|
86
|
-
|
|
106
|
+
# debug_otel_context("[WITHIN STREAM] [AFTER ATTACH]")
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
try:
|
|
109
|
+
with ag.tracer.start_as_current_span(
|
|
110
|
+
name=handler.__name__,
|
|
111
|
+
kind=self.kind,
|
|
112
|
+
context=ctx,
|
|
113
|
+
):
|
|
114
|
+
self._set_link()
|
|
115
|
+
self._pre_instrument(handler, *args, **kwargs)
|
|
96
116
|
|
|
97
|
-
|
|
117
|
+
_result = []
|
|
98
118
|
|
|
99
|
-
|
|
119
|
+
agen = handler(*args, **kwargs)
|
|
100
120
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
121
|
+
try:
|
|
122
|
+
async for chunk in agen:
|
|
123
|
+
_result.append(chunk)
|
|
124
|
+
yield chunk
|
|
105
125
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
finally:
|
|
127
|
+
if self.aggregate and callable(self.aggregate):
|
|
128
|
+
result = self.aggregate(_result)
|
|
129
|
+
elif all(isinstance(r, str) for r in _result):
|
|
130
|
+
result = "".join(_result)
|
|
131
|
+
elif all(isinstance(r, bytes) for r in _result):
|
|
132
|
+
result = b"".join(_result)
|
|
133
|
+
else:
|
|
134
|
+
result = _result
|
|
115
135
|
|
|
116
|
-
|
|
136
|
+
self._post_instrument(result)
|
|
117
137
|
|
|
118
|
-
|
|
119
|
-
|
|
138
|
+
finally:
|
|
139
|
+
# debug_otel_context("[WITHIN STREAM] [BEFORE DETACH]")
|
|
120
140
|
|
|
121
|
-
|
|
141
|
+
otel_context.detach(otel_token)
|
|
122
142
|
|
|
123
|
-
|
|
143
|
+
# debug_otel_context("[WITHIN STREAM] [AFTER DETACH]")
|
|
124
144
|
|
|
125
145
|
return wrapped_generator()
|
|
126
146
|
|
|
147
|
+
setattr(astream_wrapper, "__has_instrument__", True)
|
|
148
|
+
setattr(astream_wrapper, "__original_handler__", handler)
|
|
127
149
|
return astream_wrapper
|
|
128
150
|
|
|
129
151
|
# ---- SYNC GENERATOR ----
|
|
130
152
|
if is_sync_generator:
|
|
131
153
|
|
|
132
|
-
@wraps(
|
|
154
|
+
@wraps(handler)
|
|
133
155
|
def stream_wrapper(*args, **kwargs):
|
|
134
|
-
|
|
156
|
+
with tracing_context_manager(context=TracingContext.get()):
|
|
157
|
+
self._parse_type_and_kind()
|
|
135
158
|
|
|
136
|
-
|
|
159
|
+
token = self._attach_baggage()
|
|
137
160
|
|
|
138
|
-
|
|
161
|
+
ctx = self._get_traceparent()
|
|
139
162
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
163
|
+
def wrapped_generator():
|
|
164
|
+
try:
|
|
165
|
+
with ag.tracer.start_as_current_span(
|
|
166
|
+
name=handler.__name__,
|
|
167
|
+
kind=self.kind,
|
|
168
|
+
context=ctx,
|
|
169
|
+
):
|
|
170
|
+
self._set_link()
|
|
148
171
|
|
|
149
|
-
|
|
172
|
+
self._pre_instrument(handler, *args, **kwargs)
|
|
150
173
|
|
|
151
|
-
|
|
174
|
+
_result = []
|
|
152
175
|
|
|
153
|
-
|
|
176
|
+
gen = handler(*args, **kwargs)
|
|
154
177
|
|
|
155
|
-
|
|
178
|
+
gen_return = None
|
|
156
179
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
try:
|
|
181
|
+
while True:
|
|
182
|
+
try:
|
|
183
|
+
chunk = next(gen)
|
|
184
|
+
except StopIteration as e:
|
|
185
|
+
gen_return = e.value
|
|
186
|
+
break
|
|
164
187
|
|
|
165
|
-
|
|
166
|
-
|
|
188
|
+
_result.append(chunk)
|
|
189
|
+
yield chunk
|
|
167
190
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
191
|
+
finally:
|
|
192
|
+
if self.aggregate and callable(self.aggregate):
|
|
193
|
+
result = self.aggregate(_result)
|
|
194
|
+
elif all(isinstance(r, str) for r in _result):
|
|
195
|
+
result = "".join(_result)
|
|
196
|
+
elif all(isinstance(r, bytes) for r in _result):
|
|
197
|
+
result = b"".join(_result)
|
|
198
|
+
else:
|
|
199
|
+
result = _result
|
|
177
200
|
|
|
178
|
-
|
|
201
|
+
self._post_instrument(result)
|
|
179
202
|
|
|
180
|
-
|
|
203
|
+
return gen_return
|
|
181
204
|
|
|
182
|
-
|
|
183
|
-
|
|
205
|
+
finally:
|
|
206
|
+
self._detach_baggage(token)
|
|
184
207
|
|
|
185
208
|
return wrapped_generator()
|
|
186
209
|
|
|
210
|
+
setattr(stream_wrapper, "__has_instrument__", True)
|
|
211
|
+
setattr(stream_wrapper, "__original_handler__", handler)
|
|
187
212
|
return stream_wrapper
|
|
188
213
|
|
|
189
|
-
# ---- ASYNC FUNCTION
|
|
214
|
+
# ---- ASYNC FUNCTION ----
|
|
190
215
|
if is_coroutine_function:
|
|
191
216
|
|
|
192
|
-
@wraps(
|
|
217
|
+
@wraps(handler)
|
|
193
218
|
async def awrapper(*args, **kwargs):
|
|
219
|
+
with tracing_context_manager(context=TracingContext.get()):
|
|
220
|
+
self._parse_type_and_kind()
|
|
221
|
+
|
|
222
|
+
token = self._attach_baggage()
|
|
223
|
+
|
|
224
|
+
ctx = self._get_traceparent()
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
with ag.tracer.start_as_current_span(
|
|
228
|
+
name=handler.__name__,
|
|
229
|
+
kind=self.kind,
|
|
230
|
+
context=ctx,
|
|
231
|
+
):
|
|
232
|
+
self._set_link()
|
|
233
|
+
|
|
234
|
+
self._pre_instrument(handler, *args, **kwargs)
|
|
235
|
+
|
|
236
|
+
result = await handler(*args, **kwargs)
|
|
237
|
+
|
|
238
|
+
self._post_instrument(result)
|
|
239
|
+
|
|
240
|
+
finally:
|
|
241
|
+
self._detach_baggage(token)
|
|
242
|
+
|
|
243
|
+
return result
|
|
244
|
+
|
|
245
|
+
setattr(awrapper, "__has_instrument__", True)
|
|
246
|
+
setattr(awrapper, "__original_handler__", handler)
|
|
247
|
+
return awrapper
|
|
248
|
+
|
|
249
|
+
# ---- SYNC FUNCTION ----
|
|
250
|
+
@wraps(handler)
|
|
251
|
+
def wrapper(*args, **kwargs):
|
|
252
|
+
with tracing_context_manager(context=TracingContext.get()):
|
|
194
253
|
self._parse_type_and_kind()
|
|
195
254
|
|
|
196
255
|
token = self._attach_baggage()
|
|
@@ -199,15 +258,15 @@ class instrument: # pylint: disable=invalid-name
|
|
|
199
258
|
|
|
200
259
|
try:
|
|
201
260
|
with ag.tracer.start_as_current_span(
|
|
202
|
-
name=
|
|
261
|
+
name=handler.__name__,
|
|
203
262
|
kind=self.kind,
|
|
204
263
|
context=ctx,
|
|
205
264
|
):
|
|
206
265
|
self._set_link()
|
|
207
266
|
|
|
208
|
-
self._pre_instrument(
|
|
267
|
+
self._pre_instrument(handler, *args, **kwargs)
|
|
209
268
|
|
|
210
|
-
result =
|
|
269
|
+
result = handler(*args, **kwargs)
|
|
211
270
|
|
|
212
271
|
self._post_instrument(result)
|
|
213
272
|
|
|
@@ -216,36 +275,8 @@ class instrument: # pylint: disable=invalid-name
|
|
|
216
275
|
|
|
217
276
|
return result
|
|
218
277
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# ---- SYNC FUNCTION (non-generator) ----
|
|
222
|
-
@wraps(func)
|
|
223
|
-
def wrapper(*args, **kwargs):
|
|
224
|
-
self._parse_type_and_kind()
|
|
225
|
-
|
|
226
|
-
token = self._attach_baggage()
|
|
227
|
-
|
|
228
|
-
ctx = self._get_traceparent()
|
|
229
|
-
|
|
230
|
-
try:
|
|
231
|
-
with ag.tracer.start_as_current_span(
|
|
232
|
-
name=func.__name__,
|
|
233
|
-
kind=self.kind,
|
|
234
|
-
context=ctx,
|
|
235
|
-
):
|
|
236
|
-
self._set_link()
|
|
237
|
-
|
|
238
|
-
self._pre_instrument(func, *args, **kwargs)
|
|
239
|
-
|
|
240
|
-
result = func(*args, **kwargs)
|
|
241
|
-
|
|
242
|
-
self._post_instrument(result)
|
|
243
|
-
|
|
244
|
-
finally:
|
|
245
|
-
self._detach_baggage(token)
|
|
246
|
-
|
|
247
|
-
return result
|
|
248
|
-
|
|
278
|
+
setattr(wrapper, "__has_instrument__", True)
|
|
279
|
+
setattr(wrapper, "__original_handler__", handler)
|
|
249
280
|
return wrapper
|
|
250
281
|
|
|
251
282
|
def _parse_type_and_kind(self):
|
|
@@ -255,7 +286,7 @@ class instrument: # pylint: disable=invalid-name
|
|
|
255
286
|
self.kind = parse_span_kind(self.type)
|
|
256
287
|
|
|
257
288
|
def _get_traceparent(self):
|
|
258
|
-
context =
|
|
289
|
+
context = TracingContext.get()
|
|
259
290
|
|
|
260
291
|
traceparent = context.traceparent
|
|
261
292
|
|
|
@@ -268,7 +299,7 @@ class instrument: # pylint: disable=invalid-name
|
|
|
268
299
|
def _set_link(self):
|
|
269
300
|
span = ag.tracing.get_current_span()
|
|
270
301
|
|
|
271
|
-
context =
|
|
302
|
+
context = TracingContext.get()
|
|
272
303
|
|
|
273
304
|
if not context.link:
|
|
274
305
|
context.link = {
|
|
@@ -276,10 +307,10 @@ class instrument: # pylint: disable=invalid-name
|
|
|
276
307
|
"span_id": span.get_span_context().span_id,
|
|
277
308
|
}
|
|
278
309
|
|
|
279
|
-
|
|
310
|
+
TracingContext.set(context)
|
|
280
311
|
|
|
281
312
|
def _attach_baggage(self):
|
|
282
|
-
context =
|
|
313
|
+
context = TracingContext.get()
|
|
283
314
|
|
|
284
315
|
references = context.references
|
|
285
316
|
|
|
@@ -299,26 +330,24 @@ class instrument: # pylint: disable=invalid-name
|
|
|
299
330
|
|
|
300
331
|
def _pre_instrument(
|
|
301
332
|
self,
|
|
302
|
-
|
|
333
|
+
handler,
|
|
303
334
|
*args,
|
|
304
335
|
**kwargs,
|
|
305
336
|
):
|
|
306
337
|
span = ag.tracing.get_current_span()
|
|
307
338
|
|
|
308
|
-
context =
|
|
339
|
+
context = TracingContext.get()
|
|
309
340
|
|
|
310
341
|
with suppress():
|
|
311
342
|
trace_id = span.context.trace_id
|
|
312
343
|
|
|
313
344
|
ag.tracing.credentials.put(trace_id, context.credentials)
|
|
314
345
|
|
|
315
|
-
trace_type = context.type or "invocation"
|
|
316
346
|
span_type = self.type or "task"
|
|
317
347
|
|
|
318
348
|
span.set_attributes(
|
|
319
349
|
attributes={
|
|
320
350
|
"node": span_type,
|
|
321
|
-
"tree": trace_type,
|
|
322
351
|
},
|
|
323
352
|
namespace="type",
|
|
324
353
|
)
|
|
@@ -332,7 +361,7 @@ class instrument: # pylint: disable=invalid-name
|
|
|
332
361
|
_inputs = self._redact(
|
|
333
362
|
name=span.name,
|
|
334
363
|
field="inputs",
|
|
335
|
-
io=self._parse(
|
|
364
|
+
io=self._parse(handler, *args, **kwargs),
|
|
336
365
|
ignore=self.ignore_inputs,
|
|
337
366
|
)
|
|
338
367
|
|
|
@@ -403,14 +432,14 @@ class instrument: # pylint: disable=invalid-name
|
|
|
403
432
|
|
|
404
433
|
def _parse(
|
|
405
434
|
self,
|
|
406
|
-
|
|
435
|
+
handler,
|
|
407
436
|
*args,
|
|
408
437
|
**kwargs,
|
|
409
438
|
) -> Dict[str, Any]:
|
|
410
439
|
inputs = {
|
|
411
440
|
key: value
|
|
412
441
|
for key, value in chain(
|
|
413
|
-
zip(getfullargspec(
|
|
442
|
+
zip(getfullargspec(handler).args, args),
|
|
414
443
|
kwargs.items(),
|
|
415
444
|
)
|
|
416
445
|
}
|
|
@@ -464,6 +493,22 @@ class instrument: # pylint: disable=invalid-name
|
|
|
464
493
|
if ag.tracing.redact_on_error:
|
|
465
494
|
io = {}
|
|
466
495
|
|
|
496
|
+
if "request" in io:
|
|
497
|
+
with suppress():
|
|
498
|
+
if isinstance(io["request"], BaseModel):
|
|
499
|
+
io["request"] = io["request"].model_dump(
|
|
500
|
+
mode="json",
|
|
501
|
+
exclude_none=True,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
if "response" in io:
|
|
505
|
+
with suppress():
|
|
506
|
+
if isinstance(io["response"], BaseModel):
|
|
507
|
+
io["response"] = io["response"].model_dump(
|
|
508
|
+
mode="json",
|
|
509
|
+
exclude_none=True,
|
|
510
|
+
)
|
|
511
|
+
|
|
467
512
|
return io
|
|
468
513
|
|
|
469
514
|
def _patch(
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async def parse_service_uri(
|
|
5
|
+
uri: str,
|
|
6
|
+
) -> Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]:
|
|
7
|
+
if not uri or not uri.strip():
|
|
8
|
+
return None, None, None, None
|
|
9
|
+
|
|
10
|
+
# uri ~ [<provider>|empty]:<kind>:<key>:[<version>|'latest'|empty]
|
|
11
|
+
|
|
12
|
+
parts = uri.split(":")
|
|
13
|
+
|
|
14
|
+
if len(parts) != 4:
|
|
15
|
+
return None, None, None, None
|
|
16
|
+
|
|
17
|
+
return tuple(parts)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .tracing import Tracing, get_tracer
|