aeri 4.0.0__tar.gz
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-4.0.0/LICENSE +21 -0
- aeri-4.0.0/PKG-INFO +51 -0
- aeri-4.0.0/README.md +23 -0
- aeri-4.0.0/aeri/__init__.py +72 -0
- aeri-4.0.0/aeri/_client/_validation.py +204 -0
- aeri-4.0.0/aeri/_client/attributes.py +188 -0
- aeri-4.0.0/aeri/_client/client.py +3761 -0
- aeri-4.0.0/aeri/_client/constants.py +65 -0
- aeri-4.0.0/aeri/_client/datasets.py +302 -0
- aeri-4.0.0/aeri/_client/environment_variables.py +158 -0
- aeri-4.0.0/aeri/_client/get_client.py +149 -0
- aeri-4.0.0/aeri/_client/observe.py +661 -0
- aeri-4.0.0/aeri/_client/propagation.py +475 -0
- aeri-4.0.0/aeri/_client/resource_manager.py +510 -0
- aeri-4.0.0/aeri/_client/span.py +1519 -0
- aeri-4.0.0/aeri/_client/span_filter.py +76 -0
- aeri-4.0.0/aeri/_client/span_processor.py +206 -0
- aeri-4.0.0/aeri/_client/utils.py +132 -0
- aeri-4.0.0/aeri/_task_manager/media_manager.py +331 -0
- aeri-4.0.0/aeri/_task_manager/media_upload_consumer.py +44 -0
- aeri-4.0.0/aeri/_task_manager/media_upload_queue.py +12 -0
- aeri-4.0.0/aeri/_task_manager/score_ingestion_consumer.py +208 -0
- aeri-4.0.0/aeri/_task_manager/task_manager.py +475 -0
- aeri-4.0.0/aeri/_utils/__init__.py +19 -0
- aeri-4.0.0/aeri/_utils/environment.py +34 -0
- aeri-4.0.0/aeri/_utils/error_logging.py +47 -0
- aeri-4.0.0/aeri/_utils/parse_error.py +99 -0
- aeri-4.0.0/aeri/_utils/prompt_cache.py +188 -0
- aeri-4.0.0/aeri/_utils/request.py +137 -0
- aeri-4.0.0/aeri/_utils/serializer.py +205 -0
- aeri-4.0.0/aeri/api/.fern/metadata.json +14 -0
- aeri-4.0.0/aeri/api/__init__.py +836 -0
- aeri-4.0.0/aeri/api/annotation_queues/__init__.py +82 -0
- aeri-4.0.0/aeri/api/annotation_queues/client.py +1111 -0
- aeri-4.0.0/aeri/api/annotation_queues/raw_client.py +2288 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/__init__.py +84 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/annotation_queue.py +28 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/annotation_queue_assignment_request.py +16 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/annotation_queue_item.py +34 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/annotation_queue_object_type.py +26 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/annotation_queue_status.py +22 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/create_annotation_queue_assignment_response.py +18 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/create_annotation_queue_item_request.py +25 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/create_annotation_queue_request.py +20 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/delete_annotation_queue_assignment_response.py +14 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/delete_annotation_queue_item_response.py +15 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/paginated_annotation_queue_items.py +17 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/paginated_annotation_queues.py +17 -0
- aeri-4.0.0/aeri/api/annotation_queues/types/update_annotation_queue_item_request.py +15 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/__init__.py +73 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/client.py +550 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/raw_client.py +976 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/__init__.py +77 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_export_frequency.py +26 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_export_mode.py +26 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +14 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integration_file_type.py +26 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integration_response.py +64 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integration_status_response.py +50 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integration_type.py +26 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_integrations_response.py +15 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/blob_storage_sync_status.py +47 -0
- aeri-4.0.0/aeri/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +91 -0
- aeri-4.0.0/aeri/api/client.py +679 -0
- aeri-4.0.0/aeri/api/comments/__init__.py +44 -0
- aeri-4.0.0/aeri/api/comments/client.py +407 -0
- aeri-4.0.0/aeri/api/comments/raw_client.py +750 -0
- aeri-4.0.0/aeri/api/comments/types/__init__.py +46 -0
- aeri-4.0.0/aeri/api/comments/types/create_comment_request.py +47 -0
- aeri-4.0.0/aeri/api/comments/types/create_comment_response.py +17 -0
- aeri-4.0.0/aeri/api/comments/types/get_comments_response.py +17 -0
- aeri-4.0.0/aeri/api/commons/__init__.py +210 -0
- aeri-4.0.0/aeri/api/commons/errors/__init__.py +56 -0
- aeri-4.0.0/aeri/api/commons/errors/access_denied_error.py +12 -0
- aeri-4.0.0/aeri/api/commons/errors/error.py +12 -0
- aeri-4.0.0/aeri/api/commons/errors/method_not_allowed_error.py +12 -0
- aeri-4.0.0/aeri/api/commons/errors/not_found_error.py +12 -0
- aeri-4.0.0/aeri/api/commons/errors/unauthorized_error.py +12 -0
- aeri-4.0.0/aeri/api/commons/types/__init__.py +190 -0
- aeri-4.0.0/aeri/api/commons/types/base_score.py +90 -0
- aeri-4.0.0/aeri/api/commons/types/base_score_v1.py +70 -0
- aeri-4.0.0/aeri/api/commons/types/boolean_score.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/boolean_score_v1.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/categorical_score.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/categorical_score_v1.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/comment.py +36 -0
- aeri-4.0.0/aeri/api/commons/types/comment_object_type.py +30 -0
- aeri-4.0.0/aeri/api/commons/types/config_category.py +15 -0
- aeri-4.0.0/aeri/api/commons/types/correction_score.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/create_score_value.py +5 -0
- aeri-4.0.0/aeri/api/commons/types/dataset.py +49 -0
- aeri-4.0.0/aeri/api/commons/types/dataset_item.py +58 -0
- aeri-4.0.0/aeri/api/commons/types/dataset_run.py +63 -0
- aeri-4.0.0/aeri/api/commons/types/dataset_run_item.py +40 -0
- aeri-4.0.0/aeri/api/commons/types/dataset_run_with_items.py +19 -0
- aeri-4.0.0/aeri/api/commons/types/dataset_status.py +22 -0
- aeri-4.0.0/aeri/api/commons/types/map_value.py +11 -0
- aeri-4.0.0/aeri/api/commons/types/model.py +125 -0
- aeri-4.0.0/aeri/api/commons/types/model_price.py +14 -0
- aeri-4.0.0/aeri/api/commons/types/model_usage_unit.py +42 -0
- aeri-4.0.0/aeri/api/commons/types/numeric_score.py +17 -0
- aeri-4.0.0/aeri/api/commons/types/numeric_score_v1.py +17 -0
- aeri-4.0.0/aeri/api/commons/types/observation.py +142 -0
- aeri-4.0.0/aeri/api/commons/types/observation_level.py +30 -0
- aeri-4.0.0/aeri/api/commons/types/observation_v2.py +235 -0
- aeri-4.0.0/aeri/api/commons/types/observations_view.py +89 -0
- aeri-4.0.0/aeri/api/commons/types/pricing_tier.py +91 -0
- aeri-4.0.0/aeri/api/commons/types/pricing_tier_condition.py +68 -0
- aeri-4.0.0/aeri/api/commons/types/pricing_tier_input.py +76 -0
- aeri-4.0.0/aeri/api/commons/types/pricing_tier_operator.py +42 -0
- aeri-4.0.0/aeri/api/commons/types/score.py +201 -0
- aeri-4.0.0/aeri/api/commons/types/score_config.py +66 -0
- aeri-4.0.0/aeri/api/commons/types/score_config_data_type.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/score_data_type.py +30 -0
- aeri-4.0.0/aeri/api/commons/types/score_source.py +26 -0
- aeri-4.0.0/aeri/api/commons/types/score_v1.py +131 -0
- aeri-4.0.0/aeri/api/commons/types/session.py +25 -0
- aeri-4.0.0/aeri/api/commons/types/session_with_traces.py +15 -0
- aeri-4.0.0/aeri/api/commons/types/trace.py +84 -0
- aeri-4.0.0/aeri/api/commons/types/trace_with_details.py +43 -0
- aeri-4.0.0/aeri/api/commons/types/trace_with_full_details.py +45 -0
- aeri-4.0.0/aeri/api/commons/types/usage.py +59 -0
- aeri-4.0.0/aeri/api/core/__init__.py +111 -0
- aeri-4.0.0/aeri/api/core/api_error.py +23 -0
- aeri-4.0.0/aeri/api/core/client_wrapper.py +141 -0
- aeri-4.0.0/aeri/api/core/datetime_utils.py +30 -0
- aeri-4.0.0/aeri/api/core/enum.py +20 -0
- aeri-4.0.0/aeri/api/core/file.py +70 -0
- aeri-4.0.0/aeri/api/core/force_multipart.py +18 -0
- aeri-4.0.0/aeri/api/core/http_client.py +711 -0
- aeri-4.0.0/aeri/api/core/http_response.py +55 -0
- aeri-4.0.0/aeri/api/core/http_sse/__init__.py +48 -0
- aeri-4.0.0/aeri/api/core/http_sse/_api.py +114 -0
- aeri-4.0.0/aeri/api/core/http_sse/_decoders.py +66 -0
- aeri-4.0.0/aeri/api/core/http_sse/_exceptions.py +7 -0
- aeri-4.0.0/aeri/api/core/http_sse/_models.py +17 -0
- aeri-4.0.0/aeri/api/core/jsonable_encoder.py +102 -0
- aeri-4.0.0/aeri/api/core/pydantic_utilities.py +310 -0
- aeri-4.0.0/aeri/api/core/query_encoder.py +60 -0
- aeri-4.0.0/aeri/api/core/remove_none_from_dict.py +11 -0
- aeri-4.0.0/aeri/api/core/request_options.py +35 -0
- aeri-4.0.0/aeri/api/core/serialization.py +282 -0
- aeri-4.0.0/aeri/api/dataset_items/__init__.py +52 -0
- aeri-4.0.0/aeri/api/dataset_items/client.py +499 -0
- aeri-4.0.0/aeri/api/dataset_items/raw_client.py +973 -0
- aeri-4.0.0/aeri/api/dataset_items/types/__init__.py +50 -0
- aeri-4.0.0/aeri/api/dataset_items/types/create_dataset_item_request.py +37 -0
- aeri-4.0.0/aeri/api/dataset_items/types/delete_dataset_item_response.py +17 -0
- aeri-4.0.0/aeri/api/dataset_items/types/paginated_dataset_items.py +17 -0
- aeri-4.0.0/aeri/api/dataset_run_items/__init__.py +43 -0
- aeri-4.0.0/aeri/api/dataset_run_items/client.py +323 -0
- aeri-4.0.0/aeri/api/dataset_run_items/raw_client.py +547 -0
- aeri-4.0.0/aeri/api/dataset_run_items/types/__init__.py +44 -0
- aeri-4.0.0/aeri/api/dataset_run_items/types/create_dataset_run_item_request.py +51 -0
- aeri-4.0.0/aeri/api/dataset_run_items/types/paginated_dataset_run_items.py +17 -0
- aeri-4.0.0/aeri/api/datasets/__init__.py +55 -0
- aeri-4.0.0/aeri/api/datasets/client.py +661 -0
- aeri-4.0.0/aeri/api/datasets/raw_client.py +1368 -0
- aeri-4.0.0/aeri/api/datasets/types/__init__.py +53 -0
- aeri-4.0.0/aeri/api/datasets/types/create_dataset_request.py +31 -0
- aeri-4.0.0/aeri/api/datasets/types/delete_dataset_run_response.py +14 -0
- aeri-4.0.0/aeri/api/datasets/types/paginated_dataset_runs.py +17 -0
- aeri-4.0.0/aeri/api/datasets/types/paginated_datasets.py +17 -0
- aeri-4.0.0/aeri/api/health/__init__.py +44 -0
- aeri-4.0.0/aeri/api/health/client.py +112 -0
- aeri-4.0.0/aeri/api/health/errors/__init__.py +42 -0
- aeri-4.0.0/aeri/api/health/errors/service_unavailable_error.py +13 -0
- aeri-4.0.0/aeri/api/health/raw_client.py +227 -0
- aeri-4.0.0/aeri/api/health/types/__init__.py +40 -0
- aeri-4.0.0/aeri/api/health/types/health_response.py +30 -0
- aeri-4.0.0/aeri/api/ingestion/__init__.py +169 -0
- aeri-4.0.0/aeri/api/ingestion/client.py +221 -0
- aeri-4.0.0/aeri/api/ingestion/raw_client.py +293 -0
- aeri-4.0.0/aeri/api/ingestion/types/__init__.py +169 -0
- aeri-4.0.0/aeri/api/ingestion/types/base_event.py +27 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_event_body.py +14 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_event_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_generation_body.py +40 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_generation_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_observation_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_span_body.py +19 -0
- aeri-4.0.0/aeri/api/ingestion/types/create_span_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/ingestion_error.py +17 -0
- aeri-4.0.0/aeri/api/ingestion/types/ingestion_event.py +155 -0
- aeri-4.0.0/aeri/api/ingestion/types/ingestion_response.py +17 -0
- aeri-4.0.0/aeri/api/ingestion/types/ingestion_success.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/ingestion_usage.py +8 -0
- aeri-4.0.0/aeri/api/ingestion/types/observation_body.py +53 -0
- aeri-4.0.0/aeri/api/ingestion/types/observation_type.py +54 -0
- aeri-4.0.0/aeri/api/ingestion/types/open_ai_completion_usage_schema.py +26 -0
- aeri-4.0.0/aeri/api/ingestion/types/open_ai_response_usage_schema.py +24 -0
- aeri-4.0.0/aeri/api/ingestion/types/open_ai_usage.py +28 -0
- aeri-4.0.0/aeri/api/ingestion/types/optional_observation_body.py +36 -0
- aeri-4.0.0/aeri/api/ingestion/types/score_body.py +75 -0
- aeri-4.0.0/aeri/api/ingestion/types/score_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/sdk_log_body.py +14 -0
- aeri-4.0.0/aeri/api/ingestion/types/sdk_log_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/trace_body.py +36 -0
- aeri-4.0.0/aeri/api/ingestion/types/trace_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_event_body.py +14 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_generation_body.py +40 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_generation_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_observation_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_span_body.py +19 -0
- aeri-4.0.0/aeri/api/ingestion/types/update_span_event.py +15 -0
- aeri-4.0.0/aeri/api/ingestion/types/usage_details.py +10 -0
- aeri-4.0.0/aeri/api/legacy/__init__.py +61 -0
- aeri-4.0.0/aeri/api/legacy/client.py +105 -0
- aeri-4.0.0/aeri/api/legacy/metrics_v1/__init__.py +40 -0
- aeri-4.0.0/aeri/api/legacy/metrics_v1/client.py +214 -0
- aeri-4.0.0/aeri/api/legacy/metrics_v1/raw_client.py +322 -0
- aeri-4.0.0/aeri/api/legacy/metrics_v1/types/__init__.py +40 -0
- aeri-4.0.0/aeri/api/legacy/metrics_v1/types/metrics_response.py +19 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/__init__.py +43 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/client.py +523 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/raw_client.py +759 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/types/__init__.py +44 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/types/observations.py +17 -0
- aeri-4.0.0/aeri/api/legacy/observations_v1/types/observations_views.py +17 -0
- aeri-4.0.0/aeri/api/legacy/raw_client.py +13 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/__init__.py +43 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/client.py +329 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/raw_client.py +545 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/types/__init__.py +44 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/types/create_score_request.py +75 -0
- aeri-4.0.0/aeri/api/legacy/score_v1/types/create_score_response.py +17 -0
- aeri-4.0.0/aeri/api/llm_connections/__init__.py +55 -0
- aeri-4.0.0/aeri/api/llm_connections/client.py +311 -0
- aeri-4.0.0/aeri/api/llm_connections/raw_client.py +541 -0
- aeri-4.0.0/aeri/api/llm_connections/types/__init__.py +53 -0
- aeri-4.0.0/aeri/api/llm_connections/types/llm_adapter.py +38 -0
- aeri-4.0.0/aeri/api/llm_connections/types/llm_connection.py +77 -0
- aeri-4.0.0/aeri/api/llm_connections/types/paginated_llm_connections.py +17 -0
- aeri-4.0.0/aeri/api/llm_connections/types/upsert_llm_connection_request.py +69 -0
- aeri-4.0.0/aeri/api/media/__init__.py +58 -0
- aeri-4.0.0/aeri/api/media/client.py +427 -0
- aeri-4.0.0/aeri/api/media/raw_client.py +739 -0
- aeri-4.0.0/aeri/api/media/types/__init__.py +56 -0
- aeri-4.0.0/aeri/api/media/types/get_media_response.py +55 -0
- aeri-4.0.0/aeri/api/media/types/get_media_upload_url_request.py +51 -0
- aeri-4.0.0/aeri/api/media/types/get_media_upload_url_response.py +28 -0
- aeri-4.0.0/aeri/api/media/types/media_content_type.py +232 -0
- aeri-4.0.0/aeri/api/media/types/patch_media_body.py +43 -0
- aeri-4.0.0/aeri/api/metrics/__init__.py +40 -0
- aeri-4.0.0/aeri/api/metrics/client.py +422 -0
- aeri-4.0.0/aeri/api/metrics/raw_client.py +530 -0
- aeri-4.0.0/aeri/api/metrics/types/__init__.py +40 -0
- aeri-4.0.0/aeri/api/metrics/types/metrics_v2response.py +19 -0
- aeri-4.0.0/aeri/api/models/__init__.py +43 -0
- aeri-4.0.0/aeri/api/models/client.py +523 -0
- aeri-4.0.0/aeri/api/models/raw_client.py +993 -0
- aeri-4.0.0/aeri/api/models/types/__init__.py +44 -0
- aeri-4.0.0/aeri/api/models/types/create_model_request.py +103 -0
- aeri-4.0.0/aeri/api/models/types/paginated_models.py +17 -0
- aeri-4.0.0/aeri/api/observations/__init__.py +43 -0
- aeri-4.0.0/aeri/api/observations/client.py +522 -0
- aeri-4.0.0/aeri/api/observations/raw_client.py +641 -0
- aeri-4.0.0/aeri/api/observations/types/__init__.py +44 -0
- aeri-4.0.0/aeri/api/observations/types/observations_v2meta.py +21 -0
- aeri-4.0.0/aeri/api/observations/types/observations_v2response.py +28 -0
- aeri-4.0.0/aeri/api/opentelemetry/__init__.py +67 -0
- aeri-4.0.0/aeri/api/opentelemetry/client.py +276 -0
- aeri-4.0.0/aeri/api/opentelemetry/raw_client.py +291 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/__init__.py +65 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_attribute.py +27 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_attribute_value.py +46 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_resource.py +24 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_resource_span.py +32 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_scope.py +34 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_scope_span.py +28 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_span.py +76 -0
- aeri-4.0.0/aeri/api/opentelemetry/types/otel_trace_response.py +16 -0
- aeri-4.0.0/aeri/api/organizations/__init__.py +73 -0
- aeri-4.0.0/aeri/api/organizations/client.py +756 -0
- aeri-4.0.0/aeri/api/organizations/raw_client.py +1707 -0
- aeri-4.0.0/aeri/api/organizations/types/__init__.py +71 -0
- aeri-4.0.0/aeri/api/organizations/types/delete_membership_request.py +16 -0
- aeri-4.0.0/aeri/api/organizations/types/membership_deletion_response.py +17 -0
- aeri-4.0.0/aeri/api/organizations/types/membership_request.py +18 -0
- aeri-4.0.0/aeri/api/organizations/types/membership_response.py +20 -0
- aeri-4.0.0/aeri/api/organizations/types/membership_role.py +30 -0
- aeri-4.0.0/aeri/api/organizations/types/memberships_response.py +15 -0
- aeri-4.0.0/aeri/api/organizations/types/organization_api_key.py +31 -0
- aeri-4.0.0/aeri/api/organizations/types/organization_api_keys_response.py +19 -0
- aeri-4.0.0/aeri/api/organizations/types/organization_project.py +25 -0
- aeri-4.0.0/aeri/api/organizations/types/organization_projects_response.py +15 -0
- aeri-4.0.0/aeri/api/projects/__init__.py +67 -0
- aeri-4.0.0/aeri/api/projects/client.py +760 -0
- aeri-4.0.0/aeri/api/projects/raw_client.py +1577 -0
- aeri-4.0.0/aeri/api/projects/types/__init__.py +65 -0
- aeri-4.0.0/aeri/api/projects/types/api_key_deletion_response.py +18 -0
- aeri-4.0.0/aeri/api/projects/types/api_key_list.py +23 -0
- aeri-4.0.0/aeri/api/projects/types/api_key_response.py +30 -0
- aeri-4.0.0/aeri/api/projects/types/api_key_summary.py +35 -0
- aeri-4.0.0/aeri/api/projects/types/organization.py +22 -0
- aeri-4.0.0/aeri/api/projects/types/project.py +34 -0
- aeri-4.0.0/aeri/api/projects/types/project_deletion_response.py +15 -0
- aeri-4.0.0/aeri/api/projects/types/projects.py +15 -0
- aeri-4.0.0/aeri/api/prompt_version/__init__.py +4 -0
- aeri-4.0.0/aeri/api/prompt_version/client.py +157 -0
- aeri-4.0.0/aeri/api/prompt_version/raw_client.py +264 -0
- aeri-4.0.0/aeri/api/prompts/__init__.py +100 -0
- aeri-4.0.0/aeri/api/prompts/client.py +550 -0
- aeri-4.0.0/aeri/api/prompts/raw_client.py +987 -0
- aeri-4.0.0/aeri/api/prompts/types/__init__.py +96 -0
- aeri-4.0.0/aeri/api/prompts/types/base_prompt.py +42 -0
- aeri-4.0.0/aeri/api/prompts/types/chat_message.py +17 -0
- aeri-4.0.0/aeri/api/prompts/types/chat_message_type.py +15 -0
- aeri-4.0.0/aeri/api/prompts/types/chat_message_with_placeholders.py +8 -0
- aeri-4.0.0/aeri/api/prompts/types/chat_prompt.py +15 -0
- aeri-4.0.0/aeri/api/prompts/types/create_chat_prompt_request.py +37 -0
- aeri-4.0.0/aeri/api/prompts/types/create_chat_prompt_type.py +15 -0
- aeri-4.0.0/aeri/api/prompts/types/create_prompt_request.py +8 -0
- aeri-4.0.0/aeri/api/prompts/types/create_text_prompt_request.py +36 -0
- aeri-4.0.0/aeri/api/prompts/types/create_text_prompt_type.py +15 -0
- aeri-4.0.0/aeri/api/prompts/types/placeholder_message.py +16 -0
- aeri-4.0.0/aeri/api/prompts/types/placeholder_message_type.py +15 -0
- aeri-4.0.0/aeri/api/prompts/types/prompt.py +58 -0
- aeri-4.0.0/aeri/api/prompts/types/prompt_meta.py +35 -0
- aeri-4.0.0/aeri/api/prompts/types/prompt_meta_list_response.py +17 -0
- aeri-4.0.0/aeri/api/prompts/types/prompt_type.py +20 -0
- aeri-4.0.0/aeri/api/prompts/types/text_prompt.py +14 -0
- aeri-4.0.0/aeri/api/scim/__init__.py +94 -0
- aeri-4.0.0/aeri/api/scim/client.py +686 -0
- aeri-4.0.0/aeri/api/scim/raw_client.py +1528 -0
- aeri-4.0.0/aeri/api/scim/types/__init__.py +92 -0
- aeri-4.0.0/aeri/api/scim/types/authentication_scheme.py +20 -0
- aeri-4.0.0/aeri/api/scim/types/bulk_config.py +22 -0
- aeri-4.0.0/aeri/api/scim/types/empty_response.py +16 -0
- aeri-4.0.0/aeri/api/scim/types/filter_config.py +17 -0
- aeri-4.0.0/aeri/api/scim/types/resource_meta.py +17 -0
- aeri-4.0.0/aeri/api/scim/types/resource_type.py +27 -0
- aeri-4.0.0/aeri/api/scim/types/resource_types_response.py +21 -0
- aeri-4.0.0/aeri/api/scim/types/schema_extension.py +17 -0
- aeri-4.0.0/aeri/api/scim/types/schema_resource.py +19 -0
- aeri-4.0.0/aeri/api/scim/types/schemas_response.py +21 -0
- aeri-4.0.0/aeri/api/scim/types/scim_email.py +16 -0
- aeri-4.0.0/aeri/api/scim/types/scim_feature_support.py +14 -0
- aeri-4.0.0/aeri/api/scim/types/scim_name.py +14 -0
- aeri-4.0.0/aeri/api/scim/types/scim_user.py +24 -0
- aeri-4.0.0/aeri/api/scim/types/scim_users_list_response.py +25 -0
- aeri-4.0.0/aeri/api/scim/types/service_provider_config.py +36 -0
- aeri-4.0.0/aeri/api/scim/types/user_meta.py +20 -0
- aeri-4.0.0/aeri/api/score_configs/__init__.py +44 -0
- aeri-4.0.0/aeri/api/score_configs/client.py +526 -0
- aeri-4.0.0/aeri/api/score_configs/raw_client.py +1012 -0
- aeri-4.0.0/aeri/api/score_configs/types/__init__.py +46 -0
- aeri-4.0.0/aeri/api/score_configs/types/create_score_config_request.py +46 -0
- aeri-4.0.0/aeri/api/score_configs/types/score_configs.py +17 -0
- aeri-4.0.0/aeri/api/score_configs/types/update_score_config_request.py +53 -0
- aeri-4.0.0/aeri/api/scores/__init__.py +76 -0
- aeri-4.0.0/aeri/api/scores/client.py +420 -0
- aeri-4.0.0/aeri/api/scores/raw_client.py +656 -0
- aeri-4.0.0/aeri/api/scores/types/__init__.py +76 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response.py +17 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_data.py +211 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_data_boolean.py +15 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_data_categorical.py +15 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_data_correction.py +15 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_data_numeric.py +15 -0
- aeri-4.0.0/aeri/api/scores/types/get_scores_response_trace_data.py +38 -0
- aeri-4.0.0/aeri/api/sessions/__init__.py +40 -0
- aeri-4.0.0/aeri/api/sessions/client.py +262 -0
- aeri-4.0.0/aeri/api/sessions/raw_client.py +500 -0
- aeri-4.0.0/aeri/api/sessions/types/__init__.py +40 -0
- aeri-4.0.0/aeri/api/sessions/types/paginated_sessions.py +17 -0
- aeri-4.0.0/aeri/api/trace/__init__.py +44 -0
- aeri-4.0.0/aeri/api/trace/client.py +728 -0
- aeri-4.0.0/aeri/api/trace/raw_client.py +1208 -0
- aeri-4.0.0/aeri/api/trace/types/__init__.py +46 -0
- aeri-4.0.0/aeri/api/trace/types/delete_trace_response.py +14 -0
- aeri-4.0.0/aeri/api/trace/types/sort.py +14 -0
- aeri-4.0.0/aeri/api/trace/types/traces.py +17 -0
- aeri-4.0.0/aeri/api/utils/__init__.py +44 -0
- aeri-4.0.0/aeri/api/utils/pagination/__init__.py +40 -0
- aeri-4.0.0/aeri/api/utils/pagination/types/__init__.py +40 -0
- aeri-4.0.0/aeri/api/utils/pagination/types/meta_response.py +38 -0
- aeri-4.0.0/aeri/batch_evaluation.py +1643 -0
- aeri-4.0.0/aeri/experiment.py +1044 -0
- aeri-4.0.0/aeri/langchain/CallbackHandler.py +1377 -0
- aeri-4.0.0/aeri/langchain/__init__.py +5 -0
- aeri-4.0.0/aeri/langchain/utils.py +212 -0
- aeri-4.0.0/aeri/logger.py +28 -0
- aeri-4.0.0/aeri/media.py +352 -0
- aeri-4.0.0/aeri/model.py +477 -0
- aeri-4.0.0/aeri/openai.py +1124 -0
- aeri-4.0.0/aeri/py.typed +0 -0
- aeri-4.0.0/aeri/span_filter.py +17 -0
- aeri-4.0.0/aeri/types.py +79 -0
- aeri-4.0.0/aeri/version.py +3 -0
- aeri-4.0.0/pyproject.toml +116 -0
aeri-4.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Finto Technologies
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aeri-4.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aeri
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: Aeri AI Observability SDK
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Author: Naman Gupta
|
|
8
|
+
Author-email: naman@aeri.com
|
|
9
|
+
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Dist: backoff (>=1.10.0)
|
|
19
|
+
Requires-Dist: httpx (>=0.15.4,<1.0)
|
|
20
|
+
Requires-Dist: opentelemetry-api (>=1.33.1,<2.0.0)
|
|
21
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.33.1,<2.0.0)
|
|
22
|
+
Requires-Dist: opentelemetry-sdk (>=1.33.1,<2.0.0)
|
|
23
|
+
Requires-Dist: packaging (>=23.2,<27.0)
|
|
24
|
+
Requires-Dist: pydantic (>=2,<3)
|
|
25
|
+
Requires-Dist: wrapt (>=1.14,<2.0)
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
# Aeri Python SDK
|
|
31
|
+
|
|
32
|
+
[](https://opensource.org/licenses/MIT)
|
|
33
|
+
[](https://github.com/aeri/aeri-python/actions/workflows/ci.yml?query=branch%3Amain)
|
|
34
|
+
[](https://pypi.python.org/pypi/aeri)
|
|
35
|
+
[](https://github.com/aeri/aeri)
|
|
36
|
+
[](https://discord.gg/7NXusRtqYU)
|
|
37
|
+
[](https://www.ycombinator.com/companies/aeri)
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
> The SDK was rewritten in v3 and released in June 2025. Refer to the [v3 migration guide](https://aeri.com/docs/sdk/python/sdk-v3#upgrade-from-v2) for instructions on updating your code.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
pip install aeri
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Docs
|
|
49
|
+
|
|
50
|
+
Please [see our docs](https://aeri.com/docs/sdk/python/sdk-v3) for detailed information on this SDK.
|
|
51
|
+
|
aeri-4.0.0/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Aeri Python SDK
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://github.com/aeri/aeri-python/actions/workflows/ci.yml?query=branch%3Amain)
|
|
7
|
+
[](https://pypi.python.org/pypi/aeri)
|
|
8
|
+
[](https://github.com/aeri/aeri)
|
|
9
|
+
[](https://discord.gg/7NXusRtqYU)
|
|
10
|
+
[](https://www.ycombinator.com/companies/aeri)
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
> [!IMPORTANT]
|
|
15
|
+
> The SDK was rewritten in v3 and released in June 2025. Refer to the [v3 migration guide](https://aeri.com/docs/sdk/python/sdk-v3#upgrade-from-v2) for instructions on updating your code.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
pip install aeri
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Docs
|
|
22
|
+
|
|
23
|
+
Please [see our docs](https://aeri.com/docs/sdk/python/sdk-v3) for detailed information on this SDK.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
""".. include:: ../README.md"""
|
|
2
|
+
|
|
3
|
+
from aeri.batch_evaluation import (
|
|
4
|
+
BatchEvaluationResult,
|
|
5
|
+
BatchEvaluationResumeToken,
|
|
6
|
+
CompositeEvaluatorFunction,
|
|
7
|
+
EvaluatorInputs,
|
|
8
|
+
EvaluatorStats,
|
|
9
|
+
MapperFunction,
|
|
10
|
+
)
|
|
11
|
+
from aeri.experiment import Evaluation
|
|
12
|
+
|
|
13
|
+
from ._client import client as _client_module
|
|
14
|
+
from ._client.attributes import AeriOtelSpanAttributes
|
|
15
|
+
from ._client.constants import ObservationTypeLiteral
|
|
16
|
+
from ._client.get_client import get_client
|
|
17
|
+
from ._client.observe import observe
|
|
18
|
+
from ._client.propagation import propagate_attributes
|
|
19
|
+
from ._client.span import (
|
|
20
|
+
AeriAgent,
|
|
21
|
+
AeriChain,
|
|
22
|
+
AeriEmbedding,
|
|
23
|
+
AeriEvaluator,
|
|
24
|
+
AeriEvent,
|
|
25
|
+
AeriGeneration,
|
|
26
|
+
AeriGuardrail,
|
|
27
|
+
AeriRetriever,
|
|
28
|
+
AeriSpan,
|
|
29
|
+
AeriTool,
|
|
30
|
+
)
|
|
31
|
+
from .span_filter import (
|
|
32
|
+
KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES,
|
|
33
|
+
is_default_export_span,
|
|
34
|
+
is_genai_span,
|
|
35
|
+
is_known_llm_instrumentor,
|
|
36
|
+
is_aeri_span,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
Aeri = _client_module.Aeri
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"Aeri",
|
|
43
|
+
"get_client",
|
|
44
|
+
"observe",
|
|
45
|
+
"propagate_attributes",
|
|
46
|
+
"ObservationTypeLiteral",
|
|
47
|
+
"AeriSpan",
|
|
48
|
+
"AeriGeneration",
|
|
49
|
+
"AeriEvent",
|
|
50
|
+
"AeriOtelSpanAttributes",
|
|
51
|
+
"AeriAgent",
|
|
52
|
+
"AeriTool",
|
|
53
|
+
"AeriChain",
|
|
54
|
+
"AeriEmbedding",
|
|
55
|
+
"AeriEvaluator",
|
|
56
|
+
"AeriRetriever",
|
|
57
|
+
"AeriGuardrail",
|
|
58
|
+
"Evaluation",
|
|
59
|
+
"EvaluatorInputs",
|
|
60
|
+
"MapperFunction",
|
|
61
|
+
"CompositeEvaluatorFunction",
|
|
62
|
+
"EvaluatorStats",
|
|
63
|
+
"BatchEvaluationResumeToken",
|
|
64
|
+
"BatchEvaluationResult",
|
|
65
|
+
"is_default_export_span",
|
|
66
|
+
"is_aeri_span",
|
|
67
|
+
"is_genai_span",
|
|
68
|
+
"is_known_llm_instrumentor",
|
|
69
|
+
"KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES",
|
|
70
|
+
"experiment",
|
|
71
|
+
"api",
|
|
72
|
+
]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Pydantic V2 strict validation models for all public Aeri client entry-points.
|
|
2
|
+
|
|
3
|
+
Every payload that a caller passes to ``Aeri.start_observation``,
|
|
4
|
+
``Aeri.create_score``, or any other public method is validated through one of
|
|
5
|
+
these models *before* being passed deeper into the SDK.
|
|
6
|
+
|
|
7
|
+
Design choices
|
|
8
|
+
──────────────
|
|
9
|
+
• ``model_config = ConfigDict(strict=True)`` — rejects silent coercions (e.g.
|
|
10
|
+
"1" → 1) that can hide bugs in caller code.
|
|
11
|
+
• ``extra="forbid"`` — fails fast on unknown/misspelled fields.
|
|
12
|
+
• All fields that map to API concepts reuse the auto-generated Fern types (e.g.
|
|
13
|
+
``MapValue``, ``ScoreBody``) so there's a single source of truth.
|
|
14
|
+
• Validators use Annotated + Field constraints rather than ``@validator`` /
|
|
15
|
+
``@root_validator`` (Pydantic V1 patterns) for cleaner V2 semantics.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Annotated, Any, Dict, Literal, Optional, Union
|
|
22
|
+
|
|
23
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
24
|
+
|
|
25
|
+
from aeri._client.constants import (
|
|
26
|
+
ObservationTypeGenerationLike,
|
|
27
|
+
ObservationTypeLiteralNoEvent,
|
|
28
|
+
get_observation_types_list,
|
|
29
|
+
)
|
|
30
|
+
from aeri.api import MapValue, ScoreBody
|
|
31
|
+
from aeri.types import ScoreDataType, SpanLevel
|
|
32
|
+
|
|
33
|
+
# ─── Shared constraints ───────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
_NonEmptyStr = Annotated[str, Field(min_length=1)]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ─── Observation (span / generation / agent / tool …) ────────────────────────
|
|
39
|
+
|
|
40
|
+
class _GenerationFields(BaseModel):
|
|
41
|
+
"""Extra fields that only apply to generation-like observations."""
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(strict=True, extra="forbid")
|
|
44
|
+
|
|
45
|
+
completion_start_time: Optional[datetime] = None
|
|
46
|
+
model: Optional[str] = None
|
|
47
|
+
model_parameters: Optional[Dict[str, MapValue]] = None
|
|
48
|
+
usage_details: Optional[Dict[str, int]] = None
|
|
49
|
+
cost_details: Optional[Dict[str, float]] = None
|
|
50
|
+
prompt: Optional[Any] = None # PromptClient — avoid circular import
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ObservationInput(BaseModel):
|
|
54
|
+
"""Validated payload for ``Aeri.start_observation`` /
|
|
55
|
+
``Aeri.start_as_current_observation``."""
|
|
56
|
+
|
|
57
|
+
model_config = ConfigDict(strict=True, extra="forbid", populate_by_name=True)
|
|
58
|
+
|
|
59
|
+
name: _NonEmptyStr
|
|
60
|
+
as_type: ObservationTypeLiteralNoEvent = "span"
|
|
61
|
+
input: Optional[Any] = None
|
|
62
|
+
output: Optional[Any] = None
|
|
63
|
+
metadata: Optional[Any] = None
|
|
64
|
+
version: Optional[str] = None
|
|
65
|
+
level: Optional[SpanLevel] = None
|
|
66
|
+
status_message: Optional[str] = None
|
|
67
|
+
|
|
68
|
+
# Generation-only fields — allowed on any type but only forwarded when
|
|
69
|
+
# as_type is in ObservationTypeGenerationLike
|
|
70
|
+
completion_start_time: Optional[datetime] = None
|
|
71
|
+
model: Optional[str] = None
|
|
72
|
+
model_parameters: Optional[Dict[str, MapValue]] = None
|
|
73
|
+
usage_details: Optional[Dict[str, int]] = None
|
|
74
|
+
cost_details: Optional[Dict[str, float]] = None
|
|
75
|
+
prompt: Optional[Any] = None
|
|
76
|
+
|
|
77
|
+
@model_validator(mode="after")
|
|
78
|
+
def _warn_generation_fields_on_non_generation(self) -> "ObservationInput":
|
|
79
|
+
generation_types = get_observation_types_list(ObservationTypeGenerationLike)
|
|
80
|
+
if self.as_type not in generation_types:
|
|
81
|
+
gen_only = [
|
|
82
|
+
f
|
|
83
|
+
for f in ("completion_start_time", "model", "model_parameters",
|
|
84
|
+
"usage_details", "cost_details", "prompt")
|
|
85
|
+
if getattr(self, f) is not None
|
|
86
|
+
]
|
|
87
|
+
if gen_only:
|
|
88
|
+
import warnings
|
|
89
|
+
warnings.warn(
|
|
90
|
+
f"Fields {gen_only} are only meaningful for generation-like "
|
|
91
|
+
f"observations (as_type in {generation_types}), but "
|
|
92
|
+
f"as_type={self.as_type!r} was given. They will be ignored.",
|
|
93
|
+
stacklevel=4,
|
|
94
|
+
)
|
|
95
|
+
return self
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# ─── Score creation ───────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
class ScoreInput(BaseModel):
|
|
101
|
+
"""Validated payload for ``Aeri.create_score`` and the span ``.score()`` helpers."""
|
|
102
|
+
|
|
103
|
+
model_config = ConfigDict(strict=True, extra="forbid")
|
|
104
|
+
|
|
105
|
+
name: _NonEmptyStr
|
|
106
|
+
value: Union[float, int, bool, str]
|
|
107
|
+
data_type: Optional[ScoreDataType] = None
|
|
108
|
+
comment: Optional[str] = None
|
|
109
|
+
config_id: Optional[str] = None
|
|
110
|
+
trace_id: Optional[str] = None
|
|
111
|
+
observation_id: Optional[str] = None
|
|
112
|
+
|
|
113
|
+
@field_validator("value")
|
|
114
|
+
@classmethod
|
|
115
|
+
def _coerce_bool_to_int(cls, v: Any) -> Any:
|
|
116
|
+
# Preserve bool as-is; API handles BOOLEAN data_type separately
|
|
117
|
+
return v
|
|
118
|
+
|
|
119
|
+
@model_validator(mode="after")
|
|
120
|
+
def _validate_data_type_matches_value(self) -> "ScoreInput":
|
|
121
|
+
if self.data_type is None:
|
|
122
|
+
return self
|
|
123
|
+
# Numeric
|
|
124
|
+
if self.data_type == "NUMERIC" and not isinstance(self.value, (int, float)):
|
|
125
|
+
value_repr = repr(self.value)
|
|
126
|
+
msg = f"data_type='NUMERIC' requires a numeric value; got {value_repr!r}"
|
|
127
|
+
raise ValueError(msg)
|
|
128
|
+
# Boolean
|
|
129
|
+
if self.data_type == "BOOLEAN" and not isinstance(self.value, (bool, int)):
|
|
130
|
+
value_repr = repr(self.value)
|
|
131
|
+
msg = f"data_type='BOOLEAN' requires a bool/int value (0 or 1); got {value_repr!r}"
|
|
132
|
+
raise ValueError(msg)
|
|
133
|
+
# Categorical
|
|
134
|
+
if self.data_type == "CATEGORICAL" and not isinstance(self.value, str):
|
|
135
|
+
value_repr = repr(self.value)
|
|
136
|
+
msg = f"data_type='CATEGORICAL' requires a string value; got {value_repr!r}"
|
|
137
|
+
raise ValueError(msg)
|
|
138
|
+
return self
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# ─── Client constructor config ────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
class AeriClientConfig(BaseModel):
|
|
144
|
+
"""Validates all constructor parameters for the ``Aeri`` client.
|
|
145
|
+
|
|
146
|
+
This is applied in ``Aeri.__init__`` after environment variable resolution
|
|
147
|
+
so that misconfigured callers get a clear error immediately.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
model_config = ConfigDict(strict=False, extra="forbid") # lenient: coerce env strs
|
|
151
|
+
|
|
152
|
+
public_key: Optional[str] = None
|
|
153
|
+
secret_key: Optional[str] = None
|
|
154
|
+
base_url: str = "https://api.aeri.com"
|
|
155
|
+
timeout: int = Field(default=5, ge=1, le=300)
|
|
156
|
+
debug: bool = False
|
|
157
|
+
tracing_enabled: bool = True
|
|
158
|
+
flush_at: int = Field(default=15, ge=1, le=10_000)
|
|
159
|
+
flush_interval: float = Field(default=1.0, ge=0.1, le=3600.0)
|
|
160
|
+
environment: Optional[str] = None
|
|
161
|
+
release: Optional[str] = None
|
|
162
|
+
media_upload_thread_count: int = Field(default=1, ge=1, le=32)
|
|
163
|
+
sample_rate: float = Field(default=1.0, ge=0.0, le=1.0)
|
|
164
|
+
|
|
165
|
+
@field_validator("environment")
|
|
166
|
+
@classmethod
|
|
167
|
+
def _validate_environment_name(cls, v: Optional[str]) -> Optional[str]:
|
|
168
|
+
if v is None:
|
|
169
|
+
return v
|
|
170
|
+
if v.lower().startswith("aeri"):
|
|
171
|
+
msg = "environment name must not start with 'aeri'"
|
|
172
|
+
raise ValueError(msg)
|
|
173
|
+
import re
|
|
174
|
+
if not re.fullmatch(r"[a-z0-9_\-]+", v):
|
|
175
|
+
msg = (
|
|
176
|
+
f"environment must be lowercase alphanumeric with hyphens/underscores; "
|
|
177
|
+
f"got {v!r}"
|
|
178
|
+
)
|
|
179
|
+
raise ValueError(msg)
|
|
180
|
+
return v
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# ─── Trace context ────────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
class TraceContextInput(BaseModel):
|
|
186
|
+
"""Validates the ``trace_context`` dict passed to ``start_observation``."""
|
|
187
|
+
|
|
188
|
+
model_config = ConfigDict(strict=True, extra="forbid")
|
|
189
|
+
|
|
190
|
+
trace_id: Optional[str] = None
|
|
191
|
+
parent_span_id: Optional[str] = None
|
|
192
|
+
|
|
193
|
+
@field_validator("trace_id", "parent_span_id")
|
|
194
|
+
@classmethod
|
|
195
|
+
def _must_be_hex(cls, v: Optional[str], info: Any) -> Optional[str]:
|
|
196
|
+
if v is None:
|
|
197
|
+
return v
|
|
198
|
+
try:
|
|
199
|
+
int(v, 16)
|
|
200
|
+
except ValueError:
|
|
201
|
+
field_repr = repr(info.field_name)
|
|
202
|
+
msg = f"{field_repr} must be a hexadecimal string; got {v!r}"
|
|
203
|
+
raise ValueError(msg)
|
|
204
|
+
return v
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Span attribute management for Aeri OpenTelemetry integration.
|
|
2
|
+
|
|
3
|
+
This module defines constants and functions for managing OpenTelemetry span attributes
|
|
4
|
+
used by Aeri. It provides a structured approach to creating and manipulating
|
|
5
|
+
attributes for different span types (trace, span, generation) while ensuring consistency.
|
|
6
|
+
|
|
7
|
+
The module includes:
|
|
8
|
+
- Attribute name constants organized by category
|
|
9
|
+
- Functions to create attribute dictionaries for different entity types
|
|
10
|
+
- Utilities for serializing and processing attribute values
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from typing import Any, Dict, Literal, Optional, Union
|
|
16
|
+
|
|
17
|
+
from aeri._client.constants import (
|
|
18
|
+
ObservationTypeGenerationLike,
|
|
19
|
+
ObservationTypeSpanLike,
|
|
20
|
+
)
|
|
21
|
+
from aeri._utils.serializer import EventSerializer
|
|
22
|
+
from aeri.api import MapValue
|
|
23
|
+
from aeri.model import PromptClient
|
|
24
|
+
from aeri.types import SpanLevel
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AeriOtelSpanAttributes:
|
|
28
|
+
# Aeri-Trace attributes
|
|
29
|
+
TRACE_NAME = "aeri.trace.name"
|
|
30
|
+
TRACE_USER_ID = "user.id"
|
|
31
|
+
TRACE_SESSION_ID = "session.id"
|
|
32
|
+
TRACE_TAGS = "aeri.trace.tags"
|
|
33
|
+
TRACE_PUBLIC = "aeri.trace.public"
|
|
34
|
+
TRACE_METADATA = "aeri.trace.metadata"
|
|
35
|
+
TRACE_INPUT = "aeri.trace.input"
|
|
36
|
+
TRACE_OUTPUT = "aeri.trace.output"
|
|
37
|
+
|
|
38
|
+
# Aeri-observation attributes
|
|
39
|
+
OBSERVATION_TYPE = "aeri.observation.type"
|
|
40
|
+
OBSERVATION_METADATA = "aeri.observation.metadata"
|
|
41
|
+
OBSERVATION_LEVEL = "aeri.observation.level"
|
|
42
|
+
OBSERVATION_STATUS_MESSAGE = "aeri.observation.status_message"
|
|
43
|
+
OBSERVATION_INPUT = "aeri.observation.input"
|
|
44
|
+
OBSERVATION_OUTPUT = "aeri.observation.output"
|
|
45
|
+
|
|
46
|
+
# Aeri-observation of type Generation attributes
|
|
47
|
+
OBSERVATION_COMPLETION_START_TIME = "aeri.observation.completion_start_time"
|
|
48
|
+
OBSERVATION_MODEL = "aeri.observation.model.name"
|
|
49
|
+
OBSERVATION_MODEL_PARAMETERS = "aeri.observation.model.parameters"
|
|
50
|
+
OBSERVATION_USAGE_DETAILS = "aeri.observation.usage_details"
|
|
51
|
+
OBSERVATION_COST_DETAILS = "aeri.observation.cost_details"
|
|
52
|
+
OBSERVATION_PROMPT_NAME = "aeri.observation.prompt.name"
|
|
53
|
+
OBSERVATION_PROMPT_VERSION = "aeri.observation.prompt.version"
|
|
54
|
+
|
|
55
|
+
# General
|
|
56
|
+
ENVIRONMENT = "aeri.environment"
|
|
57
|
+
RELEASE = "aeri.release"
|
|
58
|
+
VERSION = "aeri.version"
|
|
59
|
+
|
|
60
|
+
# Internal
|
|
61
|
+
AS_ROOT = "aeri.internal.as_root"
|
|
62
|
+
|
|
63
|
+
# Experiments
|
|
64
|
+
EXPERIMENT_ID = "aeri.experiment.id"
|
|
65
|
+
EXPERIMENT_NAME = "aeri.experiment.name"
|
|
66
|
+
EXPERIMENT_DESCRIPTION = "aeri.experiment.description"
|
|
67
|
+
EXPERIMENT_METADATA = "aeri.experiment.metadata"
|
|
68
|
+
EXPERIMENT_DATASET_ID = "aeri.experiment.dataset.id"
|
|
69
|
+
EXPERIMENT_ITEM_ID = "aeri.experiment.item.id"
|
|
70
|
+
EXPERIMENT_ITEM_EXPECTED_OUTPUT = "aeri.experiment.item.expected_output"
|
|
71
|
+
EXPERIMENT_ITEM_METADATA = "aeri.experiment.item.metadata"
|
|
72
|
+
EXPERIMENT_ITEM_ROOT_OBSERVATION_ID = "aeri.experiment.item.root_observation_id"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def create_trace_attributes(
|
|
76
|
+
*,
|
|
77
|
+
input: Optional[Any] = None,
|
|
78
|
+
output: Optional[Any] = None,
|
|
79
|
+
public: Optional[bool] = None,
|
|
80
|
+
) -> dict:
|
|
81
|
+
attributes = {
|
|
82
|
+
AeriOtelSpanAttributes.TRACE_INPUT: _serialize(input),
|
|
83
|
+
AeriOtelSpanAttributes.TRACE_OUTPUT: _serialize(output),
|
|
84
|
+
AeriOtelSpanAttributes.TRACE_PUBLIC: public,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {k: v for k, v in attributes.items() if v is not None}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def create_span_attributes(
|
|
91
|
+
*,
|
|
92
|
+
metadata: Optional[Any] = None,
|
|
93
|
+
input: Optional[Any] = None,
|
|
94
|
+
output: Optional[Any] = None,
|
|
95
|
+
level: Optional[SpanLevel] = None,
|
|
96
|
+
status_message: Optional[str] = None,
|
|
97
|
+
version: Optional[str] = None,
|
|
98
|
+
observation_type: Optional[
|
|
99
|
+
Union[ObservationTypeSpanLike, Literal["event"]]
|
|
100
|
+
] = "span",
|
|
101
|
+
) -> dict:
|
|
102
|
+
attributes = {
|
|
103
|
+
AeriOtelSpanAttributes.OBSERVATION_TYPE: observation_type,
|
|
104
|
+
AeriOtelSpanAttributes.OBSERVATION_LEVEL: level,
|
|
105
|
+
AeriOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE: status_message,
|
|
106
|
+
AeriOtelSpanAttributes.VERSION: version,
|
|
107
|
+
AeriOtelSpanAttributes.OBSERVATION_INPUT: _serialize(input),
|
|
108
|
+
AeriOtelSpanAttributes.OBSERVATION_OUTPUT: _serialize(output),
|
|
109
|
+
**_flatten_and_serialize_metadata(metadata, "observation"),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {k: v for k, v in attributes.items() if v is not None}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def create_generation_attributes(
|
|
116
|
+
*,
|
|
117
|
+
name: Optional[str] = None,
|
|
118
|
+
completion_start_time: Optional[datetime] = None,
|
|
119
|
+
metadata: Optional[Any] = None,
|
|
120
|
+
level: Optional[SpanLevel] = None,
|
|
121
|
+
status_message: Optional[str] = None,
|
|
122
|
+
version: Optional[str] = None,
|
|
123
|
+
model: Optional[str] = None,
|
|
124
|
+
model_parameters: Optional[Dict[str, MapValue]] = None,
|
|
125
|
+
input: Optional[Any] = None,
|
|
126
|
+
output: Optional[Any] = None,
|
|
127
|
+
usage_details: Optional[Dict[str, int]] = None,
|
|
128
|
+
cost_details: Optional[Dict[str, float]] = None,
|
|
129
|
+
prompt: Optional[PromptClient] = None,
|
|
130
|
+
observation_type: Optional[ObservationTypeGenerationLike] = "generation",
|
|
131
|
+
) -> dict:
|
|
132
|
+
attributes = {
|
|
133
|
+
AeriOtelSpanAttributes.OBSERVATION_TYPE: observation_type,
|
|
134
|
+
AeriOtelSpanAttributes.OBSERVATION_LEVEL: level,
|
|
135
|
+
AeriOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE: status_message,
|
|
136
|
+
AeriOtelSpanAttributes.VERSION: version,
|
|
137
|
+
AeriOtelSpanAttributes.OBSERVATION_INPUT: _serialize(input),
|
|
138
|
+
AeriOtelSpanAttributes.OBSERVATION_OUTPUT: _serialize(output),
|
|
139
|
+
AeriOtelSpanAttributes.OBSERVATION_MODEL: model,
|
|
140
|
+
AeriOtelSpanAttributes.OBSERVATION_PROMPT_NAME: prompt.name
|
|
141
|
+
if prompt and not prompt.is_fallback
|
|
142
|
+
else None,
|
|
143
|
+
AeriOtelSpanAttributes.OBSERVATION_PROMPT_VERSION: prompt.version
|
|
144
|
+
if prompt and not prompt.is_fallback
|
|
145
|
+
else None,
|
|
146
|
+
AeriOtelSpanAttributes.OBSERVATION_USAGE_DETAILS: _serialize(usage_details),
|
|
147
|
+
AeriOtelSpanAttributes.OBSERVATION_COST_DETAILS: _serialize(cost_details),
|
|
148
|
+
AeriOtelSpanAttributes.OBSERVATION_COMPLETION_START_TIME: _serialize(
|
|
149
|
+
completion_start_time
|
|
150
|
+
),
|
|
151
|
+
AeriOtelSpanAttributes.OBSERVATION_MODEL_PARAMETERS: _serialize(
|
|
152
|
+
model_parameters
|
|
153
|
+
),
|
|
154
|
+
**_flatten_and_serialize_metadata(metadata, "observation"),
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {k: v for k, v in attributes.items() if v is not None}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _serialize(obj: Any) -> Optional[str]:
|
|
161
|
+
if obj is None or isinstance(obj, str):
|
|
162
|
+
return obj
|
|
163
|
+
|
|
164
|
+
return json.dumps(obj, cls=EventSerializer)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _flatten_and_serialize_metadata(
|
|
168
|
+
metadata: Any, type: Literal["observation", "trace"]
|
|
169
|
+
) -> dict:
|
|
170
|
+
prefix = (
|
|
171
|
+
AeriOtelSpanAttributes.OBSERVATION_METADATA
|
|
172
|
+
if type == "observation"
|
|
173
|
+
else AeriOtelSpanAttributes.TRACE_METADATA
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
metadata_attributes: Dict[str, Union[str, int, None]] = {}
|
|
177
|
+
|
|
178
|
+
if not isinstance(metadata, dict):
|
|
179
|
+
metadata_attributes[prefix] = _serialize(metadata)
|
|
180
|
+
else:
|
|
181
|
+
for key, value in metadata.items():
|
|
182
|
+
metadata_attributes[f"{prefix}.{key}"] = (
|
|
183
|
+
value
|
|
184
|
+
if isinstance(value, str) or isinstance(value, int)
|
|
185
|
+
else _serialize(value)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return metadata_attributes
|