aeri-python 4.0.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.
- aeri/__init__.py +72 -0
- aeri/_client/_validation.py +204 -0
- aeri/_client/attributes.py +188 -0
- aeri/_client/client.py +3761 -0
- aeri/_client/constants.py +65 -0
- aeri/_client/datasets.py +302 -0
- aeri/_client/environment_variables.py +158 -0
- aeri/_client/get_client.py +149 -0
- aeri/_client/observe.py +661 -0
- aeri/_client/propagation.py +475 -0
- aeri/_client/resource_manager.py +510 -0
- aeri/_client/span.py +1519 -0
- aeri/_client/span_filter.py +76 -0
- aeri/_client/span_processor.py +206 -0
- aeri/_client/utils.py +132 -0
- aeri/_task_manager/media_manager.py +331 -0
- aeri/_task_manager/media_upload_consumer.py +44 -0
- aeri/_task_manager/media_upload_queue.py +12 -0
- aeri/_task_manager/score_ingestion_consumer.py +208 -0
- aeri/_task_manager/task_manager.py +475 -0
- aeri/_utils/__init__.py +19 -0
- aeri/_utils/environment.py +34 -0
- aeri/_utils/error_logging.py +47 -0
- aeri/_utils/parse_error.py +99 -0
- aeri/_utils/prompt_cache.py +188 -0
- aeri/_utils/request.py +137 -0
- aeri/_utils/serializer.py +205 -0
- aeri/api/.fern/metadata.json +14 -0
- aeri/api/__init__.py +836 -0
- aeri/api/annotation_queues/__init__.py +82 -0
- aeri/api/annotation_queues/client.py +1111 -0
- aeri/api/annotation_queues/raw_client.py +2288 -0
- aeri/api/annotation_queues/types/__init__.py +84 -0
- aeri/api/annotation_queues/types/annotation_queue.py +28 -0
- aeri/api/annotation_queues/types/annotation_queue_assignment_request.py +16 -0
- aeri/api/annotation_queues/types/annotation_queue_item.py +34 -0
- aeri/api/annotation_queues/types/annotation_queue_object_type.py +26 -0
- aeri/api/annotation_queues/types/annotation_queue_status.py +22 -0
- aeri/api/annotation_queues/types/create_annotation_queue_assignment_response.py +18 -0
- aeri/api/annotation_queues/types/create_annotation_queue_item_request.py +25 -0
- aeri/api/annotation_queues/types/create_annotation_queue_request.py +20 -0
- aeri/api/annotation_queues/types/delete_annotation_queue_assignment_response.py +14 -0
- aeri/api/annotation_queues/types/delete_annotation_queue_item_response.py +15 -0
- aeri/api/annotation_queues/types/paginated_annotation_queue_items.py +17 -0
- aeri/api/annotation_queues/types/paginated_annotation_queues.py +17 -0
- aeri/api/annotation_queues/types/update_annotation_queue_item_request.py +15 -0
- aeri/api/blob_storage_integrations/__init__.py +73 -0
- aeri/api/blob_storage_integrations/client.py +550 -0
- aeri/api/blob_storage_integrations/raw_client.py +976 -0
- aeri/api/blob_storage_integrations/types/__init__.py +77 -0
- aeri/api/blob_storage_integrations/types/blob_storage_export_frequency.py +26 -0
- aeri/api/blob_storage_integrations/types/blob_storage_export_mode.py +26 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +14 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integration_file_type.py +26 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integration_response.py +64 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integration_status_response.py +50 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integration_type.py +26 -0
- aeri/api/blob_storage_integrations/types/blob_storage_integrations_response.py +15 -0
- aeri/api/blob_storage_integrations/types/blob_storage_sync_status.py +47 -0
- aeri/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +91 -0
- aeri/api/client.py +679 -0
- aeri/api/comments/__init__.py +44 -0
- aeri/api/comments/client.py +407 -0
- aeri/api/comments/raw_client.py +750 -0
- aeri/api/comments/types/__init__.py +46 -0
- aeri/api/comments/types/create_comment_request.py +47 -0
- aeri/api/comments/types/create_comment_response.py +17 -0
- aeri/api/comments/types/get_comments_response.py +17 -0
- aeri/api/commons/__init__.py +210 -0
- aeri/api/commons/errors/__init__.py +56 -0
- aeri/api/commons/errors/access_denied_error.py +12 -0
- aeri/api/commons/errors/error.py +12 -0
- aeri/api/commons/errors/method_not_allowed_error.py +12 -0
- aeri/api/commons/errors/not_found_error.py +12 -0
- aeri/api/commons/errors/unauthorized_error.py +12 -0
- aeri/api/commons/types/__init__.py +190 -0
- aeri/api/commons/types/base_score.py +90 -0
- aeri/api/commons/types/base_score_v1.py +70 -0
- aeri/api/commons/types/boolean_score.py +26 -0
- aeri/api/commons/types/boolean_score_v1.py +26 -0
- aeri/api/commons/types/categorical_score.py +26 -0
- aeri/api/commons/types/categorical_score_v1.py +26 -0
- aeri/api/commons/types/comment.py +36 -0
- aeri/api/commons/types/comment_object_type.py +30 -0
- aeri/api/commons/types/config_category.py +15 -0
- aeri/api/commons/types/correction_score.py +26 -0
- aeri/api/commons/types/create_score_value.py +5 -0
- aeri/api/commons/types/dataset.py +49 -0
- aeri/api/commons/types/dataset_item.py +58 -0
- aeri/api/commons/types/dataset_run.py +63 -0
- aeri/api/commons/types/dataset_run_item.py +40 -0
- aeri/api/commons/types/dataset_run_with_items.py +19 -0
- aeri/api/commons/types/dataset_status.py +22 -0
- aeri/api/commons/types/map_value.py +11 -0
- aeri/api/commons/types/model.py +125 -0
- aeri/api/commons/types/model_price.py +14 -0
- aeri/api/commons/types/model_usage_unit.py +42 -0
- aeri/api/commons/types/numeric_score.py +17 -0
- aeri/api/commons/types/numeric_score_v1.py +17 -0
- aeri/api/commons/types/observation.py +142 -0
- aeri/api/commons/types/observation_level.py +30 -0
- aeri/api/commons/types/observation_v2.py +235 -0
- aeri/api/commons/types/observations_view.py +89 -0
- aeri/api/commons/types/pricing_tier.py +91 -0
- aeri/api/commons/types/pricing_tier_condition.py +68 -0
- aeri/api/commons/types/pricing_tier_input.py +76 -0
- aeri/api/commons/types/pricing_tier_operator.py +42 -0
- aeri/api/commons/types/score.py +201 -0
- aeri/api/commons/types/score_config.py +66 -0
- aeri/api/commons/types/score_config_data_type.py +26 -0
- aeri/api/commons/types/score_data_type.py +30 -0
- aeri/api/commons/types/score_source.py +26 -0
- aeri/api/commons/types/score_v1.py +131 -0
- aeri/api/commons/types/session.py +25 -0
- aeri/api/commons/types/session_with_traces.py +15 -0
- aeri/api/commons/types/trace.py +84 -0
- aeri/api/commons/types/trace_with_details.py +43 -0
- aeri/api/commons/types/trace_with_full_details.py +45 -0
- aeri/api/commons/types/usage.py +59 -0
- aeri/api/core/__init__.py +111 -0
- aeri/api/core/api_error.py +23 -0
- aeri/api/core/client_wrapper.py +141 -0
- aeri/api/core/datetime_utils.py +30 -0
- aeri/api/core/enum.py +20 -0
- aeri/api/core/file.py +70 -0
- aeri/api/core/force_multipart.py +18 -0
- aeri/api/core/http_client.py +711 -0
- aeri/api/core/http_response.py +55 -0
- aeri/api/core/http_sse/__init__.py +48 -0
- aeri/api/core/http_sse/_api.py +114 -0
- aeri/api/core/http_sse/_decoders.py +66 -0
- aeri/api/core/http_sse/_exceptions.py +7 -0
- aeri/api/core/http_sse/_models.py +17 -0
- aeri/api/core/jsonable_encoder.py +102 -0
- aeri/api/core/pydantic_utilities.py +310 -0
- aeri/api/core/query_encoder.py +60 -0
- aeri/api/core/remove_none_from_dict.py +11 -0
- aeri/api/core/request_options.py +35 -0
- aeri/api/core/serialization.py +282 -0
- aeri/api/dataset_items/__init__.py +52 -0
- aeri/api/dataset_items/client.py +499 -0
- aeri/api/dataset_items/raw_client.py +973 -0
- aeri/api/dataset_items/types/__init__.py +50 -0
- aeri/api/dataset_items/types/create_dataset_item_request.py +37 -0
- aeri/api/dataset_items/types/delete_dataset_item_response.py +17 -0
- aeri/api/dataset_items/types/paginated_dataset_items.py +17 -0
- aeri/api/dataset_run_items/__init__.py +43 -0
- aeri/api/dataset_run_items/client.py +323 -0
- aeri/api/dataset_run_items/raw_client.py +547 -0
- aeri/api/dataset_run_items/types/__init__.py +44 -0
- aeri/api/dataset_run_items/types/create_dataset_run_item_request.py +51 -0
- aeri/api/dataset_run_items/types/paginated_dataset_run_items.py +17 -0
- aeri/api/datasets/__init__.py +55 -0
- aeri/api/datasets/client.py +661 -0
- aeri/api/datasets/raw_client.py +1368 -0
- aeri/api/datasets/types/__init__.py +53 -0
- aeri/api/datasets/types/create_dataset_request.py +31 -0
- aeri/api/datasets/types/delete_dataset_run_response.py +14 -0
- aeri/api/datasets/types/paginated_dataset_runs.py +17 -0
- aeri/api/datasets/types/paginated_datasets.py +17 -0
- aeri/api/health/__init__.py +44 -0
- aeri/api/health/client.py +112 -0
- aeri/api/health/errors/__init__.py +42 -0
- aeri/api/health/errors/service_unavailable_error.py +13 -0
- aeri/api/health/raw_client.py +227 -0
- aeri/api/health/types/__init__.py +40 -0
- aeri/api/health/types/health_response.py +30 -0
- aeri/api/ingestion/__init__.py +169 -0
- aeri/api/ingestion/client.py +221 -0
- aeri/api/ingestion/raw_client.py +293 -0
- aeri/api/ingestion/types/__init__.py +169 -0
- aeri/api/ingestion/types/base_event.py +27 -0
- aeri/api/ingestion/types/create_event_body.py +14 -0
- aeri/api/ingestion/types/create_event_event.py +15 -0
- aeri/api/ingestion/types/create_generation_body.py +40 -0
- aeri/api/ingestion/types/create_generation_event.py +15 -0
- aeri/api/ingestion/types/create_observation_event.py +15 -0
- aeri/api/ingestion/types/create_span_body.py +19 -0
- aeri/api/ingestion/types/create_span_event.py +15 -0
- aeri/api/ingestion/types/ingestion_error.py +17 -0
- aeri/api/ingestion/types/ingestion_event.py +155 -0
- aeri/api/ingestion/types/ingestion_response.py +17 -0
- aeri/api/ingestion/types/ingestion_success.py +15 -0
- aeri/api/ingestion/types/ingestion_usage.py +8 -0
- aeri/api/ingestion/types/observation_body.py +53 -0
- aeri/api/ingestion/types/observation_type.py +54 -0
- aeri/api/ingestion/types/open_ai_completion_usage_schema.py +26 -0
- aeri/api/ingestion/types/open_ai_response_usage_schema.py +24 -0
- aeri/api/ingestion/types/open_ai_usage.py +28 -0
- aeri/api/ingestion/types/optional_observation_body.py +36 -0
- aeri/api/ingestion/types/score_body.py +75 -0
- aeri/api/ingestion/types/score_event.py +15 -0
- aeri/api/ingestion/types/sdk_log_body.py +14 -0
- aeri/api/ingestion/types/sdk_log_event.py +15 -0
- aeri/api/ingestion/types/trace_body.py +36 -0
- aeri/api/ingestion/types/trace_event.py +15 -0
- aeri/api/ingestion/types/update_event_body.py +14 -0
- aeri/api/ingestion/types/update_generation_body.py +40 -0
- aeri/api/ingestion/types/update_generation_event.py +15 -0
- aeri/api/ingestion/types/update_observation_event.py +15 -0
- aeri/api/ingestion/types/update_span_body.py +19 -0
- aeri/api/ingestion/types/update_span_event.py +15 -0
- aeri/api/ingestion/types/usage_details.py +10 -0
- aeri/api/legacy/__init__.py +61 -0
- aeri/api/legacy/client.py +105 -0
- aeri/api/legacy/metrics_v1/__init__.py +40 -0
- aeri/api/legacy/metrics_v1/client.py +214 -0
- aeri/api/legacy/metrics_v1/raw_client.py +322 -0
- aeri/api/legacy/metrics_v1/types/__init__.py +40 -0
- aeri/api/legacy/metrics_v1/types/metrics_response.py +19 -0
- aeri/api/legacy/observations_v1/__init__.py +43 -0
- aeri/api/legacy/observations_v1/client.py +523 -0
- aeri/api/legacy/observations_v1/raw_client.py +759 -0
- aeri/api/legacy/observations_v1/types/__init__.py +44 -0
- aeri/api/legacy/observations_v1/types/observations.py +17 -0
- aeri/api/legacy/observations_v1/types/observations_views.py +17 -0
- aeri/api/legacy/raw_client.py +13 -0
- aeri/api/legacy/score_v1/__init__.py +43 -0
- aeri/api/legacy/score_v1/client.py +329 -0
- aeri/api/legacy/score_v1/raw_client.py +545 -0
- aeri/api/legacy/score_v1/types/__init__.py +44 -0
- aeri/api/legacy/score_v1/types/create_score_request.py +75 -0
- aeri/api/legacy/score_v1/types/create_score_response.py +17 -0
- aeri/api/llm_connections/__init__.py +55 -0
- aeri/api/llm_connections/client.py +311 -0
- aeri/api/llm_connections/raw_client.py +541 -0
- aeri/api/llm_connections/types/__init__.py +53 -0
- aeri/api/llm_connections/types/llm_adapter.py +38 -0
- aeri/api/llm_connections/types/llm_connection.py +77 -0
- aeri/api/llm_connections/types/paginated_llm_connections.py +17 -0
- aeri/api/llm_connections/types/upsert_llm_connection_request.py +69 -0
- aeri/api/media/__init__.py +58 -0
- aeri/api/media/client.py +427 -0
- aeri/api/media/raw_client.py +739 -0
- aeri/api/media/types/__init__.py +56 -0
- aeri/api/media/types/get_media_response.py +55 -0
- aeri/api/media/types/get_media_upload_url_request.py +51 -0
- aeri/api/media/types/get_media_upload_url_response.py +28 -0
- aeri/api/media/types/media_content_type.py +232 -0
- aeri/api/media/types/patch_media_body.py +43 -0
- aeri/api/metrics/__init__.py +40 -0
- aeri/api/metrics/client.py +422 -0
- aeri/api/metrics/raw_client.py +530 -0
- aeri/api/metrics/types/__init__.py +40 -0
- aeri/api/metrics/types/metrics_v2response.py +19 -0
- aeri/api/models/__init__.py +43 -0
- aeri/api/models/client.py +523 -0
- aeri/api/models/raw_client.py +993 -0
- aeri/api/models/types/__init__.py +44 -0
- aeri/api/models/types/create_model_request.py +103 -0
- aeri/api/models/types/paginated_models.py +17 -0
- aeri/api/observations/__init__.py +43 -0
- aeri/api/observations/client.py +522 -0
- aeri/api/observations/raw_client.py +641 -0
- aeri/api/observations/types/__init__.py +44 -0
- aeri/api/observations/types/observations_v2meta.py +21 -0
- aeri/api/observations/types/observations_v2response.py +28 -0
- aeri/api/opentelemetry/__init__.py +67 -0
- aeri/api/opentelemetry/client.py +276 -0
- aeri/api/opentelemetry/raw_client.py +291 -0
- aeri/api/opentelemetry/types/__init__.py +65 -0
- aeri/api/opentelemetry/types/otel_attribute.py +27 -0
- aeri/api/opentelemetry/types/otel_attribute_value.py +46 -0
- aeri/api/opentelemetry/types/otel_resource.py +24 -0
- aeri/api/opentelemetry/types/otel_resource_span.py +32 -0
- aeri/api/opentelemetry/types/otel_scope.py +34 -0
- aeri/api/opentelemetry/types/otel_scope_span.py +28 -0
- aeri/api/opentelemetry/types/otel_span.py +76 -0
- aeri/api/opentelemetry/types/otel_trace_response.py +16 -0
- aeri/api/organizations/__init__.py +73 -0
- aeri/api/organizations/client.py +756 -0
- aeri/api/organizations/raw_client.py +1707 -0
- aeri/api/organizations/types/__init__.py +71 -0
- aeri/api/organizations/types/delete_membership_request.py +16 -0
- aeri/api/organizations/types/membership_deletion_response.py +17 -0
- aeri/api/organizations/types/membership_request.py +18 -0
- aeri/api/organizations/types/membership_response.py +20 -0
- aeri/api/organizations/types/membership_role.py +30 -0
- aeri/api/organizations/types/memberships_response.py +15 -0
- aeri/api/organizations/types/organization_api_key.py +31 -0
- aeri/api/organizations/types/organization_api_keys_response.py +19 -0
- aeri/api/organizations/types/organization_project.py +25 -0
- aeri/api/organizations/types/organization_projects_response.py +15 -0
- aeri/api/projects/__init__.py +67 -0
- aeri/api/projects/client.py +760 -0
- aeri/api/projects/raw_client.py +1577 -0
- aeri/api/projects/types/__init__.py +65 -0
- aeri/api/projects/types/api_key_deletion_response.py +18 -0
- aeri/api/projects/types/api_key_list.py +23 -0
- aeri/api/projects/types/api_key_response.py +30 -0
- aeri/api/projects/types/api_key_summary.py +35 -0
- aeri/api/projects/types/organization.py +22 -0
- aeri/api/projects/types/project.py +34 -0
- aeri/api/projects/types/project_deletion_response.py +15 -0
- aeri/api/projects/types/projects.py +15 -0
- aeri/api/prompt_version/__init__.py +4 -0
- aeri/api/prompt_version/client.py +157 -0
- aeri/api/prompt_version/raw_client.py +264 -0
- aeri/api/prompts/__init__.py +100 -0
- aeri/api/prompts/client.py +550 -0
- aeri/api/prompts/raw_client.py +987 -0
- aeri/api/prompts/types/__init__.py +96 -0
- aeri/api/prompts/types/base_prompt.py +42 -0
- aeri/api/prompts/types/chat_message.py +17 -0
- aeri/api/prompts/types/chat_message_type.py +15 -0
- aeri/api/prompts/types/chat_message_with_placeholders.py +8 -0
- aeri/api/prompts/types/chat_prompt.py +15 -0
- aeri/api/prompts/types/create_chat_prompt_request.py +37 -0
- aeri/api/prompts/types/create_chat_prompt_type.py +15 -0
- aeri/api/prompts/types/create_prompt_request.py +8 -0
- aeri/api/prompts/types/create_text_prompt_request.py +36 -0
- aeri/api/prompts/types/create_text_prompt_type.py +15 -0
- aeri/api/prompts/types/placeholder_message.py +16 -0
- aeri/api/prompts/types/placeholder_message_type.py +15 -0
- aeri/api/prompts/types/prompt.py +58 -0
- aeri/api/prompts/types/prompt_meta.py +35 -0
- aeri/api/prompts/types/prompt_meta_list_response.py +17 -0
- aeri/api/prompts/types/prompt_type.py +20 -0
- aeri/api/prompts/types/text_prompt.py +14 -0
- aeri/api/scim/__init__.py +94 -0
- aeri/api/scim/client.py +686 -0
- aeri/api/scim/raw_client.py +1528 -0
- aeri/api/scim/types/__init__.py +92 -0
- aeri/api/scim/types/authentication_scheme.py +20 -0
- aeri/api/scim/types/bulk_config.py +22 -0
- aeri/api/scim/types/empty_response.py +16 -0
- aeri/api/scim/types/filter_config.py +17 -0
- aeri/api/scim/types/resource_meta.py +17 -0
- aeri/api/scim/types/resource_type.py +27 -0
- aeri/api/scim/types/resource_types_response.py +21 -0
- aeri/api/scim/types/schema_extension.py +17 -0
- aeri/api/scim/types/schema_resource.py +19 -0
- aeri/api/scim/types/schemas_response.py +21 -0
- aeri/api/scim/types/scim_email.py +16 -0
- aeri/api/scim/types/scim_feature_support.py +14 -0
- aeri/api/scim/types/scim_name.py +14 -0
- aeri/api/scim/types/scim_user.py +24 -0
- aeri/api/scim/types/scim_users_list_response.py +25 -0
- aeri/api/scim/types/service_provider_config.py +36 -0
- aeri/api/scim/types/user_meta.py +20 -0
- aeri/api/score_configs/__init__.py +44 -0
- aeri/api/score_configs/client.py +526 -0
- aeri/api/score_configs/raw_client.py +1012 -0
- aeri/api/score_configs/types/__init__.py +46 -0
- aeri/api/score_configs/types/create_score_config_request.py +46 -0
- aeri/api/score_configs/types/score_configs.py +17 -0
- aeri/api/score_configs/types/update_score_config_request.py +53 -0
- aeri/api/scores/__init__.py +76 -0
- aeri/api/scores/client.py +420 -0
- aeri/api/scores/raw_client.py +656 -0
- aeri/api/scores/types/__init__.py +76 -0
- aeri/api/scores/types/get_scores_response.py +17 -0
- aeri/api/scores/types/get_scores_response_data.py +211 -0
- aeri/api/scores/types/get_scores_response_data_boolean.py +15 -0
- aeri/api/scores/types/get_scores_response_data_categorical.py +15 -0
- aeri/api/scores/types/get_scores_response_data_correction.py +15 -0
- aeri/api/scores/types/get_scores_response_data_numeric.py +15 -0
- aeri/api/scores/types/get_scores_response_trace_data.py +38 -0
- aeri/api/sessions/__init__.py +40 -0
- aeri/api/sessions/client.py +262 -0
- aeri/api/sessions/raw_client.py +500 -0
- aeri/api/sessions/types/__init__.py +40 -0
- aeri/api/sessions/types/paginated_sessions.py +17 -0
- aeri/api/trace/__init__.py +44 -0
- aeri/api/trace/client.py +728 -0
- aeri/api/trace/raw_client.py +1208 -0
- aeri/api/trace/types/__init__.py +46 -0
- aeri/api/trace/types/delete_trace_response.py +14 -0
- aeri/api/trace/types/sort.py +14 -0
- aeri/api/trace/types/traces.py +17 -0
- aeri/api/utils/__init__.py +44 -0
- aeri/api/utils/pagination/__init__.py +40 -0
- aeri/api/utils/pagination/types/__init__.py +40 -0
- aeri/api/utils/pagination/types/meta_response.py +38 -0
- aeri/batch_evaluation.py +1643 -0
- aeri/experiment.py +1044 -0
- aeri/langchain/CallbackHandler.py +1377 -0
- aeri/langchain/__init__.py +5 -0
- aeri/langchain/utils.py +212 -0
- aeri/logger.py +28 -0
- aeri/media.py +352 -0
- aeri/model.py +477 -0
- aeri/openai.py +1124 -0
- aeri/py.typed +0 -0
- aeri/span_filter.py +17 -0
- aeri/types.py +79 -0
- aeri/version.py +3 -0
- aeri_python-4.0.0.dist-info/METADATA +51 -0
- aeri_python-4.0.0.dist-info/RECORD +391 -0
- aeri_python-4.0.0.dist-info/WHEEL +4 -0
- aeri_python-4.0.0.dist-info/licenses/LICENSE +21 -0
aeri/_client/span.py
ADDED
|
@@ -0,0 +1,1519 @@
|
|
|
1
|
+
"""OTEL span wrapper for Aeri.
|
|
2
|
+
|
|
3
|
+
This module defines custom span classes that extend OpenTelemetry spans with
|
|
4
|
+
Aeri-specific functionality. These wrapper classes provide methods for
|
|
5
|
+
creating, updating, and scoring various types of spans used in AI application tracing.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
- AeriObservationWrapper: Abstract base class for all Aeri spans
|
|
9
|
+
- AeriSpan: Implementation for general-purpose spans
|
|
10
|
+
- AeriGeneration: Specialized span implementation for LLM generations
|
|
11
|
+
|
|
12
|
+
All span classes provide methods for media processing, attribute management,
|
|
13
|
+
and scoring integration specific to Aeri's observability platform.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from datetime import datetime
|
|
17
|
+
from time import time_ns
|
|
18
|
+
from typing import (
|
|
19
|
+
TYPE_CHECKING,
|
|
20
|
+
Any,
|
|
21
|
+
Dict,
|
|
22
|
+
Literal,
|
|
23
|
+
Optional,
|
|
24
|
+
Type,
|
|
25
|
+
Union,
|
|
26
|
+
cast,
|
|
27
|
+
overload,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from opentelemetry import trace as otel_trace_api
|
|
31
|
+
from opentelemetry.trace.status import Status, StatusCode
|
|
32
|
+
from opentelemetry.util._decorator import _AgnosticContextManager
|
|
33
|
+
|
|
34
|
+
from aeri.model import PromptClient
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from aeri._client.client import Aeri
|
|
38
|
+
|
|
39
|
+
from typing_extensions import deprecated
|
|
40
|
+
|
|
41
|
+
from aeri._client.attributes import (
|
|
42
|
+
AeriOtelSpanAttributes,
|
|
43
|
+
create_generation_attributes,
|
|
44
|
+
create_span_attributes,
|
|
45
|
+
create_trace_attributes,
|
|
46
|
+
)
|
|
47
|
+
from aeri._client.constants import (
|
|
48
|
+
ObservationTypeGenerationLike,
|
|
49
|
+
ObservationTypeLiteral,
|
|
50
|
+
ObservationTypeLiteralNoEvent,
|
|
51
|
+
ObservationTypeSpanLike,
|
|
52
|
+
get_observation_types_list,
|
|
53
|
+
)
|
|
54
|
+
from aeri.api import MapValue, ScoreDataType
|
|
55
|
+
from aeri.logger import aeri_logger
|
|
56
|
+
from aeri.types import SpanLevel
|
|
57
|
+
|
|
58
|
+
# Factory mapping for observation classes
|
|
59
|
+
# Note: "event" is handled separately due to special instantiation logic
|
|
60
|
+
# Populated after class definitions
|
|
61
|
+
_OBSERVATION_CLASS_MAP: Dict[str, Type["AeriObservationWrapper"]] = {}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class AeriObservationWrapper:
|
|
65
|
+
"""Abstract base class for all Aeri span types.
|
|
66
|
+
|
|
67
|
+
This class provides common functionality for all Aeri span types, including
|
|
68
|
+
media processing, attribute management, and scoring. It wraps an OpenTelemetry
|
|
69
|
+
span and extends it with Aeri-specific features.
|
|
70
|
+
|
|
71
|
+
Attributes:
|
|
72
|
+
_otel_span: The underlying OpenTelemetry span
|
|
73
|
+
_aeri_client: Reference to the parent Aeri client
|
|
74
|
+
trace_id: The trace ID for this span
|
|
75
|
+
observation_id: The observation ID (span ID) for this span
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
*,
|
|
81
|
+
otel_span: otel_trace_api.Span,
|
|
82
|
+
aeri_client: "Aeri",
|
|
83
|
+
as_type: ObservationTypeLiteral,
|
|
84
|
+
input: Optional[Any] = None,
|
|
85
|
+
output: Optional[Any] = None,
|
|
86
|
+
metadata: Optional[Any] = None,
|
|
87
|
+
environment: Optional[str] = None,
|
|
88
|
+
release: Optional[str] = None,
|
|
89
|
+
version: Optional[str] = None,
|
|
90
|
+
level: Optional[SpanLevel] = None,
|
|
91
|
+
status_message: Optional[str] = None,
|
|
92
|
+
completion_start_time: Optional[datetime] = None,
|
|
93
|
+
model: Optional[str] = None,
|
|
94
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
95
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
96
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
97
|
+
prompt: Optional[PromptClient] = None,
|
|
98
|
+
):
|
|
99
|
+
"""Initialize a new Aeri span wrapper.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
otel_span: The OpenTelemetry span to wrap
|
|
103
|
+
aeri_client: Reference to the parent Aeri client
|
|
104
|
+
as_type: The type of span ("span" or "generation")
|
|
105
|
+
input: Input data for the span (any JSON-serializable object)
|
|
106
|
+
output: Output data from the span (any JSON-serializable object)
|
|
107
|
+
metadata: Additional metadata to associate with the span
|
|
108
|
+
environment: The tracing environment
|
|
109
|
+
release: Release identifier for the application
|
|
110
|
+
version: Version identifier for the code or component
|
|
111
|
+
level: Importance level of the span (info, warning, error)
|
|
112
|
+
status_message: Optional status message for the span
|
|
113
|
+
completion_start_time: When the model started generating the response
|
|
114
|
+
model: Name/identifier of the AI model used (e.g., "gpt-4")
|
|
115
|
+
model_parameters: Parameters used for the model (e.g., temperature, max_tokens)
|
|
116
|
+
usage_details: Token usage information (e.g., prompt_tokens, completion_tokens)
|
|
117
|
+
cost_details: Cost information for the model call
|
|
118
|
+
prompt: Associated prompt template from Aeri prompt management
|
|
119
|
+
"""
|
|
120
|
+
self._otel_span = otel_span
|
|
121
|
+
self._otel_span.set_attribute(
|
|
122
|
+
AeriOtelSpanAttributes.OBSERVATION_TYPE, as_type
|
|
123
|
+
)
|
|
124
|
+
self._aeri_client = aeri_client
|
|
125
|
+
self._observation_type = as_type
|
|
126
|
+
|
|
127
|
+
self.trace_id = self._aeri_client._get_otel_trace_id(otel_span)
|
|
128
|
+
self.id = self._aeri_client._get_otel_span_id(otel_span)
|
|
129
|
+
|
|
130
|
+
self._environment = environment or self._aeri_client._environment
|
|
131
|
+
if self._environment is not None:
|
|
132
|
+
self._otel_span.set_attribute(
|
|
133
|
+
AeriOtelSpanAttributes.ENVIRONMENT, self._environment
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
self._release = release or self._aeri_client._release
|
|
137
|
+
if self._release is not None:
|
|
138
|
+
self._otel_span.set_attribute(
|
|
139
|
+
AeriOtelSpanAttributes.RELEASE, self._release
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Handle media only if span is sampled
|
|
143
|
+
if self._otel_span.is_recording():
|
|
144
|
+
media_processed_input = self._process_media_and_apply_mask(
|
|
145
|
+
data=input, field="input", span=self._otel_span
|
|
146
|
+
)
|
|
147
|
+
media_processed_output = self._process_media_and_apply_mask(
|
|
148
|
+
data=output, field="output", span=self._otel_span
|
|
149
|
+
)
|
|
150
|
+
media_processed_metadata = self._process_media_and_apply_mask(
|
|
151
|
+
data=metadata, field="metadata", span=self._otel_span
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
attributes = {}
|
|
155
|
+
|
|
156
|
+
if as_type in get_observation_types_list(ObservationTypeGenerationLike):
|
|
157
|
+
attributes = create_generation_attributes(
|
|
158
|
+
input=media_processed_input,
|
|
159
|
+
output=media_processed_output,
|
|
160
|
+
metadata=media_processed_metadata,
|
|
161
|
+
version=version,
|
|
162
|
+
level=level,
|
|
163
|
+
status_message=status_message,
|
|
164
|
+
completion_start_time=completion_start_time,
|
|
165
|
+
model=model,
|
|
166
|
+
model_parameters=model_parameters,
|
|
167
|
+
usage_details=usage_details,
|
|
168
|
+
cost_details=cost_details,
|
|
169
|
+
prompt=prompt,
|
|
170
|
+
observation_type=cast(
|
|
171
|
+
ObservationTypeGenerationLike,
|
|
172
|
+
as_type,
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
else:
|
|
177
|
+
# For span-like types and events
|
|
178
|
+
attributes = create_span_attributes(
|
|
179
|
+
input=media_processed_input,
|
|
180
|
+
output=media_processed_output,
|
|
181
|
+
metadata=media_processed_metadata,
|
|
182
|
+
version=version,
|
|
183
|
+
level=level,
|
|
184
|
+
status_message=status_message,
|
|
185
|
+
observation_type=cast(
|
|
186
|
+
Optional[Union[ObservationTypeSpanLike, Literal["event"]]],
|
|
187
|
+
as_type
|
|
188
|
+
if as_type
|
|
189
|
+
in get_observation_types_list(ObservationTypeSpanLike)
|
|
190
|
+
or as_type == "event"
|
|
191
|
+
else None,
|
|
192
|
+
),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# We don't want to overwrite the observation type, and already set it
|
|
196
|
+
attributes.pop(AeriOtelSpanAttributes.OBSERVATION_TYPE, None)
|
|
197
|
+
|
|
198
|
+
self._otel_span.set_attributes(
|
|
199
|
+
{k: v for k, v in attributes.items() if v is not None}
|
|
200
|
+
)
|
|
201
|
+
# Set OTEL span status if level is ERROR
|
|
202
|
+
self._set_otel_span_status_if_error(
|
|
203
|
+
level=level, status_message=status_message
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def end(self, *, end_time: Optional[int] = None) -> "AeriObservationWrapper":
|
|
207
|
+
"""End the span, marking it as completed.
|
|
208
|
+
|
|
209
|
+
This method ends the wrapped OpenTelemetry span, marking the end of the
|
|
210
|
+
operation being traced. After this method is called, the span is considered
|
|
211
|
+
complete and can no longer be modified.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
end_time: Optional explicit end time in nanoseconds since epoch
|
|
215
|
+
"""
|
|
216
|
+
self._otel_span.end(end_time=end_time)
|
|
217
|
+
|
|
218
|
+
return self
|
|
219
|
+
|
|
220
|
+
@deprecated(
|
|
221
|
+
"Trace-level input/output is deprecated. "
|
|
222
|
+
"For trace attributes (user_id, session_id, tags, etc.), use propagate_attributes() instead. "
|
|
223
|
+
"This method will be removed in a future major version."
|
|
224
|
+
)
|
|
225
|
+
def set_trace_io(
|
|
226
|
+
self,
|
|
227
|
+
*,
|
|
228
|
+
input: Optional[Any] = None,
|
|
229
|
+
output: Optional[Any] = None,
|
|
230
|
+
) -> "AeriObservationWrapper":
|
|
231
|
+
"""Set trace-level input and output for the trace this span belongs to.
|
|
232
|
+
|
|
233
|
+
.. deprecated::
|
|
234
|
+
This is a legacy method for backward compatibility with Aeri platform
|
|
235
|
+
features that still rely on trace-level input/output (e.g., legacy LLM-as-a-judge
|
|
236
|
+
evaluators). It will be removed in a future major version.
|
|
237
|
+
|
|
238
|
+
For setting other trace attributes (user_id, session_id, metadata, tags, version),
|
|
239
|
+
use :meth:`Aeri.propagate_attributes` instead.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
input: Input data to associate with the trace.
|
|
243
|
+
output: Output data to associate with the trace.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
The span instance for method chaining.
|
|
247
|
+
"""
|
|
248
|
+
if not self._otel_span.is_recording():
|
|
249
|
+
return self
|
|
250
|
+
|
|
251
|
+
media_processed_input = self._process_media_and_apply_mask(
|
|
252
|
+
data=input, field="input", span=self._otel_span
|
|
253
|
+
)
|
|
254
|
+
media_processed_output = self._process_media_and_apply_mask(
|
|
255
|
+
data=output, field="output", span=self._otel_span
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
attributes = create_trace_attributes(
|
|
259
|
+
input=media_processed_input,
|
|
260
|
+
output=media_processed_output,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
self._otel_span.set_attributes(attributes)
|
|
264
|
+
|
|
265
|
+
return self
|
|
266
|
+
|
|
267
|
+
def set_trace_as_public(self) -> "AeriObservationWrapper":
|
|
268
|
+
"""Make this trace publicly accessible via its URL.
|
|
269
|
+
|
|
270
|
+
When a trace is published, anyone with the trace link can view the full trace
|
|
271
|
+
without needing to be logged in to Aeri. This action cannot be undone
|
|
272
|
+
programmatically - once any span in a trace is published, the entire trace
|
|
273
|
+
becomes public.
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
The span instance for method chaining.
|
|
277
|
+
"""
|
|
278
|
+
if not self._otel_span.is_recording():
|
|
279
|
+
return self
|
|
280
|
+
|
|
281
|
+
attributes = create_trace_attributes(public=True)
|
|
282
|
+
|
|
283
|
+
self._otel_span.set_attributes(attributes)
|
|
284
|
+
|
|
285
|
+
return self
|
|
286
|
+
|
|
287
|
+
@overload
|
|
288
|
+
def score(
|
|
289
|
+
self,
|
|
290
|
+
*,
|
|
291
|
+
name: str,
|
|
292
|
+
value: float,
|
|
293
|
+
score_id: Optional[str] = None,
|
|
294
|
+
data_type: Optional[
|
|
295
|
+
Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN]
|
|
296
|
+
] = None,
|
|
297
|
+
comment: Optional[str] = None,
|
|
298
|
+
config_id: Optional[str] = None,
|
|
299
|
+
timestamp: Optional[datetime] = None,
|
|
300
|
+
metadata: Optional[Any] = None,
|
|
301
|
+
) -> None: ...
|
|
302
|
+
|
|
303
|
+
@overload
|
|
304
|
+
def score(
|
|
305
|
+
self,
|
|
306
|
+
*,
|
|
307
|
+
name: str,
|
|
308
|
+
value: str,
|
|
309
|
+
score_id: Optional[str] = None,
|
|
310
|
+
data_type: Optional[
|
|
311
|
+
Literal[ScoreDataType.CATEGORICAL]
|
|
312
|
+
] = ScoreDataType.CATEGORICAL,
|
|
313
|
+
comment: Optional[str] = None,
|
|
314
|
+
config_id: Optional[str] = None,
|
|
315
|
+
timestamp: Optional[datetime] = None,
|
|
316
|
+
metadata: Optional[Any] = None,
|
|
317
|
+
) -> None: ...
|
|
318
|
+
|
|
319
|
+
def score(
|
|
320
|
+
self,
|
|
321
|
+
*,
|
|
322
|
+
name: str,
|
|
323
|
+
value: Union[float, str],
|
|
324
|
+
score_id: Optional[str] = None,
|
|
325
|
+
data_type: Optional[ScoreDataType] = None,
|
|
326
|
+
comment: Optional[str] = None,
|
|
327
|
+
config_id: Optional[str] = None,
|
|
328
|
+
timestamp: Optional[datetime] = None,
|
|
329
|
+
metadata: Optional[Any] = None,
|
|
330
|
+
) -> None:
|
|
331
|
+
"""Create a score for this specific span.
|
|
332
|
+
|
|
333
|
+
This method creates a score associated with this specific span (observation).
|
|
334
|
+
Scores can represent any kind of evaluation, feedback, or quality metric.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
name: Name of the score (e.g., "relevance", "accuracy")
|
|
338
|
+
value: Score value (numeric for NUMERIC/BOOLEAN, string for CATEGORICAL)
|
|
339
|
+
score_id: Optional custom ID for the score (auto-generated if not provided)
|
|
340
|
+
data_type: Type of score (NUMERIC, BOOLEAN, or CATEGORICAL)
|
|
341
|
+
comment: Optional comment or explanation for the score
|
|
342
|
+
config_id: Optional ID of a score config defined in Aeri
|
|
343
|
+
timestamp: Optional timestamp for the score (defaults to current UTC time)
|
|
344
|
+
metadata: Optional metadata to be attached to the score
|
|
345
|
+
|
|
346
|
+
Example:
|
|
347
|
+
```python
|
|
348
|
+
with aeri.start_as_current_observation(name="process-query") as span:
|
|
349
|
+
# Do work
|
|
350
|
+
result = process_data()
|
|
351
|
+
|
|
352
|
+
# Score the span
|
|
353
|
+
span.score(
|
|
354
|
+
name="accuracy",
|
|
355
|
+
value=0.95,
|
|
356
|
+
data_type="NUMERIC",
|
|
357
|
+
comment="High accuracy result"
|
|
358
|
+
)
|
|
359
|
+
```
|
|
360
|
+
"""
|
|
361
|
+
self._aeri_client.create_score(
|
|
362
|
+
name=name,
|
|
363
|
+
value=cast(str, value),
|
|
364
|
+
trace_id=self.trace_id,
|
|
365
|
+
observation_id=self.id,
|
|
366
|
+
score_id=score_id,
|
|
367
|
+
data_type=cast(Literal["CATEGORICAL"], data_type),
|
|
368
|
+
comment=comment,
|
|
369
|
+
config_id=config_id,
|
|
370
|
+
timestamp=timestamp,
|
|
371
|
+
metadata=metadata,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
@overload
|
|
375
|
+
def score_trace(
|
|
376
|
+
self,
|
|
377
|
+
*,
|
|
378
|
+
name: str,
|
|
379
|
+
value: float,
|
|
380
|
+
score_id: Optional[str] = None,
|
|
381
|
+
data_type: Optional[
|
|
382
|
+
Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN]
|
|
383
|
+
] = None,
|
|
384
|
+
comment: Optional[str] = None,
|
|
385
|
+
config_id: Optional[str] = None,
|
|
386
|
+
timestamp: Optional[datetime] = None,
|
|
387
|
+
metadata: Optional[Any] = None,
|
|
388
|
+
) -> None: ...
|
|
389
|
+
|
|
390
|
+
@overload
|
|
391
|
+
def score_trace(
|
|
392
|
+
self,
|
|
393
|
+
*,
|
|
394
|
+
name: str,
|
|
395
|
+
value: str,
|
|
396
|
+
score_id: Optional[str] = None,
|
|
397
|
+
data_type: Optional[
|
|
398
|
+
Literal[ScoreDataType.CATEGORICAL]
|
|
399
|
+
] = ScoreDataType.CATEGORICAL,
|
|
400
|
+
comment: Optional[str] = None,
|
|
401
|
+
config_id: Optional[str] = None,
|
|
402
|
+
timestamp: Optional[datetime] = None,
|
|
403
|
+
metadata: Optional[Any] = None,
|
|
404
|
+
) -> None: ...
|
|
405
|
+
|
|
406
|
+
def score_trace(
|
|
407
|
+
self,
|
|
408
|
+
*,
|
|
409
|
+
name: str,
|
|
410
|
+
value: Union[float, str],
|
|
411
|
+
score_id: Optional[str] = None,
|
|
412
|
+
data_type: Optional[ScoreDataType] = None,
|
|
413
|
+
comment: Optional[str] = None,
|
|
414
|
+
config_id: Optional[str] = None,
|
|
415
|
+
timestamp: Optional[datetime] = None,
|
|
416
|
+
metadata: Optional[Any] = None,
|
|
417
|
+
) -> None:
|
|
418
|
+
"""Create a score for the entire trace that this span belongs to.
|
|
419
|
+
|
|
420
|
+
This method creates a score associated with the entire trace that this span
|
|
421
|
+
belongs to, rather than the specific span. This is useful for overall
|
|
422
|
+
evaluations that apply to the complete trace.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
name: Name of the score (e.g., "user_satisfaction", "overall_quality")
|
|
426
|
+
value: Score value (numeric for NUMERIC/BOOLEAN, string for CATEGORICAL)
|
|
427
|
+
score_id: Optional custom ID for the score (auto-generated if not provided)
|
|
428
|
+
data_type: Type of score (NUMERIC, BOOLEAN, or CATEGORICAL)
|
|
429
|
+
comment: Optional comment or explanation for the score
|
|
430
|
+
config_id: Optional ID of a score config defined in Aeri
|
|
431
|
+
timestamp: Optional timestamp for the score (defaults to current UTC time)
|
|
432
|
+
metadata: Optional metadata to be attached to the score
|
|
433
|
+
|
|
434
|
+
Example:
|
|
435
|
+
```python
|
|
436
|
+
with aeri.start_as_current_observation(name="handle-request") as span:
|
|
437
|
+
# Process the complete request
|
|
438
|
+
result = process_request()
|
|
439
|
+
|
|
440
|
+
# Score the entire trace (not just this span)
|
|
441
|
+
span.score_trace(
|
|
442
|
+
name="overall_quality",
|
|
443
|
+
value=0.9,
|
|
444
|
+
data_type="NUMERIC",
|
|
445
|
+
comment="Good overall experience"
|
|
446
|
+
)
|
|
447
|
+
```
|
|
448
|
+
"""
|
|
449
|
+
self._aeri_client.create_score(
|
|
450
|
+
name=name,
|
|
451
|
+
value=cast(str, value),
|
|
452
|
+
trace_id=self.trace_id,
|
|
453
|
+
score_id=score_id,
|
|
454
|
+
data_type=cast(Literal["CATEGORICAL"], data_type),
|
|
455
|
+
comment=comment,
|
|
456
|
+
config_id=config_id,
|
|
457
|
+
timestamp=timestamp,
|
|
458
|
+
metadata=metadata,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
def _set_processed_span_attributes(
|
|
462
|
+
self,
|
|
463
|
+
*,
|
|
464
|
+
span: otel_trace_api.Span,
|
|
465
|
+
as_type: Optional[ObservationTypeLiteral] = None,
|
|
466
|
+
input: Optional[Any] = None,
|
|
467
|
+
output: Optional[Any] = None,
|
|
468
|
+
metadata: Optional[Any] = None,
|
|
469
|
+
) -> None:
|
|
470
|
+
"""Set span attributes after processing media and applying masks.
|
|
471
|
+
|
|
472
|
+
Internal method that processes media in the input, output, and metadata
|
|
473
|
+
and applies any configured masking before setting them as span attributes.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
span: The OpenTelemetry span to set attributes on
|
|
477
|
+
as_type: The type of span ("span" or "generation")
|
|
478
|
+
input: Input data to process and set
|
|
479
|
+
output: Output data to process and set
|
|
480
|
+
metadata: Metadata to process and set
|
|
481
|
+
"""
|
|
482
|
+
processed_input = self._process_media_and_apply_mask(
|
|
483
|
+
span=span,
|
|
484
|
+
data=input,
|
|
485
|
+
field="input",
|
|
486
|
+
)
|
|
487
|
+
processed_output = self._process_media_and_apply_mask(
|
|
488
|
+
span=span,
|
|
489
|
+
data=output,
|
|
490
|
+
field="output",
|
|
491
|
+
)
|
|
492
|
+
processed_metadata = self._process_media_and_apply_mask(
|
|
493
|
+
span=span,
|
|
494
|
+
data=metadata,
|
|
495
|
+
field="metadata",
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
media_processed_attributes = (
|
|
499
|
+
create_generation_attributes(
|
|
500
|
+
input=processed_input,
|
|
501
|
+
output=processed_output,
|
|
502
|
+
metadata=processed_metadata,
|
|
503
|
+
)
|
|
504
|
+
if as_type == "generation"
|
|
505
|
+
else create_span_attributes(
|
|
506
|
+
input=processed_input,
|
|
507
|
+
output=processed_output,
|
|
508
|
+
metadata=processed_metadata,
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
span.set_attributes(media_processed_attributes)
|
|
513
|
+
|
|
514
|
+
def _process_media_and_apply_mask(
|
|
515
|
+
self,
|
|
516
|
+
*,
|
|
517
|
+
data: Optional[Any] = None,
|
|
518
|
+
span: otel_trace_api.Span,
|
|
519
|
+
field: Union[Literal["input"], Literal["output"], Literal["metadata"]],
|
|
520
|
+
) -> Optional[Any]:
|
|
521
|
+
"""Process media in an attribute and apply masking.
|
|
522
|
+
|
|
523
|
+
Internal method that processes any media content in the data and applies
|
|
524
|
+
the configured masking function to the result.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
data: The data to process
|
|
528
|
+
span: The OpenTelemetry span context
|
|
529
|
+
field: Which field this data represents (input, output, or metadata)
|
|
530
|
+
|
|
531
|
+
Returns:
|
|
532
|
+
The processed and masked data
|
|
533
|
+
"""
|
|
534
|
+
return self._mask_attribute(
|
|
535
|
+
data=self._process_media_in_attribute(data=data, field=field)
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
def _mask_attribute(self, *, data: Any) -> Any:
|
|
539
|
+
"""Apply the configured mask function to data.
|
|
540
|
+
|
|
541
|
+
Internal method that applies the client's configured masking function to
|
|
542
|
+
the provided data, with error handling and fallback.
|
|
543
|
+
|
|
544
|
+
Args:
|
|
545
|
+
data: The data to mask
|
|
546
|
+
|
|
547
|
+
Returns:
|
|
548
|
+
The masked data, or the original data if no mask is configured
|
|
549
|
+
"""
|
|
550
|
+
if not self._aeri_client._mask:
|
|
551
|
+
return data
|
|
552
|
+
|
|
553
|
+
try:
|
|
554
|
+
return self._aeri_client._mask(data=data)
|
|
555
|
+
except Exception as e:
|
|
556
|
+
aeri_logger.error(
|
|
557
|
+
f"Masking error: Custom mask function threw exception when processing data. Using fallback masking. Error: {e}"
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
return "<fully masked due to failed mask function>"
|
|
561
|
+
|
|
562
|
+
def _process_media_in_attribute(
|
|
563
|
+
self,
|
|
564
|
+
*,
|
|
565
|
+
data: Optional[Any] = None,
|
|
566
|
+
field: Union[Literal["input"], Literal["output"], Literal["metadata"]],
|
|
567
|
+
) -> Optional[Any]:
|
|
568
|
+
"""Process any media content in the attribute data.
|
|
569
|
+
|
|
570
|
+
Internal method that identifies and processes any media content in the
|
|
571
|
+
provided data, using the client's media manager.
|
|
572
|
+
|
|
573
|
+
Args:
|
|
574
|
+
data: The data to process for media content
|
|
575
|
+
span: The OpenTelemetry span context
|
|
576
|
+
field: Which field this data represents (input, output, or metadata)
|
|
577
|
+
|
|
578
|
+
Returns:
|
|
579
|
+
The data with any media content processed
|
|
580
|
+
"""
|
|
581
|
+
if self._aeri_client._resources is not None:
|
|
582
|
+
return (
|
|
583
|
+
self._aeri_client._resources._media_manager._find_and_process_media(
|
|
584
|
+
data=data,
|
|
585
|
+
field=field,
|
|
586
|
+
trace_id=self.trace_id,
|
|
587
|
+
observation_id=self.id,
|
|
588
|
+
)
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
return data
|
|
592
|
+
|
|
593
|
+
def _set_otel_span_status_if_error(
|
|
594
|
+
self, *, level: Optional[SpanLevel] = None, status_message: Optional[str] = None
|
|
595
|
+
) -> None:
|
|
596
|
+
"""Set OpenTelemetry span status to ERROR if level is ERROR.
|
|
597
|
+
|
|
598
|
+
This method sets the underlying OpenTelemetry span status to ERROR when the
|
|
599
|
+
Aeri observation level is set to ERROR, ensuring consistency between
|
|
600
|
+
Aeri and OpenTelemetry error states.
|
|
601
|
+
|
|
602
|
+
Args:
|
|
603
|
+
level: The span level to check
|
|
604
|
+
status_message: Optional status message to include as description
|
|
605
|
+
"""
|
|
606
|
+
if level == "ERROR" and self._otel_span.is_recording():
|
|
607
|
+
try:
|
|
608
|
+
self._otel_span.set_status(
|
|
609
|
+
Status(StatusCode.ERROR, description=status_message)
|
|
610
|
+
)
|
|
611
|
+
except Exception:
|
|
612
|
+
# Silently ignore any errors when setting OTEL status to avoid existing flow disruptions
|
|
613
|
+
pass
|
|
614
|
+
|
|
615
|
+
def update(
|
|
616
|
+
self,
|
|
617
|
+
*,
|
|
618
|
+
name: Optional[str] = None,
|
|
619
|
+
input: Optional[Any] = None,
|
|
620
|
+
output: Optional[Any] = None,
|
|
621
|
+
metadata: Optional[Any] = None,
|
|
622
|
+
version: Optional[str] = None,
|
|
623
|
+
level: Optional[SpanLevel] = None,
|
|
624
|
+
status_message: Optional[str] = None,
|
|
625
|
+
completion_start_time: Optional[datetime] = None,
|
|
626
|
+
model: Optional[str] = None,
|
|
627
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
628
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
629
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
630
|
+
prompt: Optional[PromptClient] = None,
|
|
631
|
+
**kwargs: Any,
|
|
632
|
+
) -> "AeriObservationWrapper":
|
|
633
|
+
"""Update this observation with new information.
|
|
634
|
+
|
|
635
|
+
This method updates the observation with new information that becomes available
|
|
636
|
+
during execution, such as outputs, metadata, or status changes.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
name: Observation name
|
|
640
|
+
input: Updated input data for the operation
|
|
641
|
+
output: Output data from the operation
|
|
642
|
+
metadata: Additional metadata to associate with the observation
|
|
643
|
+
version: Version identifier for the code or component
|
|
644
|
+
level: Importance level of the observation (info, warning, error)
|
|
645
|
+
status_message: Optional status message for the observation
|
|
646
|
+
completion_start_time: When the generation started (for generation types)
|
|
647
|
+
model: Model identifier used (for generation types)
|
|
648
|
+
model_parameters: Parameters passed to the model (for generation types)
|
|
649
|
+
usage_details: Token or other usage statistics (for generation types)
|
|
650
|
+
cost_details: Cost breakdown for the operation (for generation types)
|
|
651
|
+
prompt: Reference to the prompt used (for generation types)
|
|
652
|
+
**kwargs: Additional keyword arguments (ignored)
|
|
653
|
+
"""
|
|
654
|
+
if not self._otel_span.is_recording():
|
|
655
|
+
return self
|
|
656
|
+
|
|
657
|
+
processed_input = self._process_media_and_apply_mask(
|
|
658
|
+
data=input, field="input", span=self._otel_span
|
|
659
|
+
)
|
|
660
|
+
processed_output = self._process_media_and_apply_mask(
|
|
661
|
+
data=output, field="output", span=self._otel_span
|
|
662
|
+
)
|
|
663
|
+
processed_metadata = self._process_media_and_apply_mask(
|
|
664
|
+
data=metadata, field="metadata", span=self._otel_span
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
if name:
|
|
668
|
+
self._otel_span.update_name(name)
|
|
669
|
+
|
|
670
|
+
if self._observation_type in get_observation_types_list(
|
|
671
|
+
ObservationTypeGenerationLike
|
|
672
|
+
):
|
|
673
|
+
attributes = create_generation_attributes(
|
|
674
|
+
input=processed_input,
|
|
675
|
+
output=processed_output,
|
|
676
|
+
metadata=processed_metadata,
|
|
677
|
+
version=version,
|
|
678
|
+
level=level,
|
|
679
|
+
status_message=status_message,
|
|
680
|
+
observation_type=cast(
|
|
681
|
+
ObservationTypeGenerationLike,
|
|
682
|
+
self._observation_type,
|
|
683
|
+
),
|
|
684
|
+
completion_start_time=completion_start_time,
|
|
685
|
+
model=model,
|
|
686
|
+
model_parameters=model_parameters,
|
|
687
|
+
usage_details=usage_details,
|
|
688
|
+
cost_details=cost_details,
|
|
689
|
+
prompt=prompt,
|
|
690
|
+
)
|
|
691
|
+
else:
|
|
692
|
+
# For span-like types and events
|
|
693
|
+
attributes = create_span_attributes(
|
|
694
|
+
input=processed_input,
|
|
695
|
+
output=processed_output,
|
|
696
|
+
metadata=processed_metadata,
|
|
697
|
+
version=version,
|
|
698
|
+
level=level,
|
|
699
|
+
status_message=status_message,
|
|
700
|
+
observation_type=cast(
|
|
701
|
+
Optional[Union[ObservationTypeSpanLike, Literal["event"]]],
|
|
702
|
+
self._observation_type
|
|
703
|
+
if self._observation_type
|
|
704
|
+
in get_observation_types_list(ObservationTypeSpanLike)
|
|
705
|
+
or self._observation_type == "event"
|
|
706
|
+
else None,
|
|
707
|
+
),
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
self._otel_span.set_attributes(attributes=attributes)
|
|
711
|
+
# Set OTEL span status if level is ERROR
|
|
712
|
+
self._set_otel_span_status_if_error(level=level, status_message=status_message)
|
|
713
|
+
|
|
714
|
+
return self
|
|
715
|
+
|
|
716
|
+
@overload
|
|
717
|
+
def start_observation(
|
|
718
|
+
self,
|
|
719
|
+
*,
|
|
720
|
+
name: str,
|
|
721
|
+
as_type: Literal["span"],
|
|
722
|
+
input: Optional[Any] = None,
|
|
723
|
+
output: Optional[Any] = None,
|
|
724
|
+
metadata: Optional[Any] = None,
|
|
725
|
+
version: Optional[str] = None,
|
|
726
|
+
level: Optional[SpanLevel] = None,
|
|
727
|
+
status_message: Optional[str] = None,
|
|
728
|
+
) -> "AeriSpan": ...
|
|
729
|
+
|
|
730
|
+
@overload
|
|
731
|
+
def start_observation(
|
|
732
|
+
self,
|
|
733
|
+
*,
|
|
734
|
+
name: str,
|
|
735
|
+
as_type: Literal["generation"],
|
|
736
|
+
input: Optional[Any] = None,
|
|
737
|
+
output: Optional[Any] = None,
|
|
738
|
+
metadata: Optional[Any] = None,
|
|
739
|
+
version: Optional[str] = None,
|
|
740
|
+
level: Optional[SpanLevel] = None,
|
|
741
|
+
status_message: Optional[str] = None,
|
|
742
|
+
completion_start_time: Optional[datetime] = None,
|
|
743
|
+
model: Optional[str] = None,
|
|
744
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
745
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
746
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
747
|
+
prompt: Optional[PromptClient] = None,
|
|
748
|
+
) -> "AeriGeneration": ...
|
|
749
|
+
|
|
750
|
+
@overload
|
|
751
|
+
def start_observation(
|
|
752
|
+
self,
|
|
753
|
+
*,
|
|
754
|
+
name: str,
|
|
755
|
+
as_type: Literal["agent"],
|
|
756
|
+
input: Optional[Any] = None,
|
|
757
|
+
output: Optional[Any] = None,
|
|
758
|
+
metadata: Optional[Any] = None,
|
|
759
|
+
version: Optional[str] = None,
|
|
760
|
+
level: Optional[SpanLevel] = None,
|
|
761
|
+
status_message: Optional[str] = None,
|
|
762
|
+
) -> "AeriAgent": ...
|
|
763
|
+
|
|
764
|
+
@overload
|
|
765
|
+
def start_observation(
|
|
766
|
+
self,
|
|
767
|
+
*,
|
|
768
|
+
name: str,
|
|
769
|
+
as_type: Literal["tool"],
|
|
770
|
+
input: Optional[Any] = None,
|
|
771
|
+
output: Optional[Any] = None,
|
|
772
|
+
metadata: Optional[Any] = None,
|
|
773
|
+
version: Optional[str] = None,
|
|
774
|
+
level: Optional[SpanLevel] = None,
|
|
775
|
+
status_message: Optional[str] = None,
|
|
776
|
+
) -> "AeriTool": ...
|
|
777
|
+
|
|
778
|
+
@overload
|
|
779
|
+
def start_observation(
|
|
780
|
+
self,
|
|
781
|
+
*,
|
|
782
|
+
name: str,
|
|
783
|
+
as_type: Literal["chain"],
|
|
784
|
+
input: Optional[Any] = None,
|
|
785
|
+
output: Optional[Any] = None,
|
|
786
|
+
metadata: Optional[Any] = None,
|
|
787
|
+
version: Optional[str] = None,
|
|
788
|
+
level: Optional[SpanLevel] = None,
|
|
789
|
+
status_message: Optional[str] = None,
|
|
790
|
+
) -> "AeriChain": ...
|
|
791
|
+
|
|
792
|
+
@overload
|
|
793
|
+
def start_observation(
|
|
794
|
+
self,
|
|
795
|
+
*,
|
|
796
|
+
name: str,
|
|
797
|
+
as_type: Literal["retriever"],
|
|
798
|
+
input: Optional[Any] = None,
|
|
799
|
+
output: Optional[Any] = None,
|
|
800
|
+
metadata: Optional[Any] = None,
|
|
801
|
+
version: Optional[str] = None,
|
|
802
|
+
level: Optional[SpanLevel] = None,
|
|
803
|
+
status_message: Optional[str] = None,
|
|
804
|
+
) -> "AeriRetriever": ...
|
|
805
|
+
|
|
806
|
+
@overload
|
|
807
|
+
def start_observation(
|
|
808
|
+
self,
|
|
809
|
+
*,
|
|
810
|
+
name: str,
|
|
811
|
+
as_type: Literal["evaluator"],
|
|
812
|
+
input: Optional[Any] = None,
|
|
813
|
+
output: Optional[Any] = None,
|
|
814
|
+
metadata: Optional[Any] = None,
|
|
815
|
+
version: Optional[str] = None,
|
|
816
|
+
level: Optional[SpanLevel] = None,
|
|
817
|
+
status_message: Optional[str] = None,
|
|
818
|
+
) -> "AeriEvaluator": ...
|
|
819
|
+
|
|
820
|
+
@overload
|
|
821
|
+
def start_observation(
|
|
822
|
+
self,
|
|
823
|
+
*,
|
|
824
|
+
name: str,
|
|
825
|
+
as_type: Literal["embedding"],
|
|
826
|
+
input: Optional[Any] = None,
|
|
827
|
+
output: Optional[Any] = None,
|
|
828
|
+
metadata: Optional[Any] = None,
|
|
829
|
+
version: Optional[str] = None,
|
|
830
|
+
level: Optional[SpanLevel] = None,
|
|
831
|
+
status_message: Optional[str] = None,
|
|
832
|
+
completion_start_time: Optional[datetime] = None,
|
|
833
|
+
model: Optional[str] = None,
|
|
834
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
835
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
836
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
837
|
+
prompt: Optional[PromptClient] = None,
|
|
838
|
+
) -> "AeriEmbedding": ...
|
|
839
|
+
|
|
840
|
+
@overload
|
|
841
|
+
def start_observation(
|
|
842
|
+
self,
|
|
843
|
+
*,
|
|
844
|
+
name: str,
|
|
845
|
+
as_type: Literal["guardrail"],
|
|
846
|
+
input: Optional[Any] = None,
|
|
847
|
+
output: Optional[Any] = None,
|
|
848
|
+
metadata: Optional[Any] = None,
|
|
849
|
+
version: Optional[str] = None,
|
|
850
|
+
level: Optional[SpanLevel] = None,
|
|
851
|
+
status_message: Optional[str] = None,
|
|
852
|
+
) -> "AeriGuardrail": ...
|
|
853
|
+
|
|
854
|
+
@overload
|
|
855
|
+
def start_observation(
|
|
856
|
+
self,
|
|
857
|
+
*,
|
|
858
|
+
name: str,
|
|
859
|
+
as_type: Literal["event"],
|
|
860
|
+
input: Optional[Any] = None,
|
|
861
|
+
output: Optional[Any] = None,
|
|
862
|
+
metadata: Optional[Any] = None,
|
|
863
|
+
version: Optional[str] = None,
|
|
864
|
+
level: Optional[SpanLevel] = None,
|
|
865
|
+
status_message: Optional[str] = None,
|
|
866
|
+
) -> "AeriEvent": ...
|
|
867
|
+
|
|
868
|
+
def start_observation(
|
|
869
|
+
self,
|
|
870
|
+
*,
|
|
871
|
+
name: str,
|
|
872
|
+
as_type: ObservationTypeLiteral = "span",
|
|
873
|
+
input: Optional[Any] = None,
|
|
874
|
+
output: Optional[Any] = None,
|
|
875
|
+
metadata: Optional[Any] = None,
|
|
876
|
+
version: Optional[str] = None,
|
|
877
|
+
level: Optional[SpanLevel] = None,
|
|
878
|
+
status_message: Optional[str] = None,
|
|
879
|
+
completion_start_time: Optional[datetime] = None,
|
|
880
|
+
model: Optional[str] = None,
|
|
881
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
882
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
883
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
884
|
+
prompt: Optional[PromptClient] = None,
|
|
885
|
+
) -> Union[
|
|
886
|
+
"AeriSpan",
|
|
887
|
+
"AeriGeneration",
|
|
888
|
+
"AeriAgent",
|
|
889
|
+
"AeriTool",
|
|
890
|
+
"AeriChain",
|
|
891
|
+
"AeriRetriever",
|
|
892
|
+
"AeriEvaluator",
|
|
893
|
+
"AeriEmbedding",
|
|
894
|
+
"AeriGuardrail",
|
|
895
|
+
"AeriEvent",
|
|
896
|
+
]:
|
|
897
|
+
"""Create a new child observation of the specified type.
|
|
898
|
+
|
|
899
|
+
This is the generic method for creating any type of child observation.
|
|
900
|
+
Unlike start_as_current_observation(), this method does not set the new
|
|
901
|
+
observation as the current observation in the context.
|
|
902
|
+
|
|
903
|
+
Args:
|
|
904
|
+
name: Name of the observation
|
|
905
|
+
as_type: Type of observation to create
|
|
906
|
+
input: Input data for the operation
|
|
907
|
+
output: Output data from the operation
|
|
908
|
+
metadata: Additional metadata to associate with the observation
|
|
909
|
+
version: Version identifier for the code or component
|
|
910
|
+
level: Importance level of the observation (info, warning, error)
|
|
911
|
+
status_message: Optional status message for the observation
|
|
912
|
+
completion_start_time: When the model started generating (for generation types)
|
|
913
|
+
model: Name/identifier of the AI model used (for generation types)
|
|
914
|
+
model_parameters: Parameters used for the model (for generation types)
|
|
915
|
+
usage_details: Token usage information (for generation types)
|
|
916
|
+
cost_details: Cost information (for generation types)
|
|
917
|
+
prompt: Associated prompt template (for generation types)
|
|
918
|
+
|
|
919
|
+
Returns:
|
|
920
|
+
A new observation of the specified type that must be ended with .end()
|
|
921
|
+
"""
|
|
922
|
+
if as_type == "event":
|
|
923
|
+
timestamp = time_ns()
|
|
924
|
+
event_span = self._aeri_client._otel_tracer.start_span(
|
|
925
|
+
name=name, start_time=timestamp
|
|
926
|
+
)
|
|
927
|
+
return cast(
|
|
928
|
+
AeriEvent,
|
|
929
|
+
AeriEvent(
|
|
930
|
+
otel_span=event_span,
|
|
931
|
+
aeri_client=self._aeri_client,
|
|
932
|
+
input=input,
|
|
933
|
+
output=output,
|
|
934
|
+
metadata=metadata,
|
|
935
|
+
environment=self._environment,
|
|
936
|
+
release=self._release,
|
|
937
|
+
version=version,
|
|
938
|
+
level=level,
|
|
939
|
+
status_message=status_message,
|
|
940
|
+
).end(end_time=timestamp),
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
observation_class = _OBSERVATION_CLASS_MAP.get(as_type)
|
|
944
|
+
if not observation_class:
|
|
945
|
+
aeri_logger.warning(
|
|
946
|
+
f"Unknown observation type: {as_type}, falling back to AeriSpan"
|
|
947
|
+
)
|
|
948
|
+
observation_class = AeriSpan
|
|
949
|
+
|
|
950
|
+
with otel_trace_api.use_span(self._otel_span):
|
|
951
|
+
new_otel_span = self._aeri_client._otel_tracer.start_span(name=name)
|
|
952
|
+
|
|
953
|
+
common_args = {
|
|
954
|
+
"otel_span": new_otel_span,
|
|
955
|
+
"aeri_client": self._aeri_client,
|
|
956
|
+
"environment": self._environment,
|
|
957
|
+
"release": self._release,
|
|
958
|
+
"input": input,
|
|
959
|
+
"output": output,
|
|
960
|
+
"metadata": metadata,
|
|
961
|
+
"version": version,
|
|
962
|
+
"level": level,
|
|
963
|
+
"status_message": status_message,
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if as_type in get_observation_types_list(ObservationTypeGenerationLike):
|
|
967
|
+
common_args.update(
|
|
968
|
+
{
|
|
969
|
+
"completion_start_time": completion_start_time,
|
|
970
|
+
"model": model,
|
|
971
|
+
"model_parameters": model_parameters,
|
|
972
|
+
"usage_details": usage_details,
|
|
973
|
+
"cost_details": cost_details,
|
|
974
|
+
"prompt": prompt,
|
|
975
|
+
}
|
|
976
|
+
)
|
|
977
|
+
|
|
978
|
+
return observation_class(**common_args) # type: ignore[no-any-return,return-value,arg-type]
|
|
979
|
+
|
|
980
|
+
@overload
|
|
981
|
+
def start_as_current_observation(
|
|
982
|
+
self,
|
|
983
|
+
*,
|
|
984
|
+
name: str,
|
|
985
|
+
as_type: Literal["span"],
|
|
986
|
+
input: Optional[Any] = None,
|
|
987
|
+
output: Optional[Any] = None,
|
|
988
|
+
metadata: Optional[Any] = None,
|
|
989
|
+
version: Optional[str] = None,
|
|
990
|
+
level: Optional[SpanLevel] = None,
|
|
991
|
+
status_message: Optional[str] = None,
|
|
992
|
+
) -> _AgnosticContextManager["AeriSpan"]: ...
|
|
993
|
+
|
|
994
|
+
@overload
|
|
995
|
+
def start_as_current_observation(
|
|
996
|
+
self,
|
|
997
|
+
*,
|
|
998
|
+
name: str,
|
|
999
|
+
as_type: Literal["generation"],
|
|
1000
|
+
input: Optional[Any] = None,
|
|
1001
|
+
output: Optional[Any] = None,
|
|
1002
|
+
metadata: Optional[Any] = None,
|
|
1003
|
+
version: Optional[str] = None,
|
|
1004
|
+
level: Optional[SpanLevel] = None,
|
|
1005
|
+
status_message: Optional[str] = None,
|
|
1006
|
+
completion_start_time: Optional[datetime] = None,
|
|
1007
|
+
model: Optional[str] = None,
|
|
1008
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
1009
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
1010
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
1011
|
+
prompt: Optional[PromptClient] = None,
|
|
1012
|
+
) -> _AgnosticContextManager["AeriGeneration"]: ...
|
|
1013
|
+
|
|
1014
|
+
@overload
|
|
1015
|
+
def start_as_current_observation(
|
|
1016
|
+
self,
|
|
1017
|
+
*,
|
|
1018
|
+
name: str,
|
|
1019
|
+
as_type: Literal["embedding"],
|
|
1020
|
+
input: Optional[Any] = None,
|
|
1021
|
+
output: Optional[Any] = None,
|
|
1022
|
+
metadata: Optional[Any] = None,
|
|
1023
|
+
version: Optional[str] = None,
|
|
1024
|
+
level: Optional[SpanLevel] = None,
|
|
1025
|
+
status_message: Optional[str] = None,
|
|
1026
|
+
completion_start_time: Optional[datetime] = None,
|
|
1027
|
+
model: Optional[str] = None,
|
|
1028
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
1029
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
1030
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
1031
|
+
prompt: Optional[PromptClient] = None,
|
|
1032
|
+
) -> _AgnosticContextManager["AeriEmbedding"]: ...
|
|
1033
|
+
|
|
1034
|
+
@overload
|
|
1035
|
+
def start_as_current_observation(
|
|
1036
|
+
self,
|
|
1037
|
+
*,
|
|
1038
|
+
name: str,
|
|
1039
|
+
as_type: Literal["agent"],
|
|
1040
|
+
input: Optional[Any] = None,
|
|
1041
|
+
output: Optional[Any] = None,
|
|
1042
|
+
metadata: Optional[Any] = None,
|
|
1043
|
+
version: Optional[str] = None,
|
|
1044
|
+
level: Optional[SpanLevel] = None,
|
|
1045
|
+
status_message: Optional[str] = None,
|
|
1046
|
+
) -> _AgnosticContextManager["AeriAgent"]: ...
|
|
1047
|
+
|
|
1048
|
+
@overload
|
|
1049
|
+
def start_as_current_observation(
|
|
1050
|
+
self,
|
|
1051
|
+
*,
|
|
1052
|
+
name: str,
|
|
1053
|
+
as_type: Literal["tool"],
|
|
1054
|
+
input: Optional[Any] = None,
|
|
1055
|
+
output: Optional[Any] = None,
|
|
1056
|
+
metadata: Optional[Any] = None,
|
|
1057
|
+
version: Optional[str] = None,
|
|
1058
|
+
level: Optional[SpanLevel] = None,
|
|
1059
|
+
status_message: Optional[str] = None,
|
|
1060
|
+
) -> _AgnosticContextManager["AeriTool"]: ...
|
|
1061
|
+
|
|
1062
|
+
@overload
|
|
1063
|
+
def start_as_current_observation(
|
|
1064
|
+
self,
|
|
1065
|
+
*,
|
|
1066
|
+
name: str,
|
|
1067
|
+
as_type: Literal["chain"],
|
|
1068
|
+
input: Optional[Any] = None,
|
|
1069
|
+
output: Optional[Any] = None,
|
|
1070
|
+
metadata: Optional[Any] = None,
|
|
1071
|
+
version: Optional[str] = None,
|
|
1072
|
+
level: Optional[SpanLevel] = None,
|
|
1073
|
+
status_message: Optional[str] = None,
|
|
1074
|
+
) -> _AgnosticContextManager["AeriChain"]: ...
|
|
1075
|
+
|
|
1076
|
+
@overload
|
|
1077
|
+
def start_as_current_observation(
|
|
1078
|
+
self,
|
|
1079
|
+
*,
|
|
1080
|
+
name: str,
|
|
1081
|
+
as_type: Literal["retriever"],
|
|
1082
|
+
input: Optional[Any] = None,
|
|
1083
|
+
output: Optional[Any] = None,
|
|
1084
|
+
metadata: Optional[Any] = None,
|
|
1085
|
+
version: Optional[str] = None,
|
|
1086
|
+
level: Optional[SpanLevel] = None,
|
|
1087
|
+
status_message: Optional[str] = None,
|
|
1088
|
+
) -> _AgnosticContextManager["AeriRetriever"]: ...
|
|
1089
|
+
|
|
1090
|
+
@overload
|
|
1091
|
+
def start_as_current_observation(
|
|
1092
|
+
self,
|
|
1093
|
+
*,
|
|
1094
|
+
name: str,
|
|
1095
|
+
as_type: Literal["evaluator"],
|
|
1096
|
+
input: Optional[Any] = None,
|
|
1097
|
+
output: Optional[Any] = None,
|
|
1098
|
+
metadata: Optional[Any] = None,
|
|
1099
|
+
version: Optional[str] = None,
|
|
1100
|
+
level: Optional[SpanLevel] = None,
|
|
1101
|
+
status_message: Optional[str] = None,
|
|
1102
|
+
) -> _AgnosticContextManager["AeriEvaluator"]: ...
|
|
1103
|
+
|
|
1104
|
+
@overload
|
|
1105
|
+
def start_as_current_observation(
|
|
1106
|
+
self,
|
|
1107
|
+
*,
|
|
1108
|
+
name: str,
|
|
1109
|
+
as_type: Literal["guardrail"],
|
|
1110
|
+
input: Optional[Any] = None,
|
|
1111
|
+
output: Optional[Any] = None,
|
|
1112
|
+
metadata: Optional[Any] = None,
|
|
1113
|
+
version: Optional[str] = None,
|
|
1114
|
+
level: Optional[SpanLevel] = None,
|
|
1115
|
+
status_message: Optional[str] = None,
|
|
1116
|
+
) -> _AgnosticContextManager["AeriGuardrail"]: ...
|
|
1117
|
+
|
|
1118
|
+
def start_as_current_observation( # type: ignore[misc]
|
|
1119
|
+
self,
|
|
1120
|
+
*,
|
|
1121
|
+
name: str,
|
|
1122
|
+
as_type: ObservationTypeLiteralNoEvent = "span",
|
|
1123
|
+
input: Optional[Any] = None,
|
|
1124
|
+
output: Optional[Any] = None,
|
|
1125
|
+
metadata: Optional[Any] = None,
|
|
1126
|
+
version: Optional[str] = None,
|
|
1127
|
+
level: Optional[SpanLevel] = None,
|
|
1128
|
+
status_message: Optional[str] = None,
|
|
1129
|
+
completion_start_time: Optional[datetime] = None,
|
|
1130
|
+
model: Optional[str] = None,
|
|
1131
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
1132
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
1133
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
1134
|
+
prompt: Optional[PromptClient] = None,
|
|
1135
|
+
# TODO: or union of context managers?
|
|
1136
|
+
) -> _AgnosticContextManager[
|
|
1137
|
+
Union[
|
|
1138
|
+
"AeriSpan",
|
|
1139
|
+
"AeriGeneration",
|
|
1140
|
+
"AeriAgent",
|
|
1141
|
+
"AeriTool",
|
|
1142
|
+
"AeriChain",
|
|
1143
|
+
"AeriRetriever",
|
|
1144
|
+
"AeriEvaluator",
|
|
1145
|
+
"AeriEmbedding",
|
|
1146
|
+
"AeriGuardrail",
|
|
1147
|
+
]
|
|
1148
|
+
]:
|
|
1149
|
+
"""Create a new child observation and set it as the current observation in a context manager.
|
|
1150
|
+
|
|
1151
|
+
This is the generic method for creating any type of child observation with
|
|
1152
|
+
context management. It delegates to the client's _create_span_with_parent_context method.
|
|
1153
|
+
|
|
1154
|
+
Args:
|
|
1155
|
+
name: Name of the observation
|
|
1156
|
+
as_type: Type of observation to create
|
|
1157
|
+
input: Input data for the operation
|
|
1158
|
+
output: Output data from the operation
|
|
1159
|
+
metadata: Additional metadata to associate with the observation
|
|
1160
|
+
version: Version identifier for the code or component
|
|
1161
|
+
level: Importance level of the observation (info, warning, error)
|
|
1162
|
+
status_message: Optional status message for the observation
|
|
1163
|
+
completion_start_time: When the model started generating (for generation types)
|
|
1164
|
+
model: Name/identifier of the AI model used (for generation types)
|
|
1165
|
+
model_parameters: Parameters used for the model (for generation types)
|
|
1166
|
+
usage_details: Token usage information (for generation types)
|
|
1167
|
+
cost_details: Cost information (for generation types)
|
|
1168
|
+
prompt: Associated prompt template (for generation types)
|
|
1169
|
+
|
|
1170
|
+
Returns:
|
|
1171
|
+
A context manager that yields a new observation of the specified type
|
|
1172
|
+
"""
|
|
1173
|
+
return self._aeri_client._create_span_with_parent_context(
|
|
1174
|
+
name=name,
|
|
1175
|
+
as_type=as_type,
|
|
1176
|
+
remote_parent_span=None,
|
|
1177
|
+
parent=self._otel_span,
|
|
1178
|
+
input=input,
|
|
1179
|
+
output=output,
|
|
1180
|
+
metadata=metadata,
|
|
1181
|
+
version=version,
|
|
1182
|
+
level=level,
|
|
1183
|
+
status_message=status_message,
|
|
1184
|
+
completion_start_time=completion_start_time,
|
|
1185
|
+
model=model,
|
|
1186
|
+
model_parameters=model_parameters,
|
|
1187
|
+
usage_details=usage_details,
|
|
1188
|
+
cost_details=cost_details,
|
|
1189
|
+
prompt=prompt,
|
|
1190
|
+
)
|
|
1191
|
+
|
|
1192
|
+
def create_event(
|
|
1193
|
+
self,
|
|
1194
|
+
*,
|
|
1195
|
+
name: str,
|
|
1196
|
+
input: Optional[Any] = None,
|
|
1197
|
+
output: Optional[Any] = None,
|
|
1198
|
+
metadata: Optional[Any] = None,
|
|
1199
|
+
version: Optional[str] = None,
|
|
1200
|
+
level: Optional[SpanLevel] = None,
|
|
1201
|
+
status_message: Optional[str] = None,
|
|
1202
|
+
) -> "AeriEvent":
|
|
1203
|
+
"""Create a new Aeri observation of type 'EVENT'.
|
|
1204
|
+
|
|
1205
|
+
Args:
|
|
1206
|
+
name: Name of the span (e.g., function or operation name)
|
|
1207
|
+
input: Input data for the operation (can be any JSON-serializable object)
|
|
1208
|
+
output: Output data from the operation (can be any JSON-serializable object)
|
|
1209
|
+
metadata: Additional metadata to associate with the span
|
|
1210
|
+
version: Version identifier for the code or component
|
|
1211
|
+
level: Importance level of the span (info, warning, error)
|
|
1212
|
+
status_message: Optional status message for the span
|
|
1213
|
+
|
|
1214
|
+
Returns:
|
|
1215
|
+
The AeriEvent object
|
|
1216
|
+
|
|
1217
|
+
Example:
|
|
1218
|
+
```python
|
|
1219
|
+
event = aeri.create_event(name="process-event")
|
|
1220
|
+
```
|
|
1221
|
+
"""
|
|
1222
|
+
timestamp = time_ns()
|
|
1223
|
+
|
|
1224
|
+
with otel_trace_api.use_span(self._otel_span):
|
|
1225
|
+
new_otel_span = self._aeri_client._otel_tracer.start_span(
|
|
1226
|
+
name=name, start_time=timestamp
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1229
|
+
return cast(
|
|
1230
|
+
"AeriEvent",
|
|
1231
|
+
AeriEvent(
|
|
1232
|
+
otel_span=new_otel_span,
|
|
1233
|
+
aeri_client=self._aeri_client,
|
|
1234
|
+
input=input,
|
|
1235
|
+
output=output,
|
|
1236
|
+
metadata=metadata,
|
|
1237
|
+
environment=self._environment,
|
|
1238
|
+
release=self._release,
|
|
1239
|
+
version=version,
|
|
1240
|
+
level=level,
|
|
1241
|
+
status_message=status_message,
|
|
1242
|
+
).end(end_time=timestamp),
|
|
1243
|
+
)
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
class AeriSpan(AeriObservationWrapper):
|
|
1247
|
+
"""Standard span implementation for general operations in Aeri.
|
|
1248
|
+
|
|
1249
|
+
This class represents a general-purpose span that can be used to trace
|
|
1250
|
+
any operation in your application. It extends the base AeriObservationWrapper
|
|
1251
|
+
with specific methods for creating child spans, generations, and updating
|
|
1252
|
+
span-specific attributes. If possible, use a more specific type for
|
|
1253
|
+
better observability and insights.
|
|
1254
|
+
"""
|
|
1255
|
+
|
|
1256
|
+
def __init__(
|
|
1257
|
+
self,
|
|
1258
|
+
*,
|
|
1259
|
+
otel_span: otel_trace_api.Span,
|
|
1260
|
+
aeri_client: "Aeri",
|
|
1261
|
+
input: Optional[Any] = None,
|
|
1262
|
+
output: Optional[Any] = None,
|
|
1263
|
+
metadata: Optional[Any] = None,
|
|
1264
|
+
environment: Optional[str] = None,
|
|
1265
|
+
release: Optional[str] = None,
|
|
1266
|
+
version: Optional[str] = None,
|
|
1267
|
+
level: Optional[SpanLevel] = None,
|
|
1268
|
+
status_message: Optional[str] = None,
|
|
1269
|
+
):
|
|
1270
|
+
"""Initialize a new AeriSpan.
|
|
1271
|
+
|
|
1272
|
+
Args:
|
|
1273
|
+
otel_span: The OpenTelemetry span to wrap
|
|
1274
|
+
aeri_client: Reference to the parent Aeri client
|
|
1275
|
+
input: Input data for the span (any JSON-serializable object)
|
|
1276
|
+
output: Output data from the span (any JSON-serializable object)
|
|
1277
|
+
metadata: Additional metadata to associate with the span
|
|
1278
|
+
environment: The tracing environment
|
|
1279
|
+
release: Release identifier for the application
|
|
1280
|
+
version: Version identifier for the code or component
|
|
1281
|
+
level: Importance level of the span (info, warning, error)
|
|
1282
|
+
status_message: Optional status message for the span
|
|
1283
|
+
"""
|
|
1284
|
+
super().__init__(
|
|
1285
|
+
otel_span=otel_span,
|
|
1286
|
+
as_type="span",
|
|
1287
|
+
aeri_client=aeri_client,
|
|
1288
|
+
input=input,
|
|
1289
|
+
output=output,
|
|
1290
|
+
metadata=metadata,
|
|
1291
|
+
environment=environment,
|
|
1292
|
+
release=release,
|
|
1293
|
+
version=version,
|
|
1294
|
+
level=level,
|
|
1295
|
+
status_message=status_message,
|
|
1296
|
+
)
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
class AeriGeneration(AeriObservationWrapper):
|
|
1300
|
+
"""Specialized span implementation for AI model generations in Aeri.
|
|
1301
|
+
|
|
1302
|
+
This class represents a generation span specifically designed for tracking
|
|
1303
|
+
AI/LLM operations. It extends the base AeriObservationWrapper with specialized
|
|
1304
|
+
attributes for model details, token usage, and costs.
|
|
1305
|
+
"""
|
|
1306
|
+
|
|
1307
|
+
def __init__(
|
|
1308
|
+
self,
|
|
1309
|
+
*,
|
|
1310
|
+
otel_span: otel_trace_api.Span,
|
|
1311
|
+
aeri_client: "Aeri",
|
|
1312
|
+
input: Optional[Any] = None,
|
|
1313
|
+
output: Optional[Any] = None,
|
|
1314
|
+
metadata: Optional[Any] = None,
|
|
1315
|
+
environment: Optional[str] = None,
|
|
1316
|
+
release: Optional[str] = None,
|
|
1317
|
+
version: Optional[str] = None,
|
|
1318
|
+
level: Optional[SpanLevel] = None,
|
|
1319
|
+
status_message: Optional[str] = None,
|
|
1320
|
+
completion_start_time: Optional[datetime] = None,
|
|
1321
|
+
model: Optional[str] = None,
|
|
1322
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
1323
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
1324
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
1325
|
+
prompt: Optional[PromptClient] = None,
|
|
1326
|
+
):
|
|
1327
|
+
"""Initialize a new AeriGeneration span.
|
|
1328
|
+
|
|
1329
|
+
Args:
|
|
1330
|
+
otel_span: The OpenTelemetry span to wrap
|
|
1331
|
+
aeri_client: Reference to the parent Aeri client
|
|
1332
|
+
input: Input data for the generation (e.g., prompts)
|
|
1333
|
+
output: Output from the generation (e.g., completions)
|
|
1334
|
+
metadata: Additional metadata to associate with the generation
|
|
1335
|
+
environment: The tracing environment
|
|
1336
|
+
release: Release identifier for the application
|
|
1337
|
+
version: Version identifier for the model or component
|
|
1338
|
+
level: Importance level of the generation (info, warning, error)
|
|
1339
|
+
status_message: Optional status message for the generation
|
|
1340
|
+
completion_start_time: When the model started generating the response
|
|
1341
|
+
model: Name/identifier of the AI model used (e.g., "gpt-4")
|
|
1342
|
+
model_parameters: Parameters used for the model (e.g., temperature, max_tokens)
|
|
1343
|
+
usage_details: Token usage information (e.g., prompt_tokens, completion_tokens)
|
|
1344
|
+
cost_details: Cost information for the model call
|
|
1345
|
+
prompt: Associated prompt template from Aeri prompt management
|
|
1346
|
+
"""
|
|
1347
|
+
super().__init__(
|
|
1348
|
+
as_type="generation",
|
|
1349
|
+
otel_span=otel_span,
|
|
1350
|
+
aeri_client=aeri_client,
|
|
1351
|
+
input=input,
|
|
1352
|
+
output=output,
|
|
1353
|
+
metadata=metadata,
|
|
1354
|
+
environment=environment,
|
|
1355
|
+
release=release,
|
|
1356
|
+
version=version,
|
|
1357
|
+
level=level,
|
|
1358
|
+
status_message=status_message,
|
|
1359
|
+
completion_start_time=completion_start_time,
|
|
1360
|
+
model=model,
|
|
1361
|
+
model_parameters=model_parameters,
|
|
1362
|
+
usage_details=usage_details,
|
|
1363
|
+
cost_details=cost_details,
|
|
1364
|
+
prompt=prompt,
|
|
1365
|
+
)
|
|
1366
|
+
|
|
1367
|
+
|
|
1368
|
+
class AeriEvent(AeriObservationWrapper):
|
|
1369
|
+
"""Specialized span implementation for Aeri Events."""
|
|
1370
|
+
|
|
1371
|
+
def __init__(
|
|
1372
|
+
self,
|
|
1373
|
+
*,
|
|
1374
|
+
otel_span: otel_trace_api.Span,
|
|
1375
|
+
aeri_client: "Aeri",
|
|
1376
|
+
input: Optional[Any] = None,
|
|
1377
|
+
output: Optional[Any] = None,
|
|
1378
|
+
metadata: Optional[Any] = None,
|
|
1379
|
+
environment: Optional[str] = None,
|
|
1380
|
+
release: Optional[str] = None,
|
|
1381
|
+
version: Optional[str] = None,
|
|
1382
|
+
level: Optional[SpanLevel] = None,
|
|
1383
|
+
status_message: Optional[str] = None,
|
|
1384
|
+
):
|
|
1385
|
+
"""Initialize a new AeriEvent span.
|
|
1386
|
+
|
|
1387
|
+
Args:
|
|
1388
|
+
otel_span: The OpenTelemetry span to wrap
|
|
1389
|
+
aeri_client: Reference to the parent Aeri client
|
|
1390
|
+
input: Input data for the event
|
|
1391
|
+
output: Output from the event
|
|
1392
|
+
metadata: Additional metadata to associate with the generation
|
|
1393
|
+
environment: The tracing environment
|
|
1394
|
+
release: Release identifier for the application
|
|
1395
|
+
version: Version identifier for the model or component
|
|
1396
|
+
level: Importance level of the generation (info, warning, error)
|
|
1397
|
+
status_message: Optional status message for the generation
|
|
1398
|
+
"""
|
|
1399
|
+
super().__init__(
|
|
1400
|
+
otel_span=otel_span,
|
|
1401
|
+
as_type="event",
|
|
1402
|
+
aeri_client=aeri_client,
|
|
1403
|
+
input=input,
|
|
1404
|
+
output=output,
|
|
1405
|
+
metadata=metadata,
|
|
1406
|
+
environment=environment,
|
|
1407
|
+
release=release,
|
|
1408
|
+
version=version,
|
|
1409
|
+
level=level,
|
|
1410
|
+
status_message=status_message,
|
|
1411
|
+
)
|
|
1412
|
+
|
|
1413
|
+
def update(
|
|
1414
|
+
self,
|
|
1415
|
+
*,
|
|
1416
|
+
name: Optional[str] = None,
|
|
1417
|
+
input: Optional[Any] = None,
|
|
1418
|
+
output: Optional[Any] = None,
|
|
1419
|
+
metadata: Optional[Any] = None,
|
|
1420
|
+
version: Optional[str] = None,
|
|
1421
|
+
level: Optional[SpanLevel] = None,
|
|
1422
|
+
status_message: Optional[str] = None,
|
|
1423
|
+
completion_start_time: Optional[datetime] = None,
|
|
1424
|
+
model: Optional[str] = None,
|
|
1425
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
1426
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
1427
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
1428
|
+
prompt: Optional[PromptClient] = None,
|
|
1429
|
+
**kwargs: Any,
|
|
1430
|
+
) -> "AeriEvent":
|
|
1431
|
+
"""Update is not allowed for AeriEvent because events cannot be updated.
|
|
1432
|
+
|
|
1433
|
+
This method logs a warning and returns self without making changes.
|
|
1434
|
+
|
|
1435
|
+
Returns:
|
|
1436
|
+
self: Returns the unchanged AeriEvent instance
|
|
1437
|
+
"""
|
|
1438
|
+
aeri_logger.warning(
|
|
1439
|
+
"Attempted to update AeriEvent observation. Events cannot be updated after creation."
|
|
1440
|
+
)
|
|
1441
|
+
return self
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
class AeriAgent(AeriObservationWrapper):
|
|
1445
|
+
"""Agent observation for reasoning blocks that act on tools using LLM guidance."""
|
|
1446
|
+
|
|
1447
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1448
|
+
"""Initialize a new AeriAgent span."""
|
|
1449
|
+
kwargs["as_type"] = "agent"
|
|
1450
|
+
super().__init__(**kwargs)
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
class AeriTool(AeriObservationWrapper):
|
|
1454
|
+
"""Tool observation representing external tool calls, e.g., calling a weather API."""
|
|
1455
|
+
|
|
1456
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1457
|
+
"""Initialize a new AeriTool span."""
|
|
1458
|
+
kwargs["as_type"] = "tool"
|
|
1459
|
+
super().__init__(**kwargs)
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
class AeriChain(AeriObservationWrapper):
|
|
1463
|
+
"""Chain observation for connecting LLM application steps, e.g. passing context from retriever to LLM."""
|
|
1464
|
+
|
|
1465
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1466
|
+
"""Initialize a new AeriChain span."""
|
|
1467
|
+
kwargs["as_type"] = "chain"
|
|
1468
|
+
super().__init__(**kwargs)
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
class AeriRetriever(AeriObservationWrapper):
|
|
1472
|
+
"""Retriever observation for data retrieval steps, e.g. vector store or database queries."""
|
|
1473
|
+
|
|
1474
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1475
|
+
"""Initialize a new AeriRetriever span."""
|
|
1476
|
+
kwargs["as_type"] = "retriever"
|
|
1477
|
+
super().__init__(**kwargs)
|
|
1478
|
+
|
|
1479
|
+
|
|
1480
|
+
class AeriEmbedding(AeriObservationWrapper):
|
|
1481
|
+
"""Embedding observation for LLM embedding calls, typically used before retrieval."""
|
|
1482
|
+
|
|
1483
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1484
|
+
"""Initialize a new AeriEmbedding span."""
|
|
1485
|
+
kwargs["as_type"] = "embedding"
|
|
1486
|
+
super().__init__(**kwargs)
|
|
1487
|
+
|
|
1488
|
+
|
|
1489
|
+
class AeriEvaluator(AeriObservationWrapper):
|
|
1490
|
+
"""Evaluator observation for assessing relevance, correctness, or helpfulness of LLM outputs."""
|
|
1491
|
+
|
|
1492
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1493
|
+
"""Initialize a new AeriEvaluator span."""
|
|
1494
|
+
kwargs["as_type"] = "evaluator"
|
|
1495
|
+
super().__init__(**kwargs)
|
|
1496
|
+
|
|
1497
|
+
|
|
1498
|
+
class AeriGuardrail(AeriObservationWrapper):
|
|
1499
|
+
"""Guardrail observation for protection e.g. against jailbreaks or offensive content."""
|
|
1500
|
+
|
|
1501
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1502
|
+
"""Initialize a new AeriGuardrail span."""
|
|
1503
|
+
kwargs["as_type"] = "guardrail"
|
|
1504
|
+
super().__init__(**kwargs)
|
|
1505
|
+
|
|
1506
|
+
|
|
1507
|
+
_OBSERVATION_CLASS_MAP.update(
|
|
1508
|
+
{
|
|
1509
|
+
"span": AeriSpan,
|
|
1510
|
+
"generation": AeriGeneration,
|
|
1511
|
+
"agent": AeriAgent,
|
|
1512
|
+
"tool": AeriTool,
|
|
1513
|
+
"chain": AeriChain,
|
|
1514
|
+
"retriever": AeriRetriever,
|
|
1515
|
+
"evaluator": AeriEvaluator,
|
|
1516
|
+
"embedding": AeriEmbedding,
|
|
1517
|
+
"guardrail": AeriGuardrail,
|
|
1518
|
+
}
|
|
1519
|
+
)
|